From afc555b18d06035db91b3c36bd6dbd414e0c0b73 Mon Sep 17 00:00:00 2001 From: Schalli Date: Wed, 24 Jun 2026 11:27:59 +0200 Subject: [PATCH] docs(05-01): complete dashboard grid + clock widget plan --- .planning/REQUIREMENTS.md | 16 +-- .planning/ROADMAP.md | 4 +- .planning/STATE.md | 28 ++-- .../05-dashboard-calendar/05-01-SUMMARY.md | 134 ++++++++++++++++++ 4 files changed, 159 insertions(+), 23 deletions(-) create mode 100644 .planning/phases/05-dashboard-calendar/05-01-SUMMARY.md diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 89ed561..a715f11 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -39,13 +39,13 @@ Requirements for initial release. Each maps to roadmap phases. ### Dashboard -- [ ] **DASH-01**: Konfigurierbares Dashboard als Startseite mit Drag & Drop Grid -- [ ] **DASH-02**: Widgets koennen frei positioniert und in der Groesse geaendert werden -- [ ] **DASH-03**: Uhr-Widget (analog oder digital) +- [x] **DASH-01**: Konfigurierbares Dashboard als Startseite mit Drag & Drop Grid +- [x] **DASH-02**: Widgets koennen frei positioniert und in der Groesse geaendert werden +- [x] **DASH-03**: Uhr-Widget (analog oder digital) - [ ] **DASH-04**: Suchleiste-Widget (oeffnet Google/Suchmaschine im Browser) - [ ] **DASH-05**: Kalender-Widget mit Terminvorschau - [ ] **DASH-06**: Notiz-Widget (Freitext-Kachel) -- [ ] **DASH-07**: Dashboard-Layout wird pro Benutzer gespeichert +- [x] **DASH-07**: Dashboard-Layout wird pro Benutzer gespeichert ### Kalender-Integration @@ -143,13 +143,13 @@ Which phases cover which requirements. Updated during roadmap creation. | MRKT-02 | Phase 4 | Pending | | MRKT-03 | Phase 4 | Pending | | MRKT-04 | Phase 4 | Pending | -| DASH-01 | Phase 5 | Pending | -| DASH-02 | Phase 5 | Pending | -| DASH-03 | Phase 5 | Pending | +| DASH-01 | Phase 5 | Complete | +| DASH-02 | Phase 5 | Complete | +| DASH-03 | Phase 5 | Complete | | DASH-04 | Phase 5 | Pending | | DASH-05 | Phase 5 | Pending | | DASH-06 | Phase 5 | Pending | -| DASH-07 | Phase 5 | Pending | +| DASH-07 | Phase 5 | Complete | | CAL-01 | Phase 5 | Pending | | CAL-02 | Phase 5 | Pending | | CAL-03 | Phase 5 | Pending | diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index e0ed48c..f688767 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -165,7 +165,7 @@ Decimal phases appear between their surrounding integers in numeric order. **Wave 1** -- [ ] 05-01-PLAN.md -- Dashboard foundation: Prisma models, CRUD API, grid, edit-mode, clock widget, settings shell, header link, i18n (DASH-01/02/03/07) +- [x] 05-01-PLAN.md -- Dashboard foundation: Prisma models, CRUD API, grid, edit-mode, clock widget, settings shell, header link, i18n (DASH-01/02/03/07) **Wave 2** *(blocked on Wave 1 completion)* @@ -210,5 +210,5 @@ Phases execute in numeric order: 1 -> 2 -> 3 -> 4 -> 5 -> 6 | 2. Authentication & Multi-Tenancy | 2/5 | In Progress| | | 3. Module System & Domaincheck | 3/4 | In Progress| | | 4. Marketplace & Portal Navigation | 0/4 | Not started | - | -| 5. Dashboard & Calendar | 0/5 | Planned | - | +| 5. Dashboard & Calendar | 1/5 | In Progress| | | 6. Desktop Client & CI/CD | 0/TBD | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index f854be6..4ae80f5 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -2,15 +2,15 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone -status: completed -stopped_at: context exhaustion at 76% (2026-06-24) -last_updated: "2026-06-24T08:12:35.458Z" -last_activity: 2026-06-23 -- Plan 04-03 completed (sidebar enhancement) +status: executing +stopped_at: Completed 05-01-PLAN.md +last_updated: "2026-06-24T09:27:38.939Z" +last_activity: 2026-06-24 -- Phase 05 execution started progress: total_phases: 6 completed_phases: 3 total_plans: 21 - completed_plans: 15 + completed_plans: 16 percent: 50 --- @@ -21,14 +21,14 @@ progress: See: .planning/PROJECT.md (updated 2026-06-18) **Core value:** Eine zentrale Plattform, in der beliebige Workflow-Tools als Module lizenziert, aktiviert und genutzt werden koennen -- ohne zwischen verschiedenen Anwendungen wechseln zu muessen. -**Current focus:** Phase 04 — marketplace-portal-navigation +**Current focus:** Phase 05 — dashboard-calendar ## Current Position -Phase: 04 (marketplace-portal-navigation) — EXECUTING -Plan: 4 of 4 -Status: Plan 04-03 complete, ready for 04-04 -Last activity: 2026-06-23 -- Plan 04-03 completed (sidebar enhancement) +Phase: 05 (dashboard-calendar) — EXECUTING +Plan: 2 of 5 +Status: Ready to execute +Last activity: 2026-06-24 -- Phase 05 execution started Progress: [██▓░░░░░░░] 25% @@ -54,6 +54,7 @@ Progress: [██▓░░░░░░░] 25% *Updated after each plan completion* | Phase 02-authentication-multi-tenancy P02 | 8min | 3 tasks | 26 files | | Phase 02-authentication-multi-tenancy P03 | 5min | 2 tasks | 20 files | +| Phase 05-dashboard-calendar P01 | 14min | 4 tasks | 28 files | ## Accumulated Context @@ -74,6 +75,7 @@ Recent decisions affecting current work: - [Phase ?]: Route groups (auth)/(portal) for layout separation: auth pages standalone, portal pages wrapped in AppShell - [Phase ?]: Controller-level tenant isolation for ADMIN role as defense-in-depth alongside RLS - [Phase ?]: Remember-me controls cookie maxAge (30d session vs browser-session) not separate token type +- [Phase ?]: react-grid-layout v2 uses dragConfig/resizeConfig instead of isDraggable/isResizable ### Pending Todos @@ -93,6 +95,6 @@ Items acknowledged and carried forward from previous milestone close: ## Session Continuity -Last session: 2026-06-24T08:03:21.832Z -Stopped at: context exhaustion at 76% (2026-06-24) -Resume file: .planning/phases/05-dashboard-calendar/05-CONTEXT.md +Last session: 2026-06-24T09:27:38.933Z +Stopped at: Completed 05-01-PLAN.md +Resume file: None diff --git a/.planning/phases/05-dashboard-calendar/05-01-SUMMARY.md b/.planning/phases/05-dashboard-calendar/05-01-SUMMARY.md new file mode 100644 index 0000000..3732153 --- /dev/null +++ b/.planning/phases/05-dashboard-calendar/05-01-SUMMARY.md @@ -0,0 +1,134 @@ +--- +phase: 05-dashboard-calendar +plan: 01 +subsystem: dashboard +tags: [dashboard, widgets, grid, settings, prisma, nestjs, react-grid-layout] +dependency_graph: + requires: [] + provides: [DashboardModule, DashboardGrid, ClockWidget, WidgetRegistry, SettingsLayout] + affects: [apps/api/prisma/schema.prisma, apps/api/src/app.module.ts, apps/web/src/app/(portal)/page.tsx, apps/web/src/components/layout/header.tsx] +tech_stack: + added: [react-grid-layout@2.2.3, react-resizable] + patterns: [Zustand store without persist, react-grid-layout v2 Responsive API, widget-registry pattern, dragConfig/resizeConfig v2 API] +key_files: + created: + - apps/api/src/dashboard/dashboard.module.ts + - apps/api/src/dashboard/dashboard.controller.ts + - apps/api/src/dashboard/dashboard.service.ts + - apps/api/src/dashboard/dto/save-layout.dto.ts + - apps/api/src/dashboard/dto/create-widget.dto.ts + - apps/api/src/dashboard/dto/update-widget-config.dto.ts + - apps/web/src/components/dashboard/dashboard-grid.tsx + - apps/web/src/components/dashboard/edit-mode-toggle.tsx + - apps/web/src/components/dashboard/widget-catalog-modal.tsx + - apps/web/src/components/dashboard/widget-registry.tsx + - apps/web/src/components/dashboard/widgets/clock-widget.tsx + - apps/web/src/components/dashboard/widgets/widget-wrapper.tsx + - apps/web/src/lib/dashboard-api.ts + - apps/web/src/lib/stores/dashboard-store.ts + - apps/web/src/app/(portal)/settings/layout.tsx + - apps/web/src/app/(portal)/settings/page.tsx + - apps/web/src/components/settings/settings-sidebar.tsx + - apps/web/src/components/dashboard/dashboard-grid.test.tsx + - apps/web/src/components/dashboard/widgets/clock-widget.test.tsx + modified: + - apps/api/prisma/schema.prisma + - apps/api/src/app.module.ts + - apps/web/package.json + - apps/web/src/app/(portal)/page.tsx + - apps/web/src/components/layout/header.tsx + - apps/web/src/messages/de.json + - apps/web/src/messages/en.json + - apps/web/vitest.config.ts + - apps/web/src/test/setup.ts +decisions: + - "react-grid-layout v2 uses dragConfig/resizeConfig instead of isDraggable/isResizable" + - "react-resizable installed as direct dependency (pnpm strict isolation requires it)" + - "widget-registry.tsx uses wireClockWidget() deferred wiring to avoid circular deps" + - "ResizeObserver polyfill added to test setup for jsdom compatibility" + - "Prisma JSON fields cast via unknown to InputJsonValue for type safety" +metrics: + duration: 14min + completed: 2026-06-24T09:25:00Z + tasks: 4 + files_created: 19 + files_modified: 9 +--- + +# Phase 05 Plan 01: Dashboard Grid + Clock Widget + Settings Shell Summary + +Full vertical stack for dashboard: Prisma models (DashboardLayout, WidgetInstance), NestJS CRUD API with userId ownership verification, react-grid-layout v2 Responsive grid with 4-widget registry, clock widget using Intl.DateTimeFormat, Zustand store without persist (D-05), settings page shell with sub-sidebar, and all phase i18n keys. + +## Tasks Completed + +| Task | Name | Commit | Key Files | +|------|------|--------|-----------| +| 1 | Dashboard backend | 950eebb | schema.prisma, dashboard.controller.ts, dashboard.service.ts | +| 2 | Dashboard grid + clock widget + store | d5e1c42 | dashboard-grid.tsx, clock-widget.tsx, widget-registry.tsx, dashboard-store.ts | +| 2 (RED) | Failing tests | 792b766 | dashboard-grid.test.tsx, clock-widget.test.tsx | +| 3 | Settings shell + header link + i18n | 8a9c1ae | settings/layout.tsx, settings-sidebar.tsx, de.json, en.json | +| 4 | Prisma schema push | (no code change) | Database tables created | + +## Verification Results + +- `prisma validate`: PASS +- `tsc --noEmit` (apps/api): PASS +- `tsc --noEmit` (apps/web): PASS +- `vitest run src/components/dashboard`: 5/5 PASS +- `vitest run` (all tests): 31/31 PASS +- JSON parse (de.json, en.json): PASS +- `prisma db push`: "database is already in sync" + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 3 - Blocking] react-grid-layout v2 API changes** +- **Found during:** Task 2 +- **Issue:** react-grid-layout v2 uses `dragConfig`/`resizeConfig` objects instead of `isDraggable`/`isResizable` props. The type `Layouts` is renamed to `ResponsiveLayouts`. +- **Fix:** Rewrote grid component to use v2 API: `dragConfig: { enabled, handle }` and `resizeConfig: { enabled }`. +- **Files modified:** apps/web/src/components/dashboard/dashboard-grid.tsx + +**2. [Rule 3 - Blocking] pnpm strict isolation for react-resizable CSS** +- **Found during:** Task 2 +- **Issue:** `react-resizable/css/styles.css` import failed in tests because react-resizable is a transitive dep of react-grid-layout, not directly installed. pnpm strict isolation blocks resolution. +- **Fix:** Added `react-resizable` as direct dependency in apps/web/package.json. +- **Files modified:** apps/web/package.json + +**3. [Rule 3 - Blocking] ResizeObserver not available in jsdom** +- **Found during:** Task 2 +- **Issue:** DashboardGrid uses ResizeObserver for container width measurement, which jsdom doesn't provide. +- **Fix:** Added ResizeObserver polyfill to apps/web/src/test/setup.ts that fires immediately with mock dimensions. +- **Files modified:** apps/web/src/test/setup.ts + +**4. [Rule 3 - Blocking] widget-registry.ts JSX in .ts file** +- **Found during:** Task 2 +- **Issue:** PlaceholderWidget component uses JSX but file was `.ts` extension. +- **Fix:** Renamed to `widget-registry.tsx`. +- **Files modified:** apps/web/src/components/dashboard/widget-registry.tsx + +**5. [Rule 1 - Bug] Prisma JSON type mismatch** +- **Found during:** Task 1 +- **Issue:** `Record` not assignable to Prisma's `InputJsonValue` type. +- **Fix:** Cast JSON fields via `as unknown as Prisma.InputJsonValue`. +- **Files modified:** apps/api/src/dashboard/dashboard.service.ts + +## Decisions Made + +| Decision | Context | Outcome | +|----------|---------|---------| +| react-grid-layout v2 Responsive API | v2 is a complete TypeScript rewrite with different prop names | Used `dragConfig`/`resizeConfig` objects instead of boolean props | +| react-resizable as direct dep | pnpm strict isolation prevents resolving transitive CSS imports | Added as explicit dependency in apps/web | +| wireClockWidget() pattern | Avoid circular deps between widget-registry and clock-widget | Deferred wiring function called from page.tsx at mount time | +| Prisma db push via docker exec | DB port not exposed to host | Copied schema into API container and ran prisma db push from there | + +## Known Stubs + +| File | Line | Stub | Reason | +|------|------|------|--------| +| widget-registry.tsx | search/calendar/note entries | PlaceholderWidget component | Implemented in plans 05-02 (search/note) and 05-03 (calendar) | +| settings-sidebar.tsx | /settings/dashboard, /settings/dashboard/calendar links | Links to pages not yet created | Created in plans 05-02 and 05-03 | + +## Self-Check: PASSED + +All 19 created files verified present. All 4 commit hashes found in git log.