Files
tessera-ctl/.planning/quick/260916-bwo-dashboard-feineres-raster-spalten-und-ze/260916-bwo-VERIFICATION.md
T
schalli 7a6f42ea74
Tessera CI/CD / Lint & Type Check (push) Successful in 48s
Tessera CI/CD / Tests (push) Successful in 1m6s
Tessera CI/CD / Build & Publish Images (push) Successful in 3m3s
docs(quick-260916-bwo): Dashboard-Umbau abgeschlossen, verifiziert 8/8 und im Browser bewiesen — Zusammenfassung, Verifikation, Aktenstand
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018N9CD3ebPKm1b32bPpBknY
2026-09-16 09:36:50 +02:00

21 KiB

phase, verified, status, score, covered_files, covered_digest, behavior_unverified, overrides_applied
phase verified status score covered_files covered_digest behavior_unverified overrides_applied
quick-260916-bwo 2026-09-16T09:32:00Z passed 8/8 must-haves (Code-Ebene) verifiziert; Bounding-Box-/Browser-Nachweis steht beim Orchestrator aus (siehe eigener Abschnitt, zaehlt laut Auftrag NICHT als human_needed)
.planning/quick/260916-bwo-dashboard-feineres-raster-spalten-und-ze/260916-bwo-PLAN.md
.planning/quick/260916-bwo-dashboard-feineres-raster-spalten-und-ze/260916-bwo-SUMMARY.md
apps/api/src/dashboard/dashboard.service.spec.ts
apps/web/src/app/(portal)/page.tsx
apps/web/src/components/dashboard/dashboard-grid.test.tsx
apps/web/src/components/dashboard/dashboard-grid.tsx
apps/web/src/components/dashboard/widget-registry.test.tsx
apps/web/src/components/dashboard/widget-registry.tsx
apps/web/src/components/dashboard/widgets/calculator-widget.test.tsx
apps/web/src/components/dashboard/widgets/calculator-widget.tsx
apps/web/src/components/dashboard/widgets/calendar-widget.tsx
apps/web/src/components/dashboard/widgets/clock-font-size.ts
apps/web/src/components/dashboard/widgets/clock-widget.test.tsx
apps/web/src/components/dashboard/widgets/clock-widget.tsx
apps/web/src/components/dashboard/widgets/favorites-widget.tsx
apps/web/src/components/dashboard/widgets/link-widget.tsx
apps/web/src/components/dashboard/widgets/note-widget.tsx
apps/web/src/components/dashboard/widgets/search-widget.tsx
apps/web/src/components/dashboard/widgets/stopwatch-widget.test.tsx
apps/web/src/components/dashboard/widgets/stopwatch-widget.tsx
apps/web/src/components/dashboard/widgets/widget-wrapper.tsx
apps/web/src/components/layout/app-shell.tsx
apps/web/src/components/settings/widget-settings-panel.test.tsx
apps/web/src/components/settings/widget-settings-panel.tsx
apps/web/src/lib/grid-layout-migration.test.ts
apps/web/src/lib/grid-layout-migration.ts
apps/web/src/lib/stores/dashboard-store.test.ts
apps/web/src/lib/stores/dashboard-store.ts
apps/web/src/messages/de.json
apps/web/src/messages/en.json
docs/anleitung-anwender.md
v1:sha256:dacef1a2fbd450d5f16d8d363537e171cdc2e0a539edff4c8287fe508922f96f 0 0

Quick-Task 260916-bwo: Dashboard — feineres Raster, skalierende Widget-Inhalte, halbe Abstaende — Verifikation

Auftrag: Raster doppelt so fein (24/20/12/8/2 Spalten, rowHeight 20, margin [8,8], WIDGET_CONSTRAINTS x2), einmalige Umrechnung gespeicherter Anordnungen mit Marker __gridVersion: 2, Container-Query-Skalierung fuer Uhr/Stoppuhr/Rechner, Uhr mit einstellbarer Punktgroesse, Abstaende halbiert, Anwenderhandbuch, gepusht, CI gruen.

Verifiziert: 2026-09-16, gegen HEAD 1aefaa3 (main == origin/main) Status: passed (Code-Ebene vollstaendig verifiziert; Browser-/Bounding-Box-Nachweis ist explizit Aufgabe des Orchestrators, siehe unten — laut Auftrag NICHT als human_needed zu werten)

Ich habe der SUMMARY.md an keiner Stelle vertraut, sondern jede Zahl, jede Datei und jeden Testlauf selbst erneut gemessen.

