# Implementation Plan: Todo web app (local)

> **Status: Accepted** (implementation complete 2026-04-29)

## Overview

Ship a client-only Vite + React + TypeScript SPA with MUI, Dexie/IndexedDB persistence, and @dnd-kit for reordering, matching [requirements.md](requirements.md) and [design.md](design.md). **Order of work:** project scaffold and dependency setup (including removal of default test tooling per design scope) → persisted data layer and repository invariants → `useTodoList` (optimistic updates, rollback) → add form and validation → sortable list UI → app shell, empty state, and error surface → manual verification against the design’s correctness properties.

## Tasks

- [x] 1. Scaffold Vite + React + TypeScript and add dependencies
  - Run `create-vite` (or equivalent) for React + TypeScript; set app entry to a single-page shell
  - Install and configure **MUI** (`@mui/material` + required Emotion peers per MUI install docs) and a baseline **theme** in the root layout
  - Install **Dexie**, **@dnd-kit/core**, **@dnd-kit/sortable**, and any minimal **@dnd-kit** utilities needed for keyboard/pointer sensors per design
  - If the Vite template adds Vitest/Jest (or other test scaffolds), **remove** unused test config, scripts, and sample test files so the experiment stays test-free as specified in design
  - Confirm `npm run dev` and `npm run build` succeed
  - _Requirements: 5.1, 5.4, 6.1, 6.2, 6.3_
  - _Design: Key design decisions (stack, no Vitest/Jest) — [design.md](design.md)_

