feat(t-paliad-073): audit polish-2 DEFER cleanup (F-23/32/38/40/48/49) #1

Merged
mAi merged 1 commits from mai/ritchie/audit-polish-2-defer into main 2026-04-30 00:31:06 +00:00
Collaborator

Summary

Six small DEFER findings from docs/audit-polish-2-2026-04-29.md shipped as one PR. All low-risk visual / wiring polish, no architectural changes. F-25 (mobile tables → card layout) is redesign-class and is scoped at the bottom of this description as t-paliad-074, not implemented here.

Findings shipped

  • F-23 — STATUS column on /deadlines + /projects is hidden when every visible row shares the same status. Toggle is a CSS class on the table that flips at every render; the column re-appears the moment filters re-introduce variety, so the header is never permanently removed from the DOM.
  • F-32 — Per-card urgency pill on /agenda now renders only when it disagrees with the day-bucket heading. Computed expectedUrgency(bucket.day) mirrors the server's bucketing rule. Common case (a "Heute" item under HEUTE, a "Diese Woche" item under "in 3 Tagen") drops the redundant tag; outliers (e.g. an Überfällig deadline that landed in today's bucket through a filter quirk) still show the pill so the disagreement reads clearly.
  • F-38/api/deadlines/summary already returned a today bucket and the badge code already summed overdue + today (option (b) per brief). Added a localized title= + aria-label so a "2" badge on the bottom-nav now reads as "X überfällig + Y heute fällig" (DE) / "X overdue + Y due today" (EN) instead of an opaque number.
  • F-40glossar.filter.litigation / glossar.filter.prosecution keys translated for DE: "Streitsachen" / "Erteilungsverfahren". EN keeps "Litigation" / "Prosecution". Same keys also wired through the Suggest-modal <select> so the language stays consistent across the chip row and the category dropdown.
  • F-48/projects/{id}/sub-projects now 301-redirects to the canonical /projects/{id}/children. Added via a small parameterised redirect on the outer mux in redirects.go; new redirects_test.go locks the alias in (preserves query string).
  • F-49 — Dropped the 2026-04-22 "Neuigkeiten / What's New" changelog entry that referenced "this changelog" itself. Tests in changelog/changelog_test.go are length-agnostic and stay green.

Verification

  • go build ./... && go vet ./... && go test ./... — clean
  • cd frontend && bun run build — clean (branding: firm="HLC", all bundles emitted)
  • redirects_test.go covers /projects/abc-123/sub-projects/projects/abc-123/children (with and without query string)

Test plan

  • After merge + Dokploy redeploy, smoke as tester@hlc.de on paliad.de:
    • /deadlines with default filter (pending) → STATUS column hidden; switch filter to "Alle offen & erledigt" with mixed rows → column re-appears
    • /projects with all-statuses filter and at least one archived/closed project → column visible; filter to a single status → column hidden
    • /agenda HEUTE bucket: "Heute"-urgency items have no pill; an overdue item that lands in HEUTE keeps its pill
    • Mobile bottom-nav agenda badge: hover (or focus-visible on touch devices) shows the localized "X überfällig + Y heute fällig" tooltip
    • /glossary DE: chips read "Streitsachen / Erteilungsverfahren / Allgemein"; switch to EN → "Litigation / Prosecution / General"; suggest modal category dropdown matches
    • curl -i https://paliad.de/projects/<some-id>/sub-projects → 301 to /children
    • /changelog no longer leads with the meta-circular "Neuigkeiten / What's New" entry; first entry is the 2026-04-20 settings card

Coordination

t-paliad-069 is a separate worker on internal/services/reminder_service.go. No file overlap with this PR — merge order does not matter.

Self-merge

Authorized by the task brief.


Follow-up: t-paliad-074 — Mobile tables → card layout (F-25, scope only)

