--- phase: quick-260928-ujj plan: 01 quick_id: 260928-ujj status: complete subsystem: web, api, shared, docs tags: [design-mosaik, dashboard-background, prisma-migration, changelog, 1.5.0] requires: - design/mosaik (76d17fe) provides: - Design Mosaik auf main (Merge 9fa0a3f) - User.dashboardBackground (JSONB) + PATCH /users/me/dashboard-background - parseDashboardBackground / DASHBOARD_BACKGROUND_PRESET_IDS in @tessera/shared - CHANGELOG "Unveröffentlicht" mit Neu/Geändert/Behoben fuer 1.5.0 affects: - apps/web (115 Dateien aus dem Merge) - apps/api user/auth tech-stack: added: [] patterns: - "Gemeinsame Pruefregel in @tessera/shared, angewendet beim Schreiben (Controller) und Lesen (getMe)" - "Hook liest Benutzerwahl aus dem Auth-Store und speichert optimistisch ueber Server-Aktion mit Ruecksetzen" key-files: created: - apps/api/prisma/migrations/20260928120000_user_dashboard_background/migration.sql - apps/web/src/components/dashboard/dashboard-background.test.tsx modified: - packages/shared/src/index.ts - apps/api/prisma/schema.prisma - apps/api/src/auth/auth.service.ts - apps/api/src/auth/auth.service.spec.ts - apps/api/src/user/user.controller.ts - apps/api/src/user/user.controller.spec.ts - apps/web/src/lib/auth-actions.ts - apps/web/src/lib/stores/auth-store.ts - apps/web/src/components/layout/header.tsx - apps/web/src/components/layout/header.test.tsx - apps/web/src/lib/dashboard-background.ts - apps/web/src/lib/dashboard-background.test.ts - apps/web/src/components/dashboard/dashboard-background.tsx - apps/web/src/app/(portal)/page.tsx - apps/web/src/messages/de.json - apps/web/src/messages/en.json - docs/mandantentrennung-zugriffsklassifikation.md - docs/anleitung-anwender.md - docs/anleitung-entwicklung.md - CHANGELOG.md decisions: - "Dashboard-Hintergrund als JSONB-Spalte User.dashboardBackground; null = nie gewaehlt, { kind: 'none' } = bewusst kein Hintergrund" - "parseDashboardBackground in @tessera/shared ist die einzige Pruefregel (Allowlist kind/Preset, imageId nur UUID) fuer API-Schreiben, API-Lesen und Web-Altdatenuebernahme" - "Alter localStorage-Schluessel wird immer einmal gelesen und entfernt, uebernommen nur bei Server-Wert null" - "Biome: nur vom Merge neu eingebrachte Befunde behoben; vorbestehende Format-/Importbefunde (158 an der Basis) bleiben ausser Umfang" metrics: duration: 17min completed: 2026-09-28 estimate: tokens: 95000 tasks: 3 actuals: tokens: 95700 tasks: 3 commits: 17 plan_head_before: a8a910fd29cf6f2e4c3b228e2a71b2af226f39da plan_head_after: cb45d2663ac65954463e8c5a6bf859f73a555e86 --- # Quick 260928-ujj Plan 01: Design Mosaik uebernehmen und fuer 1.5.0 vorbereiten — Summary Design „Mosaik“ per `--no-ff`-Merge (zweiter Elternteil 76d17fe) auf main übernommen. Der Dashboard-Hintergrund wird jetzt pro Benutzer in `User.dashboardBackground` (JSONB) gespeichert: `PATCH /users/me/dashboard-background` prüft mit dem gemeinsamen `parseDashboardBackground`, und der Wert kommt zusammen mit `accentColor` über `getMe` zurück. Die alte Wahl aus dem localStorage wird einmal übernommen. CHANGELOG und beide Anleitungen sind für 1.5.0 vorbereitet. ## Commits | Task | Commit | Beschreibung | |------|--------|--------------| | 1 | 9fa0a3f | feat(260928-ujj): Design Mosaik uebernehmen (Merge, Eltern a8a910f + 76d17fe; bringt 12 Commits aus design/mosaik mit) | | 2 (RED) | 76f6d87 | test(260928-ujj): rote Tests fuer Dashboard-Hintergrund in der Datenbank | | 2 (GREEN) | 0aaa152 | feat(260928-ujj): Dashboard-Hintergrund pro Benutzer in der Datenbank | | 3 (Biome) | 69d1730 | fix(260928-ujj): Biome-Formatierung der mit Design Mosaik eingebrachten Dateien | | 3 | cb45d26 | docs(260928-ujj): CHANGELOG und Anleitungen fuer Design Mosaik | `commits: 17` wurde gemessen mit `git rev-list --count a8a910f..HEAD`. Die Zahl enthält die 12 Commits aus design/mosaik, die der Merge mitbringt. Auf der ersten Elternlinie stehen 5 eigene Commits. ## Verifikation - `git merge-base --is-ancestor 76d17fe HEAD`: erfolgreich. `RESIZE_AXIS_FALLBACK` steht in `dashboard-grid.tsx`. - Web-Tests (vitest 4.1.9): 97 Dateien, **952 Tests grün**. Direkt nach dem Merge waren es 96 Dateien und 940 Tests. - API-Tests (vitest 3.2.6): 85 Dateien, **1462 Tests grün**, einschließlich `rls-access-inventory.spec.ts`. - tsc: shared, api und web sind sauber. - Builds: `pnpm --filter api build` und `pnpm --filter web build` sind erfolgreich. - Biome bringt **keine neuen Fehler**. In den seit 3fc33e3 geänderten ts/tsx-Dateien standen an der Basis 158 Fehler, jetzt sind es 156. Alle verbleibenden Befunde bestanden schon vorher (84 format, 72 organizeImports in 93 Dateien). - Die Migration ist lokal eingespielt (`prisma migrate deploy` gegen 172.19.0.2). Die Spalte `dashboardBackground` hat den Typ jsonb. - Lokaler Stack neu gebaut mit `docker compose up -d --build api web`. Die API meldet die Route `Mapped {/users/me/dashboard-background, PATCH}`. Ein Aufruf ohne Anmeldung ergibt 401. - Nichts gepusht, kein Tag gesetzt, den live-Zweig nicht angefasst. `.planning/HANDOFF.json` ist weiter nur eine lokale Änderung und wurde nicht gestaged. ## Deviations from Plan ### Auto-fixed Issues **1. [Rule 3 - Blocking] Das Biome-Gate des Plans kann auf den geänderten Dateien nicht fehlerfrei werden** - **Found during:** Task 2 und Task 3 - **Issue:** Die Verify-Zeile `biome check $(git diff --name-only --diff-filter=AM 3fc33e3 HEAD ...)` endet mit Exit 1. Die 93 betroffenen Dateien hatten schon an der Basis 3fc33e3 zusammen 158 Format- und Importbefunde. - **Fix:** Ich habe nur die Befunde behoben, die der Merge neu eingebracht hat (12 Dateien, nur Formatierung und Importreihenfolge, eigener Commit 69d1730), dazu alle Befunde in den von mir geschriebenen Zeilen und neuen Dateien. Den Rest ganzer Dateien habe ich nicht umformatiert. Die Vorgabe des Auftraggebers („no new errors“) ist erfüllt: 158 → 156. - **Commit:** 69d1730 **2. [Rule 2 - Missing critical] Der alte localStorage-Schlüssel wird auch bei gesetztem Server-Wert aufgeräumt** - **Found during:** Task 2 - **Issue:** Nach Plan hätte bei gesetztem Server-Wert keine Übernahme stattgefunden, der alte Schlüssel wäre dann aber für immer liegen geblieben. - **Fix:** `takeLegacyDashboardBackground` wird je Benutzer einmal aufgerufen und entfernt den Schlüssel immer. Übernommen wird die alte Wahl nur, wenn der Server-Wert `null` ist. Ein Test deckt das ab. **3. [Rule 1 - Doc] Die Anwender-Anleitung war schon vor dem Merge an drei Stellen veraltet** - Die Seitenleiste zeigte bereits vorher keine Sprachumschaltung und keine Name/Rolle-Zeile mehr. Die Reiter standen seit 1.4.0 in der Kopfzeile. Der Stift-Schalter ist mit Mosaik zu „Bearbeiten“/„Fertig“ oben rechts geworden. Diese Stellen habe ich beim Nachziehen gegen den gemergten Code korrigiert. ### Nicht ausgeführt - **Browser-Prüfung per Playwright MCP** (Hintergrund wählen, neu laden, zweiter Browserkontext): In dieser Ausführungsumgebung gab es kein Playwright-MCP-Werkzeug. Ersatzweise habe ich den lokalen Stack neu gebaut und geprüft, dass die Route gemappt ist, ohne Anmeldung 401 liefert und die Spalte in der DB existiert. Die Prüfung über zwei Geräte im Browser steht noch aus. ## Hinweise - Eine Übernahme der alten Wahl, die fehlschlägt (z. B. wegen eines API-Ausfalls genau in dem Moment), geht verloren, weil der Schlüssel schon beim Lesen entfernt wird. Der Benutzer wählt dann einfach neu. Das ist bewusst so, damit die Übernahme garantiert nur einmal passiert. - Alte Prototyp-Werte mit einer Bildkennung, die keine UUID ist, werden nicht übernommen. Echte Bilderrahmen-Kennungen sind immer UUIDs. - Das Web liest `@tessera/shared` jetzt auch in `dashboard-background.ts` zur Laufzeit. `parseDashboardBackground` enthält nur löschbare Syntax (Regel aus dem Warnkommentar über `WIDGET_TYPES`). ## Threat Flags Keine über das Threat-Register hinaus. T-ujj-01 und T-ujj-02 sind wie geplant umgesetzt: Allowlist und UUID-Prüfung beim Schreiben und Lesen, `forTenant` mit `where id = currentUser.id`, kein Kennungsparameter. ## Self-Check: PASSED - FOUND: apps/api/prisma/migrations/20260928120000_user_dashboard_background/migration.sql - FOUND: apps/web/src/components/dashboard/dashboard-background.test.tsx - FOUND commits: 9fa0a3f, 76f6d87, 0aaa152, 69d1730, cb45d26