Apps

Todo

# todo — a normal app with an app-owned persisted model A small TUI app that demonstrates the recommended app-state persistence pattern: define your own schema directory, load the last snapshot at startup, and `[$model persist]` after each change. Launch: ```sh retro app deft/todo retra app deft/todo ```` ## Layout ```text packages/todo/ ├── package.dft ├── src/store.dft # headless load/save + pure state edits ├── src/todo.dft # Deftlet panel (draw + keys) ├── test/test_todo.dft └── todo.scm/ # app-owned schema, generated by Schema Builder ├── types.dft ├── design.dft ├── persist.dft ├── model.dft └── schema-meta.dft ```` `todo.scm/` defines two tables: - `Todo` — `id`, `title`, `done`, `created`. - `AppState` — a singleton (`id "app"`) holding the last filter, selected todo id, and save time. ## State State lives in `.deft/todo.db` (override with `TODO_DB`). On startup the app calls `[$model load]`; a missing `_persist_meta_` is a normal first run. The interface is composed with `deft/ui/compose` (`[div]`, `|> [children …]`, `|> [props …]`) from the standard UI components: a `ui/multiline-text` editor for new todos, a `ui/checkbox` per todo, and `ui/button` / `ui/label` / `ui/row` / `ui/column` for actions and layout. There are no dialogs in the input path. After every mutation it rebuilds a fresh model snapshot and calls `[$model persist]`. This is a snapshot replace, not an append: deleting a todo in the UI removes its row on the next save. ## Keys | Key | Action | |-----|--------| | type + `enter` | Add the current editor text as a todo | | `Add` button | Add the current editor text as a todo | | click checkbox | Toggle that todo done | | `space` / `enter` | Toggle the selected todo (editor unfocused) | | click `✕` / `delete` | Delete that / the selected todo | | `All` / `Active` / `Done` | Filter buttons | | `f` | Cycle filter: all / active / done | | `↑` / `↓` | Move selection while the editor is unfocused | | `/` / `tab` | Focus the multiline editor | | `esc` | Leave the editor so list shortcuts work | | `r` | Reload from disk | | `m` | Migrate the DB to `todo.scm` after a schema change | The filter and selected todo are persisted, so reopening the app restores the same view. ## Schema changes Edit/regenerate `todo.scm/` with the Schema Builder. The generated schema version is checked by `[$model load]`; after a schema change press `m` to run the generated `migrate`, or run it directly through `deft/persist`. The schema descriptor is stored in `_persist_meta_`; it identifies the exact version and layout of the persisted data. See the manual page Persisting App State for the full walkthrough. ## Tests ```sh deft test packages/todo/test/test_todo.dft ````