Files
Meal-Planner/Review/sprint4-verification.md
admin 62dfc1eb4a docs(review): Sprint 4 verification log + plan/handoff/audit updates
Sprint 4 (F7 + F6) is now documented across the project:

- Review/sprint4-verification.md: new 100-line deploy + smoke-check
  doc. Frontend-only deploy (git pull + docker compose up -d --build
  frontend). 5 smoke-check tables: A) success toasts still work for
  all 11 actions, B) error path shows FastAPI detail (network-down
  is the easiest test; full Pydantic 422 verification via curl +
  DevTools 'Edit and resend'), C) pre-flight toasts still fire
  without a network call, D) plan-status Badge has correct
  aria-label in DevTools, E) Sprint 1-3 regression spot-check.
  Includes rollback instructions (single-commit revert).

- fix-ui-audit.md: new Sprint 4 section with full per-task notes
  (S4.1 F7 implementation details, S4.2 F6 aria-label, S4.3
  verification gate). 'Done when (overall)' block updated to 4
  sprints + 7 commits + 16 findings closed. No new commit in
  fix-ui-audit.md for the F8/F9 §Future addendum (those are noted
  in Review/handoff-ui-audit.md but live in the doc/proposals/
  tree, not in the UI-audit plan).

- Review/handoff-ui-audit.md: updated to a 4-sprint cycle. TL;DR
  table includes the d71b67a row, file-list includes the new
  verification doc, file-level diff summary gains 5 new rows for
  Sprint 4, §Future list now strikethroughs F6 and F7, and the
  Quick-start deploy commands list Sprint 4.

- Review/ui-nielsen-audit.md: new Sprint 4 status block at the
  top with the F7/F6 changes, the no-backend-changes note, and
  a cross-ref to the new verification log.

- docs/HANDOFF.md: Last-updated line bumped to 4 sprints / 7
  commits / 16 findings. New 'Sprint 4' subsection in the
  2026-06-03 session block. Commit table gained the d71b67a row.
  Files-modified list gained the lib/toast.tsx, App.tsx, and
  three pages changes for Sprint 4 (with B-tags preserved).

No code changes; the 5 pre-existing WIP files (backend/app/api/
meals.py, recipes.py, schemas/recipe.py, frontend/src/api/index.ts,
nginx/nginx.conf) are deliberately not staged.
2026-06-03 19:39:35 -07:00

7.1 KiB

Sprint 4 — Deploy & smoke-check (F7 + F6)

Goal: verify the global react-query error handler and plan-status aria-label work end-to-end on http://100.108.208.56:8082/.

Commit: d71b67a (feat(ui): global react-query error handler + plan-status a11y (Sprint 4 F7+F6)) Sprint scope: F7 + F6 (both small, both polish, no new deps) Backend changes: none Frontend changes: App.tsx, lib/toast.tsx, pages/Dashboard.tsx, Pantry.tsx, MealDetail.tsx

1. Deploy

This sprint is frontend-only — no backend rebuild, no migration, no schema change.

# On deployment host (100.108.224.12)
cd /path/to/MealPlanner
git pull
docker compose -f docker-compose.yml up -d --build frontend
docker compose logs -f frontend   # wait for "Application startup complete"

Then sanity-check the bundle is the new one:

curl -s http://100.108.208.56:8082/ | grep -o 'index-[A-Za-z0-9_-]*\.js'
# Should contain a new hash (e.g. index-C_trtYuT.js → new one). Compare to the
# dist/assets/ output from the last `npm run build` on this machine.

2. Build verification (already green)

$ cd frontend && npm run build
> tsc && vite build
✓ 1891 modules transformed.
dist/index.html                   0.54 kB │ gzip:   0.31 kB
dist/assets/index-DudtjbEb.css   37.14 kB │ gzip:   6.67 kB
dist/assets/index-C_trtYuT.js   466.14 kB │ gzip: 144.12 kB
✓ built in 7.27s

tsc 0 errors, vite 0 errors. (The C_trtYuT hash was from Sprint 3; the new bundle will have a different hash. Check the output of your local build for the actual filename.)

3. Smoke checks

S4.A — F7 happy path: success toasts still work

For each of the following actions, the success toast should fire with the same string as before:

