diff --git a/backend-spec.md b/backend-spec.md index d3aa7b4..ded8816 100644 --- a/backend-spec.md +++ b/backend-spec.md @@ -10,7 +10,7 @@ This document has been validated against the current codebase (v1) to ensure the Date reviewed: 2025-11-01 (post-cutover: JWT + households live, Argon2-only, members endpoint added, v2 routers inlined; all checks green; OpenAPI exported) -Repo modules checked: `main.py`, `api/*` (v2-only; *_v2 modules removed), `users/*`, `households/*`, `meals/*`, `ingredients/*`, `recipes/*`, `products/*`, `shopping/*`, `common.py`, `db.py`, `settings.py`, tests in `tests/*`. `persons/*` remains for migration compatibility but has no routes. +Repo modules checked: `main.py`, `api/*` (v2-only; no `*_v2.py` files remain), `users/*`, `households/*`, `meals/*`, `ingredients/*`, `recipes/*`, `products/*`, `shopping/*`, `common.py`, `db.py`, `settings.py`, tests in `tests/*`. `persons/*` remains for migration compatibility but has no routes. Key conventions in v1: - Response shape uses camelCase aliases (via `ApiModel` in `common.py`). @@ -38,7 +38,7 @@ Special-case 401: Removed. v1 cookie-based auth and routes have been retired in - GET `/api/v1/persons` → `Page` with optional name filter `q`, cursor pagination. - POST `/api/v1/persons` → create Person; sets `Location` header. -- Recipes (`api/recipes.py`) + - Recipes (`api/recipes.py`) - GET `/api/v1/recipes` → `Page`; loads ingredients per page. - GET `/api/v1/recipes/{id}` → full recipe (ingredients + createdBy). - GET `/api/v1/recipes/parse?url=...` (auth required) → scrape/parse a recipe; 400 if not found. @@ -160,7 +160,7 @@ Notes: - Scoped router `/api/v1/households/{householdSlug}` with `GET /whoami` and `GET /members` (returns `{ id, displayName, role }`). Household-scoped routes (implemented): -- `api/recipes_v2.py`: `/api/v1/households/{householdSlug}/recipes` list/get/create/delete. +- `api/recipes.py`: `/api/v1/households/{householdSlug}/recipes` list/get/create/delete. - `api/meals.py`: `/api/v1/households/{householdSlug}/meals` upcoming/get/create/update/consumed/delete (inlined from v2). - `api/shopping.py`: `/api/v1/households/{householdSlug}/shopping` current/list-by-id/purchase/request/unrequest (inlined from v2, with shared DTOs in `api/shopping_models.py`). @@ -254,7 +254,7 @@ Route surface lockdown: - Notes: - Migration added `household_id` columns and indices, enabling next step to filter by household without additional schema changes. - - Data access policy: API layers must delegate persistence to repository modules; no direct SQL in routers. Current status: recipes, meals, and shopping routers call into their repositories for reads/writes. Legacy `api/recipes.py` has been removed; v2-only `api/recipes_v2.py` remains. + - Data access policy: API layers must delegate persistence to repository modules; no direct SQL in routers. Current status: recipes, meals, and shopping routers call into their repositories for reads/writes. Legacy `*_v2.py` files have been removed; canonical routers are `api/recipes.py`, `api/meals.py`, and `api/shopping.py`. 4. **[~] Implement Household & Invitation Logic**: - ✅ Households router implemented for listing and creating households. @@ -336,3 +336,20 @@ Final-state definition (what “done” looks like): - No legacy v1 endpoints mounted; no `*_v2.py` files in repo (done). - No `persons` package in codebase or responses; all tests ported from v1 and no tests are skipped. - OpenAPI reflects only JWT-secured, household-scoped endpoints. + +--- + +Implementation policy updates (2025-11-01): + +- Routers must use repository helpers for all persistence; direct `conn.execute(...)` calls in routers are prohibited, except for controlled PRAGMA/transaction management in `api/deps.py`. +- Recipes create now accepts a lean body (`RecipeCreate`) without internal IDs and sets `createdById` from the JWT user; delete uses a repository helper to set `date_hidden` and `hidden_by_id` atomically. +- Canonical API files are: + - `api/recipes.py` (household-scoped recipes) + - `api/meals.py` (household-scoped meals) + - `api/shopping.py` (household-scoped shopping) + - `api/households.py` (memberships and scoped helpers) + - `api/auth.py` (JWT register/login/refresh/logout) + +Outstanding cleanup: +- Remove remaining `Person` fallbacks in domain repositories and delete the `persons/` package once tests are migrated. Ensure no code paths depend on `cookie_person`. +- Consider adding versioning endpoints for recipes explicitly rather than overloading POST.