1. Git-Historie

Pruefung Befehl Ergebnis Status
Commit-Reihenfolge git log --oneline 50f201e..HEAD 1aefaa3, a175c00, 2d8efe1, 3f5afb0 (genau die vier erwarteten, in der erwarteten Reihenfolge) OK
Gesamtumfang git diff --stat 5f50c5f -- . ':!.planning' 29 files changed, 895 insertions(+), 60 deletions(-) OK
Unantastbare Dateien git diff --name-only 5f50c5f -- '.env*' docker-compose*.yml pnpm-lock.yaml apps/web/package.json apps/api/package.json apps/api/prisma apps/api/src/dashboard/dashboard.service.ts apps/api/src/dashboard/dto apps/web/src/app/globals.css apps/web/src/messages/umlaut-dictionary.ts leer OK
Dateien je Commit `git show --stat | grep -c ' '` 3f5afb0=9, 2d8efe1=12, a175c00=7, 1aefaa3=1
Dateiliste je Commit vs. Plan-Aufgabenliste git show --stat --name-only <commit> gegen die <files>-Listen der Tasks 1-3 identisch (alle Dateien der Aufgabenliste, keine fehlt, keine zusaetzliche) OK

2. Testsuiten, Typprüfung, Lockfile (selbst erneut ausgefuehrt)

Suite Befehl Erwartet Gemessen Status
Web-Vitest pnpm -C apps/web exec vitest run 46/286 Test Files 46 passed (46) / Tests 286 passed (286) OK
API-Vitest pnpm -C apps/api exec vitest run 67/1078 Test Files 67 passed (67) / Tests 1078 passed (1078) OK
tsc shared pnpm -C packages/shared exec tsc --noEmit 0 Exit 0 OK
tsc api pnpm -C apps/api exec tsc --noEmit 0 Exit 0 OK
tsc web pnpm -C apps/web exec tsc --noEmit 0 Exit 0 OK
Lockfile pnpm install --frozen-lockfile Exit 0, Lockfile unveraendert Exit 0; git status --porcelain -- pnpm-lock.yaml leer OK

3. Code-Lesung — Raster, Konstanten, Umrechnung, Store

Datei Pruefung Befund Status
dashboard-grid.tsx COLS, rowHeight, margin, BREAKPOINTS, Fallback ?? 4 COLS = { lg: 24, md: 20, sm: 12, xs: 8, xxs: 2 }, rowHeight={20}, margin={[8, 8]}, BREAKPOINTS unveraendert ({ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }), data-grid-Fallback jetzt ?? 4 ✓ VERIFIED
widget-registry.tsx Diff gegen git show 5f50c5f:...widget-registry.tsx Alle 8 Widget-Typen x 4 Felder (32 Werte) exakt verdoppelt: clock 2/2/2/2→4/4/4/4, search 3/2/6/2→6/4/12/4, calendar 3/3/4/6→6/6/8/12, note 2/3/3/4→4/6/6/8, calculator 2/4/3/5→4/8/6/10, favorites 2/3/3/5→4/6/6/10, link 2/2/2/2→4/4/4/4, stopwatch 2/2/3/3→4/4/6/6 ✓ VERIFIED
grid-layout-migration.ts Volltext gelesen GRID_VERSION=2, GRID_VERSION_KEY='__gridVersion', GRID_SCALE_FACTOR=2; migrateGridLayouts markiert nur bei typeof === 'number' als Marker (Zeichenkette zaehlt als alt), skaliert x,y,w,h,minW,minH,maxW,maxH sofern typeof === 'number', ueberspringt Nicht-Array-Breakpoints, entfernt den Marker aus der Rueckgabe, isPlainObject faengt null/undefined/Zahl/Array ab; withGridVersion haengt den Marker unmutierend an ✓ VERIFIED
grid-layout-migration.test.ts Volltext gelesen, 7 Tests inhaltlich mit <behavior> abgeglichen Testfaelle 1-7 decken alt→x2, markiert→unveraendert, leer→leer, Idempotenz, withGridVersion, Zukunft/Zeichenketten-Marker/nicht-numerische Felder, Fremdwerte — Wortlaut und Erwartungswerte stimmen mit dem Plan ueberein ✓ VERIFIED
dashboard-store.ts Volltext gelesen, Aufrufstellen gezaehlt grep -c "withGridVersion(" = 2 (Sofort-Speichern nach Migration in loadDashboard, sowie saveLayout); grep -c "migrateGridLayouts(" = 1 (nur in loadDashboard); Migrationsfehler landet in einem eigenen inneren try/catch, NICHT im aeusseren Lade-Fehlerzustand; Zustand traegt nie den Marker (Store iteriert Object.keys + Spread in addWidget/removeWidget) ✓ VERIFIED
dashboard-store.test.ts it(...)-Titel gelesen Genau 6 Tests, inhaltlich passend zu den 6 im Plan beschriebenen Faellen (Umrechnung+Sofortspeichern, markiert bleibt, leer kein Speichern, jedes Speichern traegt Marker, Sofort-Speichern scheitert leise, neues Widget in verdoppelten Vorgaben) ✓ VERIFIED
dashboard.service.spec.ts grep auf __gridVersion/timeFontSizePt Test A (__gridVersion uebersteht saveLayout→getLayout) und Test B (timeFontSizePt gemischt, null ueberschreibt, timezone bleibt) vorhanden, exakter Wortlaut wie im Plan ✓ VERIFIED
dashboard.service.ts, dto/, prisma/ git diff --stat 5f50c5f leer (keine Aenderung) ✓ VERIFIED — Durchreichung ohne Codeaenderung, wie im Plan begruendet