Action Expected success toast
Dashboard: drag a meal to a different slot "Meal moved"
Dashboard: click Approve on a pending meal "Meal approved"
Dashboard: click Deny on a pending meal "Meal denied"
Dashboard: click the trash icon on a meal "Meal deleted" (with Undo button)
Dashboard: click Undo on the delete toast within 5s "Slot filled with a new meal"
Dashboard: click Generate on an empty slot "Meal generated"
Dashboard: send the weekly vote email "queued" (or similar from res.data.status)
Pantry: add a new item "Item added to pantry"
Pantry: remove an item "Item removed" (with Undo button)
Pantry: click Undo on the remove toast within 5s "Item restored"
MealDetail: submit feedback "Feedback saved!"

S4.B — F7 error path: backend errors show the FastAPI detail

The simplest way to trigger a backend error is to send an out-of-range day_of_week or an invalid meal_type. Without a frontend tweak, the easiest check is to stop the backend before exercising the actions:

docker compose stop backend

Then, in the browser, try each of the 7 Dashboard mutations. Each should show a toast with a message like Network Error or Failed to load data (the global handler's fallback), NOT the legacy "Failed to move meal" / "Failed to approve meal" / etc.

Then restart the backend and verify success paths still work:

docker compose start backend

For a real FastAPI 4xx (not a network error), the cleanest check is the /meals/<id>/move action with an invalid target. The frontend doesn't expose a way to send an invalid meal_type directly, so the smoke check is the network-down case. If you want to test the FastAPI 422 path, the pantry form does it naturally: type a 1-char name (the schema has min_length=1 → 1 char is fine, but try an empty name, which the frontend blocks, or use a recipe rating > 5 via DevTools).

For a controlled test, hit the API directly with curl:

# Should return 422 with a Pydantic detail array
curl -i -X POST http://100.108.208.56:8082/api/feedback \
  -H 'Content-Type: application/json' \
  -d '{"meal_plan_item_id":"00000000-0000-0000-0000-000000000000","rating":99}'
# Expected body: {"detail":[{"type":"greater_than_equal","loc":["body","rating"],"msg":"Input should be greater than or equal to 1",...}]}

Then in the MealDetail page for any meal, click "Submit feedback" with rating 5 stars. Then open DevTools → Network → find the POST → "Edit and resend" with rating: 99. The toast should show the first msg from the Pydantic array ("Input should be greater than or equal to 1") — not the legacy "Failed to save feedback. Please try again.".

S4.C — F7 pre-flight checks still work

These are the local checks we deliberately didn't route through the global handler:

Action Expected toast
Pantry: open the Add form, leave name empty, click Add "Please enter an ingredient name"
Pantry: try to remove an item whose ingredient_id is null (none in seed data, but visible in DevTools if you clear the field) "Cannot remove: missing ingredient link"

Both should fire immediately (no network call), and no global error toast should follow.

S4.D — F6 plan-status aria-label

  1. Open the Dashboard (http://100.108.208.56:8082/).
  2. In the top-right of the meal-plan card, there is a status badge (e.g. "awaiting approval", "approved", or "draft").
  3. Open DevTools → Elements tab → find the badge → confirm it has aria-label="Plan status: awaiting approval" (or whatever the status text is).
  4. Optional: turn on a screen reader (VoiceOver on macOS: Cmd+F5; NVDA on Windows). Tab to the badge. It should announce "Plan status: awaiting approval" (or similar).

S4.E — Regression check: Sprints 1-3 still work

Quick spot-check of the headline features from previous sprints:

  • /recommended redirects to /recipes/recommended (Sprint 1 B4)
  • /this-does-not-exist renders the NotFound page (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 (390 px) shows empty meal slots (Sprint 1 B5)
  • Dashboard delete shows the Undo toast (Sprint 3 B12)
  • Nav links have aria-current="page" on the active route (Sprint 3 S3.5)

4. Acceptance criteria

Sprint 4 is done when:

  • git pull + docker compose up -d --build frontend on the deployment host succeeds
  • Browser at http://100.108.208.56:8082/ loads the new bundle
  • All S4.A success toasts still fire with the same text
  • At least one S4.B error path is verified (network-down is the easiest)
  • S4.C pre-flight toasts still fire without a network call
  • S4.D DevTools confirms the plan-status badge has the right aria-label
  • No regression in S4.E

5. Rollback

Sprint 4 is a single frontend commit. To roll back:

git revert d71b67a
docker compose -f docker-compose.yml up -d --build frontend

No DB migration to revert. No data loss possible — the only "writes" are user actions, and a backend call that fails simply doesn't write.