- [x] 2. Dexie schema, database bootstrap, and `todoRepository`
  - Define the `todos` table and Dexie `version` schema with index on `sortOrder` as in design ([Data contracts](design.md#data-contracts))
  - Implement `getAllOrdered()`; `add` with trim, max **2 000** characters after trim, and `sortOrder` assignment + normalization (or equivalent) so the gap-free **0…n-1** invariant holds in one transaction
  - Implement toggle (by id), delete with **re-number** of `sortOrder` in one transaction, and `reorder(orderedIds: string[])` that rewrites contiguous `0…n-1` in **one** Dexie transaction
  - Keep repository free of UI concerns; map DB rows to the `Todo` domain type
  - _Requirements: 1.1, 1.2, 1.3, 2.1, 2.2, 2.3, 3.1, 3.2, 4.3, 6.1_
  - _Design: Data contracts, invariants — [design.md](design.md#data-contracts) — Correctness **Property 3**_

- [x] 3. `useTodoList` hook: load, CRUD, reorder, errors
  - On mount, call `getAllOrdered()`; handle read failure with user-visible error + optional retry (per [Error handling](design.md#error-handling))
  - Expose `add`, `toggle`, `delete`, `reorder` used by the UI; implement **optimistic** updates and **revert** to last successful data + short message on persistence failure
  - Ensure the hook’s in-memory list order always matches the optimistic model until a failed write triggers rollback
  - _Requirements: 1.1, 1.2, 1.3, 2.1, 2.2, 2.3, 3.1, 3.2, 4.1, 4.2, 4.3, 5.2, 5.4, 6.1, 6.2_
  - _Design: Layer and component responsibilities — `useTodoList` — [design.md](design.md#layer-and-component-responsibilities) — Optimistic UI decision — [design.md](design.md#key-design-decisions) — Correctness **Properties 1, 2, 4**_

- [x] 4. `AddTodoForm` component
  - MUI `TextField` (or equivalent) and submit action; **trim** input; block empty/whitespace-only submit (disabled button and/or helper text) — _Requirements: 1.1, 1.2_
  - Enforce **2 000**-character cap after trim with user-visible failure per design — _Requirements: 1.3_
  - Wire to `useTodoList.add` — _Requirements: 1.1_
  - _Design: `AddTodoForm` — [design.md](design.md#layer-and-component-responsibilities)_

- [x] 5. `TodoSortableList`, `TodoRow`, and dnd-kit integration
  - Compose **SortableContext** and sortable items; use `PointerSensor` and **KeyboardSensor**; apply activation constraints if using a drag handle
  - Each row: completion control (single repeatable toggle, e.g. checkbox), unambiguous **completed** styling, delete control, and accessible labels
  - On drag end, compute new id order, update hook state, call repository `reorder` via the hook; visible order matches immediately — _Requirements: 2.1, 2.2, 2.3, 4.1, 4.2_
  - List semantics and focus order as far as MUI + dnd-kit allow (per [Accessibility (DnD)](design.md#layer-and-component-responsibilities))
  - _Requirements: 2.1, 2.2, 2.3, 3.1, 4.1, 4.2, 4.3, 5.2, 5.3_
  - _Design: `TodoSortableList` + `TodoRow` — [design.md](design.md#layer-and-component-responsibilities) — DnD flow — [design.md](design.md#architecture)_

- [x] 6. `TodoApp` (or `App`) shell: layout, empty state, errors
  - MUI `Container` (or equivalent) and single primary view; `ThemeProvider` and global layout
  - When there are **no** todos, show a clear **empty state**; when there are todos, show the full ordered list — _Requirements: 5.2, 5.3_
  - Surface persistence/read errors (e.g. MUI `Snackbar` or `Alert`) as in design, without leaving contradictory UI after rollback
  - Confirm add, toggle, delete, and reorder are usable without a custom backend (offline / no project API) — _Requirements: 5.1, 5.4, 6.1, 6.2, 6.3_
  - _Design: `TodoApp` / Error handling — [design.md](design.md#layer-and-component-responsibilities) — [design.md](design.md#error-handling)_

- [x] 6.1 Manual verification (no automated tests in scope)
  - **Property 1: Persisted order after reorder** — Reorder, wait for success, hard refresh: order matches; **Validates: Requirements 4.1, 4.2, 4.3, 6.1** — [design.md](design.md#property-1-persisted-order-matches-last-successful-reorder) — _Requirements: 4.1, 4.2, 4.3, 6.1_
  - **Property 2: CRUD durability** — Add/toggle/delete sequences, then refresh and cold restart: data matches last success; **Validates: Requirements 1.1, 2, 3, 6.1, 6.2** — [design.md](design.md#property-2-crud-durability) — _Requirements: 1.1, 1.2, 1.3, 2.1, 2.2, 2.3, 3.1, 3.2, 6.1, 6.2_
  - **Property 3: `sortOrder` invariant** — After mutations, devtools/optional logging confirm contiguous `0…n-1` (or user-visible order consistency); **Validates: Requirements 4.3** — [design.md](design.md#property-3-invariant-on-sortorder) — _Requirements: 4.3_
  - **Property 4: Rapid operations** — Rapid toggles/reorders/deletes: no stuck duplicate/missing order after operations settle; **Validates: Requirements 2, 3, 4** — [design.md](design.md#property-4-rapid-operations) — _Requirements: 2.1, 2.2, 2.3, 3.1, 3.2, 4.1, 4.2, 4.3_
  - **Offline check:** Airplane mode or no network, refresh: still local-only; **Validates: Requirements 5.4, 6** — [design.md](design.md#testing-and-verification) — _Requirements: 5.4, 6.1, 6.2, 6.3_

## Notes

- **Gate:** No application implementation should start until this plan is **human-accepted**; then follow [.cursor/skills/sdd-execute-plan/SKILL.md](.cursor/skills/sdd-execute-plan/SKILL.md) to derive a Cursor Plan and mark checkboxes `[x]` in this file as work completes.
- **Traceability:** Criterion numbers match [requirements.md](requirements.md) (e.g. `3.1` = Requirement 3, criterion 1). Design anchors cite [design.md](design.md) sections and **Correctness property** names.
- **PR / batching:** Scaffold + repository can land in one small PR, then UI in a second, if you prefer reviewability; the hook (task 3) should be merged before or with list UI so integration stays green.
