# Shelves data model Replace the TODO-state-based book model with shelf-based organization. Shelves are top-level Org headings; books are nested underneath them. ## Motivation Books-as-top-level-headings with TODO states (WANT/READING/READ/ABANDONED) made the file's structure reflect lifecycle status rather than organizing concepts. The user wants arbitrary grouping ("shelves") as the primary organizing axis. TODO states are removed — logbook entries (already present) record when reading happened. ## Org data model ```org #+TITLE: Spine * Fiction ** Piranesi :PROPERTIES: :AUTHOR: Susanna Clarke :FORMAT: ebook :REC_BY: Alex :REC_NOTE: Le Guin at her most human :RATING: :ADDED: [2026-04-01] :LAST_MODIFIED: [2026-04-01] :ID: 5e8d-pir :END: ::LOGBOOK: - State "READ" from "WANT" [2026-01-10] ::END: - [2025-11-22] The pronoun game is a genuinely fresh take on identity. * Non-Fiction ** The Checklist Manifesto ... ``` - Shelves are level-1 headlines (`*`) - Books are level-2 headlines (`**`) - Books keep their TODO keyword syntax for `org-mode` compatibility, but the app ignores it entirely - The `#+TODO:` line is removed — no TODO states - Empty shelves (a level-1 headline with no children) are valid and appear in the UI - LOGBOOK drawers remain for historical state-change records but are not surfaced by the UI ## Key functions ### `spine-shelves` (new) Returns an ordered list of shelf names (strings), one per level-1 headline that is not a COMMENT or archive target. Empty shelves are included. ### `spine-books` (modified) Walks level-1 headlines as shelves. For each shelf, walks level-2 children as books. Returns flat plist list; each book plist gains a `:shelf` key with the parent headline text. No status/TODO filtering. Places that previously checked Todo state (e.g. `spine-set-status`) are removed — the only remaining mutable fields are notes, rating, format. ### `spine-index-model` (modified) Groups books by `:shelf` instead of `:status`. Accepts an optional `shelf` filter (instead of `read`/`want`/`all`) to show one shelf. Includes shelf nav items for all shelves (even empty ones, from `spine-shelves`). Removes: - Summary groups (READ/ABANDONED links) - Concise view truncation - Status-related book model fields (status_class, status_label) ### `spine-add-book` (modified) Takes required `:shelf` argument. Inserts the new book heading under the matching level-1 shelf headline instead of at file end. If the shelf doesn't exist, signals an error (shelves are created manually). Removes: - `org-todo "WANT"` call - `#+TODO:` file initialization - Category field logic (replaced by shelf) ### Functions removed - `spine-set-status` — no status to change. Logbook records history. - All HTTP endpoints and UI actions that invoke it. ## UI changes ### Index view (`index.mustache`) - **Titlebar**: `N books · M shelves` - **Filter bar**: replaced with shelf nav — links for each shelf name plus "All" (default). Active shelf highlighted. - **Groups**: one section per shelf. Each shelf shows its books in the existing row format, minus the status pill. - **Empty shelves**: shown as a group with the shelf name and "(empty)" subtext. No expandable books. - **Minibuffer** (when a book is selected): simplified to two actions — **Add note**, **Set rating**. Same for every book. ### Add form (`add.mustache`) - "Category" free-text field replaced with "Shelf" `