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.
17 KiB
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 —
langattr 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-labelblocks → 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 inclient/deadlines.tsonly. Optional follow-up: backfillfristen.rule.<slug>keys. - F-12 (AKTE column header) — flip
fristen.col.akteandtermine.col.akteto "Projekt" / "Matter" (DE/EN), plus thedata-i18nattribute label. - F-21 ("Deadline updated" in Verlauf) — same shape as F-07; one Go edit
(
deadline_service.go:306title → 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 inprojects.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 introducebtn-archivewith neutral/outline styling). Modal confirm button stays red. - F-24 (mobile filter row wrapping) —
/projectsfilter container CSS:flex-direction: column+align-items: stretchat<480px; each filter as its own labelled block. - F-27 (single-child breadcrumb) —
renderBreadcrumbearly-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-refand.agenda-item-project. - F-36 (Mandant default) — add a
<option value="" disabled selected>/Bitte wählen…first row inProjectFormFields.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: ellipsison.frist-project-titlewith atitle=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/teamSTANDORT). Touchesglobal.css:4089-4093admin-team.tsxchip 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@extendthe 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
- 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.
- 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.
- F-04 — Raw
fristen.field.project.choosekey on /deadlines/new. Visible, plainly broken text in a primary form. One-line fix. - 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.
- 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)
- F-46 (Good day → Hello) — one-line warmth fix on EN dashboard.
- F-29 (empty-state link not real) — feels broken when you click the word and nothing happens.
- F-16 (type pill saturated colors) — calmer chip palette makes /projects feel less alarming.
- F-35 (subtitle taxonomy "Fälle") — small but visible on /projects intro.
- 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-projectsURL alias. The canonical/childrenworks; 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
- Every BATCH finding (F-01..F-50) classified KEEP / OBSOLETE / RESCOPED / DEFER against current code state.
- Keeps grouped into 3 PR bundles with effort + risk + finding IDs.
- Top 5 ranked with rationale.
- Defer list with reason per item.
- Head greenlights individual PRs before any coder shift.