phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics
phase
plan
subsystem
tags
dependency_graph
tech_stack
key_files
decisions
metrics
05-dashboard-calendar
02
dashboard
dashboard
widgets
search
notes
markdown
settings
prisma
i18n
requires
provides
affects
DashboardModule
WidgetRegistry
SettingsLayout
SearchWidget
NoteWidget
WidgetSettingsPanel
SearchProviderForm
SearchProviderModel
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
added
patterns
@uiw/react-md-editor@4.1.1
rehype-sanitize
AbortController for in-flight request cancellation
debounced autosave
wireWidget deferred wiring
SearchProvider defaults-as-constants merged with user rows
created
modified
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
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
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)
duration
completed
tasks
files_created
files_modified
4min
2026-06-24T12:57:00Z
4
8
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<ReturnType<typeof setTimeout>>() without an argument fails in React 19 with strict TypeScript -- Expected 1 arguments, but got 0
Fix: Changed to useRef<ReturnType<typeof setTimeout> | 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