4. Unabhaengige Falsifizierung (Schritt 4 des Auftrags)

Eingriff: needsScaling = version < GRID_VERSION; in migrateGridLayouts zu const needsScaling = true; geaendert (Marker-Pruefung ausgehebelt).

pnpm -C apps/web exec vitest run src/lib/grid-layout-migration.test.ts
→ Test Files  1 failed (1)
     Tests  3 failed | 4 passed (7)

Rot wurden genau die Tests, die die Marker-Pruefung absichern: Test 2 (markierte Anordnung bleibt unveraendert), Test 4 (Idempotenz, T-BWO-02) indirekt ueber Test 2/6, und Test 6 (Zukunft: Marker 3 bleibt unveraendert). Damit ist bewiesen, dass die Idempotenz/Marker-Logik tatsaechlich von der Pruefung abhaengt und nicht zufaellig gruen ist.

Ruecksetzung: git checkout -- apps/web/src/lib/grid-layout-migration.ts; danach git status --porcelain -- apps/ leer (geprueft). Kein Rest des Eingriffs im Arbeitsbaum.

5. Widget-Skalierung, Punktgroesse, Einstellungen, i18n

Pruefung Befund Status
widget-wrapper.tsx Rumpf `@container-size h-full ${isEditMode ? 'pt-0' : ''}` mit Kommentar zur definiten Hoehe (aus der Karte, h-full) ✓ VERIFIED
clock-font-size.ts CLOCK_FONT_SIZE_MIN_PT=8, MAX_PT=200, CLOCK_DATE_FACTOR=0.4; resolveClockTimeFontSizePt prueft typeof === 'number', Number.isFinite, Bereich 8..200 — Zeichenketten, NaN, Infinity, negative Zahlen, 7, 201 liefern alle null (Code selbst gelesen, nicht nur Test) ✓ VERIFIED
clock-widget.tsx data-font-mode auto/fixed, style nur bei Zahl gesetzt (${fixedPt}pt bzw. ${fixedPt*0.4}pt), Klassen text-[clamp(12px,min(20cqw,50cqh),400px)] / text-[clamp(10px,min(8cqw,20cqh),160px)], p-1, keine vw-Formel mehr ✓ VERIFIED
stopwatch-widget.tsx text-[clamp(14px,min(16cqw,35cqh),400px)], p-1.5, kein vw ✓ VERIFIED
calculator-widget.tsx baseBtn = 'h-full min-h-7 ...', Zahlen/Operator/Gleich clamp(11px,min(4cqw,4.5cqh),40px), Funktionstasten clamp(10px,min(3.2cqw,3.6cqh),32px), Anzeige clamp(14px,min(8cqw,10cqh),96px), Speicherzeile bewusst h-7 text-xs ✓ VERIFIED
widget-settings-panel.tsx Feld id="clock-font-size", fontSizeDraft/fontSizeError/commitFontSize nutzen resolveClockTimeFontSizePt aus derselben Quelldatei wie das Widget (eine Grenze) ✓ VERIFIED
de.json/en.json widgets.clock.fontSizeLabel/fontSizeAuto/fontSizeHint/fontSizeInvalid in beiden Sprachen, Sie-Form mit echten Umlauten geprueft, Wortlaut exakt wie im Plan ✓ VERIFIED
Umlaut-Waechter / tenderRadar-Paritaet pnpm -C apps/web exec vitest run src/messages → Test Files 2 passed (2) / Tests 6 passed (6); git diff --stat 5f50c5f -- apps/web/src/messages/umlaut-dictionary.ts leer ✓ VERIFIED

