# 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`, `done` boolean, `qty` text nullable, `notes` text nullable, `due_at` timestamptz nullable, `assignee_id` fk users nullable, `position` int (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 - `/lists` index 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/NOTIFY` channel `list:`; thin SSE route handler bridges it. Document the pattern in `docs/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 }`. `resolveConfigOptions` returns 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. - [ ] `type` is `text` not `enum` — adding a third type works without a migration. - [ ] Playwright: add item → check it off → archive list.