Brief for head to file as a standalone task once this PR lands. Below ~640px, four pages render data tables that overflow horizontally and force the user to scroll: /projects, /deadlines, /appointments, /admin/team. The right fix is a card layout — each row collapses into a stacked card with the most important fields up top.

Today's table structure → card layout migration per page

  • /projects (frontend/src/projects.tsx + client/projects.ts)

    • Table cols: TITEL · TYP · REFERENZ · CLIENTMATTER · STATUS · ZULETZT GEÄNDERT
    • Card target: title as headline, type-chip + reference as sub-line, ClientMatter as a small tag, status-chip top-right (subject to F-23 hide-when-single rule), updated-at as a footer time. Tappable card → /projects/{id}.
  • /deadlines (frontend/src/deadlines.tsx + client/deadlines.ts)

    • Table cols: ✓ · FÄLLIG · TITEL · PROJEKT · REGEL · STATUS
    • Card target: due date with traffic-light dot as headline, title below, project ref + title as sub-line, rule label as a small tag, status-chip top-right (F-23 hide rule), checkbox as a top-right action. Tappable card body → /deadlines/{id}; checkbox stays a hit-target.
  • /appointments (frontend/src/appointments.tsx + client/appointments.ts)

    • Table cols: WANN · TITEL · ART · ORT · PROJEKT
    • Card target: date+time as headline, title below, type-chip + location as sub-line, project ref+title as footer link.
  • /admin/team (frontend/src/admin-team.tsx + client/admin-team.ts)

    • Table cols: NAME · E-MAIL · BÜRO · ROLLE · STATUS · LETZTER LOGIN · …actions
    • Card target: name as headline, email below as muted line, office-chip + role-chip as sub-line, status as a small tag, last login + admin actions in a card footer (edit modal trigger remains tappable).

Shared CSS plan

  • New utility class .card-row (or .mobile-card) with companion .card-row-headline, .card-row-sub, .card-row-meta, .card-row-footer blocks.
  • Below ~640px breakpoint, hide .akten-table-wrap / .fristen-table-wrap / .admin-team-table / .appointments-table and reveal a <ul class="card-row-list"> rendered alongside.
  • Both renderers share the same data source, so the JS just emits both the <table> rows and a <ul> of cards from the same filtered array — CSS picks which is visible. No server-side knowledge of viewport needed; everything stays one HTML payload.
  • Bottom-nav clearance (F-50) already lives on <main>; no extra padding needed.

Test plan

  • Desktop (≥ 1024px): tables render exactly as today, no card output visible.
  • Tablet (768–1023px): tables render with horizontal scroll suppressed via existing overflow-x: auto — unchanged.
  • Mobile (≤ 640px): cards render, table is display: none. Tap targets ≥ 44px. Headline truncation respects existing ellipsis rules. Sort/filter/search continue to drive both renderers.
  • Accessibility: each card is a <li role="link"> or wraps <a> so screen readers announce a single tappable region; status chips and action buttons keep their aria-labels.
  • Smoke: walk the four pages on a 375×812 viewport (Pixel 7 / iPhone 13) plus a 768×1024 (iPad) to confirm the breakpoint splits cleanly.
