Files
Meal-Planner/Review/sprint6-verification.md
admin a616138e7c docs(review): Sprint 6 verification log + plan/handoff/audit updates
Sprint 6 (F3 + F4) is now documented across the project:

- Review/sprint6-verification.md: new deploy + smoke-check doc.
  Backend + frontend deploy (no migration). 5 smoke-check
  sections: A) ShoppingList bulk-add end-to-end, B) F3 partial-
  failure edge case, C) F4 'Plan the week' button + dropdown,
  D) F4 edge cases (no empty slots, all recipes used, invalid
  meal_types), E) Sprints 1-5 regression spot-check. Rollback
  section covers revert (no migration to undo).

- fix-ui-audit.md: new Sprint 6 section (S6.1 F3, S6.2 F4,
  S6.3 verification gate). 'Done when' block updated to 6
  sprints / 10 commits / 20 findings closed.

- Review/handoff-ui-audit.md: updated to a 6-sprint cycle. TL;DR
  table includes the 8ad4ef6 row. File list includes sprint6-
  verification.md. File-level diff summary gains 8 new rows for
  Sprint 6 (F3 backend + F4 backend + 3 new schemas + 2 api
  bindings + 2 page changes). §Future list now strikethroughs
  F3 and F4. Follow-up tickets section added: the no-op
  'Generate Meal Plan' empty-state CTA, the (now-narrower) Pantry
  bulk-add ticket, and the 'Sprints 2-5 + Sprint 6 separate
  batch' deploy note.

- Review/ui-nielsen-audit.md: new Sprint 6 status block at the
  top. F3 + F4 documented with the design-decision context
  (ShoppingList-only scope; dropdown for All/Dinners; partial-
  success with detailed report).

- docs/HANDOFF.md: Last-updated line bumped to 6 sprints / 10
  commits / 20 findings / 6 §Future items. Header commit list
  gains the 8ad4ef6 row. New 'Sprint 6' subsection in the
  2026-06-04 session block. Commit table gained the 8ad4ef6 row.
  Files-modified + Files-added lists updated.

No code changes; the 3 pre-existing WIP files (backend/app/api/
recipes.py, schemas/recipe.py, nginx/nginx.conf) are deliberately
not staged.
2026-06-04 14:05:51 -07:00

6.2 KiB

Sprint 6 — Deploy & smoke-check (F3 + F4)

Goal: verify the bulk pantry add (F3) and the plan-the-week button (F4) work end-to-end on http://100.108.208.56:8082/.

Commit: 8ad4ef6 (feat(ui): bulk pantry add + plan-the-week button (Sprint 6 F3+F4)) Sprint scope: F3 (ShoppingList bulk add) + F4 (Dashboard plan-the-week button) Backend changes: pantry.py (new bulk endpoint), meals.py (new fill-empty-slots endpoint), schemas/__init__.py (3 new schemas) Frontend changes: api/index.ts (2 new bindings), Dashboard.tsx (Plan the week button + dropdown), ShoppingList.tsx (Add to pantry button)

1. Deploy

Sprint 6 has both backend and frontend changes. No migrations needed.

# On deployment host (100.108.224.12)
cd /path/to/MealPlanner
git pull
docker compose -f docker-compose.yml up -d --build backend frontend

2. Build verification (already green locally)

$ cd frontend && npm run build
> tsc && vite build
✓ 1894 modules transformed.
dist/index.html                   0.54 kB │ gzip:   0.31 kB
dist/assets/index-DBX6fwsX.css   38.10 kB │ gzip:   6.82 kB
dist/assets/index-CTd7xPlC.js   478.22 kB │ gzip: 147.53 kB
✓ built in 7.02s

tsc 0 errors, vite 0 errors.

3. Backend smoke (local dev, already verified)

# F3 — bulk pantry add with an unknown ingredient
curl -s -X POST http://100.108.208.56:8082/api/pantry/bulk \
  -H 'Content-Type: application/json' \
  -d '{"items":[{"ingredient_id":"00000000-0000-0000-0000-000000000001"}]}'
# Expected: {"added":0,"updated":0,"skipped":1,"results":[{"ingredient_id":"...","status":"skipped","id":null,"reason":"Unknown ingredient"}]}

