--- phase: 08-dashboard-widgets-vollimplementierung plan: "01" subsystem: dashboard-widgets tags: [calculator, widget-registry, tdd, dashboard, i18n, validation] status: complete dependency_graph: requires: [] provides: - WidgetType union with calculator/favorites/link/stopwatch - WIDGET_CONSTRAINTS for all 8 widget types (DASH-11) - wireCalculatorWidget / wireFavoritesWidget / wireLinkWidget / wireStopwatchWidget - CalculatorWidget component (fully functional) affects: - apps/web/src/components/dashboard/widget-registry.tsx - apps/web/src/components/dashboard/widget-catalog-modal.tsx - apps/web/src/app/(portal)/page.tsx - apps/api/src/dashboard/dto/create-widget.dto.ts tech_stack: added: [] patterns: - TDD Red/Green cycle for widget + registry tests - Arithmetic logic ported from personal-dashboard (parseDisplay/formatNumber/calculate) - Tailwind-only styling (no CSS modules) - wireXWidget() lazy-loading pattern extended to 4 new widget types - @IsIn() allow-list in DTO updated (T-08-01 threat mitigated) key_files: created: - apps/web/src/components/dashboard/widgets/calculator-widget.tsx - apps/web/src/components/dashboard/widgets/calculator-widget.test.tsx - apps/web/src/components/dashboard/widget-registry.test.tsx modified: - apps/web/src/components/dashboard/widget-registry.tsx - apps/web/src/components/dashboard/widget-catalog-modal.tsx - apps/web/src/app/(portal)/page.tsx - apps/web/src/messages/de.json - apps/web/src/messages/en.json - apps/api/src/dashboard/dto/create-widget.dto.ts decisions: - "Grid constraints defined per-widget (D-01): calculator minW:2 minH:4 defaultW:3 defaultH:5; favorites minW:2 minH:3 defaultW:3 defaultH:5; link minW:2 minH:2 defaultW:2 defaultH:2; stopwatch minW:2 minH:2 defaultW:3 defaultH:3" - "Calculator keyboard handler uses stopPropagation() in all handled branches (T-08-02 / Pitfall 1)" - "Pre-existing API TypeScript errors (avatarPath) out of scope — not introduced by this plan" metrics: duration: "~10 minutes" completed: "2026-07-01" tasks_completed: 3 tests_added: 16 files_created: 3 files_modified: 7 --- # Phase 08 Plan 01: Widget Registry Foundation + Calculator Summary Widget-Registry-Grundlage fuer alle Phase-8-Typen (DASH-11) und voll funktionsfaehiger Calculator-Widget (DASH-08) via TDD Red/Green-Zyklus. ## What Was Built - **Calculator Widget** (`calculator-widget.tsx`): Vollstaendige Implementierung portiert aus personal-dashboard. Grundrechenarten (+, −, ×, ÷), Tastatureingabe, Dezimalkomma, Division-durch-Null-Schutz ("Fehler"), Memory-Funktionen (MC/MR/M+/M−/MS). `stopPropagation()` in jedem Keyboard-Handler-Branch verhindert react-grid-layout-Interferenz. - **Widget Registry Foundation**: `WidgetType`-Union auf 8 Typen erweitert. `WIDGET_CONSTRAINTS` mit einheitlicher Feldstruktur (minW/minH/defaultW/defaultH) fuer alle 8 Typen. Vier neue SVG-Icons, vier neue WIDGET_REGISTRY-Eintraege, vier neue `wireXWidget()`-Funktionen fuer spaetere Plaene. - **Catalog Modal**: `WIDGET_TYPES`-Array auf alle 8 Typen erweitert — neue Widgets erscheinen im Dashboard-Katalog. - **API DTO**: `@IsIn()`-Allowlist auf alle 8 WidgetTypes erweitert — POST `/dashboard/widgets` akzeptiert neue Typen ohne 400-Fehler. - **i18n**: Schluesselsatz fuer calculator/favorites/link/stopwatch in `de.json` und `en.json` ergaenzt. ## Tasks | Task | Description | Status | Commit | |------|-------------|--------|--------| | 1 | RED: Failing tests fuer Calculator und Registry-Constraints | Complete | b751ae7 | | 2 | GREEN: Registry-Foundation + Calculator-Implementierung | Complete | 63ec93b | | 3 | Full Suite + TypeCheck-Gate | Complete | — (no changes needed) | ## Test Results - **calculator-widget.test.tsx**: 6 Tests — initiales Display "0", 7+3=10, 8×2=16, Division-durch-Null=Fehler, Keyboard 5*6Enter=30, Dezimalkomma 1,5+1,5=3 - **widget-registry.test.tsx**: 10 Tests — alle 8 WidgetTypes haben 4 numerische Constraint-Felder - **Full Web Suite**: 67/67 Tests bestehen - **Web TypeScript**: sauber (0 Fehler) - **API TypeScript**: 6 Pre-existing-Fehler (avatarPath — nicht durch diesen Plan verursacht) ## Deviations from Plan ### Pre-Existing Issue (out of scope) **API TypeScript-Fehler (avatarPath):** `src/auth/auth.service.ts` und `src/user/user.controller.ts` referenzieren `avatarPath` das noch nicht im Prisma-Client generiert wurde (Quick Plan 260630-gbh fugte Avatar-Feature hinzu, aber `prisma generate` wurde nach `db push` nicht in den Commit aufgenommen). Diese 6 Fehler existieren identisch im Main-Branch und wurden durch Plan 01 nicht eingefuehrt. Scope: DEFERRED. ### Node Modules (worktree setup) Symlinks von `apps/web/node_modules` und `apps/api/node_modules` im Worktree auf Main-Repo-node_modules wurden erstellt um Tests lauffaehig zu machen. Die Symlinks sind in `.gitignore` (`node_modules/`) und werden nicht committed. ### Test-Ausführungsbefehl (auto-fix) Der Plan spezifiziert `pnpm --filter @tessera/web test --run` — dieser Befehl existiert im Worktree nicht (`node_modules` fehlen initial). Fix: Symlinks erstellt, dann direkt `node_modules/.bin/vitest run` aufgerufen. Gleiches Ergebnis. ### "Gleich"-Button ariaLabel Der `=`-Button hat `ariaLabel={`Gleich ${getOperatorLabel(pendingOperator)}`}`. Die Tests nutzen `getByRole('button', { name: /gleich/i })` (case-insensitive regex) statt des genauen Labels, was mit dem dynamischen Label kompatibel ist. ## Known Stubs Keine Stubs. Calculator-Widget ist vollstaendig implementiert. Die Placeholder-Komponente fuer favorites/link/stopwatch in WIDGET_REGISTRY ist bewusst — diese Widgets werden in Plaenen 02-04 implementiert. ## Threat Surface Scan Keine neuen Sicherheitsoberflaechen eingefuehrt. T-08-01 (Tampering via widgetType) und T-08-02 (DoS via Keyboard-Events) wurden gemaess Threat Model mitigiert. ## Self-Check: PASSED | Item | Status | |------|--------| | calculator-widget.tsx | FOUND | | calculator-widget.test.tsx | FOUND | | widget-registry.test.tsx | FOUND | | Commit b751ae7 (RED) | FOUND | | Commit 63ec93b (GREEN) | FOUND |