## Summary Six small DEFER findings from `docs/audit-polish-2-2026-04-29.md` shipped as one PR. All low-risk visual / wiring polish, no architectural changes. F-25 (mobile tables → card layout) is redesign-class and is scoped at the bottom of this description as **t-paliad-074**, not implemented here. ### Findings shipped - **F-23** — STATUS column on `/deadlines` + `/projects` is hidden when every visible row shares the same status. Toggle is a CSS class on the table that flips at every render; the column re-appears the moment filters re-introduce variety, so the header is never permanently removed from the DOM. - **F-32** — Per-card urgency pill on `/agenda` now renders only when it disagrees with the day-bucket heading. Computed `expectedUrgency(bucket.day)` mirrors the server's bucketing rule. Common case (a "Heute" item under HEUTE, a "Diese Woche" item under "in 3 Tagen") drops the redundant tag; outliers (e.g. an Überfällig deadline that landed in today's bucket through a filter quirk) still show the pill so the disagreement reads clearly. - **F-38** — `/api/deadlines/summary` already returned a `today` bucket and the badge code already summed `overdue + today` (option (b) per brief). Added a localized `title=` + `aria-label` so a "2" badge on the bottom-nav now reads as `"X überfällig + Y heute fällig"` (DE) / `"X overdue + Y due today"` (EN) instead of an opaque number. - **F-40** — `glossar.filter.litigation` / `glossar.filter.prosecution` keys translated for DE: `"Streitsachen"` / `"Erteilungsverfahren"`. EN keeps `"Litigation"` / `"Prosecution"`. Same keys also wired through the Suggest-modal `<select>` so the language stays consistent across the chip row and the category dropdown. - **F-48** — `/projects/{id}/sub-projects` now 301-redirects to the canonical `/projects/{id}/children`. Added via a small parameterised redirect on the outer mux in `redirects.go`; new `redirects_test.go` locks the alias in (preserves query string). - **F-49** — Dropped the 2026-04-22 "Neuigkeiten / What's New" changelog entry that referenced "this changelog" itself. Tests in `changelog/changelog_test.go` are length-agnostic and stay green. ### Verification - `go build ./... && go vet ./... && go test ./...` — clean - `cd frontend && bun run build` — clean (`branding: firm="HLC"`, all bundles emitted) - `redirects_test.go` covers `/projects/abc-123/sub-projects` → `/projects/abc-123/children` (with and without query string) ### Test plan - [ ] After merge + Dokploy redeploy, smoke as `tester@hlc.de` on paliad.de: - [ ] `/deadlines` with default filter (`pending`) → STATUS column hidden; switch filter to "Alle offen & erledigt" with mixed rows → column re-appears - [ ] `/projects` with all-statuses filter and at least one archived/closed project → column visible; filter to a single status → column hidden - [ ] `/agenda` HEUTE bucket: "Heute"-urgency items have no pill; an overdue item that lands in HEUTE keeps its pill - [ ] Mobile bottom-nav agenda badge: hover (or focus-visible on touch devices) shows the localized "X überfällig + Y heute fällig" tooltip - [ ] `/glossary` DE: chips read "Streitsachen / Erteilungsverfahren / Allgemein"; switch to EN → "Litigation / Prosecution / General"; suggest modal category dropdown matches - [ ] `curl -i https://paliad.de/projects/<some-id>/sub-projects` → 301 to `/children` - [ ] `/changelog` no longer leads with the meta-circular "Neuigkeiten / What's New" entry; first entry is the 2026-04-20 settings card ### Coordination t-paliad-069 is a separate worker on `internal/services/reminder_service.go`. No file overlap with this PR — merge order does not matter. ### Self-merge Authorized by the task brief. --- ## Follow-up: t-paliad-074 — Mobile tables → card layout (F-25, scope only) Brief for head to file as a standalone task once this PR lands. Below ~640px, four pages render data tables that overflow horizontally and force the user to scroll: `/projects`, `/deadlines`, `/appointments`, `/admin/team`. The right fix is a card layout — each row collapses into a stacked card with the most important fields up top. ### Today's table structure → card layout migration per page - **`/projects`** (`frontend/src/projects.tsx` + `client/projects.ts`) - Table cols: TITEL · TYP · REFERENZ · CLIENTMATTER · STATUS · ZULETZT GEÄNDERT - Card target: title as headline, type-chip + reference as sub-line, ClientMatter as a small tag, status-chip top-right (subject to F-23 hide-when-single rule), updated-at as a footer time. Tappable card → `/projects/{id}`. - **`/deadlines`** (`frontend/src/deadlines.tsx` + `client/deadlines.ts`) - Table cols: ✓ · FÄLLIG · TITEL · PROJEKT · REGEL · STATUS - Card target: due date with traffic-light dot as headline, title below, project ref + title as sub-line, rule label as a small tag, status-chip top-right (F-23 hide rule), checkbox as a top-right action. Tappable card body → `/deadlines/{id}`; checkbox stays a hit-target. - **`/appointments`** (`frontend/src/appointments.tsx` + `client/appointments.ts`) - Table cols: WANN · TITEL · ART · ORT · PROJEKT - Card target: date+time as headline, title below, type-chip + location as sub-line, project ref+title as footer link. - **`/admin/team`** (`frontend/src/admin-team.tsx` + `client/admin-team.ts`) - Table cols: NAME · E-MAIL · BÜRO · ROLLE · STATUS · LETZTER LOGIN · …actions - Card target: name as headline, email below as muted line, office-chip + role-chip as sub-line, status as a small tag, last login + admin actions in a card footer (edit modal trigger remains tappable). ### Shared CSS plan - New utility class `.card-row` (or `.mobile-card`) with companion `.card-row-headline`, `.card-row-sub`, `.card-row-meta`, `.card-row-footer` blocks. - Below `~640px` breakpoint, hide `.akten-table-wrap` / `.fristen-table-wrap` / `.admin-team-table` / `.appointments-table` and reveal a `<ul class="card-row-list">` rendered alongside. - Both renderers share the same data source, so the JS just emits both the `<table>` rows and a `<ul>` of cards from the same `filtered` array — CSS picks which is visible. No server-side knowledge of viewport needed; everything stays one HTML payload. - Bottom-nav clearance (F-50) already lives on `<main>`; no extra padding needed. ### Test plan - Desktop (≥ 1024px): tables render exactly as today, no card output visible. - Tablet (768–1023px): tables render with horizontal scroll suppressed via existing `overflow-x: auto` — unchanged. - Mobile (≤ 640px): cards render, table is `display: none`. Tap targets ≥ 44px. Headline truncation respects existing ellipsis rules. Sort/filter/search continue to drive both renderers. - Accessibility: each card is a `<li role="link">` or wraps `<a>` so screen readers announce a single tappable region; status chips and action buttons keep their `aria-label`s. - Smoke: walk the four pages on a 375×812 viewport (Pixel 7 / iPhone 13) plus a 768×1024 (iPad) to confirm the breakpoint splits cleanly.
mAi added 1 commit 2026-04-30 00:30:49 +00:00
Six findings from docs/audit-polish-2-2026-04-29.md DEFER list:

