make categories global

This commit is contained in:
2026-08-01 19:09:22 -04:00
parent b71bdb2d5d
commit 2542f010b1
7 changed files with 139 additions and 126 deletions
+21 -16
View File
@@ -1,6 +1,6 @@
# Meal Feature Plan
Status: planning (not yet implemented)
Status: Part A implemented; Parts BF not yet implemented
This plan adds the concept of a **meal** to Sustenance. A meal has a name, an
optional description/recipe (markdown), and a list of ingredients. Meals are
@@ -14,11 +14,13 @@ The plan is split into parts so each can be implemented and tested independently
## Part A — Refactor categories to be global
**Status: implemented**
Currently `categories` are per-list (`categories.list_id`, with a
`UNIQUE (list_id, name)` constraint). Since meals are global and ingredients
reference categories, categories become global too.
### Schema change (in `migrate` in `src/sqlite.rs`)
### Schema change (in `migrate` in `src/sqlite.rs`) — done
```sql
categories (
@@ -29,27 +31,26 @@ categories (
)
```
- Drop `list_id`; `name` becomes globally unique.
- Dropped `list_id`; `name` is globally unique.
- `items.category_id` stays a FK to `categories(id)` — unchanged.
- **Migration concern:** the current `CREATE TABLE IF NOT EXISTS` won't alter an
existing DB. Need a real migration (or accept recreating the dev DB).
- Default categories are now seeded once at startup via `seed_default_categories`
(called from `SqliteDatabase::open` / `open_in_memory`).
- **Migration:** since `CREATE TABLE IF NOT EXISTS` won't reshape an existing DB,
the dev DB is recreated (see Open decisions).
### Repo / port changes (`CategoryRepository` in `src/ports.rs`)
### Repo / port changes (`CategoryRepository` in `src/ports.rs`) — done
- `categories(txn)` → returns **all** global categories (no `list_id` param).
- `categories(txn)` → returns all global categories (no `list_id` param).
- `create_category(txn, name)` → global, no `list_id`, no per-list revision bump.
- Add `category_by_name(txn, name)` for resolving ingredient categories.
- `ListRepository::create_list` **no longer seeds** default categories (they're
global now). Default categories become a one-time seed at startup instead.
- Added `category_by_name(txn, name)` for resolving ingredient categories.
- `ListRepository::create_list` no longer seeds default categories.
### Service / HTTP changes
### Service / HTTP changes — done
- `ListService::categories()` no longer takes `list_id`.
- `create_category` handler moves from `/lists/{list_id}/categories` to a global
`/categories` route (or a categories management page).
- The list page's categories panel now shows the global category set.
- `create_category` no longer bumps a list revision (not list-scoped anymore),
so no realtime event for it.
- `create_category` handler moved to a global `POST /categories` route.
- The list page's categories panel shows the global category set.
- `create_category` no longer bumps a list revision, so no realtime event for it.
---
@@ -157,7 +158,11 @@ Implemented as an htmx-powered modal that fetches a meal list/search fragment.
1. **Migration handling for the category refactor** — since `CREATE TABLE IF NOT
EXISTS` won't reshape an existing DB, write a proper migration, or is it fine
to drop/recreate the dev DB?
**Resolution (Part A):** drop/recreate the dev DB. The app was never
deployed, so there is no production data to preserve.
2. **Category management UI** — with categories now global, do we want a
dedicated categories page (e.g. `/categories`) to add/rename/delete them, or
keep it minimal (just the add form on the list page, now creating global
categories)?
**Resolution (Part A):** keep it minimal — the add form stays on the list
page's categories panel, now posting to the global `POST /categories` route.