From 7616365cbe2084cb38888cc68566c4bf0fb62f05 Mon Sep 17 00:00:00 2001 From: Schalli Date: Wed, 24 Jun 2026 15:03:55 +0200 Subject: [PATCH] docs(05-02): complete search + notes widgets + settings plan --- .planning/REQUIREMENTS.md | 8 +- .planning/ROADMAP.md | 4 +- .planning/STATE.md | 17 +-- .../05-dashboard-calendar/05-02-SUMMARY.md | 106 ++++++++++++++++++ 4 files changed, 122 insertions(+), 13 deletions(-) create mode 100644 .planning/phases/05-dashboard-calendar/05-02-SUMMARY.md diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index a715f11..2590d5b 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -42,9 +42,9 @@ Requirements for initial release. Each maps to roadmap phases. - [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) +- [x] **DASH-04**: Suchleiste-Widget (oeffnet Google/Suchmaschine im Browser) - [ ] **DASH-05**: Kalender-Widget mit Terminvorschau -- [ ] **DASH-06**: Notiz-Widget (Freitext-Kachel) +- [x] **DASH-06**: Notiz-Widget (Freitext-Kachel) - [x] **DASH-07**: Dashboard-Layout wird pro Benutzer gespeichert ### Kalender-Integration @@ -146,9 +146,9 @@ Which phases cover which requirements. Updated during roadmap creation. | DASH-01 | Phase 5 | Complete | | DASH-02 | Phase 5 | Complete | | DASH-03 | Phase 5 | Complete | -| DASH-04 | Phase 5 | Pending | +| DASH-04 | Phase 5 | Complete | | DASH-05 | Phase 5 | Pending | -| DASH-06 | Phase 5 | Pending | +| DASH-06 | Phase 5 | Complete | | DASH-07 | Phase 5 | Complete | | CAL-01 | Phase 5 | Pending | | CAL-02 | Phase 5 | Pending | diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index f688767..90c4b52 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -169,7 +169,7 @@ Decimal phases appear between their surrounding integers in numeric order. **Wave 2** *(blocked on Wave 1 completion)* -- [ ] 05-02-PLAN.md -- Search + Notes widgets, widget settings panel, SearchProvider backend (DASH-04/06) +- [x] 05-02-PLAN.md -- Search + Notes widgets, widget settings panel, SearchProvider backend (DASH-04/06) **Wave 3** *(blocked on Wave 2 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 | 1/5 | In Progress| | +| 5. Dashboard & Calendar | 2/5 | In Progress| | | 6. Desktop Client & CI/CD | 0/TBD | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 4ae80f5..95c133d 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,14 +3,14 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone status: executing -stopped_at: Completed 05-01-PLAN.md -last_updated: "2026-06-24T09:27:38.939Z" +stopped_at: Completed 05-02-PLAN.md +last_updated: "2026-06-24T13:02:42.630Z" last_activity: 2026-06-24 -- Phase 05 execution started progress: total_phases: 6 completed_phases: 3 total_plans: 21 - completed_plans: 16 + completed_plans: 17 percent: 50 --- @@ -26,11 +26,11 @@ See: .planning/PROJECT.md (updated 2026-06-18) ## Current Position Phase: 05 (dashboard-calendar) — EXECUTING -Plan: 2 of 5 +Plan: 3 of 5 Status: Ready to execute Last activity: 2026-06-24 -- Phase 05 execution started -Progress: [██▓░░░░░░░] 25% +Progress: [████████░░] 81% ## Performance Metrics @@ -55,6 +55,7 @@ Progress: [██▓░░░░░░░] 25% | 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 | +| Phase 05-dashboard-calendar P02 | 4min | 4 tasks | 16 files | ## Accumulated Context @@ -76,6 +77,8 @@ Recent decisions affecting current work: - [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 +- [05-02]: SearchProvider defaults as constants merged with user DB rows (no seed migration) +- [05-02]: useRef with explicit undefined initial value for React 19 strict TypeScript ### Pending Todos @@ -95,6 +98,6 @@ Items acknowledged and carried forward from previous milestone close: ## Session Continuity -Last session: 2026-06-24T09:27:38.933Z -Stopped at: Completed 05-01-PLAN.md +Last session: 2026-06-24T12:57:00Z +Stopped at: Completed 05-02-PLAN.md Resume file: None diff --git a/.planning/phases/05-dashboard-calendar/05-02-SUMMARY.md b/.planning/phases/05-dashboard-calendar/05-02-SUMMARY.md new file mode 100644 index 0000000..27a22dd --- /dev/null +++ b/.planning/phases/05-dashboard-calendar/05-02-SUMMARY.md @@ -0,0 +1,106 @@ +--- +phase: 05-dashboard-calendar +plan: 02 +subsystem: dashboard +tags: [dashboard, widgets, search, notes, markdown, settings, prisma, i18n] +dependency_graph: + requires: [DashboardModule, WidgetRegistry, SettingsLayout] + provides: [SearchWidget, NoteWidget, WidgetSettingsPanel, SearchProviderForm, SearchProviderModel] + affects: [apps/api/prisma/schema.prisma, apps/web/src/components/dashboard/widget-registry.tsx, apps/web/src/lib/dashboard-api.ts, apps/web/src/messages/en.json, apps/web/src/messages/de.json] +tech_stack: + added: ["@uiw/react-md-editor@4.1.1", rehype-sanitize] + patterns: [AbortController for in-flight request cancellation, debounced autosave, wireWidget deferred wiring, SearchProvider defaults-as-constants merged with user rows] +key_files: + created: + - apps/web/src/components/dashboard/widgets/search-widget.tsx + - apps/web/src/components/dashboard/widgets/note-widget.tsx + - apps/web/src/components/dashboard/widgets/search-widget.test.tsx + - apps/web/src/components/dashboard/widgets/note-widget.test.tsx + - apps/web/src/app/(portal)/settings/dashboard/page.tsx + - apps/web/src/components/settings/widget-settings-panel.tsx + - apps/web/src/components/settings/search-provider-form.tsx + - apps/api/src/dashboard/dto/create-search-provider.dto.ts + modified: + - apps/web/src/components/dashboard/widget-registry.tsx + - apps/web/src/lib/dashboard-api.ts + - apps/web/package.json + - apps/web/src/messages/en.json + - apps/web/src/messages/de.json + - apps/api/prisma/schema.prisma + - apps/api/src/dashboard/dashboard.controller.ts + - apps/api/src/dashboard/dashboard.service.ts +decisions: + - "useRef with explicit undefined initial value for React 19 strict TypeScript compatibility" + - "SearchProvider defaults as code constants merged with user DB rows (no seed migration needed)" + - "typeof narrowing for unknown config.title to satisfy ReactNode type constraint" + - "prisma db push via host-to-container IP (DB port not exposed to host)" +metrics: + duration: 4min + completed: 2026-06-24T12:57:00Z + tasks: 4 + files_created: 8 + files_modified: 8 +--- + +# Phase 05 Plan 02: Search + Notes Widgets + Widget Settings Summary + +Search widget with provider dropdown and new-tab open via window.open(url, '_blank', 'noopener,noreferrer'), Notes widget with MDEditor + rehype-sanitize + debounced autosave using AbortController, SearchProvider Prisma model with defaults-as-constants CRUD, and Widget Settings panel (Settings > Dashboard) with clock timezone/date toggle, note title editor, and custom search provider management with {query} client-side validation. + +## Tasks Completed + +| Task | Name | Commit | Key Files | +|------|------|--------|-----------| +| 1 (RED) | Failing tests for search + note widgets | 97c1380 | search-widget.test.tsx, note-widget.test.tsx | +| 1 (GREEN) | Search + Notes widgets implementation | dd02098 | search-widget.tsx, note-widget.tsx, widget-registry.tsx, dashboard-api.ts | +| 2 | SearchProvider backend (model + CRUD + defaults) | 38dcfdf | schema.prisma, dashboard.controller.ts, dashboard.service.ts, create-search-provider.dto.ts | +| 3 | Widget settings panel (Settings > Dashboard) | 7e2592b | page.tsx, widget-settings-panel.tsx, search-provider-form.tsx, en.json, de.json | +| 4 | Prisma schema push | (no code change) | Database SearchProvider table created | + +## Verification Results + +- `prisma validate`: PASS +- `tsc --noEmit` (apps/api): PASS +- `tsc --noEmit` (apps/web): PASS +- `vitest run src/components/dashboard`: 14/14 PASS (4 test files) +- `prisma db push`: "database is already in sync" (second run confirms) + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 1 - Bug] useRef missing initial value for React 19 strict mode** +- **Found during:** Task 3 (tsc --noEmit verification) +- **Issue:** `useRef>()` without an argument fails in React 19 with strict TypeScript -- `Expected 1 arguments, but got 0` +- **Fix:** Changed to `useRef | undefined>(undefined)` for both timerRef and abortRef +- **Files modified:** apps/web/src/components/dashboard/widgets/note-widget.tsx +- **Commit:** 7e2592b (included in Task 3 commit) + +**2. [Rule 1 - Bug] unknown type not assignable to ReactNode in JSX** +- **Found during:** Task 3 (tsc --noEmit verification) +- **Issue:** `widget.config.title` is `unknown`, and using it in a `&&` JSX chain caused TS2322: `Type 'unknown' is not assignable to type 'ReactNode'` +- **Fix:** Changed to `typeof widget.config.title === 'string' && widget.config.title !== ''` narrowing +- **Files modified:** apps/web/src/components/settings/widget-settings-panel.tsx +- **Commit:** 7e2592b (included in Task 3 commit) + +**3. [Rule 2 - Missing critical] i18n keys for search provider management** +- **Found during:** Task 3 (search-provider-form.tsx creation) +- **Issue:** SearchProviderForm uses t('search.providers'), t('search.addProvider'), t('search.addProviderButton') which did not exist in the translation files +- **Fix:** Added 3 new i18n keys to both en.json and de.json +- **Files modified:** apps/web/src/messages/en.json, apps/web/src/messages/de.json +- **Commit:** 7e2592b (included in Task 3 commit) + +## Decisions Made + +| Decision | Context | Outcome | +|----------|---------|---------| +| useRef explicit undefined init | React 19 strict TS requires argument | Added `undefined` initial value with union type | +| typeof narrowing for config.title | unknown not assignable to ReactNode in JSX | Used typeof string check instead of truthiness | +| DB push via container IP | DB port not exposed to host, docker exec path doesn't have schema | Used Docker internal IP 172.22.0.2 with DATABASE_URL from host | + +## Known Stubs + +| File | Line | Stub | Reason | +|------|------|------|--------| +| widget-registry.tsx | calendar entry (line 181) | PlaceholderWidget for calendar | Implemented in plan 05-03 | + +## Self-Check: PASSED