Re-verified every BATCH finding from docs/audit-polish-2026-04-27.md against the post-PR-B/D/E + palette + firm-name codebase. - 18 OBSOLETE (already shipped via t-paliad-060/061/062/063/064/065). - 26 KEEP — bundled into PR-1 (i18n leak sweep + activity log), PR-2 (visual residue + small per-page polish), PR-3 (tab/chip/notes-hint consistency). - 1 RESCOPED (F-20 colour fixed by palette sweep, structural rule consolidation still pending). - 7 DEFER — design-call or redesign-class items (F-23, F-25, F-32, F-38, F-40, F-48, F-49). Top-5 user-visible items ranked: F-07 dashboard activity narrative, F-15 red archive button, F-04 raw i18n key on /deadlines/new, F-12 AKTE column header (rename residue), F-13 appointments AKTE cell collision. DESIGN-READY GATE — head reviews before any coder shift.
260 lines
17 KiB
Markdown
260 lines
17 KiB
Markdown
# 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 `<th data-i18n="fristen.col.akte">Akte</th>` / `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 `<span class="frist-project-title">` 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 `<a href="/checklists">` 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 `<a className="btn-cancel" data-i18n="projekte.cancel">Abbrechen</a>`. |
|
||
| 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 `<option value="client">Mandant</option>` 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 `<main>` (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.<slug>` 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 `<a>`.
|
||
- 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 `<option value="" disabled selected>` /
|
||
`Bitte wählen…` first row in `ProjectFormFields.tsx:18`.
|
||
- F-39 (search counter format) — match flat ("11 / 11") to tree view, or
|
||
the other way, by editing the tree-view counter.
|
||
- F-42 (deadlines AKTE wrapping) — same CSS rename as F-13 + `text-overflow:
|
||
ellipsis` on `.frist-project-title` with a `title=` for the full text.
|
||
- F-43 (parties empty state) — add an empty-state CTA card with a "Partei
|
||
hinzufügen" call.
|
||
- F-47 (settings placeholder mixed) — pick all-DE or all-EN; one i18n edit.
|
||
- F-50 (mobile bottom-nav overlap) — `<main>` `padding-bottom: var(--bottom-nav-h)`
|
||
at `<768px`.
|
||
|
||
**Risk:** low. Each change is local; the only cross-cutting bit is the F-13
|
||
+ F-42 CSS rename, but the class is referenced in exactly two TS files.
|
||
|
||
### PR-3 — visual consistency: tabs + chips + Notiz hint 🟡
|
||
|
||
Single concern: harmonization that touches several pages with one change
|
||
each.
|
||
|
||
**Includes:** F-16, F-20, F-37.
|
||
|
||
- F-16 (type pill saturated colors) — neutralize to a single chip background
|
||
with the type icon for differentiation; reserve color-as-signal for the
|
||
*Mandant* root (or for `/admin/team` STANDORT). Touches `global.css:4089-4093`
|
||
+ `admin-team.tsx` chip render.
|
||
- F-20 (tab styling) — collapse the three active-tab rules
|
||
(`.akten-tab.active`, `.login-tab.active`, `.gebuehren-tab.active`) to one
|
||
shared style. Could simply make the two minority rules `@extend` the
|
||
canonical lime-underline + midnight-text + 600-weight pattern.
|
||
- F-37 (Notiz textarea hint) — small footer line under the textarea with
|
||
"Strg+Enter zum Speichern" (DE) / "Cmd+Enter to save" (EN).
|
||
|
||
**Risk:** medium. Tab rule consolidation is the riskiest edit in the
|
||
backlog — it touches every `.login-tab` and `.gebuehren-tab` consumer
|
||
(login page + Gebührentabellen page). Verify both visually post-edit.
|
||
The chip change is visually larger but lower risk because the saturated
|
||
colors carry no behaviour.
|
||
|
||
---
|
||
|
||
## Top 5 — what m notices first on Monday morning
|
||
|
||
1. **F-07 — Dashboard activity log English event types.** The activity
|
||
widget is on the landing page, every login. Reading "Test Tester
|
||
project_type_changed" or "Note zu deadline hinzugefügt" makes the app
|
||
feel half-baked in 30 seconds. Sibling F-21 lives on the project Verlauf
|
||
tab (next-most-read). High visibility, medium effort.
|
||
2. **F-15 — "Projekt archivieren" red button.** Wrong affordance changes
|
||
user behaviour: real lawyers will hesitate to archive routine matters
|
||
because "red = scary". Trivial fix, biggest behaviour delta.
|
||
3. **F-04 — Raw `fristen.field.project.choose` key on /deadlines/new.**
|
||
Visible, plainly broken text in a primary form. One-line fix.
|
||
4. **F-12 — AKTE column header on /deadlines and /appointments.** The
|
||
filter dropdown was renamed to "Projekt" in PR-D; the *column header* still
|
||
says "Akte" in the same row. Side-by-side inconsistency screams "rename
|
||
half-done". Trivial.
|
||
5. **F-13 — `L-2026-001Siemens AG ./.` collision on /appointments AKTE
|
||
cell.** Looks like a data-corruption bug at first glance. Caused by a
|
||
single CSS class rename that was missed; one-line fix.
|
||
|
||
(All five fit in PR-1 + PR-2 above. Recommend shipping those two first.)
|
||
|
||
### Honourable mentions (#6–10)
|
||
|
||
6. F-46 (Good day → Hello) — one-line warmth fix on EN dashboard.
|
||
7. F-29 (empty-state link not real) — feels broken when you click the word
|
||
and nothing happens.
|
||
8. F-16 (type pill saturated colors) — calmer chip palette makes /projects
|
||
feel less alarming.
|
||
9. F-35 (subtitle taxonomy "Fälle") — small but visible on /projects intro.
|
||
10. F-50 (mobile bottom-nav overlap on dashboard) — only mobile, but
|
||
immediately visible to anyone on a phone.
|
||
|
||
---
|
||
|
||
## Defer list
|
||
|
||
Findings where polish-2 isn't the right scope — either they need a design
|
||
call, span a redesign-class change, or carry low value-per-effort.
|
||
|
||
- **F-23** — STATUS column noise. Hiding when single-valued is a usability
|
||
call (some users like the redundancy). Defer to a "table density" pass.
|
||
- **F-25** — Mobile tables → card layout. Genuine redesign across four
|
||
pages. Should be its own t-task with screenshots and an alignment
|
||
pass on the mobile pattern. Out of scope for "polish".
|
||
- **F-32** — Agenda redundant urgency pill. After the day-bucket redesign,
|
||
the pill *can* still differ from the bucket (e.g. an overdue item under
|
||
HEUTE). Keeping it is defensible; design call before changing.
|
||
- **F-38** — Bottom-nav agenda badge semantics. Needs to match the agenda
|
||
redesign decision; tackle there.
|
||
- **F-40** — Glossary chip language (EN/DE mix). Product decision (m).
|
||
- **F-48** — `/sub-projects` URL alias. The canonical `/children` works;
|
||
guessable-URL-alias is low value. Document the canonical path instead.
|
||
- **F-49** — Already DEFER in original audit (meta-circular changelog
|
||
entry).
|
||
|
||
---
|
||
|
||
## Recommendation summary
|
||
|
||
- Ship **PR-1** (i18n leak sweep + activity log narrative) first — biggest
|
||
user-visible delta, contains 3 of the top-5.
|
||
- Ship **PR-2** (small visual residue) right after — low-risk, high
|
||
per-edit value, contains the other 2 top-5 items + F-46 / F-50.
|
||
- **PR-3** (tab + chip consistency) is worthwhile but riskier; OK to land
|
||
after PR-1/PR-2 stabilize. Leave for later in the week or punt to a
|
||
separate t-task if velocity is constrained.
|
||
- **DEFER list** to a later "design-pass" or "mobile-pass" task; do not
|
||
bundle them with these PRs.
|
||
|
||
## Acceptance
|
||
|
||
- [x] Every BATCH finding (F-01..F-50) classified KEEP / OBSOLETE /
|
||
RESCOPED / DEFER against current code state.
|
||
- [x] Keeps grouped into 3 PR bundles with effort + risk + finding IDs.
|
||
- [x] Top 5 ranked with rationale.
|
||
- [x] Defer list with reason per item.
|
||
- [ ] Head greenlights individual PRs before any coder shift.
|