6. Tailwind-Kompilat (Schritt 7 des Auftrags — unabhaengig nachgemessen)

Da npx next build zu schwer waere, habe ich @tailwindcss/postcss (dieselbe Version wie im Projekt) direkt ueber ein Wegwerf-Skript gegen den echten Quellbaum (apps/web) laufen lassen (@import "tailwindcss"; als Eingabe, base: apps/web), das Ergebnis geprueft und danach die temporaeren Dateien geloescht (git status --porcelain -- apps/web anschliessend leer):

.\@container-size { container-type: size; }
.text-\[clamp\(...\)\] { font-size: clamp(12px, min(20cqw, 50cqh), 400px); }

Beide Kernklassen kompilieren tatsaechlich zu den erwarteten CSS-Eigenschaften. Damit ist die Kompilierbarkeit unabhaengig bestaetigt, nicht nur behauptet.

7. Abstaende

Datei Erwartung Befund Status
app-shell.tsx main p-3, kein p-6 className="app-shell-main ... p-3", kein p-6-Treffer ✓ VERIFIED
page.tsx relative p-2, right-2 top-2, mt-8 bleibt mit Begruendung alle drei vorhanden, Kommentar mit Umschalter-Geometrie (36 px hoch, top-2 8..44 px, mt-8 → 48 px) ✓ VERIFIED
link-widget.tsx p-1 flex flex-col h-full overflow-auto p-1 gap-2 ✓ VERIFIED
favorites-widget.tsx p-1 dieselbe Klasse ✓ VERIFIED
calendar-widget.tsx Rumpf p-1.5, Zustandsansichten p-2 Zeilen 80/91/102 p-2, Rumpf p-1.5 ✓ VERIFIED
search-widget.tsx px-1.5 px-1.5 ✓ VERIFIED
note-widget.tsx px-1.5 py-1.5 vorhanden ✓ VERIFIED

8. Dokumentation

docs/anleitung-anwender.md: „feinen Schritten“ (1x), „Schriftgröße“ (2x, korrekt an den drei im Plan genannten Stellen), Text nennt feines Raster, mitwachsende Uhrzeit und die neue Punktgroessen-Einstellung, Alltagssprache mit echten Umlauten. ✓ VERIFIED

9. CI und Push (unabhaengig ueber die Gitea-API geprueft, Token nicht ausgegeben)

curl -H "Authorization: token $TOK" ".../actions/runs?limit=5"
→ Lauf 351, head_sha 1aefaa36c1e3ae7c3055e714b059223a1e5aff77, status completed, conclusion success

docker run --rm --entrypoint node localhost:3002/schalli/tessera-ctl/api:beta -e '...' → v1.0.0-10-g1aefaa3 beta 1aefaa3 — exakt wie im SUMMARY behauptet. Die dritte im Auftrag genannte Messdiskrepanz („APP_VERSION“ = kurzer SHA erwartet, tatsaechlich git describe-Format) ist eine Fehlerwartung des PLANS: APP_COMMIT traegt korrekt den kurzen SHA 1aefaa3, beide Werte spiegeln den gepushten Stand. Kein Fund gegen den Executor.

git fetch -q && git status -sb | head -1 → ## main...origin/main (kein [ahead, kein [behind). ✓ VERIFIED

10. Zwei dokumentierte Abweichungen — Bewertung

  1. Versehentlicher git stash waehrend Task 1 (sofort per stash pop zurueckgeholt): Der Dateivergleich git show --stat --name-only 3f5afb0 gegen die Task-1-Dateiliste zeigt exakt die neun erwarteten Dateien mit dem inhaltlich erwarteten Code (siehe Abschnitt 3) — nichts wurde durch den Stash-Zwischenfall verloren. Bewertung: harmlos, korrekt dokumentiert.
  2. Grep-Gate " p-6" traf einen eigenen Kommentar (umformuliert): app-shell.tsx enthaelt tatsaechlich p-3 an der main-Klasse und keinen p-6-Treffer mehr; der Kommentar spricht jetzt von „24 px (Stufe 6)“ statt „p-6“. Bewertung: kosmetische Korrektur am eigenen Kommentartext, keine Funktionsaenderung, korrekt dokumentiert.

Keine der beiden Abweichungen hat Code oder Testabdeckung beeintraechtigt.

