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.3 KiB
2.3 KiB
11 — Lists module (shopping + task)
Goal
Implement the lists module supporting two list types out of the box (shopping, task), with the schema designed so additional types can be added later without migration.
Depends on
- 04, 07
Scope
Schema
lists:id,household_id,type(text — not an enum, to allow extension),name,archived,created_at.list_items:id,list_id,text,doneboolean,qtytext nullable,notestext nullable,due_attimestamptz nullable,assignee_idfk users nullable,positionint (for ordering),created_at,updated_at.
Seed: one default list of each type per household on first access (idempotent).
Server
listLists({ type? }),getList(id),createList,renameList,archiveList.addItem,toggleItem,updateItem,deleteItem,reorderItems.
UI
/listsindex showing all lists grouped by type./lists/[id]— fast keyboard-driven entry: focus stays in input, Enter adds, checkbox toggles, swipe-left (mobile) deletes.- Realtime: SSE subscription on the list id; updates from the other user appear without refresh. (Implementation detail: Postgres
LISTEN/NOTIFYchannellist:<id>; thin SSE route handler bridges it. Document the pattern indocs/decisions/.)
Manifest
- Entity types:
lists.list(shareable read+write via share token),lists.item(inherits via list, not directly shareable). - Quick-adds: "Add to shopping" / "Add to tasks" (single item to the household's default list of that type), "New list".
- Widget (uniform contract per task 04):
lists.list—config: { listIds: "all" | string[]; showCompleted: boolean; limit?: number }. Default{ listIds: "all", showCompleted: false }.resolveConfigOptionsreturns the user's accessible lists with type/name. Multiple instances per dashboard supported (one per list, or merged across several).
Out of scope
- Reordering across lists.
- Per-item images.
- Recurring tasks (use reminders module later if needed).
Acceptance criteria
- Both default lists are auto-seeded.
- Adding an item on one device appears on the other within ~1s via SSE.
typeistextnotenum— adding a third type works without a migration.- Playwright: add item → check it off → archive list.