From a616138e7ce0c788c0726d5389753bfe6a6cacfd Mon Sep 17 00:00:00 2001 From: Peter Woolery Date: Thu, 4 Jun 2026 14:05:51 -0700 Subject: [PATCH] docs(review): Sprint 6 verification log + plan/handoff/audit updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- Review/handoff-ui-audit.md | 27 +++++-- Review/sprint6-verification.md | 128 +++++++++++++++++++++++++++++++++ Review/ui-nielsen-audit.md | 6 ++ docs/HANDOFF.md | 29 +++++++- fix-ui-audit.md | 30 +++++++- 5 files changed, 211 insertions(+), 9 deletions(-) create mode 100644 Review/sprint6-verification.md diff --git a/Review/handoff-ui-audit.md b/Review/handoff-ui-audit.md index 18323e6..eef1882 100644 --- a/Review/handoff-ui-audit.md +++ b/Review/handoff-ui-audit.md @@ -1,6 +1,6 @@ # UI/UX Audit & Fix — Agent Handoff -You are taking over a 5-sprint UI/UX audit and fix cycle. All code changes are committed and build green. The user's deployment host (Tailscale `100.108.224.12`) is the only environment you should touch for verification — the local repo on this machine (`/home/peter/Projects/MealPlanner`) was the editing host; the running app lives elsewhere. +You are taking over a 6-sprint UI/UX audit and fix cycle. All code changes are committed and build green. The user's deployment host (Tailscale `100.108.224.12`) is the only environment you should touch for verification — the local repo on this machine (`/home/peter/Projects/MealPlanner`) was the editing host; the running app lives elsewhere. **Date of handoff: 2026-06-04.** @@ -8,7 +8,7 @@ You are taking over a 5-sprint UI/UX audit and fix cycle. All code changes are c ## TL;DR -Nine commits land all 14 audit findings + 4 of the §Future items: +Ten commits land all 14 audit findings + 6 of the §Future items: | Sprint | Commit | Scope | Build | Deploy | |---|---|---|---|---| @@ -18,12 +18,13 @@ Nine commits land all 14 audit findings + 4 of the §Future items: | 4 | `d71b67a` | F7 global error handler + F6 plan-status aria-label | ✅ green | ⚠️ not yet deployed (frontend-only) | | 5 | `d78bd18` | F5 URL week selector + **CRITICAL 0015 cast fix** | ✅ green | ⚠️ not yet deployed | | 5 | `f740f40` | F2 keyboard shortcuts + ShortcutHelpBanner | ✅ green | ⚠️ not yet deployed | +| 6 | `8ad4ef6` | F3 bulk pantry add + F4 plan-the-week (ShoppingList + Dashboard) | ✅ green | ⚠️ not yet deployed (backend + frontend, no migration) | -All work is on `main` ahead of `origin/main` (pre-existing WIP also present). All five sprints compile. **Sprint 1 is live. Sprints 2, 3, 4, 5 are not yet live on `100.108.208.56:8082/`.** +All work is on `main` ahead of `origin/main` (pre-existing WIP also present). All six sprints compile. **Sprint 1 is live. Sprints 2, 3, 4, 5, 6 are not yet live on `100.108.208.56:8082/`.** **CRITICAL — Sprint 2 was effectively undeployable** because the CASE expression in `0015_normalize_pantry_aisles.py` failed with `text = boolean` on the `varchar(100) aisle` column. The bug is fixed in `d78bd18` (Sprint 5). Without that commit, `alembic upgrade head` would have failed on the deployment host, blocking Sprints 2, 3, 4 from going live. **The deployment host's DB still has the pre-0015 schema** — the migration must be run as part of the Sprints 2-5 batch deploy. -**Next action:** the user runs the deploy commands in `Review/sprint2-verification.md`, `Review/sprint3-verification.md`, `Review/sprint4-verification.md`, and `Review/sprint5-verification.md` on the deployment host, then smoke-checks per the checklists. The Sprints 2-5 deploy is a single batch (one `git pull`, one migration, one rebuild). After verification, any remaining items move to the §Future backlog in `fix-ui-audit.md` (F1 onboarding, F3 bulk add, F4 plan-whole-week, F8 Spoonacular enrichment, F9 Ollama matcher). +**Next action:** the user runs the deploy commands in `Review/sprint2-verification.md`, `Review/sprint3-verification.md`, `Review/sprint4-verification.md`, `Review/sprint5-verification.md`, and `Review/sprint6-verification.md` on the deployment host, then smoke-checks per the checklists. Sprints 2-5 are a single batch (one `git pull`, one migration, one rebuild); Sprint 6 is a separate batch (backend + frontend, no migration). After verification, any remaining items move to the §Future backlog in `fix-ui-audit.md` (F1 onboarding tour, F8 Spoonacular enrichment, F9 Ollama matcher — F3, F4, F5, F6, F7 now done across Sprints 4-6). --- @@ -37,6 +38,7 @@ All work is on `main` ahead of `origin/main` (pre-existing WIP also present). Al │ ├── sprint3-verification.md # Deploy + smoke checks for Sprint 3 (frontend only). │ ├── sprint4-verification.md # Deploy + smoke checks for Sprint 4 (F7+F6, frontend only). │ ├── sprint5-verification.md # Deploy + smoke checks for Sprint 5 (F5+F2+0015 fix; backend+frontend). +│ ├── sprint6-verification.md # Deploy + smoke checks for Sprint 6 (F3+F4; backend+frontend, no migration). │ ├── docs-claude.md # Prior docs adversarial review (not yours). │ ├── docs-gpt5.5.md # Prior docs adversarial review. │ ├── repo-gpt5.5.md # Prior repo adversarial review. @@ -144,17 +146,22 @@ The user's flow is: read the smoke check, run the deploy, click around, mark eac ## What's NOT in scope (per audit §Future) -F2, F5, F6, and F7 are done in Sprints 4-5. The audit intentionally deferred these. If the user asks, they become a new plan: +F2, F3, F4, F5, F6, and F7 are done across Sprints 4-6. The audit intentionally deferred these. If the user asks, they become a new plan: - F1. Onboarding hints / tour (H10) - ~~F2. Keyboard shortcuts (`/`, `g p`, `g s`, `n m`)~~ — done in Sprint 5 -- F3. Bulk add on Pantry/Shopping List (H7) -- F4. Plan-the-whole-week button (H7) +- ~~F3. Bulk add on Pantry/Shopping List (H7)~~ — done in Sprint 6 (ShoppingList only) +- ~~F4. Plan-the-whole-week button (H7)~~ — done in Sprint 6 - ~~F5. Persistent week selector in URL~~ — done in Sprint 5 - ~~F6. Badge a11y for color-only signals (generalized)~~ — done in Sprint 4 - ~~F7. Global `react-query` `onError` toast handler~~ — done in Sprint 4 - F8. Backend Spoonacular enrichment (separate proposal in `docs/proposals/`) - F9. Ollama LLM matcher (separate proposal in `docs/proposals/`) +**Follow-up tickets surfaced during Sprints 4-6:** +- Wire the no-op `Generate Meal Plan` empty-state CTA at `Dashboard.tsx:415` to a real user-facing "create a new plan" path (orchestrator/admin flow). Distinct from F4 (which is "plan exists, slots are empty"). Currently the user sees the CTA on `/` only if their family has NO plan at all. +- Pantry bulk-add (F3 was scoped to ShoppingList in Sprint 6; adding multi-select to a 4-column table on mobile is a larger surface). +- "Sprints 2-5 batch" deployment: Sprints 2, 3, 4, 5 are deployable as a single batch now that the 0015 cast fix is in. Sprint 6 is a separate batch (no migration). See the per-sprint `sprintN-verification.md` deploy sections. + --- ## File-level diff summary (audit work only) @@ -201,6 +208,12 @@ F2, F5, F6, and F7 are done in Sprints 4-5. The audit intentionally deferred the | 5 | `frontend/src/App.tsx` | F2: mount GlobalShortcuts + ShortcutHelpBanner | | 5 | `frontend/src/pages/Pantry.tsx` | F2: useFocusSearchOnShortcut on search input | | 5 | `frontend/src/pages/Recipes.tsx` | F2: useFocusSearchOnShortcut on search input | +| 6 | `backend/app/api/pantry.py` | F3: POST /api/pantry/bulk with per-item upsert | +| 6 | `backend/app/api/meals.py` | F4: POST /api/meals/{id}/fill-empty-slots with partial-success result | +| 6 | `backend/app/schemas/__init__.py` | F3+F4: HomePantryBulkCreate, HomePantryBulkResult, FillEmptySlotsRequest, FillEmptySlotsResult, FilledSlot, FailedSlot | +| 6 | `frontend/src/api/index.ts` | F3: pantry.addBulk; F4: meals.fillEmptySlots | +| 6 | `frontend/src/pages/ShoppingList.tsx` | F3: 'Add N to pantry' button + addCheckedToPantry handler | +| 6 | `frontend/src/pages/Dashboard.tsx` | F4: 'Plan the week' button + Dinners only / All meals dropdown | --- diff --git a/Review/sprint6-verification.md b/Review/sprint6-verification.md new file mode 100644 index 0000000..d8b2b54 --- /dev/null +++ b/Review/sprint6-verification.md @@ -0,0 +1,128 @@ +# 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. + +```bash +# 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) + +```bash +# 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. )`). +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 `