11. Anti-Pattern-Scan

grep auf TBD|FIXME|XXX|TODO|HACK|PLACEHOLDER (case-insensitiv, plus placeholder|coming soon|not yet implemented) ueber alle in dieser Phase veraenderten Dateien: ausschliesslich legitime HTML-placeholder-Attribute (Eingabefelder) und ein VORBESTEHENDER Kommentar „Placeholder widget for types not yet implemented“ in widget-registry.tsx, der schon in 5f50c5f (vor dieser Phase) unveraendert vorhanden war (per git show 5f50c5f:... bestaetigt) und nicht zu den 32 verdoppelten Werten gehoert. Kein neuer Debt-Marker durch diese Phase. Keine Stub-Returns (return null/{}/[] an Render-Pfaden) gefunden.

12. Requirements-Abdeckung

Quick-Task mit requirements: [QUICK-260916-BWO] — kein separates .planning/REQUIREMENTS.md-Register fuer Quick-Tasks in diesem Projekt (projekttypisch); die Anforderung ist vollstaendig im PLAN/SUMMARY beschrieben und oben Punkt fuer Punkt gegen den Code verifiziert.


Vom Orchestrator im Browser zu pruefen

Dies ist laut Auftrag AUSDRUECKLICH nicht Teil dieser Verifikation und zaehlt nicht als human_needed, sondern als eigener Nachweisschritt des Orchestrators (Playwright MCP gegen die lokalen Container). Vorher docker compose up -d --build web (Web-Abbild war 39h alt; up allein baut nicht neu). Anmeldung: Benutzername admin, Kennwort admin123.

  1. Anordnung anlegen: Dashboard → „Dashboard bearbeiten“ → Uhr-Widget und Suchleiste hinzufuegen, Uhr rechts neben die Suchleiste ziehen, Bearbeitungsmodus beenden (speichert).
  2. Abstaende (Bounding-Boxen, boundingBox(), NIE per fetch): main.app-shell-main links vs. erstes [data-widget-id] links → 28 px (±1; vorher 56); zwei horizontal benachbarte Widgets → Luecke 8 px (±1; vorher 16); main oben vs. erstes Widget → 60 px (±1; vorher 88). Zweite Seite /admin/users: Abstand main-Rand zum ersten Inhaltselement 12 px (vorher 24).
  3. Raster: Uhr im Bearbeitungsmodus um eine Rasterstufe nach rechts ziehen → Versatz eine Spaltenbreite (Containerbreite - 8*23 - 8*2)/24 px (bei 1200 px ca. 41 px statt ca. 83 px vorher).
  4. Skalierung: Uhr auf 12x8 vergroessern → getComputedStyle(time).fontSize deutlich groesser als bei 4x4 (Erwartung 4x4 ca. 38-42 px, 12x8 ca. 80+ px); verkleinern → schrumpft; data-font-mode="auto". Ist cqh 0 (Uhr unsichtbar klein), fehlt die definite Hoehe in widget-wrapper.tsx/Karte.
  5. Punktgroesse: Einstellungen → Dashboard → Widgets → „Uhr #1“ → „Schriftgröße der Uhrzeit (Punkt)“ auf 36, Feld verlassen → time.style.fontSize === '36pt', getComputedStyle(time).fontSize === '48px' bei 4x4 UND 12x8, data-font-mode="fixed", Datum 14.4pt. Danach 300 → Fehlermeldung, kein Speichern (kein PATCH im Netzwerktab). Feld leeren, Enter → wieder automatisch.
  6. SQL-Umrechnungs-Probe (lokale DB, Rolle tessera, BYPASSRLS, RLS-Schalter AUS):
    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";'
    
    Gespeicherten Stand (neue Einheiten, __gridVersion: 2) lesen, dann per UPDATE/INSERT (siehe SUMMARY Abschnitt „Fuer den Verifizierer/Orchestrator“, wortgleiche SQL-Bloecke dort) in ALTE Einheiten ohne Marker zuruecksetzen bzw. neu anlegen. Seite laden → Uhr optisch an derselben Stelle rechts neben der Suchleiste (nicht halb so gross, nicht verrutscht); danach:
    docker exec tessera-ctl-db-1 psql -U tessera -d tessera -At -c 'SELECT layouts->''__gridVersion'', layouts->''lg'' FROM "DashboardLayout";'
    
    → 2, Suchleiste x:0,w:12,h:4, Uhr x:12,w:4,h:4. Seite ein zweites Mal laden → Werte unveraendert (keine erneute Verdopplung). Probe-Datensaetze danach aufraeumen, falls per INSERT angelegt.
  7. Rechner/Stoppuhr: hinzufuegen, vergroessern → Anzeige/Tasten wachsen mit, 4x5-Tastenraster ueberlaeuft nicht; auf Mindestgroesse (Rechner 4x8, Stoppuhr 4x4) verkleinern → Rechner bleibt bedienbar (im SUMMARY als offene Messfrage benannt — Rueckfalloption „nur Anzeige skalieren“, falls er ueberlaeuft), Stoppuhr-Anzeige lesbar.

