135 lines
6.8 KiB
Markdown
135 lines
6.8 KiB
Markdown
---
|
|
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<string, unknown>` 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.
|