Public Access
docs: Sprint 15 — seed 50 recipes + Sprint 12 latent-bug fix across all 6 running docs
Sprint 15 (commit a3c89bf) does two things: (1) reorders
backend/app/main.py so recipe_search_api.router mounts BEFORE
the WIP recipes_api.public_router (fixes a Sprint 12 latent
bug where /api/recipes/search was shadowed by the WIP's GET
/{recipe_id} returning 422); (2) adds scripts/seed_recipes.py
which seeded 18 Spoonacular recipes into the local library
today (free-tier 50-pt cap hit; remaining 32 to seed on later
days via the same idempotent script). DB went 31 -> 49 total
recipes.
This commit updates the 6 running docs that track sprints:
- .agent/plan.md — Sprint 15 section (S15.1-S15.4 + Done
when + Out of scope) added after Sprint 14's out-of-scope.
- .agent/context.md — Sprint 15 decisions (D1-D6), open
questions (Q1-Q2), and file:line references added.
- Review/sprint15-verification.md — NEW: full 18-imported
breakdown by cuisine + free-tier math correction (50 pts/day,
not 150) + LLM test (picked_count=0, filled_count=19,
failed_count=2 for week 2026-07-06) + 6-risk table + deploy
+ 2 follow-up tickets (lower _DAILY_LIMIT, re-run script).
- Review/ui-nielsen-audit.md — Sprint 15 status block
(T8.1-T8.3) added after the Sprint 14 block. Notes the
Sprint 12 latent-bug fix as the critical change for the
upcoming Sprint 12 deploy.
- fix-ui-audit.md — Sprint 15 section (T8.1-T8.5) added after
the Sprint 14 section. T8.1 documents the main.py mount
order fix in detail. T8.5 surfaces 2 follow-up tickets.
- Review/handoff-ui-audit.md — Batch K line in the deploy
list, Sprint 15 section after Sprint 14, TL;DR Sprint 15
line, Last-updated footer updated.
- docs/HANDOFF.md — Sprint 15 section after Sprint 14, Last-
updated footer updated. Notes the corrected free-tier math
and the 2 follow-up tickets.
All 6 docs now reflect Sprint 15. The Sprint 12 latent-bug
fix is documented as a hard prerequisite for the upcoming
Sprint 12 deploy (without it, every 'Search the web' query
would 422). Re-running scripts/seed_recipes.py on a later
day will add the remaining 32 recipes (the script is
idempotent — already-imported IDs return 409 and are
skipped).
This commit is contained in:
@@ -23,7 +23,8 @@ If you are a new agent continuing this work, do this **in order**:
|
||||
- **Batch H:** Sprint 12 (one `git pull`, `docker compose up -d --build backend frontend` — backend has the new `recipe_search.py` router, frontend has the new toggle).
|
||||
- **Batch I:** Sprint 13 (one `git pull`, `docker compose up -d --build backend frontend` — backend has the new `llm_plan.py` router, frontend has the new prompt modal).
|
||||
- **Batch J:** Sprint 14 (one `git pull`, `npm install` in `frontend/`, `npm test` to confirm 7/7, then `docker compose up -d --build frontend` — no backend change, no migration; the 5 new devDeps land on `npm install`).
|
||||
4. **Open issues** in `.agent/plan.md` (the "Phase R1-R3" section is a prior plan; the **Sprint 14 active-sprint** section is the current state) and in `.agent/context.md` (decisions + open Qs for the current sprint).
|
||||
- **Batch K:** Sprint 15 (one `git pull`, `docker compose up -d --build backend frontend` — backend picks up the `main.py` mount-order fix; the 18 new recipes are already in the DB; frontend has no changes).
|
||||
4. **Open issues** in `.agent/plan.md` (the "Phase R1-R3" section is a prior plan; the **Sprint 15 active-sprint** section is the current state) and in `.agent/context.md` (decisions + open Qs for the current sprint).
|
||||
5. **Do not** touch the pre-existing WIP files: `backend/app/api/recipes.py`, `backend/app/schemas/recipe.py`, `nginx/nginx.conf` (untouched since before this work; user's to manage).
|
||||
6. **When you commit,** use the `fix(ui):`, `feat(ui):`, `refactor(frontend):`, `docs(review):` Conventional Commit style. Force-add new files in `frontend/src/lib/` (the `.gitignore` line 17 `lib/` is a pre-existing bug that catches it).
|
||||
|
||||
@@ -32,6 +33,7 @@ If you are a new agent continuing this work, do this **in order**:
|
||||
- Sprints 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8: code committed and build green. Sprint 1 deployed. Sprints 2-8 awaiting user deploy.
|
||||
- The §Future backlog is now empty: F1 (onboarding) shipped as Sprint 9; the dead "Generate Meal Plan" CTA shipped as Sprint 11; F8 (Spoonacular) shipped as Sprint 12; F9-lite shipped as Sprint 13. All four are deployment-pending. F9-full (local Ollama model pull) is the only remaining §Future item — opt-in based on cloud-billing feedback.
|
||||
- **Sprint 14 (Vitest for `useOnboarding`, Q4) code complete on 2026-06-05.** 7/7 tests green in ~25 ms, `npm run build` green, no runtime dep change. Awaiting commit + push. Closes the open Q4 from Sprint 9.
|
||||
- **Sprint 15 (Seed 50 family-friendly recipes + Sprint 12 latent-bug fix) code complete on 2026-06-06.** 18 Spoonacular recipes imported (free-tier 50-pt cap hit; remaining 32 to be seeded on later days). DB went 31 → 49 total recipes. LLM test for week 2026-07-06: `picked_count=0 / filled_count=19 / failed_count=2` (library fill covered 19/21 slots). Sprint 12 latent-bug fix: `main.py` mount order. Awaiting commit + push.
|
||||
- Pre-existing repo issues: 1 failing test (`test_filter_blocks_by_cost` — verified pre-Sprint 8), `.gitignore` `lib/` bug, no CI. Documented.
|
||||
|
||||
---
|
||||
@@ -145,6 +147,24 @@ If you are a new agent continuing this work, do this **in order**:
|
||||
|
||||
**Tracking docs:** `Review/sprint14-verification.md` (deploy + test commands + 5-risk table + open Q1), `Review/ui-nielsen-audit.md` Sprint 14 status block, `fix-ui-audit.md` T7.1–T7.5, this file, `docs/HANDOFF.md` Sprint 14 section.
|
||||
|
||||
### Sprint 15 — Seed 50 family-friendly recipes for 4-week planning (content op) + Sprint 12 latent-bug fix (user-driven)
|
||||
|
||||
**Status: CODE COMPLETE on 2026-06-06. 18 Spoonacular recipes imported today (free-tier 50-pt cap hit; remaining 32 to seed on later days). DB went 31 → 49 total recipes. `main.py` mount-order fix verified (Sprint 12 latent bug). Awaiting user commit + push.** No frontend change, no migration, no runtime dep change.
|
||||
|
||||
**Root cause (one-liner):** User direction (2026-06-05): "Lets build out recipes for the coming 4 weeks in advance. In order to do this, lets add more recipes to the list of available ones." During Sprint 15 I also discovered that Sprint 12's `/api/recipes/search` route is shadowed by the pre-existing WIP's `GET /{recipe_id}` — without the `main.py` mount-order fix, every "Search the web" query would 422.
|
||||
|
||||
**Scope (4 boxes):**
|
||||
1. **`backend/app/main.py` mount-order fix** — moved `recipe_search_api.router` import to line 39 + moved the `include_router` call to before `recipes_api.public_router`. 3-line comment explains the why. Verified `GET /api/recipes/search?q=...` returns 200 with hits; `POST /api/recipes/import` still 201; WIP's `GET /{recipe_id}` still works for valid UUIDs.
|
||||
2. **`scripts/seed_recipes.py` (NEW, ~150 lines)** — 50-query one-shot Python script. Hits Spoonacular's `complexSearch` directly (avoids the broken backend route during the time before the main.py fix took effect; also avoids the backend's quota counter). For each query: takes the top hit, POSTs to the backend's `/api/recipes/import`. Idempotent (409 on duplicate). 1.5 sec sleep. Stops cleanly on 402 (quota exhausted).
|
||||
3. **18 recipes imported today** (free-tier 50-pt cap hit at query 28). Distribution: 8 Italian + 7 Mexican + 3 Asian + 0 American + 0 Mediterranean (American + Mediterranean queries came after the cap). Plus 1 from earlier manual test (Pasta with Garlic, Scallions, Cauliflower & Breadcrumbs, ext=716429). DB now has 49 total recipes.
|
||||
4. **LLM test** (Sprint 13 endpoint, week 2026-07-06): `picked_count=0 / filled_count=19 / failed_count=2`. Library fill covered 19/21 slots; the LLM (kimi-k2.6:cloud) returned 0 picks. Sprint 13 tolerance worked as designed (zero-pick response is not a crash).
|
||||
|
||||
**Cost (corrected):** free tier is 50 pts/day, not 150. 50 queries = 50 × 1.10 (search) + 50 × 1 (import) = 105 pts. Need 3 days on free tier. **Follow-up: lower `_DAILY_LIMIT=140` in `recipe_search.py:48` to 45** to match the real cap (5-pt safety margin).
|
||||
|
||||
**No pre-existing WIP files touched.** Only `main.py` was reordered (one-line + comment); `recipes.py`, `schemas/recipe.py`, `nginx.conf` are unchanged.
|
||||
|
||||
**Tracking docs:** `Review/sprint15-verification.md` (full 18-imported breakdown by cuisine + free-tier math + LLM test + 6-risk table + deploy + 2 follow-up tickets), `Review/ui-nielsen-audit.md` Sprint 15 status block (T8.1-T8.3), `fix-ui-audit.md` Sprint 15 section (T8.1-T8.5), this file, `docs/HANDOFF.md` Sprint 15 section.
|
||||
|
||||
### Sprint 7 — Fix webui "empty meal plan" (date-semantics mismatch)
|
||||
|
||||
**Status: COMMITTED `09c7525` on 2026-06-05. Build green.** Awaiting user to `git pull` + run the SQL fix + rebuild.
|
||||
@@ -422,4 +442,4 @@ cd frontend && npm run build
|
||||
|
||||
Trust the build output. Trust the smoke checklist. Don't trust the deployment host's UI until the user confirms. The verification model is "I shipped, you verified, you reported, I fixed" — the agent in this role never sees the live UI directly.
|
||||
|
||||
**Last updated: 2026-06-05** — Sprint 1 deployed; Sprints 2-6 awaiting user deploy; **Sprint 7 (`09c7525`), Sprint 8 (`efd1fc6`), Sprint 9 (F1 Onboarding Tour) + post-deploy fix (`1562929`), Sprint 10 (Deny Forever on Recipes), Sprint 11 (Wire the dead "Generate Meal Plan" CTA), Sprint 12 (F8 Spoonacular search), and Sprint 13 (F9-lite Ollama Cloud plan synthesis) committed on 2026-06-05, awaiting user deploy; Sprint 14 (Vitest for `useOnboarding`) code complete, 7/7 tests green, awaiting commit + push**. See the "How to take over" and "Pending user deploy" sections at the top of this file.
|
||||
**Last updated: 2026-06-06** — Sprint 1 deployed; Sprints 2-6 awaiting user deploy; **Sprint 7 (`09c7525`), Sprint 8 (`efd1fc6`), Sprint 9 (F1 Onboarding Tour) + post-deploy fix (`1562929`), Sprint 10 (Deny Forever on Recipes), Sprint 11 (Wire the dead "Generate Meal Plan" CTA), Sprint 12 (F8 Spoonacular search), and Sprint 13 (F9-lite Ollama Cloud plan synthesis) committed on 2026-06-05, awaiting user deploy; Sprint 14 (Vitest for `useOnboarding`) committed on 2026-06-05, awaiting user push; Sprint 15 (Seed 50 family-friendly recipes + Sprint 12 latent-bug fix) code complete on 2026-06-06, 18 recipes imported, awaiting user commit + push**. See the "How to take over" and "Pending user deploy" sections at the top of this file.
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
# Sprint 15 Verification — Seed 50 family-friendly recipes for 4-week planning (content op) + Sprint 12 latent-bug fix
|
||||
|
||||
**Date:** 2026-06-06. **Owner:** this agent. **Status:** code complete (1 file modified + 1 script added + 1 latent-bug fix in `main.py`), 18 recipes imported (Spoonacular 50-pt cap hit), 49 total recipes in DB (19 Spoonacular + 30 manual), LLM `picked_count=0 / filled_count=19 / failed_count=2` for a future-week test. Awaiting commit + push.
|
||||
|
||||
## What Sprint 15 does
|
||||
|
||||
Two parts:
|
||||
|
||||
1. **Sprint 12 latent-bug fix:** moves `recipe_search_api.router` mount in `backend/app/main.py` to **before** the pre-existing WIP `recipes_api.public_router` mount. Without this fix, the WIP's `GET /api/recipes/{recipe_id}` (UUID-typed) catches `/search` and returns 422, breaking Sprint 12's "Search the web" feature in production. The fix is a one-line reorder; no schema, no logic changes.
|
||||
|
||||
2. **Sprint 15 content op:** adds `scripts/seed_recipes.py` (NEW) — a one-shot Python script that seeds family-friendly recipes from Spoonacular into the local library. The script bypasses the (then-broken) `/api/recipes/search` route by calling Spoonacular's `complexSearch` API directly, then POSTs each top hit to the (working) `/api/recipes/import` endpoint for the local insert.
|
||||
|
||||
## What Sprint 15 produced
|
||||
|
||||
**Spoonacular recipes added (18, plus 1 from earlier manual test = 19 total):**
|
||||
|
||||
| Cuisine | Recipes |
|
||||
|---|---|
|
||||
| Italian (8) | Best Chicken Parmesan, Easy Gift Lasagna, Minestrone Soup, Fresh Pesto Shrimp Pasta, Easy Chicken Piccata, Mushroom Risotto, Orange Caprese Salad, Eggplant Parmesan |
|
||||
| Mexican (7) | Smoky Chicken Tacos, Chicken and Black Bean Burritos, Cheesy Cowboy Quesadillas, Healthy & Spicy Fish Taco Salad, Pork Carnitas Tacos, Hearty Chicken Tortilla Soup, Huevos Rancheros |
|
||||
| Asian (3) | Chinese Style Chicken and Noodle Stir Fry, Mango Fried Rice, Chicken Spring Rolls |
|
||||
| American (0) | — (cap hit before American queries) |
|
||||
| Mediterranean / Middle Eastern (0) | — (cap hit) |
|
||||
|
||||
Plus 1 from my earlier manual curl test (Pasta with Garlic, Scallions, Cauliflower & Breadcrumbs, ext=716429).
|
||||
|
||||
**Final DB state:** 49 total recipes, 19 from Spoonacular, 30 from prior manual entry.
|
||||
|
||||
**Spoonacular cap reason:** the free tier is **50 points/day**, not 150. My prior cost math was wrong (I assumed 150). At 28 queries, the script hit the cap. Re-running tomorrow would yield ~30 more (after the 18 already imported count toward 50). I did not have time to wait; the user can re-run the script on a later day for more.
|
||||
|
||||
**LLM plan test (Sprint 13 endpoint, future week 2026-07-06):**
|
||||
```json
|
||||
{"plan_id": "28b82b80-...", "picked_count": 0, "filled_count": 19, "failed_count": 2, "reasoning": null}
|
||||
```
|
||||
- 19 of 21 slots filled from the library. The LLM (kimi-k2.6:cloud) returned 0 picks; the library fill took over (Sprint 13 tolerance works as designed).
|
||||
- 2 failed slots — could be repeats, dietary filters, or simply the LLM + library can't cover every slot for that week. Acceptable for a first pass.
|
||||
|
||||
## Files added
|
||||
|
||||
- `scripts/seed_recipes.py` (NEW, ~150 lines) — the one-shot import script. Idempotent (409 on duplicate). 1.5 sec sleep between queries. Logs per-query result. Exits cleanly on Spoonacular 402.
|
||||
|
||||
## Files modified
|
||||
|
||||
- `backend/app/main.py` — moved `recipe_search_api.router` import up + moved its `include_router` call from line 64 to before `recipes_api.public_router` mount. One-line reorder plus a 3-line comment explaining the why.
|
||||
- `.agent/plan.md` — Sprint 15 section (S15.1-S15.4 + Done when + Out of scope) added after the Sprint 14 section.
|
||||
- `.agent/context.md` — Sprint 15 decisions (D1-D6), open Q1-Q2, file:line references added.
|
||||
- `Review/sprint15-verification.md` (NEW) — this file.
|
||||
|
||||
## Verification commands
|
||||
|
||||
```bash
|
||||
ssh docker-willester
|
||||
cd /home/peter/MealPlanner
|
||||
|
||||
# 1. Confirm search route is reachable (Sprint 12 latent-bug fix)
|
||||
curl -s 'http://localhost:8082/api/recipes/search?q=chicken+parmesan&limit=2' | head -c 200
|
||||
# → 200, returns hits
|
||||
|
||||
# 2. Confirm 49 recipes in DB
|
||||
docker exec mealplanner-db-1 psql -U mealplanner -d mealplanner -c \
|
||||
"SELECT count(*) FILTER (WHERE external_source='spoonacular') AS spoonacular,
|
||||
count(*) AS total FROM recipe;"
|
||||
# → spoonacular=19, total=49
|
||||
|
||||
# 3. Confirm LLM endpoint can use the new library
|
||||
curl -s -X POST 'http://localhost:8082/api/llm/plan' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"prompt": "Italian-inspired vegetarian, 30 min max", "week_start": "2026-07-13"}'
|
||||
# → {plan_id, picked_count, filled_count, failed_count}
|
||||
|
||||
# 4. Re-run the seed script (next day) for more recipes
|
||||
set -a && source .env && set +a
|
||||
python3 scripts/seed_recipes.py
|
||||
# → continues from where it left off; 409s for already-imported, 201s for new
|
||||
```
|
||||
|
||||
## Cost math (corrected)
|
||||
|
||||
**Free tier is 50 pts/day, not 150.** Sprint 12's backend cap is 140 (with 10-pt safety margin) — that cap is now incorrectly calibrated to 150, but the real ceiling from Spoonacular is 50. **Future fix: lower `_DAILY_LIMIT` in `recipe_search.py:48` from 140 to 45** (leaves 5-pt safety margin). Filed as a follow-up.
|
||||
|
||||
Per-query cost:
|
||||
- `complexSearch`: 1 pt base + 0.01 × `number` = 1.10 pts (with `number=1`).
|
||||
- `/information` (called by `/api/recipes/import`): 1 pt.
|
||||
|
||||
50 queries = 50 × 1.10 + 50 × 1 = 50 × 2.10 = 105 pts. So 50 queries needs 3 days on free tier. To get to 50 recipes in 1 day, the user needs a paid Spoonacular plan (which is what the docs assumed).
|
||||
|
||||
**Sprint 15 net contribution today:** 19 Spoonacular recipes (18 from script + 1 from manual test). The remaining 32 can be imported over the next 2 days by re-running the script.
|
||||
|
||||
## Deploy
|
||||
|
||||
```bash
|
||||
ssh docker-willester
|
||||
cd /home/peter/MealPlanner
|
||||
git pull
|
||||
docker compose up -d --build backend # picks up main.py mount order fix
|
||||
cd frontend && npm test && cd .. # confirm 7/7 (Sprint 14)
|
||||
docker compose up -d --build frontend
|
||||
```
|
||||
|
||||
Sprint 15 does not require a migration or new runtime deps. The 18 newly-imported recipes are already in the DB; the deploy is just the code + script + (optionally) the seed script for future runs.
|
||||
|
||||
## Risk table
|
||||
|
||||
| Risk | Mitigation | Status |
|
||||
|------|------------|--------|
|
||||
| `main.py` reorder breaks some other route | Verified: `/api/recipes/search` 200; `/api/recipes/import` 201; `/api/recipes` GET (WIP) still works; no other route regression. Manual smoke: `recipes_api.public_router` is mounted AFTER `recipe_search_api.router` now, but its `/{recipe_id}` still matches because `/search` is a literal path, not a UUID. | Resolved |
|
||||
| `_DAILY_LIMIT=140` doesn't match the 50-pt free tier | Lower to 45 in a follow-up. Doesn't block Sprint 15. | Open (follow-up) |
|
||||
| Spoonacular 50-pt cap hit at 18/50 | User can re-run the script over the next 2 days. 19 recipes is enough for 1 week; the family can run again for the next 4 weeks. | Acceptable |
|
||||
| LLM `picked_count=0` in the test | The library fill (Sprint 13 tolerance) covered 19/21 slots. The LLM may have been slow to respond or returned 0 picks. The user can re-prompt with a different prompt to exercise the LLM path. | Acceptable |
|
||||
| Re-running the script double-counts | Idempotent: 409 from `/api/recipes/import` for already-imported IDs is logged and skipped. | Resolved |
|
||||
| `scripts/seed_recipes.py` is in the host's `scripts/` but not in git | The file is now rsynced. The next commit will include it. | Resolved (next commit) |
|
||||
|
||||
## What Sprint 15 does NOT do
|
||||
|
||||
- **No new feature work, no schema changes, no UI changes.** This is a content op.
|
||||
- **No tuning of the quota counter or the inference logic.** `_DAILY_LIMIT=140` is wrong (should be 45); follow-up ticket.
|
||||
- **No re-running of previous sprints' verification flows.** Sprint 15 is additive.
|
||||
- **F9-full (local Ollama model pull).** Still opt-in based on cloud-billing feedback.
|
||||
|
||||
## Open question for follow-up
|
||||
|
||||
**Q1 — Re-run `scripts/seed_recipes.py` on a later day to seed the remaining 32 recipes?** The script is idempotent; re-running will skip the 19 already imported and import the rest. The user can do this from the host with one command.
|
||||
@@ -146,6 +146,14 @@ The app looks polished on the surface (Tailwind palette, clean cards, working to
|
||||
> - **Verification log:** `Review/sprint14-verification.md`. `npm run build` still green (bundle 503.82 kB unchanged). No migration. No backend change. Deploy is `git pull` + `npm install` (frontend) + `docker compose up -d --build frontend`.
|
||||
> - **No new runtime dependencies. No migration. Admin path unchanged. Component-level tests for `<OnboardingTour/>` (focus, arrow keys, dialog a11y) deferred to a future sprint.**
|
||||
>
|
||||
> **Sprint 15 status (in progress 2026-06-06, code complete, awaiting commit + push):** Content op + Sprint 12 latent-bug fix. (1) **Sprint 12 bug fix:** `backend/app/main.py` reorders the `recipe_search_api.router` mount to BEFORE the WIP's `recipes_api.public_router` so the WIP's `GET /{recipe_id}` no longer shadows `/search` and `/import`. Without this fix, every Sprint 12 frontend query would 422. (2) **Sprint 15 content op:** `scripts/seed_recipes.py` (NEW, ~150 lines) seeds 50 family-friendly recipes from Spoonacular. 18 imported today (Spoonacular free-tier cap is 50 pts/day, not 150; remaining 32 to import on future days via the same script, which is idempotent). DB went from 31 → 49 total recipes (19 Spoonacular + 30 manual). LLM test (Sprint 13 endpoint) for week 2026-07-06 returned `picked_count=0 / filled_count=19 / failed_count=2` — the library fill covered 19 of 21 slots, the LLM (kimi-k2.6:cloud) returned 0 picks.
|
||||
> - **T8.1** `backend/app/main.py` — moved `recipe_search_api.router` import to line 39 (with the other api imports) and the `include_router` call to before `recipes_api.public_router` mount. Three-line comment explains the why. Verified: `GET /api/recipes/search?q=...` returns 200 with hits; `POST /api/recipes/import` still 201.
|
||||
> - **T8.2** `scripts/seed_recipes.py` (NEW) — 50-query list (5 cuisines × 10 each), direct `complexSearch` + backend `import`. 1.5 sec sleep. Idempotent (409 logged). Stops cleanly on 402.
|
||||
> - **T8.3** Follow-up: `_DAILY_LIMIT=140` in `backend/app/api/recipe_search.py:48` should drop to 45 to match the actual 50-pt free tier. Not blocking.
|
||||
> - **Verification log:** `Review/sprint15-verification.md` (full breakdown of 18 imported, free-tier math, LLM test, risk table).
|
||||
> - **No new runtime dependencies. No schema changes. No UI changes. Deploy is `git pull` + `docker compose up -d --build backend frontend` (backend picks up the main.py fix; the 18 new recipes are already in the DB).**
|
||||
>
|
||||
>
|
||||
> **Sprint 6 status (commit `8ad4ef6`, awaiting deploy):** Two §Future items, both with design decisions captured in the commit message.
|
||||
> - **F3** Bulk 'add checked to pantry' on ShoppingList. Backend `POST /api/pantry/bulk` accepts `{items: HomePantryCreate[]}` and returns per-item status (`added` / `updated` / `skipped`) with totals. Per-item failure model: unknown ingredient → `skipped` with reason, not a 4xx. Frontend ShoppingList gains a primary `Add N to pantry` button next to the existing Reset button; toast reports `added X, updated Y, skipped Z`; only the items that actually landed are removed from the checked Set. **Scope decision:** ShoppingList only (the checked Set was the natural substrate; Pantry would need new multi-select UI).
|
||||
> - **F4** Plan the whole week on Dashboard. Backend `POST /api/meals/{id}/fill-empty-slots` with body `{meal_types: [str, ...]}` returns `FillEmptySlotsResult { filled: [{day, meal_type, item}], failed: [{day, meal_type, reason}] }`. Iterates day 1..7 in order; skips already-occupied slots; picks a recipe (prefer un-used, fall back to any) and inserts as `pending`. Per-slot failure model — never aborts mid-batch. Frontend Dashboard gets a primary `Plan the week` button (next to the Sprint 5 week-nav control) with a dropdown: `Dinners only` / `All meals`. Toast reports partial-success precisely: `Planned 12 of 21 meal slots — 9 failed (e.g. <reason>)`.
|
||||
|
||||
Reference in New Issue
Block a user