Architecture refinements before module work begins: - Calendars become first-class entities (mirror of lists). Each calendar has its own visibility (private | household) and is independently shareable. Updated CLAUDE.md data model and task 10. - Drop the singleton/parameterized split for dashboard widgets. Every widget declares a configSchema + defaultConfig + resolveConfigOptions and every placement is an independent instance — same widgetId can appear multiple times on one dashboard pointed at different things. Updated task 04 contract; tasks 11/12 widget sections aligned. - Add tasks 25 (multiple dashboards per user) and 26 (customizable layout + widget configuration). Replaces the previously-considered three-task plan with a cleaner two-task split that the uniform contract enables. Phase 3 index updated; STATUS records the rationale. - Task 20 reframed as a single-dashboard MVP that exercises the new contract end-to-end before the customization layer lands.
2.8 KiB
2.8 KiB
20 — Dashboard composition (single-dashboard MVP)
Goal
Each user sees a single default dashboard with widgets pre-seeded from the registry. Every widget is rendered with a config (per the task 04 contract). No customization yet — task 25/26 add multiple dashboards and the editor.
Why
Lands a working dashboard quickly so the app is usable while the customization layer is built. Validates the configurable widget contract end-to-end. The schema introduced here (one row per user) gets generalized in task 25 to support many dashboards per user.
Depends on
- 10 (calendar), 11 (lists), 12 (notes)
Scope
Schema (interim, generalized in task 25)
Add a default_dashboard_layout jsonb column on users. Shape:
{
"version": 1,
"widgets": [
{
"widgetId": "calendar.upcoming",
"config": { "calendarIds": "all", "days": 3 },
"x": 0,
"y": 0,
"w": 6,
"h": 3,
},
{
"widgetId": "lists.list",
"config": { "listIds": "all", "showCompleted": false },
"x": 6,
"y": 0,
"w": 6,
"h": 3,
},
],
}
If null, fall back to the registry's default seed (sorted by defaultPriority, packed by defaultSize).
Layout
- 12-col responsive grid using basic CSS Grid (no drag library yet — task 26 introduces it).
- Mobile: single column ordered by
ythenx. - Each widget is a server component that receives
configand renders inside a card. Suspense boundary per widget so they load in parallel.
Seeded widgets the registry must contribute
These are widget definitions, not hardcoded slots:
calendar.upcoming(calendar module)calendar.month(calendar module)lists.list(lists module)notes.filtered(notes module)core.activity(_core; depends on task 22 — until then render a placeholder card)
Header
- Page title "Dashboard".
- "+" floating action button opens the quick-add menu (task 21).
- No edit-mode toggle yet — that lands in task 26.
Out of scope
- Multiple dashboards (task 25).
- Drag, resize, picker, configure UI (task 26).
- User-configurable widget order. Defaults are taken from
defaultPriority.
Acceptance criteria
- First-time user lands on a populated dashboard with widgets seeded from the registry's
defaultPriority+defaultSize. - Every widget receives a typed
configand renders withoutif (widgetId === ...)branches in the dashboard code. - Removing a module from
src/modules/index.tscleanly removes its widgets — no errors, no blank slot. - Widgets load in parallel (verify in network tab — no waterfall).
- Mobile (375px) is usable without horizontal scroll.
- The schema column added here has a clean migration path to the
dashboardstable introduced in task 25 (a one-line copy-into-default-dashboard migration is enough).