{"ns":"todos","title":"Task List","version":"2.4","summary":"Task List is a classic personal todo list. People type a title and press Enter to add a task, tick tasks off, edit them inline, delete them, switch between All, Active and Completed views and clear what is done. Each browser tab keeps its own list on the server.","problem":"A todo list is only useful if the counter, the visible items and the stored list always agree, and if keyboard-only use is as complete as mouse use.","personas":[{"name":"Everyday user","need":"Capture, tick off and tidy tasks quickly, mostly from the keyboard."}],"goals":["The \"items left\" counter always equals the number of active todos.","Every edit gesture (Enter, Escape, blur, empty title) has one predictable outcome.","Bulk actions only affect the todos they promise to affect."],"features":[{"id":"LST","title":"List and counter","summary":"Seeded list, footer counter and empty state.","reqs":[{"id":"FR-LST-01","weight":"Must","text":"A fresh tab shows three seeded todos, with the completed one struck through, and a footer with the active counter, the All / Active / Completed filters and Clear completed.","accept":["Buy oat milk (active), Book dentist appointment (completed), Renew library card (active)","Footer \"2 items left\" with All selected"]},{"id":"FR-LST-02","weight":"Must","text":"The footer counter equals the number of active (not completed) todos, and is singular for one: \"1 item left\".","accept":["Ticking Buy oat milk: \"1 item left\"; unticking: \"2 items left\"","All completed: \"0 items left\""]},{"id":"FR-LST-03","weight":"Could","text":"With no todos the list, footer and toggle-all chevron are hidden and a hint is shown.","accept":["\"Nothing to do — add your first todo above.\""]}]},{"id":"ADD","title":"Adding todos","summary":"Keyboard-only entry.","reqs":[{"id":"FR-ADD-01","weight":"Must","text":"Typing a title in \"What needs to be done?\" and pressing Enter appends an unchecked todo and empties the input; there is no add button.","accept":["\"Water the plants\" is last and unchecked; \"3 items left\""]},{"id":"FR-ADD-02","weight":"Should","text":"Todos keep the order in which they were added.","accept":["Three more todos added in sequence appear after the seeded three in the same order; \"5 items left\""]},{"id":"FR-ADD-03","weight":"Should","text":"Empty or whitespace-only input adds nothing; surrounding spaces are trimmed from a valid title.","accept":["Enter on empty and on \"     \" leaves three todos","\"   Feed the cat   \" is added as \"Feed the cat\""]},{"id":"FR-ADD-04","weight":"Could","text":"Titles are shown as plain text and long titles wrap inside the list.","accept":["<b>bold?</b> & \"quotes\" is displayed literally, not as bold","A 100-character title wraps without horizontal scroll"]}]},{"id":"CMP","title":"Completing todos","summary":"Single and bulk completion.","reqs":[{"id":"FR-CMP-01","weight":"Must","text":"The checkbox toggles a todo between active and completed (struck through) and updates the counter."},{"id":"FR-CMP-02","weight":"Must","text":"The chevron left of the input (\"Mark all as complete\") completes every todo; clicking it again reopens every todo and hides Clear completed.","accept":["All three struck through, \"0 items left\"; again: none completed, \"3 items left\""]},{"id":"FR-CMP-03","weight":"Must","text":"Clear completed removes only the completed todos and then hides itself.","accept":["After ticking Buy oat milk: only Renew library card remains, \"1 item left\", button hidden","With the seed, clearing leaves Buy oat milk and Renew library card and \"2 items left\"","Mark all then Clear completed leaves the empty-list state"]}]},{"id":"EDT","title":"Editing and deleting","summary":"Inline edit and hover delete.","reqs":[{"id":"FR-EDT-01","weight":"Must","text":"Double-click opens an inline editor with the current text; Enter saves the trimmed text and the change survives a reload.","accept":["\"Renew library card online  \" is saved as \"Renew library card online\""]},{"id":"FR-EDT-02","weight":"Should","text":"Escape discards the edit and keeps the original title.","accept":["Typing \"Buy almond milk\" then Escape leaves \"Buy oat milk\""]},{"id":"FR-EDT-03","weight":"Should","text":"Clicking elsewhere (blur) saves the edit.","accept":["\"Buy oat milk and bread\" is kept after clicking the heading"]},{"id":"FR-EDT-04","weight":"Must","text":"Saving an empty title deletes the todo; no blank row is ever left.","accept":["Clearing Renew library card and pressing Enter leaves two todos and \"1 item left\""]},{"id":"FR-EDT-05","weight":"Should","text":"A × button is revealed only while hovering a row and deletes that todo.","accept":["No × without hover; after hover and click, Buy oat milk is gone and \"1 item left\""]}]},{"id":"FLT","title":"Filters","summary":"Hash-routed All / Active / Completed views.","reqs":[{"id":"FR-FLT-01","weight":"Should","text":"Filters show the right subset and are reflected in the URL hash; the current filter is outlined.","accept":["Active: #/active, Buy oat milk and Renew library card","Completed: #/completed, only Book dentist appointment","All shows all three"]},{"id":"FR-FLT-02","weight":"Could","text":"A filter URL opens directly on that filter and the browser Back button returns to the previous filter.","accept":["/todos/#/completed shows only Book dentist appointment; Active then Back shows Completed again"]},{"id":"FR-FLT-03","weight":"Should","text":"Completing a todo while the Active filter is selected removes it from the view.","accept":["Ticking Buy oat milk: it disappears, \"1 item left\""]}]},{"id":"PER","title":"Persistence and API","summary":"Per-tab server state and REST interface.","reqs":[{"id":"FR-PER-01","weight":"Should","text":"Changes survive a reload in the same tab; a new tab starts from the seeded three todos.","accept":["Added Water the plants, reload: four todos, \"3 items left\"; new tab: seeded three"]},{"id":"FR-PER-02","weight":"Should","text":"The REST API supports list, add, update, delete and reset with specific errors.","accept":["GET lists 3 todos, active 2, completed 1","Blank title: 422 \"Title is required\"","Add returns 201 with id t4; PATCH completed true and DELETE return 200; DELETE again 404","Reset restores the seeded three"]}]}],"nfr":[{"id":"NFR-01","weight":"Must","text":"Data integrity: the counter, the visible list and the stored list never disagree after any add, edit, delete, toggle or clear."},{"id":"NFR-02","weight":"Should","text":"Keyboard accessibility: add, save and cancel are available from the keyboard (Enter, Escape)."}],"glossary":[{"term":"Active","meaning":"A todo that is not completed."},{"term":"Toggle all","meaning":"The chevron left of the input that completes or reopens every todo."}],"outOfScope":["Drag to reorder","Multiple lists"]}