# F4 — fill empty slots for dinners only
PLAN_ID=$(curl -s http://100.108.208.56:8082/api/meals | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('id','') if d else '')")
curl -s -X POST "http://100.108.208.56:8082/api/meals/$PLAN_ID/fill-empty-slots" \
  -H 'Content-Type: application/json' \
  -d '{"meal_types":["dinner"]}'
# Expected: {"filled":[...],"failed":[]}  (filled has the newly-inserted dinner slots; failed is empty if there were empty dinner slots and recipes available)

# F4 — invalid meal_type
curl -s -X POST "http://100.108.208.56:8082/api/meals/$PLAN_ID/fill-empty-slots" \
  -H 'Content-Type: application/json' \
  -d '{"meal_types":["brunch"]}'
# Expected: {"filled":[],"failed":[{"day_of_week":0,"meal_type":"brunch","reason":"Unknown meal_type: brunch"}]}

4. UI smoke checks

S6.A — F3 ShoppingList "Add checked to pantry"

  1. Open http://100.108.208.56:8082/shopping-list.
  2. Confirm a shopping list is displayed (current week has a plan).
  3. Tick 3-5 checkboxes in different aisles. The header should show a primary Add 5 to pantry button next to the Reset button.
  4. Click the Add 5 to pantry button.
  5. Toast should appear: Pantry: added 3, updated 1, skipped 1 (counts will vary).
  6. Open http://100.108.208.56:8082/pantry in a new tab. The 4 successfully added items should be there.
  7. Return to the ShoppingList. The 4 items should now be unchecked; the 1 skipped item (if any) should still be checked.

S6.B — F3 partial-failure edge case

To force a "skipped" count, you'd need a shopping list item without an ingredient_id. The seed data may not include any. If your DB does have such an item:

  • Tick one such item + one normal item.
  • Click Add 2 to pantry.
  • Toast should show skipped 1 and the un-skipped item should be added.

If your DB has no such items, the toast will show only added / updated and that's correct.

S6.C — F4 Dashboard "Plan the week"

  1. Open http://100.108.208.56:8082/.
  2. The header should show a primary Plan the week button (with a Sparkles icon and a chevron-down caret) next to the week-nav control.
  3. Click the button. A dropdown should appear with two options:
    • Dinners only (subtitle: "Fill every empty dinner slot this week")
    • All meals (subtitle: "Fill every empty slot (breakfast, lunch, dinner) this week")
  4. Click Dinners only. The button should show a spinner + Planning… and be disabled.
  5. After 1-2 seconds, a toast should appear: Planned N meal slots (or Planned N of M meal slots — X failed (e.g. <reason>)).
  6. The weekly grid should refresh and the previously-empty dinner slots should now show generated meals.
  7. Click Plan the week again, choose All meals. The grid should fill in any remaining empty breakfast/lunch slots too.

S6.D — F4 edge cases

  • No empty slots: if every slot is already filled, the toast should say No empty meal slots to fill.
  • All recipes used: the backend reuses recipes when the un-used pool is empty. If your family has very few recipes, the toast might say Planned 21 of 21 meal slots (with recipes repeated across days). That's expected.
  • Invalid meal_types: the frontend only sends dinner or breakfast+lunch+dinner, so the backend's Unknown meal_type failure mode is not triggerable from the UI. (Documented in the backend test for completeness.)

S6.E — Regression check: Sprints 1-5 still work

Quick spot-check:

  • /recommended redirects to /recipes/recommended (Sprint 1 B4)
  • Recipe detail shows ingredients with proper spacing (Sprint 1 B1)
  • Meal detail shows $X.XX per serving (Sprint 1 B3)
  • Pantry aisle <select> has all 9 canonical options (Sprint 2 B8)
  • Shopping list section headers are sentence-case (Sprint 2 B9)
  • Recipes filter panel has Apply/Reset and active count badge (Sprint 2 B11)
  • Dashboard mobile viewport shows empty meal slots (Sprint 1 B5)
  • Dashboard delete shows the Undo toast (Sprint 3 B12)
  • Failed mutations show a toast with the FastAPI detail (Sprint 4 F7)
  • URL week selector: ?week=2026-05-15 works (Sprint 5 F5)
  • Keyboard shortcuts: g d / g p / ? (Sprint 5 F2)

5. Acceptance criteria

Sprint 6 is done when:

  • git pull + container rebuild on the deployment host succeeds
  • S6.A bulk pantry add works
  • S6.C plan-the-week button works
  • No regression in S6.E

6. Rollback

git revert 8ad4ef6
docker compose -f docker-compose.yml up -d --build backend frontend

No migrations to revert. No data loss possible — both endpoints only insert or upsert user-controlled data.