Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018N9CD3ebPKm1b32bPpBknY
31 KiB
phase, plan, subsystem, tags, requires, provides, affects, actuals, plan_head_before, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, coverage, duration, completed, status
| phase | plan | subsystem | tags | requires | provides | affects | actuals | plan_head_before | tech-stack | key-files | key-decisions | patterns-established | requirements-completed | coverage | duration | completed | status | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| quick-260916-bwo | 01 | ui, dashboard |
|
|
|
|
|
50f201ecc1 |
|
|
|
|
|
|
18 min (07:04Z bis 07:22Z, davon ca. 4 min Suiten-Laeufe und 5,5 min CI-Beobachtung) | 2026-09-16 | complete |
Quick 260916-bwo Plan 01: Dashboard — feineres Raster, skalierende Widget-Inhalte, halbe Abstaende — Summary
Das Dashboard-Raster ist doppelt so fein (24 statt 12 Spalten, 20 statt 40 px Zeilenhoehe, 8 statt 16 px Abstand) bei optisch gleich grossen Widgets (alle 32 Konstanten in WIDGET_CONSTRAINTS verdoppelt und im Test festgenagelt); gespeicherte Anordnungen in alten Einheiten werden beim Laden GENAU EINMAL mit 2 multipliziert und mit __gridVersion: 2 im gespeicherten JSON markiert (reine Funktion migrateGridLayouts, Marker nie im Zustand, Idempotenz-Test); der Widget-Rumpf ist ein CSS-Groessen-Container, sodass Uhrzeit, Stoppuhr-Anzeige und Rechner (Anzeige und Tasten) per cqw/cqh mit der Kachel wachsen; die Uhrzeit laesst sich unter Einstellungen -> Dashboard -> Uhr in Punkt fest einstellen (8..200, leer = automatisch, Fremdwerte fallen auf automatisch zurueck, T-BWO-01); Seitenrahmen (app-shell.tsx, alle Seiten), Dashboard-Container, Grid-Abstand und Widget-Innenabstaende sind halbiert. Vier Commits auf main (3f5afb0, 2d8efe1, a175c00, 1aefaa3), gepusht, CI-Lauf 351 success in 5 min 26 s, api:beta traegt 1aefaa3 beta.
Ausgangslage und Bezugspunkt
Alle Gates gegen 5f50c5f (Code unangetastet seit Planung; HEAD bei Start 50f201e = Plan-Commit, Arbeitsbaum sauber). git status -sb bei Start: ## main...origin/main [voraus 2] — die beiden Plan-Commits des Orchestrators (7eb2516, 50f201e) waren noch nicht gepusht; sie gingen mit dem Push in Task 3 mit (5f50c5f..1aefaa3). Vorbedingung Task 3: curl localhost:3002/api/v1/version -> {"version":"1.26.2"}, docker ps | grep -c '^gitea-runner$' -> 1.
Baseline vor jeder Aenderung (frisch gemessen, identisch mit der Planung):
| Suite | Vorher | Nachher (Ziel des Plans) |
|---|---|---|
Web pnpm -C apps/web exec vitest run |
Test Files 43 passed (43) / Tests 260 passed (260) |
Test Files 46 passed (46) / Tests 286 passed (286) |
API pnpm -C apps/api exec vitest run |
Test Files 67 passed (67) / Tests 1076 passed (1076) |
Test Files 67 passed (67) / Tests 1078 passed (1078) |
tsc --noEmit shared / api / web |
0 / 0 / 0 | 0 / 0 / 0 |
Bestand an Anordnungen (nur lesend, docker exec tessera-ctl-db-1 psql -U tessera -d tessera -At): lokal DashboardLayout 0, WidgetInstance 0 (erneut gemessen 07:19Z); alpha 0/0 laut Planung (nicht erneut gemessen); live nicht gemessen — die Umrechnung bleibt Pflicht.
Task 1 — Raster verdoppelt, Umrechnung, Store, API-Durchreich-Specs (3f5afb0, 9 Dateien)
RED (Schritt A) pnpm -C apps/web exec vitest run src/lib/grid-layout-migration.test.ts src/lib/stores/dashboard-store.test.ts src/components/dashboard:
FAIL src/lib/grid-layout-migration.test.ts — Failed to resolve import "./grid-layout-migration"
× dashboard-store Test 1: expected { i: 'a', x: 1, y: 1, w: 2, h: 2 } to deeply equal { i: 'a', x: 2, y: 2, w: 4, h: 4 }
× dashboard-store Test 2: expected [ 'lg', 'md', 'sm', 'xs', 'xxs', …(1) ] to not include '__gridVersion'
× dashboard-store Test 4: expected "vi.fn()" to be called with arguments: [ ObjectContaining{…} ]
× dashboard-store Test 5: expected 1 to be 2
× dashboard-store Test 6: expected [ { i: 'n1', x: +0, y: +0, …(2) } ] to deep equally contain { i: 'n1', x: +0, y: +0, w: 4, h: 4 }
× dashboard-grid Test 4: expected { Object (lg, md, ...) } to deeply equal { lg: 24, md: 20, sm: 12, xs: 8, …(1) }
× dashboard-grid Test 5: expected { x: +0, y: +0, w: 2, h: 2, …(2) } to deeply equal { x: +0, y: +0, w: 4, h: 4, …(2) }
× widget-registry Tabelle: expected { …(8) } to deeply equal { …(8) }
Test Files 4 failed | 8 passed (12)
Tests 8 failed | 55 passed (63)
(Store-Test 3 „leer -> kein Speichern“ war nach altem Code bereits gruen — erwartbar, alter Code speicherte beim Laden nie.)
API-Spec (+2) pnpm -C apps/api exec vitest run src/dashboard/dashboard.service.spec.ts -> Test Files 1 passed (1) / Tests 31 passed (31) (vorher 29 it(-Bloecke). Beide neuen Tests waren nach heutigem Code sofort gruen — das ist der Beleg der Durchreichung (@IsObject(), return record.layouts, { ...widget.config, ...dto.config }), kein RED.
GREEN (Schritt E) und Verify-Block:
Web (4 Dateien): Test Files 4 passed (4) / Tests 29 passed (29)
API: Test Files 1 passed (1) / Tests 31 passed (31)
greps: COLS 1, rowHeight 1, margin 1, clock 1, search 1, calculator 1, withGridVersion( 2, migrateGridLayouts( 1, GRID_VERSION 1
U_EXIT=0 U_EMPTY=0 (dashboard.service.ts, dto/, prisma/ unangetastet)
TSC_web=0 TSC_api=0
Messung widerspricht dem Plan (beide festgehalten): Der Plan nennt fuer die vier Web-Dateien Tests 22 passed (22) („5 + 4 + 7 + 6“); gemessen 29. Ursache: widget-registry.test.tsx hatte vorher 10 Testfaelle (1 + it.each ueber 8 Typen + 1), der Plan zaehlte 3 it(-Bloecke. Mit +1 sind es 11 (pnpm -C apps/web exec vitest run src/components/dashboard/widget-registry.test.tsx -> Tests 11 passed (11)): 5 + 11 + 7 + 6 = 29. Die Zielzahl der Gesamtsuite (260 + 26 = 286) ist davon nicht betroffen und wurde exakt erreicht.
Task 2 — Teil 2a: Skalierung, Punktgroesse, i18n (2d8efe1, 12 Dateien)
RED (Schritt A) pnpm -C apps/web exec vitest run src/components/dashboard/widgets src/components/settings/widget-settings-panel.test.tsx:
FAIL src/components/dashboard/widgets/clock-widget.test.tsx — Failed to resolve import "./clock-font-size"
× stopwatch quick-260916-bwo: expected 'font-mono font-semibold tabular-nums …' to match /cqw/
× calculator quick-260916-bwo: expected 'flex min-h-[2.5rem] items-end justify…' to match /cqw/
× widget-settings-panel Test 1-4: It looks like undefined was passed instead of a matcher (de.widgets.clock.fontSizeLabel fehlte noch)
Test Files 4 failed | 5 passed (9)
Tests 6 failed | 39 passed (45)
GREEN (Schritt H) ... src/components/dashboard/widgets src/components/settings/widget-settings-panel.test.tsx src/messages -> Test Files 11 passed (11) / Tests 57 passed (57); je Datei: clock 6, stopwatch 8, calculator 7, widget-settings-panel 4, src/messages 6 (Umlaut-Waechter und tenderRadar-Paritaet gruen OHNE Aenderung an umlaut-dictionary.ts); TSC_web=0.
Messung widerspricht dem Plan (beide festgehalten): Der Plan nennt fuer Commit 2a „genau 11 Dateien“, zaehlt in Klammern aber 12 auf (widget-wrapper, clock-font-size, clock + Test, stopwatch + Test, calculator + Test, widget-settings-panel + Test, de.json, en.json). git show --stat 2d8efe1 -> 12 files changed. 9 + 12 + 7 + 1 = 29 stimmt mit der Gesamtzahl des Plans ueberein; die „11“ ist ein Zaehlfehler des Plans, nicht des Commits.
Task 2 — Teil 2b: Abstaende halbiert (a175c00, 7 Dateien)
Tabelle aus dem Plan eins zu eins umgesetzt (link 238 p-1, favorites 174 p-1, calendar 112 p-1.5 und 80/91/102 p-2, search 89 px-1.5, note 89 px-1.5 py-1.5, page.tsx relative p-2 / right-2 top-2 / mt-8 bleibt mit Kommentar, app-shell main p-3 mit Kommentar).
Verify-Block Task 2 (volle Web-Suite und 29 greps):
Test Files 46 passed (46) / Tests 286 passed (286)
@container-size 2 | Uhr-Klasse 1 | data-font-mode 1 | vw clock 0 | vw stopwatch 0 | cqw stopwatch 1 | cqw calculator 5 | h-full min-h-7 1
MIN 1 | MAX 1 | id=clock-font-size 1 | fontSizeLabel de 1 | fontSizeInvalid en 1 | D2_EXIT=0 DICT_UNCHANGED=0
relative p-2 1 | right-2 top-2 1 | "mt-8" 1 | app-shell p-3 2 | app-shell " p-6" 0 (nach Korrektur, s. Abweichung 2)
link 1 | favorites 1 | calendar Rumpf 1 | calendar Zustandsansichten 3 | search 1 | note 1 | clock 1 | stopwatch 1 | calculator 1 | TSC_web=0
Task 3 — Handbuch, Abschluss-Gates, Push, CI (1aefaa3, 1 Datei)
grep -c "Schriftgröße" docs/anleitung-anwender.md -> 2; grep -c "feinen Schritten" -> 1.
Abschluss-Gates (nach dem Handbuch, vor dem Commit):
Web: Test Files 46 passed (46) / Tests 286 passed (286)
API: Test Files 67 passed (67) / Tests 1078 passed (1078)
TSC_packages/shared=0 TSC_apps/api=0 TSC_apps/web=0
FROZEN=0 (pnpm install --frozen-lockfile)
GIT_EXIT=0 29 files changed, 895 insertions(+), 60 deletions(-) (git diff --stat 5f50c5f -- . ':!.planning')
U_EXIT=0 U_EMPTY=0 (.env*, Compose, Lockfile, package.json, prisma, dashboard.service.ts, dto/, globals.css unangetastet)
Push 07:15:03Z: 5f50c5f..1aefaa3 main -> main; git fetch -q && git status -sb | head -1 -> ## main...origin/main (kein [ahead, kein [behind).
CI-Lauf nach dem Push
| Feld | Versuch 1 (einziger) |
|---|---|
| Lauf-ID | 351 (event push, ref main, head_sha 1aefaa36c1e3ae7c3055e714b059223a1e5aff77) |
| status / conclusion | completed / success |
| started_at / completed_at | 09:15:08 / 09:20:34 (+02:00) — 5 min 26 s (17 Polls a 20 s, kein Warten in der Warteschlange: der Lauf war beim ersten Poll 11 s nach dem Push bereits in_progress) |
| Jobs | Lint & Type Check success (07:15:08-07:15:57Z), Tests success (07:16:00-07:16:57Z), Build & Publish Images success (07:16:59-07:20:33Z) |
api:beta node APP_VERSION APP_CHANNEL APP_COMMIT |
v1.0.0-10-g1aefaa3 beta 1aefaa3 — Messinstrument-Befund: der Plan erwartet fuer APP_VERSION den „kurzen SHA“; seit dem Tag v1.0.0 (260915) liefert git describe v1.0.0-10-g1aefaa3, der kurze SHA steht in APP_COMMIT = 1aefaa3 = git rev-parse --short HEAD. Beide Werte sind das erwartete Abbild des gepushten Stands |
docker image inspect Created web:beta / api:beta |
2026-09-16T09:18:31+02:00 / 2026-09-16T09:19:29+02:00 (nach dem Lauf-Start; fuer die Probe wurde api:beta per docker pull geholt, kein Container gebaut oder gestartet) |
Falsifizierungen (a)-(c) — rot/gruen
Jede einmal durchgefuehrt, Rueckstellung per git checkout -- <Datei>, danach git status --porcelain leer.
| Falsifizierung | Eingriff | Rot (Testnamen woertlich) | Zurueckgesetzt |
|---|---|---|---|
| (a) Marker-Pruefung entfernt | grid-layout-migration.ts: const needsScaling = true; |
`Tests 4 failed | 9 passed (13)`: Migration „Test 2: markierte Anordnung (__gridVersion 2) bleibt unveraendert, migrated false“, „Test 4: Idempotenz — einmal umgerechnet und markiert wird nicht erneut verdoppelt (T-BWO-02)“, „Test 6: Zukunft und Robustheit …“; Store „Test 2: markierte Anordnung bleibt unveraendert, kein Speichern, kein Marker im Zustand“ |
(b) resolveClockTimeFontSizePt ohne Typpruefung |
clock-font-size.ts: const value = Number(config.timeFontSizePt) |
`Tests 2 failed | 4 passed (6): „Test 3 (quick-260916-bwo): resolveClockTimeFontSizePt laesst nur endliche Zahlen 8..200 durch (T-BWO-01)“ (expected 36 to be null), „Test 6 (quick-260916-bwo): Zeichenketten-Wert wird ignoriert — auto, kein Inline-Style (T-BWO-01)“ (expected '36pt' to be '') — genau der Angriff: '36'` wuerde zum Style |
| (c1) eine Konstante auf den alten Wert | widget-registry.tsx: clock.minW: 2 |
`Tests 2 failed | 14 passed (16)`: „quick-260916-bwo: jede Groesse ist exakt das Doppelte der alten 12-Spalten-Werte“, dashboard-grid „quick-260916-bwo Test 5: Widget ohne gespeicherten Eintrag bekommt die verdoppelten Vorgaben als data-grid“ |
(c2) rowHeight auf 40 |
dashboard-grid.tsx |
`Tests 1 failed | 4 passed (5)`: „quick-260916-bwo Test 4: Grid-Props — 24/20/12/8/2 Spalten, rowHeight 20, margin 8, Breakpoints unveraendert, containerPadding folgt dem margin“ |
Gemessene Befunde und Entscheidungen (Kurzform)
- jsdom 29.1.1 / cssstyle (Planungsmessung, in der Ausfuehrung durch die Tests bestaetigt):
style.fontSize = 'clamp(...)'wird verworfen (''),'36pt'bleibt. Folge: automatische Groessen als Tailwind-Klassen (text-[clamp(12px,min(20cqw,50cqh),400px)]usw.), feste Punktgroesse als Inline-Style; Tests lesenclassName,data-font-modeundstyle.fontSize— Test 5/6 der Uhr laufen exakt so gruen. - Tailwind 4.3.1 (Planungsmessung):
@container-size->container-type: size;text-[clamp(12px,min(20cqw,50cqh),400px)]kompiliert mit verschachtelten Funktionen. Alle Klassen stehen woertlich im JSX bzw. als String-Literale in derselben Datei (Scanner). Nicht erneut kompiliert — der Browser-Nachweis prueft das Ergebnis. - Umrechnung im Frontend (siehe key-decisions): Einheiten sind Frontend-Konstanten; die API reicht durch (Spec Test A/B pinnen es); kein Schreiben auf GET; reine Funktion ohne Prisma testbar. Preis: bis zum ersten gelungenen PUT rechnet jedes Laden erneut aus den unveraenderten alten DB-Werten — korrekt, weil
saveLayoutMarker und Werte immer gemeinsam schreibt. mt-8bleibt: Umschalterp-2+ 20-px-Symbol = 36 px, mittop-2bei 8..44 px; erstes Widget mitmt-8bei 8+32+8 = 48 px (4 px Abstand), mitmt-4bei 32 px (12 px IM Umschalter). Kommentar inpage.tsx.- Annahme „Listen-Widgets skalieren nicht“: note, calendar, favorites, link, search behalten ihre Schriftgroessen — bei mehr Platz zeigen sie mehr Inhalt. Nur ihre Aussen-Innenabstaende sind halbiert.
- Beobachtung: Das
ClockConfig-Formular traegt weiterhin ein hart englisches Label „Timezone“ und die Zeile „Saving...“ (ausserhalb des Auftrags, unveraendert). Ebenso „Title“ im Notiz-Formular und der englische Kalender-Hinweis. - Rechner-Speicherzeile (
h-7 text-xs) bleibt bewusst klein; die Tasten fuellen ihre Rasterzelle (h-full min-h-7), damit das 4x5-Raster mitwaechst.
Task Commits
- Task 1: Raster, Umrechnung, Store, API-Specs —
3f5afb0(feat) — 9 Dateien - Task 2a: Skalierung, Punktgroesse, i18n —
2d8efe1(feat) — 12 Dateien - Task 2b: Abstaende halbiert —
a175c00(feat) — 7 Dateien - Task 3: Anwenderhandbuch —
1aefaa3(docs) — 1 Datei
commits: 4 gemessen aus git rev-list --count 50f201e..HEAD (Ledger plan_head_before = 50f201ecc1292232ff96e13226b62386cfc36e76). actuals.tokens = 291.763 Zeichen ueber die 29 geaenderten Dateien / 4 = 72.941 (Methode wie 260914-m97; der reine Diff waere 65.872 Zeichen = 16.468). Der Plan schaetzte 120.000 bei confidence: low.
git log --oneline 50f201e..HEAD (vor dem SUMMARY, 07:21Z):
1aefaa3 docs(quick-260916-bwo): Anwenderhandbuch — feines Raster, Uhrzeit skaliert mit der Kachel, Schriftgroesse in Punkt
a175c00 feat(quick-260916-bwo): Abstaende halbiert — Seitenrahmen p-3 (alle Seiten), Dashboard p-2, Grid 8 px, Widget-Innenabstaende
2d8efe1 feat(quick-260916-bwo): Widget-Inhalt skaliert per Container-Queries (Uhr, Stoppuhr, Rechner), Punktgroesse der Uhrzeit einstellbar
3f5afb0 feat(quick-260916-bwo): Dashboard-Raster verdoppelt (24 Spalten, 20 px, 8 px Abstand), Konstanten x2, einmalige Umrechnung gespeicherter Anordnungen mit Marker __gridVersion
git status --porcelain (vor dem SUMMARY): leer. git status -sb | head -1: ## main...origin/main.
Deviations from Plan
Auto-fixed Issues
1. [Rule 3 - Blocking] Versehentliches git stash waehrend Task 1, sofort zurueckgeholt
- Found during: Task 1, zwischen GREEN-Lauf und Commit
- Issue: In einem Messbefehl (Zaehlen der Registry-Testfaelle) lief ein
git stash -qmit, das die sechs geaenderten, noch nicht committeten Dateien instash@{0}verschob (die drei neuen Dateien blieben als unversioniert liegen). Die Stash-Liste war vor Beginn leer (geprueft), der einzige Eintrag war mein eigener auf HEAD50f201e; kein Worktree, keine Nebenlaeufer. - Fix:
git stash pop(Ausgabe: alle sechs Dateien wieder geaendert,refs/stash@{0} … geloescht), Stash-Liste danach leer; Inhalt per grep und erneutem Testlauf (Test Files 4 passed (4)/Tests 29 passed (29)) bestaetigt, dann erst committet. - Files modified: keine (Wiederherstellung des Arbeitsbaums)
- Commit: — (
3f5afb0enthaelt den unveraenderten Stand)
2. [Rule 1 - Bug] Gate grep -c " p-6" in app-shell.tsx musste 0 sein, lieferte 1
- Found during: Task 2b, Verify-Block
- Issue: Die Klasse
p-6war korrekt durchp-3ersetzt, aber mein neuer JSX-Kommentar enthielt wörtlich „statt p-6 (24 px)“ und traf das Muster. - Fix: Kommentar umformuliert („statt vorher 24 px (Stufe 6)“); Gate danach
0,p-3weiterhin2(Kommentar + Klasse), tsc 0. Innerhalb der Allowlist, vor dem Commit 2b. - Files modified:
apps/web/src/components/layout/app-shell.tsx - Commit:
a175c00
Messungen, die dem Plan widersprechen (beide Zahlen oben festgehalten)
- Task 1 Web-Vitest-Zeile: Plan
22, gemessen29—it.eachueber 8 Typen inwidget-registry.test.tsx(Plan zaehlteit(-Bloecke). Gesamtsuite 286 wie geplant. - Commit 2a: Plan „11 Dateien“, gemessen
12— der Plan listet selbst 12 auf; 9 + 12 + 7 + 1 = 29 stimmt. - Abbild-Probe: Plan „
APP_VERSION-> kurzer SHA“, gemessenv1.0.0-10-g1aefaa3(git describeseit dem Tag v1.0.0); der kurze SHA1aefaa3steht inAPP_COMMIT.
Was bewusst offen bleibt
- Browser-Nachweis (Bounding-Boxen, Rasterstufe, Skalierung, Punktgroesse, SQL-Probe der Umrechnung, Rechner bei Mindestgroesse): nicht im Executor moeglich (jsdom rechnet keine Container-Queries, keine Container gebaut) — Human-Check
end-of-phase, Anleitung unten. - Rechner bei Mindestgroesse (4x8 = 8 Zeilen x 20 px + 7 x 8 px = 216 px): Der Plan nennt den heutigen Ueberlauf bei alter Mindestgroesse; ob der Rechner mit
h-full min-h-7-Tasten (5 x 28 px = 140 px + Anzeige 40 + Speicherzeile 28 + Luecken ca. 24 = ca. 232 px) bei 216 px bedienbar bleibt, ist im Browser zu messen (Punkt 7 unten). Faellt er durch, ist die Rueckfalloption des Plans „nur die Anzeige skalieren“ — vorher messen. - Hart englische Texte im Einstellungsformular („Timezone“, „Saving...“, „Title“, Kalender-Hinweis): ausserhalb des Auftrags, unveraendert.
- Marker-Persistenz bei dauerhaft scheiterndem PUT: bis zum ersten gelungenen Speichern rechnet jedes Laden erneut aus den alten DB-Werten (korrekt, aber jedes Laden loest einen PUT-Versuch aus,
console.errorje Versuch). - Live (
tessera.ctl.de): Bestand nicht gemessen; nach dem naechsten Deploy rechnet jeder Benutzer seine Anordnung beim ersten Laden selbst um.
Fuer den Verifizierer/Orchestrator (Browser-Nachweis)
Vorher docker compose up -d --build web (Web-Abbild vom 14.09.; up allein baut nicht neu). Die API braucht keinen Neubau. Anmelden mit Benutzername admin, Kennwort admin123. Alle Bounding-Boxen per Playwright boundingBox(), nie per fetch aus der Seite.
- Anordnung anlegen: Dashboard -> „Dashboard bearbeiten“ -> Uhr und Suchleiste hinzufuegen, Uhr rechts neben die Suchleiste ziehen, Bearbeitungsmodus beenden (speichert).
- Abstaende:
main.app-shell-mainlinks vs. erstes[data-widget-id]links -> 28 px (+/-1; vorher 56); zwei horizontal benachbarte Widgets -> Luecke 8 px (+/-1; vorher 16);mainoben vs. erstes Widget -> 60 px (+/-1; vorher 88). Zweite Seite/admin/users:main-Rand zum ersten Inhaltselement 12 px (vorher 24). - Raster: Uhr im Bearbeitungsmodus um EINE Stufe nach rechts ziehen -> Versatz eine Spaltenbreite
(Containerbreite - 8*23 - 8*2) / 24px (bei 1200 px ca. 41 px, vorher ca. 83 px). - Skalierung: Uhr auf 12x8 vergroessern ->
getComputedStyle(time).fontSizedeutlich groesser als bei 4x4 (Zahlen notieren; Erwartung 4x4 ca. 38-42 px, 12x8 ca. 80+ px); verkleinern -> schrumpft;time.dataset.fontMode === 'auto'. Istcqh0 (Uhr unsichtbar klein), fehlt die definite Hoehe — dannwidget-wrapper.tsxpruefen (Rumpfh-fullin der Karteh-full). - Punktgroesse: Einstellungen -> Dashboard -> Widgets, „Uhr #1“ aufklappen, „Schriftgröße der Uhrzeit (Punkt)“ auf
36, Feld verlassen -> zurueck zum Dashboard:time.style.fontSize === '36pt',getComputedStyle(time).fontSize === '48px'bei 4x4 UND 12x8,data-font-mode="fixed", Datum14.4pt. Dann300-> Fehlermeldung „Bitte geben Sie eine Zahl zwischen 8 und 200 ein oder lassen Sie das Feld leer.“, kein Speichern (Netzwerk: kein PATCH). Feld leeren, Enter -> wieder automatisch. - Umrechnungs-Probe (SQL, lokale DB, Rolle
tesserahat BYPASSRLS, Schalter AUS). Zuerst den gespeicherten Stand lesen und die Kennungen notieren:Erwartung nach Schritt 1:docker exec tessera-ctl-db-1 psql -U tessera -d tessera -At -c 'SELECT "userId", layouts::text FROM "DashboardLayout";' docker exec tessera-ctl-db-1 psql -U tessera -d tessera -At -c 'SELECT id, "widgetType" FROM "WidgetInstance" ORDER BY "createdAt";'__gridVersion: 2, Suchleistex: 0, w: 12, h: 4, Uhrx: 12, w: 4, h: 4(o. ae.). Dann die Zeile in ALTE Einheiten ohne Marker zurueckschreiben (<uhr-id>/<such-id>aus der zweiten Abfrage;userIddes lokalen Admins ist1166431d-a556-47d0-9e19-6bd3616f148f):Falls noch keine Widgets/Anordnung existieren (lokal waren es zum Zeitpunkt der Ausfuehrung 0/0), stattdessen alles in einem Rutsch anlegen — Uhr und Suchleiste alsUPDATE "DashboardLayout" SET layouts = jsonb_build_object( 'lg', jsonb_build_array( jsonb_build_object('i','<uhr-id>','x',6,'y',0,'w',2,'h',2), jsonb_build_object('i','<such-id>','x',0,'y',0,'w',6,'h',2)), 'md','[]'::jsonb,'sm','[]'::jsonb,'xs','[]'::jsonb,'xxs','[]'::jsonb), "updatedAt" = now() WHERE "userId" = '1166431d-a556-47d0-9e19-6bd3616f148f';WidgetInstanceplus die Anordnung in ALTEN Einheiten (Admin-User1166431d-a556-47d0-9e19-6bd3616f148f, Mandante2592907-0118-4cce-a407-7e27d375b68d; beide Kennungen am 16.09. aus"User"gelesen, bei einer neu aufgesetzten DB erneut perSELECT id, "tenantId" FROM "User" WHERE username = 'admin';holen):(Alte Einheiten: Suchleiste 6x2 ab Spalte 0, Uhr 2x2 ab Spalte 6 — die frueheren Vorgabegroessen, Uhr direkt rechts neben der Suchleiste.) Seite laden -> Uhr steht rechts neben der Suchleiste (Uhr links = Suchleiste rechts + 8 px, Bounding-Boxen), nicht halb so gross und nicht verrutscht; danach:INSERT INTO "WidgetInstance" (id, "userId", "tenantId", "widgetType", config, "createdAt", "updatedAt") VALUES ('probe-suche-1', '1166431d-a556-47d0-9e19-6bd3616f148f', 'e2592907-0118-4cce-a407-7e27d375b68d', 'search', '{}'::jsonb, now(), now()), ('probe-uhr-1', '1166431d-a556-47d0-9e19-6bd3616f148f', 'e2592907-0118-4cce-a407-7e27d375b68d', 'clock', '{"timezone":"Europe/Berlin","showDate":true}'::jsonb, now() + interval '1 second', now()); INSERT INTO "DashboardLayout" (id, "userId", "tenantId", layouts, "createdAt", "updatedAt") VALUES ('probe-layout-1', '1166431d-a556-47d0-9e19-6bd3616f148f', 'e2592907-0118-4cce-a407-7e27d375b68d', '{"lg":[{"i":"probe-suche-1","x":0,"y":0,"w":6,"h":2},{"i":"probe-uhr-1","x":6,"y":0,"w":2,"h":2}],"md":[],"sm":[],"xs":[],"xxs":[]}'::jsonb, now(), now());->docker exec tessera-ctl-db-1 psql -U tessera -d tessera -At -c 'SELECT layouts->''__gridVersion'', layouts->''lg'' FROM "DashboardLayout";'2und Suchleistex: 0, w: 12, h: 4, Uhrx: 12, w: 4, h: 4. Seite ein ZWEITES Mal laden -> Werte unveraendert (keine erneute Verdopplung). Aufraeumen der Probe:DELETE FROM "DashboardLayout" WHERE id = 'probe-layout-1'; DELETE FROM "WidgetInstance" WHERE id IN ('probe-suche-1','probe-uhr-1');(nur falls per INSERT angelegt). - Rechner und Stoppuhr: beide hinzufuegen, vergroessern -> Anzeige und Tasten wachsen mit, das Tastenraster bleibt 4x5 und ueberlaeuft nicht; auf Mindestgroesse (Rechner 4x8, Stoppuhr 4x4) verkleinern -> Rechner bedienbar, Stoppuhr-Anzeige lesbar. Ueberlaeuft der Rechner bei 4x8: Hoehe der Tasten und der Anzeige notieren (siehe „Was bewusst offen bleibt“).
Fuer den Changelog
- Das Dashboard-Raster ist doppelt so fein: Widgets lassen sich in kleineren Schritten verschieben und in der Groesse ziehen, bleiben dabei aber genauso gross wie bisher. Bereits gespeicherte Anordnungen werden beim ersten Aufruf automatisch uebernommen und verrutschen nicht.
- Uhrzeit, Stoppuhr und Rechner wachsen und schrumpfen jetzt mit ihrer Kachel — eine grosse Uhr-Kachel zeigt eine grosse Uhrzeit.
- Die Uhr hat eine neue Einstellung: unter Einstellungen > Dashboard laesst sich die Schriftgroesse der Uhrzeit fest in Punkt (8 bis 200) vorgeben; leer gelassen passt sie sich weiter automatisch an.
- Die Raender sind ueberall enger: der aeussere Seitenrahmen auf allen Seiten, der Abstand zwischen den Widgets und die Innenabstaende in den Widgets sind halbiert.
- Das Anwenderhandbuch beschreibt das feine Raster, die mitwachsende Uhrzeit und die neue Schriftgroessen-Einstellung.
Self-Check: PASSED
- Dateien: alle 5 neu angelegten Dateien vorhanden (
grid-layout-migration.ts/.test.ts,dashboard-store.test.ts,clock-font-size.ts,widget-settings-panel.test.tsx). - Commits:
3f5afb0,2d8efe1,a175c00,1aefaa3ingit log --oneline --allgefunden;git ls-remote origin main=1aefaa3;main == origin/main. commits: 4=git rev-list --count 50f201e..HEAD;git status --porcelainleer vor dem SUMMARY.