Angenommene Risiken

  • Container-Query-Aufloesung im echten Browser (cqh/cqw, definite Hoehe der Kette Karte→Rumpf) ist mit jsdom prinzipiell nicht pruefbar; ich habe den Tailwind-Kompilat-Pfad unabhaengig verifiziert (Abschnitt 6), aber die tatsaechliche visuelle Skalierung im Chromium-basierten WebView bleibt Sache des Browser-Nachweises oben.
  • Rechner bei Mindestgroesse (4x8): rechnerisch knapp (vom Executor selbst als offene Frage benannt, ca. 216 px Kachelhoehe vs. ca. 232 px benoetigter Inhalt) — nicht durch Code-Lesung entscheidbar, siehe Browser-Punkt 7.
  • Marker-Persistenz bei dauerhaft scheiterndem PUT: akzeptiertes Verhalten laut Threat-Model (T-BWO-05, accept) — jedes Laden loest bis zum ersten erfolgreichen Speichern einen erneuten PUT-Versuch aus; kein Datenverlust, nur wiederholte Log-Eintraege.
  • Bestand an Anordnungen auf alpha/live wurde vom Executor nicht zum Verifikationszeitpunkt erneut gemessen (nur zur Planungszeit 0/0 auf alpha, live gar nicht erreichbar) — die Umrechnung selbst ist unabhaengig vom Bestand korrekt (Code- und Falsifizierungsnachweis oben), aber ich kann den tatsaechlichen Produktivbestand nicht bestaetigen.
  • git show-Autorenzeile der Commits nennt „Claude Opus 5 (1M context)“ statt der in dieser Sitzung vorgegebenen Attribution — das ist die Attribution der AUSFUEHRENDEN Sitzung (nicht dieser Verifikationssitzung) und kein inhaltlicher Mangel; nur der Vollstaendigkeit halber vermerkt.

Nachtrag des Orchestrators — Browser-Check durchgefuehrt (2026-09-16, 07:33-07:36Z)

Umgebung: lokale Container aus main (1aefaa3) frisch gebaut, Playwright MCP (Chromium), Anmeldung als lokaler Admin.

Schritt Beobachtung
SQL-Probe Umrechnung Anordnung in ALTEN Einheiten eingespielt (search 6x2 bei 0/0, clock 2x2 bei 6/0, kein Marker). Nach dem ersten Laden des Dashboards in der DB: search 12x4 bei 0/0, clock 4x4 bei 12/0, "__gridVersion": 2 — genau verdoppelt, optisch an derselben Stelle
Abstaende (Bounding-Boxen) main padding 12 px (vorher 24); Rand bis erstes Widget 28 px (vorher 56); Abstand zwischen zwei Widgets 8 px (vorher 16); erstes Widget bei top 120
Uhr automatisch Kachel 264x104 px -> Uhrzeit 51 px, data-font-mode="auto", Rumpf container-type: size. Im Bearbeitungsmodus per Griff auf 536x300 px vergroessert -> Uhrzeit 106,8 px: skaliert mit der Kachel
Uhr feste Punktgroesse Einstellungen -> Dashboard -> Widgets -> Uhr #1, Feld "Schriftgroesse der Uhrzeit (Punkt)" = 36 -> DB timeFontSizePt: 36 (Zahl); Dashboard: Inline-Style 36pt, berechnet 48 px, data-font-mode="fixed", unabhaengig von der Kachelgroesse (264x104)
Rahmen auf anderer Seite /admin/users: main padding 12 px, Klasse p-3
Rasterstufe Kachel 4x4 = 264x104 px -> eine Spalte ca. 41 px, eine Zeile 20 px + 8 px Abstand (vorher 12 Spalten / 40 px)

Nach der Probe: Probe-Zeilen aus der lokalen DB entfernt (0/0), Playwright-Artefakte entfernt, Arbeitsbaum unveraendert bis auf die Akten dieses Quick-Tasks.