# Paliad Polish Audit — Triage 2 — 2026-04-29
**Source audit:** `docs/audit-polish-2026-04-27.md` (50 findings, 41 screenshots).
**Method:** for every BATCH-tagged finding, re-verified against the current
codebase (post-PRs B/D/E + the brand palette sweep + firm-name sweep).
**Goal:** mark each finding KEEP / OBSOLETE / RESCOPED / DEFER, group the keeps
into 2–3 ship-ready PRs, and rank what m would notice first on Monday morning.
**What already shipped since the original audit:**
- t-paliad-060 (PR-B): F-05, F-06 — `lang` attr on date/time inputs.
- t-paliad-061 (PR-D): F-11, F-17, F-18, F-19, F-26, F-44, F-45.
- t-paliad-062 (PR-E): F-02, F-03, F-08, F-09.
- t-paliad-063 (palette): F-14, F-30, F-31 (explicitly superseded per commit).
- t-paliad-064 (reminder redesign): the new settings UI uses inline-flex
`caldav-toggle-label` blocks → incidentally fixes F-22.
- t-paliad-065 (firm-name): F-01.
- Pre-audit (t-paliad-049 modal/breadcrumb polish): /projects/new already has
a Cancel button (`btn-cancel`) → F-34 OBSOLETE.
---
## Verification table
| ID | Status | Notes |
|---|---|---|
| F-01 | OBSOLETE | Stripped by t-paliad-065 firm sweep. Curl of `/` and `/login` shows only "Paliad" + "HLC". |
| F-02 | OBSOLETE | t-paliad-062 (search input padding). |
| F-03 | OBSOLETE | t-paliad-062 (migration 024 column rename). |
| F-04 | KEEP | `frontend/src/client/deadlines-new.ts:45` still references `fristen.field.project.choose`; `i18n.ts` only has `fristen.field.akte.choose` → renders raw key. Either rename in deadlines-new.ts to `fristen.field.akte.choose`, or add the new key. |
| F-05 | OBSOLETE | t-paliad-060. |
| F-06 | OBSOLETE | t-paliad-060. |
| F-07 | KEEP | `internal/services/project_service.go:625` emits `project_type_changed` with English title "Project type changed"; description embeds raw English values (`case → litigation`). Dashboard activity widget renders these verbatim. Plus mixed-language nouns ("Note zu deadline hinzugefügt"). Same class as the t-paliad-037 sweep but for newer events. |
| F-08 | OBSOLETE | t-paliad-062. |
| F-09 | OBSOLETE | t-paliad-062. |
| F-10 | KEEP | The `inf.rejoin` raw slug renders because client-side rule lookup falls through when no matching rule label exists. Need a missing-rule label fallback (display "—" or a humanized variant) and/or i18n key for known catalog slugs. |
| F-11 | OBSOLETE | t-paliad-061. |
| F-12 | KEEP | `frontend/src/deadlines.tsx:101` and `frontend/src/appointments.tsx:101` still ship `
Akte | ` / `termine.col.akte`; i18n.ts L541/1043 still maps to "Akte". PR-D fixed the *filter* dropdown; the *column header* was deliberately left for PR-A which never ran. |
| F-13 | KEEP | `client/appointments.ts:153` and `client/deadlines.ts:197` render `` but `global.css:4716` only styles `.frist-akte-title { display: block; }` — class-name mismatch from the rename → ref + title render inline → "L-2026-001Siemens AG ./." collision. Trivial: rename the CSS or the markup. |
| F-14 | OBSOLETE | t-paliad-063 (palette sweep). |
| F-15 | KEEP | `projects-detail.tsx:334` still uses `className="btn-danger"` (red `#dc2626`) for the "Projekt archivieren" button. The destructive-modal confirm action also uses `btn-danger`, which is fine — it's the entry-point button on the working surface that screams. |
| F-16 | KEEP | `global.css:4089-4093` still ships saturated random colors per type chip (`akten-type-client` lavender, `akten-type-litigation` pink-red, `akten-type-patent` cyan, `akten-type-case` salmon, `akten-type-project` neutral-green). Same classes drive `/projects` and `/admin/team`. |
| F-17 | OBSOLETE | t-paliad-061. |
| F-18 | OBSOLETE | t-paliad-061. |
| F-19 | OBSOLETE | t-paliad-061. |
| F-20 | RESCOPED | Palette sweep harmonized the *colour* (every active tab now points at `--hlc-lime`), but the structural inconsistency remains: `.akten-tab.active` uses `font-weight: 600` + midnight text, while `.login-tab.active` and `.gebuehren-tab.active` use accent-coloured text. Drop to one rule. |
| F-21 | KEEP | `internal/services/deadline_service.go:306` still inserts events with title `"Deadline updated"` (English, in DE narrative on /projects/{id}/history). Same fix lane as F-07. |
| F-22 | OBSOLETE | t-paliad-064 PR-3/4 introduced `caldav-toggle-label` (`display: inline-flex`, `gap: 0.5rem`) for every checkbox row — labels and checkboxes are now adjacent. |
| F-23 | DEFER | Hiding STATUS when single-valued is a design call (some users like the redundancy as a trust signal). Punt to a later "table density" pass. |
| F-24 | KEEP | Mobile filter row still stacks awkwardly. Single-page CSS fix on `/projects` (and adjacent `/deadlines`/`/appointments`). |
| F-25 | DEFER | Card-layout-on-mobile is a design refactor, not a polish edit. Spans `/projects`, `/deadlines`, `/appointments`, `/admin/team`. Out of scope for polish-2; flag as a standalone t-task. |
| F-26 | OBSOLETE | t-paliad-061. |
| F-27 | KEEP | `client/projects-detail.ts:1143` always renders the breadcrumb; no path-depth check. One conditional in `renderBreadcrumb()`. |
| F-28 | KEEP | Cell empty-placeholder is split: `/admin/team` and `/projects/{id}/deadlines` use "—"; `/projects` (REFERENZ, CLIENTMATTER) and `/appointments` (ORT) render blank. Pick one and grep for empty-cell renders. |
| F-29 | KEEP | TSX has a real `` but `i18n.ts` strings (L949/2190) ship plain text "…unter Checklisten angelegt." On runtime translation, the anchor disappears. Fix: store the link in i18n with a placeholder (`{link}`) and substitute at render, or render two strings and inject the anchor. |
| F-30 | OBSOLETE | t-paliad-063 sidebar reskin. |
| F-31 | OBSOLETE | t-paliad-063 (button restyle). |
| F-32 | DEFER | The agenda was redesigned (day-bucket section headings now exist). The per-card urgency pill is still rendered, but it now carries information *only* when the urgency disagrees with the bucket (e.g. an "Überfällig" item appearing under HEUTE). Keeping it is defensible. Mark as design-call, not polish. |
| F-33 | KEEP | One `title=` attribute per project-ref render in `dashboard.ts` and `agenda.ts`. Trivial. |
| F-34 | OBSOLETE | `projects-new.tsx:46` already ships `Abbrechen`. |
| F-35 | KEEP | `projects.tsx:34` + `i18n.ts:844` still read "Mandanten, Streitsachen, Patente und Fälle …". Actual taxonomy is Mandant / Streitsache / Patent / Verfahren / Projekt. Replace "Fälle" → "Verfahren" (and possibly mention "Projekte"). |
| F-36 | KEEP | `ProjectFormFields.tsx:19` still ships `` first → implicit default. Switch to a "Bitte wählen…" placeholder option, or default to `case`. |
| F-37 | KEEP | `client/notes.ts` textarea has no Strg+Enter / Cmd+Enter hint, no character counter, no markdown hint. Add a small footer line. |
| F-38 | DEFER | Bottom-nav badge semantics is a design decision — needs to match the agenda urgency definition. Tackle alongside any future agenda-redesign task. |
| F-39 | KEEP | Tree view shows "11" while flat shows "11 / 11"; pick one format. One client edit. |
| F-40 | DEFER | Glossary chip language ("Litigation" / "Prosecution" vs "Allgemein") is a product decision, not a polish fix. m to call. |
| F-41 | OBSOLETE | Was tagged OK in the audit. |
| F-42 | KEEP | Same fix as F-13 (`frist-project-title` CSS class) plus a monospace ref pill style + ellipsis on title. Bundle with F-13. |
| F-43 | KEEP | Empty state on `/projects/{id}/parties` is a single line — add an empty-state CTA card (matches the pattern used elsewhere). |
| F-44 | OBSOLETE | t-paliad-061. |
| F-45 | OBSOLETE | t-paliad-061. |
| F-46 | KEEP | `i18n.ts:1906` still maps `dashboard.greeting.prefix` to "Good day". Change to "Hello" (or "Hi"). One-line. |
| F-47 | KEEP | `/settings` profile placeholder "z.B. Associate, Partner, PA" still mixed EN/DE in i18n. One-line. |
| F-48 | DEFER | `/projects/{id}/sub-projects` would 404, but the canonical `/children` URL works and tabs auto-resolve to it. Aliasing is low-value; flag the canonical path in docs instead. |
| F-49 | DEFER | Tagged DEFER in original audit. |
| F-50 | KEEP | One CSS rule on `` (or `body`) — bottom-padding equal to bottom-nav height on `<768px`. |
**Summary:** 18 OBSOLETE (already shipped), 26 KEEP, 1 RESCOPED (F-20), 7 DEFER (F-23, F-25, F-32, F-38, F-40, F-48, F-49). The KEEP set is the polish-2 backlog.
---
## PR plan — 3 bundles
### PR-1 — i18n leak sweep + activity log narrative 🟡
Single concern: text rendered to a German narrative that's still English or
raw-keyed. Ship as one PR — they're touched in adjacent files and the
reviewer can verify them together by walking the dashboard and the activity
tab.
**Includes:** F-04, F-07, F-10, F-12, F-21, F-29, F-35, F-46.
- F-04 (deadlines-new picker key) — i18n key add or rename. *Pure i18n.ts.*
- F-07 (dashboard activity event types + narrative nouns) — needs three
edits: (a) Go service-side, switch event titles from "Project type changed"
/ "Note added to deadline" to neutral identifiers; (b) i18n.ts add
`dashboard.action.project_type_changed`, `…note_added`, etc.; (c) frontend
dashboard renderer translates the event_type and the dynamic values
(`case` → t("projekte.type.case")) before joining into the narrative.
*This is the only Go-side change in the bundle.*
- F-10 (raw `inf.rejoin`) — frontend rule-label lookup falls back to "—"
when no label exists; can be done in `client/deadlines.ts` only. Optional
follow-up: backfill `fristen.rule.` keys.
- F-12 (AKTE column header) — flip `fristen.col.akte` and `termine.col.akte`
to "Projekt" / "Matter" (DE/EN), plus the `data-i18n` attribute label.
- F-21 ("Deadline updated" in Verlauf) — same shape as F-07; one Go edit
(`deadline_service.go:306` title → neutral identifier) plus i18n key add.
- F-29 (checklists empty-state link) — store the empty-state copy as two
i18n strings or a `{link}` placeholder; render with a real ``.
- F-35 (subtitle taxonomy) — flip "Fälle" → "Verfahren" in
`projekte.subtitle` (DE+EN) and the SSR fallback in `projects.tsx:34`.
- F-46 (Good day) — one-line i18n change.
**Risk:** medium. Go-side event-emission edits need a smoke test of the
activity feed (dashboard widget + project Verlauf tab) post-deploy. Existing
events in the DB carry the *old* English titles — the renderer should
translate the event_type, not the stored title (so historical rows benefit
too). Worth calling out explicitly in the PR description.
### PR-2 — visual residue + small per-page polish 🟢
Single concern: small CSS/markup edits, mostly self-contained per page.
**Includes:** F-13, F-15, F-24, F-27, F-28, F-33, F-36, F-39, F-42, F-43,
F-47, F-50.
- F-13 (appointments AKTE collision) — rename CSS rule
`.frist-akte-title` → `.frist-project-title` (or add the new selector).
Same rule fixes F-42 partially.
- F-15 (red archive button) — change `className="btn-danger"` →
`btn-secondary` (or introduce `btn-archive` with neutral/outline styling).
Modal confirm button stays red.
- F-24 (mobile filter row wrapping) — `/projects` filter container CSS:
`flex-direction: column` + `align-items: stretch` at `<480px`; each
filter as its own labelled block.
- F-27 (single-child breadcrumb) — `renderBreadcrumb` early-return when
the chain has length ≤ 1.
- F-28 (placeholder consistency) — grep cell renderers; render "—" for
empty REFERENZ, CLIENTMATTER, ORT, REGEL, WEITERE STANDORTE.
- F-33 (truncated ref tooltip) — `title=` attr on
`.dashboard-upcoming-project-ref` and `.agenda-item-project`.
- F-36 (Mandant default) — add a `