7.5 KiB
7.5 KiB
Phase 8: Dashboard Widgets Vollimplementierung - Context
Gathered: 2026-07-01 Status: Ready for planning
## Phase BoundaryDrei neue Dashboard-Widgets implementieren (Calculator, Favorites-Liste, Einzellink, Stoppuhr) und alle Widget-Grid-Constraints auf sinnvolle, nutzbare Werte setzen. Widget-Registry um neue Typen erweitern. Favoriten brauchen Backend (DB-Tabelle + API + server-seitiges Icon-Discovery). Stoppuhr-Zustand wird persistiert. DomainCheck-Widget wird NICHT implementiert.
## Implementation DecisionsGrid-Constraints (DASH-11)
- D-01: Kein universeller Einheitswert. Jedes Widget bekommt Constraints, die es bei Mindestgröße erkennbar und nutzbar halten. Neue Widgets (Calculator, Favorites, Einzellink, Stoppuhr) kriegen sinnvolle Werte passend zum Inhalt. Claude legt konkrete minW/minH/defaultW/defaultH fest.
Favoriten-Widget (DASH-09)
- D-02: Backend: neue Prisma-Tabelle
FavoriteLinkmit Feldern:id,userId,tenantId,widgetId,title,url,iconUrl,position. Eigene Tabelle (nicht JSON-Blob in WidgetInstance.config) — sauber abfragbar und sortierbar. - D-03: Standard-Ansicht im Widget: Liste (Icon + Titel untereinander). Grid-Ansicht (Kacheln nebeneinander) umschaltbar. Bei Grid-Ansicht auf saubere Formatierung achten (kein abgeschnittener Text, Icon + Titel klar lesbar).
- D-04: Favoriten hinzufügen/bearbeiten/löschen direkt im Widget im Dashboard-Edit-Modus ('+'-Button + Inline-Formular). Kein separater Einstellungen-Tab.
- D-05: Icon-Discovery: Server-seitig beim Anlegen eines Favoriten. NestJS-API fetcht die Seite, parst
<link rel="apple-touch-icon">,<link rel="icon">,<link rel="shortcut icon">, OG-Image aus HTML. Fallback:/favicon.ico. Sicherheit: SSRF-Schutz gegen private IPs und localhost (Logik auspersonal-dashboard/src/lib/favorite-icons.tsportieren).iconUrlwird inFavoriteLinkgespeichert. Client rendert<img src={iconUrl}>mit Buchstaben-Fallback.
Einzellink-Widget (neu, kein eigenes Requirement — Teil von DASH-09)
- D-06: Separater WidgetType
linkin der Registry. Zeigt genau einen Link an. Ansicht umschaltbar: Listendesign (Icon + Titel als Zeile) oder Kachel. Teilt Backend-Infrastruktur mit FavoritesWidget (gleiche FavoriteLink-Tabelle, widgetId zur Zuordnung).
Stoppuhr-Widget (DASH-10)
- D-07: Stoppuhr läuft durch — Startzeit (Unix-Timestamp) + Zustand (running/paused/elapsed) wird in
WidgetInstance.configgespeichert. Beim Laden aus dem gespeicherten Timestamp rekonstruiert. Kein separater API-Endpunkt nötig — nutzt vorhandenes Widget-Config-Update (PATCH /dashboard/widgets/:id/config). - D-08: Funktionen: Start, Stop/Pause, Reset. Rundenzeiten (Lap) optional, Claude entscheidet ob im ersten Schritt oder later.
Calculator-Widget (DASH-08)
- D-09: Grundrechenarten (+, −, ×, ÷), Tastatureingabe unterstützt. Kein Persist-Bedarf (in-memory). Logik aus
personal-dashboard/src/components/CalculatorWidget.tsxportieren, CSS-Module durch Tailwind ersetzen (wie alle anderen Tessera-Widgets).
Claude's Discretion
- Konkrete minW/minH/defaultW/defaultH-Werte für neue Widgets
- Lap-Timer in Stoppuhr: im ersten Schritt oder später
- Reihenfolge der Kacheln im Favoriten-Grid
- Keyboard-Shortcuts im Calculator-Widget
- SSRF-Timeout und max-redirect-Werte für Icon-Discovery (aus personal-dashboard übernehmen oder anpassen)
<canonical_refs>
Canonical References
Downstream agents MUST read these before planning or implementing.
Bestehendes Dashboard-Code (Tessera)
apps/web/src/components/dashboard/widget-registry.tsx— WidgetType, WIDGET_CONSTRAINTS, wireXWidget()-Pattern, WidgetDefinition-Interfaceapps/web/src/components/dashboard/widgets/clock-widget.tsx— Referenz-Implementierung für Widget-Komponente (WidgetProps-Interface, Tailwind-Styling)apps/web/src/components/dashboard/widgets/note-widget.tsx— Referenz für Widget mit updateWidgetConfig()-Aufrufapps/web/src/components/dashboard/widget-catalog-modal.tsx— Wie neue Widget-Typen im Katalog erscheinenapps/api/src/dashboard/dashboard.controller.ts— Bestehende Widget-API-Endpunkteapps/api/src/dashboard/dto/create-widget.dto.ts— DTO-Pattern für Widget-Requestsapps/api/prisma/schema.prisma— WidgetInstance-Modell (config: Json), Prisma-Schema für neue FavoriteLink-Tabelle
Referenz-Implementierungen (personal-dashboard)
/home/vicolab/Schreibtisch/personal-dashboard/src/components/CalculatorWidget.tsx— Vollständige Calculator-Logik (434 Zeilen), zu portieren/home/vicolab/Schreibtisch/personal-dashboard/src/components/FavoritesWidget.tsx— Favoriten-UI-Logik (482 Zeilen), zu adaptieren/home/vicolab/Schreibtisch/personal-dashboard/src/lib/favorite-icons.ts— Server-seitiges Icon-Discovery mit SSRF-Schutz, zu portieren
Anforderungen
.planning/REQUIREMENTS.md— DASH-08, DASH-09, DASH-10, DASH-11.planning/ROADMAP.md— Phase 8 Goal + Success Criteria.planning/phases/05-dashboard-calendar/05-CONTEXT.md— D-01..D-07 (Edit-Modus, Widget-Einstellungen, mehrfach platzierbar) — diese Entscheidungen gelten weiterhin
</canonical_refs>
<code_context>
Existing Code Insights
Reusable Assets
wireXWidget(component)— Pattern für lazy-loading Widget-Komponenten ohne zirkuläre Abhängigkeiten. Neue Widgets folgen exakt diesem Muster.updateWidgetConfig(instanceId, config)inapps/web/src/lib/dashboard-api.ts— bestehende Funktion für Widget-Config-Updates, für Stoppuhr-Persistenz direkt verwendbar.apps/api/src/dashboard/dashboard.service.ts— bestehende Service-Logik für Widget CRUD, FavoriteLink-Service kann als eigenes Module daneben leben.
Established Patterns
- Widget-Komponenten:
'use client'+WidgetPropsInterface + Tailwind-Styling (keine CSS-Module) - Icons im Widget-Registry: Inline SVG als React-Komponente (kein Lucide, kein externe Icon-Library)
- API-Endpunkte in NestJS: Controller → Service → Prisma, DTOs mit class-validator
- i18n:
useTranslations()ausnext-intlfür alle UI-Strings
Integration Points
widget-registry.tsx:WidgetType-Union erweitern ('calculator' | 'favorites' | 'link' | 'stopwatch'),WIDGET_CONSTRAINTS+WIDGET_REGISTRY+ je einewireXWidget()-Funktion hinzufügenapps/api/prisma/schema.prisma:FavoriteLink-Modell hinzufügen +prisma db push- NestJS-API: neues
FavoritesModulemit Controller/Service/DTOs für FavoriteLink-CRUD + Icon-Discovery
</code_context>
## Specific Ideas- Calculator-Logik aus personal-dashboard portieren (parseDisplay, formatNumber, calculate-Funktionen erhalten — bewährt)
- Favoriten-Icon-Discovery: SSRF-Schutz aus
favorite-icons.tsvollständig portieren (private IP-Blöcke, localhost-Check, max-redirects, timeout) - Stoppuhr läuft nach Seiten-Reload weiter (Startzeit als ISO-String in config speichern, elapsed time berechnen)
- Stoppuhr: später ggf. in Browser-Titelzeile anzeigen (deferred)
- Favoriten-Widget Listenansicht als Standard, Grid optional umschaltbar
- Einzellink-Widget teilt FavoriteLink-Tabelle (widgetId als FK)
- Stoppuhr-Anzeige im Browser-Seitentitel + Taskleiste (spätere Phase)
- DomainCheck-Widget (explizit ausgeschlossen aus Phase 8)
- Lap-Timer in Stoppuhr (falls nicht in Phase 8 umgesetzt: separater Task in späterer Phase)
Phase: 8-dashboard-widgets-vollimplementierung Context gathered: 2026-07-01