feat(api): scope ingredient parse to household and align recipe parse-from-url with RecipeCreate

This commit is contained in:
jableader 2025-11-01 23:39:14 +11:00
parent 29ebbe7a37
commit 854b924a28

View file

@ -5,8 +5,8 @@
- DELETE `/api/v1/households/{householdSlug}/shopping/current/meals/{mealId}` unrequests the meal (scoped) and returns `{ ok: true }`.
- POST `/api/v1/households/{householdSlug}/shopping/current/ingredients` requests an adhoc ingredient scoped to household+user; duplicates deduped per user per household.
- DELETE `/api/v1/households/{householdSlug}/shopping/current/ingredients` removes an adhoc ingredient request for the current user in this household; idempotent.
- POST `/api/v1/households/{householdSlug}/recipes/parse-from-url` returns structured JSONLD recipe data for a URL (stateless; household auth enforced).
- GET `/api/v1/recipes/ingredients/parse?ingredients=...&ingredients=...` parses raw ingredient lines into Ingredient DTOs (stateless, public); attempts best-effort product matching.
- POST `/api/v1/households/{householdSlug}/recipes/parse-from-url` returns a RecipeCreate payload parsed from a URL (stateless; household auth enforced). Shape matches the body accepted by `POST /recipes`.
- GET `/api/v1/households/{householdSlug}/ingredients/parse?line=...` parses a single ingredient line into an `Ingredient` (scoped; JWT + membership). Attempts best-effort product matching.
- Comprehensive v2 coverage exists for scoping, purchases, request/unrequest, meals CRUD/consumed, and OpenAPI security. PASS.
# Backend Specification: Household Multi-Tenancy (v2)
@ -43,8 +43,8 @@ Special-case 401: Removed. v1 cookie-based auth and routes have been retired in
- Recipes (`api/recipes.py`)
- GET `/api/v1/recipes``Page<Recipe>`; loads ingredients per page.
- GET `/api/v1/recipes/{id}` → full recipe (ingredients + createdBy).
- POST `/api/v1/households/{householdSlug}/recipes/parse-from-url` (auth required) → scrape/parse a recipe URL; 404 if not found.
- GET `/api/v1/recipes/ingredients/parse?ingredients=...&ingredients=...` → parse raw ingredient lines (no auth); matches existing products. Implemented in v2 as public utility under the same path.
- POST `/api/v1/households/{householdSlug}/recipes/parse-from-url` (auth required) → scrape/parse a recipe URL; returns `RecipeCreate` (no id/createdBy); 404 if not found.
- GET `/api/v1/households/{householdSlug}/ingredients/parse?line=...` → parse a single raw ingredient line (JWT + membership); matches existing products.
- POST `/api/v1/recipes` (auth required) → validate (≥1 ingredient), perform versioning (hide base if id≥0), set createdById, insert ingredients; sets `Location` header.
- DELETE `/api/v1/recipes/{id}` (auth required) → soft-delete (hide) recipe.
@ -205,8 +205,8 @@ Route surface lockdown:
Completed:
- Auth endpoints (`/api/v1/auth/*`) migrated to JWT with tokens/refresh cookie.
- Household-scoped recipes/meals/shopping endpoints in place.
- `POST /api/v1/households/{householdSlug}/recipes/parse-from-url` implemented.
- `GET /api/v1/recipes/ingredients/parse` ported as a public stateless NLP parser returning `Ingredient[]`.
- `POST /api/v1/households/{householdSlug}/recipes/parse-from-url` implemented (returns `RecipeCreate`).
- `GET /api/v1/households/{householdSlug}/ingredients/parse` implemented (returns single `Ingredient`, scoped).
Outstanding (tracked):
- None identified blocking parity for shopping/recipes needed by the frontend as of 2025-11-01. Re-check if any v1 product scrape/create endpoint needs re-exposure; current frontend uses household flows and parsing utilities.