- F-23: hide STATUS column on /deadlines + /projects when every visible
  row shares the same status. Toggled at render time via a CSS class on
  the table; the column re-appears the moment filters re-introduce
  variety.
- F-32: agenda urgency pill now renders only when it disagrees with
  the day-bucket heading (e.g. an Überfällig deadline that lands in
  HEUTE through a filter quirk). Common case drops the redundant tag.
- F-38: bottom-nav agenda badge already counted overdue+today (the
  brief's option (b)); added a localized title + aria-label so the
  count's semantics ("X überfällig + Y heute fällig") is no longer
  ambiguous.
- F-40: glossary filter chips no longer mix EN+DE — DE shows
  "Streitsachen / Erteilungsverfahren / Allgemein", EN keeps
  "Litigation / Prosecution / General". Same i18n keys cover the
  Suggest-modal category dropdown.
- F-48: /projects/{id}/sub-projects now 301-redirects to the canonical
  /children URL via the existing redirects.go mechanism. Added a small
  redirects_test.go to lock the alias in.
- F-49: dropped the meta-circular 2026-04-22 "Neuigkeiten / What's New"
  changelog entry that referenced "this changelog" itself.

go build/vet/test clean, bun run build clean.

F-25 (mobile tables → card layout) is redesign-class and is scoped at
the bottom of the PR description as t-paliad-074, not implemented here.
mAi merged commit 2c67299740 into main 2026-04-30 00:31:06 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: m/paliad#1
No description provided.