From bd1415e9e8aae4f97534cf7061d6b709f0692b0a Mon Sep 17 00:00:00 2001 From: SemianiakaVY Date: Thu, 8 Oct 2026 15:45:44 +0000 Subject: [PATCH] chore(template): sync SPEC.md --- SPEC.md | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 SPEC.md diff --git a/SPEC.md b/SPEC.md new file mode 100644 index 0000000..a6e686d --- /dev/null +++ b/SPEC.md @@ -0,0 +1,123 @@ +# Simple Todo List — product specification + +This is the contract the project is built against. It is written for the agent that scaffolds the +repository, but it doubles as the human-readable brief: every requirement below is meant to be +implementable and verifiable. + +This is the **minimal demo** template. The goal is the smallest website that is genuinely useful, +so the spec is deliberately short and the non-goals matter as much as the goals. + +Values in angle brackets (``, ``) come from the project-creation dialog and +are recorded in the project record (`.w4c/project.json` → `fields`); replace them as you read. + +## 1. Goal + +A single static page that manages a todo list — add a todo, mark it done or undone, delete it, +clear the completed ones, filter by all / active / done — and remembers the list in the browser +between visits. It must be **usable the moment it is served**: no install step, no build step, no +backend and no account. `` is the page title; `` is the single accent colour. + +### Non-goals (do not build) + +- No backend, API, database or authentication. +- No framework, package manager, bundler or third-party runtime — plain HTML, CSS and JavaScript. +- No accounts, sharing, sync between devices or server persistence. +- No service worker / offline caching, no analytics, no ads. +- No admin panel, control panel, workflows or database layer. + +## 2. The screen + +One route, `/` (the static `index.html`). It contains: + +- a **header** with ``; +- a **composer** — a labelled text input plus an Add control (Enter also submits); +- a **list** of todos, each row: a checkbox/toggle ("done"), the title, a Delete control + (visible or on row hover/focus — always reachable by keyboard); +- a **footer** with the count of remaining active todos, the filters (All / Active / Done) and a + **Clear completed** action shown only when at least one todo is done; +- an explicit **empty state** when there are no todos (and a distinct message when the filter has + no matches), and a **hidden/disabled** Delete/Checkbox state that never leaves a row inaccessible. + +No routing beyond the single page; `/404` is not required. + +## 3. Data model + +One entity, persisted as a JSON array in `localStorage`: + +- **Todo** — `id` (unique, e.g. a stringified timestamp or `crypto.randomUUID()`), `title` + (non-empty, trimmed), `done` (boolean), `createdAt` (ISO timestamp). + +Storage contract: a single documented key holds the array (e.g. `simple-todo.items`). A missing, +empty or unparseable value is treated as an empty list — never throw. Unknown fields are ignored; +a malformed stored item is dropped, not rendered as a broken row. The filter selection is UI state +and does **not** need to persist (persisting just the filter is optional). + +## 4. Key flows + +1. **Add.** The user types a non-empty title and presses Add (or Enter): the todo appears at the + top of the list, the input clears and refocuses. Whitespace-only input is rejected (the Add + control is disabled and the input stays unchanged). +2. **Toggle.** Clicking the checkbox / row toggles `done`; the title gets a struck-through done + style and the remaining count updates. +3. **Delete.** The Delete control removes the row; the list and the empty state update immediately. +4. **Clear completed.** Shown only when at least one todo is done; removes every done todo after + the built-in confirmation (a native `confirm()` is acceptable) and updates the list. +5. **Filter.** All / Active / Done switches the visible rows; the active filter is visibly marked + and exposed to assistive tech (`aria-pressed` or equivalent). The footer count reflects the + active todos regardless of the filter. +6. **Persist.** Every mutation writes the list to `localStorage`; reloading the page restores the + list exactly (order, done state, titles) and the correct remaining count. + +## 5. Functional requirements + +- **Input validation:** titles are trimmed; empty/whitespace titles are never added; long titles + wrap instead of overflowing; a sensible maximum is enforced (e.g. 200 characters, hinted to the + user) rather than silently truncating stored data. +- **Rendering:** the list is rendered from the stored array (a single `render()` function is + enough); the DOM never accumulates stale rows across re-renders. +- **Counts:** the "X active" count updates on every add / toggle / delete / clear / filter change. +- **Keyboard:** everything the mouse can do is reachable and operable with the keyboard; focus is + visible and focus order follows the visual order. The composer supports Enter to add. +- **Safe text:** todo titles are inserted as **text**, never as HTML (no `innerHTML` with user + input), so a title like `` renders as literal text. +- **No network:** the page makes no requests; it works when opened directly from the filesystem. + +## 6. Non-functional requirements + +- **Dependency-free:** plain HTML + CSS + JavaScript. ES modules or one `