docs(review): Sprint 5 verification log + plan/handoff/audit updates

Sprint 5 (F5 + F2 + 0015 cast fix) is now documented across the project:

- Review/sprint5-verification.md: new deploy + smoke-check doc.
  Backend + frontend deploy (one batch with Sprints 2-4). Migration
  0015 MUST be run as part of this deploy (the cast fix is what
  makes it runnable). 7 smoke-check sections: A) curl tests for
  ?week_start=, B/C/D) URL week nav on Dashboard and Shopping List
  with query-key isolation, E) keyboard shortcut matrix, F) post-
  migration canonical-aisle verification query, G) Sprints 1-4
  regression spot-check. Rollback section covers reverts + the
  persist_aisle_backup recovery path.

- fix-ui-audit.md: new Sprint 5 section (S5.0 critical 0015 fix,
  S5.1 F5 implementation, S5.2 F2 implementation, S5.3 verification
  gate). 'Done when (overall)' block updated to 5 sprints + 9
  commits + 18 findings closed + the 0015 fix unblocks Sprint 2.

- Review/handoff-ui-audit.md: updated to a 5-sprint cycle. TL;DR
  table includes the d78bd18 + f740f40 rows with the CRITICAL 0015
  fix callout. file-list includes the new sprint5-verification doc.
  file-level diff summary gains 16 new rows (S5 backend + frontend +
  0015 + hooks/components). §Future list now strikethroughs F2 and
  F5. Quick-start deploy commands list Sprints 2-5 as a single
  batch (backup → migrate → rebuild backend + frontend).

- Review/ui-nielsen-audit.md: new Sprint 5 status block at the
  top. F5 + F2 + the 0015 fix all documented. Cross-ref to
  Review/sprint5-verification.md.

- docs/HANDOFF.md: Last-updated line bumped to 5 sprints / 9
  commits / 18 findings / with the 0015 fix CRITICAL callout.
  Header commit list gains the two Sprint 5 commits. New 'Sprint
  5' subsection in the 2026-06-04 session block. Commit table
  gained the d78bd18 + f740f40 rows. Files-modified list now
  includes all 5 sprints' changes. New 'Files added by Sprint 5'
  subsection for the 3 new files in hooks/ + components/.

No code changes; the 3 pre-existing WIP files (backend/app/api/
recipes.py, schemas/recipe.py, nginx/nginx.conf) are deliberately
not staged.
This commit is contained in:
2026-06-04 12:42:54 -07:00
parent f740f40103
commit 2029e80c5a
5 changed files with 332 additions and 35 deletions
+61 -14
View File
@@ -2,8 +2,10 @@
You are taking over a project in mid-flight. Read `docs/ORIENTATION.md` first for the high-level. This file is the deep dive: what's real, what's stubbed, where the bodies are buried, and what to do next.
**Date of handoff: 2026-06-03. Last commits before handoff:**
**Date of handoff: 2026-06-04. Last commits before handoff:**
```
f740f40 feat(ui): global keyboard shortcuts + shortcut help banner (Sprint 5 F2)
d78bd18 feat(ui): URL week selector + aisle-migration 0015 cast fix (Sprint 5 F5)
d71b67a feat(ui): global react-query error handler + plan-status a11y (Sprint 4 F7+F6)
427d8ac docs(review): add handoff document for UI audit work
e90a9d6 feat(ui): close 3 P2 audit findings + a11y sweep (Sprint 3)
@@ -299,7 +301,7 @@ Trust the tests. Trust the live runs. Don't trust prose claims that something is
**Current open proposals:**
- `docs/proposals/2026-05-23-feedback-driven-recipe-discovery.md` — pending user approval. No code yet (per the 2026-05-23 section below).
**Last updated: 2026-06-03** — UI/UX audit & fix cycle (Sprints 1, 2, 3, 4) complete. 16 findings closed (5 P0 + 6 P1 + 3 P2 + 2 §Future), code committed across 7 commits (`f3e4a44`, `36038bb`, `ccc70aa`, `f5fb755`, `e90a9d6`, `427d8ac`, `d71b67a`), build green. Sprint 1 deployed; Sprints 2, 3, and 4 awaiting deploy on the user's home server (4 is frontend-only). Backend migration `0015_normalize_pantry_aisles.py` not yet run on prod (dry-run shows 21k rows would change on dev DB). Full UI-audit handoff at `Review/handoff-ui-audit.md`.
**Last updated: 2026-06-04** — UI/UX audit & fix cycle (Sprints 1, 2, 3, 4, 5) complete. 18 findings closed (5 P0 + 6 P1 + 3 P2 + 4 §Future), code committed across 9 commits (`f3e4a44`, `36038bb`, `ccc70aa`, `f5fb755`, `e90a9d6`, `427d8ac`, `d71b67a`, `d78bd18`, `f740f40`), build green. **CRITICAL: Sprint 2's deploy was blocked on a cast bug in migration 0015; that bug is fixed in `d78bd18`. Sprints 2-5 are now deployable as a single batch (Sprint 1 already live; Sprints 2-5 require backend rebuild + migration + frontend rebuild).** Full UI-audit handoff at `Review/handoff-ui-audit.md`.
---
@@ -315,6 +317,7 @@ A full Nielsen-10-heuristics audit of the live deployment at `http://100.108.208
- `Review/sprint2-verification.md` — Sprint 2 deploy + smoke-check checklist (includes the **backend migration** step)
- `Review/sprint3-verification.md` — Sprint 3 deploy + smoke-check checklist (frontend only)
- `Review/sprint4-verification.md` — Sprint 4 deploy + smoke-check checklist (F7 + F6, frontend only)
- `Review/sprint5-verification.md` — Sprint 5 deploy + smoke-check (F5 + F2 + 0015 fix; backend + frontend)
- `Review/handoff-ui-audit.md` — focused handoff for a fresh agent continuing UI-audit work
**Commits on `main` (ahead of `origin/main` by 9 prior WIP commits plus these 7):**
@@ -328,6 +331,8 @@ A full Nielsen-10-heuristics audit of the live deployment at `http://100.108.208
| `e90a9d6` | 3 | 3 P2s + a11y: undo-toast (Dashboard refills slot; Pantry fully reversible), mobile nav nowrap, aria-current, `<main id="main-content">`, Badge `aria-label`/`icon` props |
| `427d8ac` | (docs) | Review/handoff-ui-audit.md |
| `d71b67a` | 4 | F7 global error handler (10 try/catch blocks deleted, QueryCache/MutationCache onError wired) + F6 plan-status aria-label |
| `d78bd18` | 5 | F5 URL week selector (backend `?week_start=`, frontend prev/next + `useSearchParams`) + **CRITICAL 0015 cast fix** (was blocking Sprint 2 deploy) |
| `f740f40` | 5 | F2 keyboard shortcuts (vim-style sequences, focus-search bus, help banner) + new `hooks/` and `components/ShortcutHelpBanner.tsx` |
**Critical Sprint 2 deploy note:** the user must run on the deployment host *after* `git pull`:
@@ -375,6 +380,36 @@ git pull
docker compose -f docker-compose.yml up -d --build frontend
```
### Sprint 5 — F5 (URL week selector) + F2 (keyboard shortcuts)
Second wave of §Future. F5 is the only §Future item needing backend support; F2 is fully frontend. **Plus a critical bug fix to Sprint 2's migration 0015** that was blocking the deploy.
**F5 — URL week selector (`?week=YYYY-MM-DD`):**
- Backend: `GET /api/meals` and `GET /api/shopping-list` now accept `?week_start=YYYY-MM-DD` (FastAPI `Optional[date] Query`). When set, the response is the MealPlan for that week (any status). When omitted, behaviour is unchanged.
- Frontend: new `isoMonday()`, `parseIsoDate()`, `shiftIsoDate()`, `formatIsoDate()` helpers in `lib/utils.ts`. `meals.getPlanned(weekStart?)` and `shoppingList.get(weekStart?)` take an optional ISO date.
- Dashboard + ShoppingList both: `useSearchParams('week')` reads the URL; `queryKey: [..., weekStart]` so navigating weeks fetches the right plan; segmented control (chevron-left | 'This week'/'Current' jump button | chevron-right) in the header. Mutations invalidate the week-aware key. Empty state branches on `isCurrentWeek` ('No plan for that week' vs 'No shopping list yet').
**F2 — Keyboard shortcuts (`g d/r/p/s` nav, `/` focus, `?` help):**
- New `hooks/useKeyboardShortcuts.ts`: vim-style sequence support (1.5s timeout), suppressed in inputs/textareas/contenteditable, ref-based so the listener is registered once.
- New `hooks/useFocusSearch.ts`: CustomEvent bus for cross-page focus. Pantry + Recipes subscribe.
- New `components/ShortcutHelpBanner.tsx`: dismissible help dialog (slide-down under nav) with `role=dialog` + `aria-label`. Auto-dismisses 6s; Escape dismisses.
- App.tsx mounts `<GlobalShortcuts />` (registers the shortcuts) and `<ShortcutHelpBanner />`.
**0015 cast fix (CRITICAL — blocks Sprint 2 deploy):**
- The CASE expression in `0015_normalize_pantry_aisles.py` failed with `operator does not exist: text = boolean` on the `varchar(100) aisle` column. Sprint 2's dry-run query used a different path so the bug was not caught.
- Fixed with explicit `::varchar(100)` cast on the whole CASE expression + simplified `WHEN '' THEN NULL` branch. Verified on local dev DB: migration now succeeds; the 21,196 rows the Sprint 2 dry-run predicted normalize correctly. The deployment host would have hit the same error.
**Sprint 5 deploy (backend + frontend):**
```bash
git pull
docker compose exec -T db psql -U mealplanner -d mealplanner \
-f /dev/stdin < backend/scripts/persist_aisle_backup.sql
docker compose exec backend alembic upgrade head
docker compose -f docker-compose.yml up -d --build backend frontend
```
The order matters: backup → migration → rebuild. The migration will lock the `ingredient` and `grocery_item` tables for the duration; the persist script creates recoverable backups.
### Deployment-host vs dev-host (Tailscale gotcha)
This repo lives on a dev host (Tailscale `100.108.146.47`). The user's home server (Tailscale `100.108.224.12`) serves the live app at `100.108.208.56:8082`. The user's workflow is **commit locally, `git pull` on the deployment host, rebuild there**. Don't `docker compose up` on the local dev host expecting it to update the live site — it won't.
@@ -401,21 +436,33 @@ backend/scripts/persist_aisle_backup.sql # Persistent backup
### Files modified by this session
```
frontend/src/App.tsx # Routes, nav, aria, QueryCache/MutationCache
frontend/src/api/index.ts # (pre-existing WIP, not mine)
frontend/src/components/ui/Badge.tsx # icon + aria-label props
frontend/src/components/ui/EmptyState.tsx # optional to prop
frontend/src/lib/toast.ts → toast.tsx # renamed for JSX; showToast.undo() (B12), extractErrorMessage/showApiError (F7)
frontend/src/lib/utils.ts # cleanDescription() (B7)
frontend/src/pages/Dashboard.tsx # B5, B6, B12, F6 aria-label, F7 handler refactor
frontend/src/pages/MealDetail.tsx # B2, B3, B7, F7 submitFeedback onError
frontend/src/pages/Pantry.tsx # B8, B10, B12, F7 add/remove/createIngredient onError
frontend/src/pages/RecipeDetail.tsx # B1
frontend/src/pages/Recipes.tsx # B11
frontend/src/pages/ShoppingList.tsx # B9, S3.3
backend/app/api/meals.py # (pre-existing WIP + Sprint 5) added ?week_start= param
backend/app/api/shopping_list.py # (pre-existing WIP + Sprint 5) added ?week_start= param
backend/alembic/versions/0015_normalize_pantry_aisles.py # (Sprint 2 + Sprint 5) cast fix
frontend/src/App.tsx # Sprint 4: QueryCache/MutationCache onError; Sprint 5: GlobalShortcuts + ShortcutHelpBanner
frontend/src/api/index.ts # (pre-existing WIP + Sprint 5) getPlanned/get take weekStart
frontend/src/components/ui/Badge.tsx # icon + aria-label props
frontend/src/components/ui/EmptyState.tsx # optional to prop
frontend/src/lib/toast.ts → toast.tsx # renamed for JSX; showToast.undo() (B12), extractErrorMessage/showApiError (F7)
frontend/src/lib/utils.ts # cleanDescription() (B7), isoMonday/parseIsoDate/shiftIsoDate/formatIsoDate (F5)
frontend/src/pages/Dashboard.tsx # B5, B6, B12, F6 aria-label, F7 handler refactor, F5 useSearchParams + week nav
frontend/src/pages/MealDetail.tsx # B2, B3, B7, F7 submitFeedback onError
frontend/src/pages/Pantry.tsx # B8, B10, B12, F7 add/remove/createIngredient onError, F2 useFocusSearchOnShortcut
frontend/src/pages/RecipeDetail.tsx # B1
frontend/src/pages/Recipes.tsx # B11, F2 useFocusSearchOnShortcut
frontend/src/pages/ShoppingList.tsx # B9, S3.3, F5 useSearchParams + week nav
frontend/src/types/index.ts # PANTRY_AISLES, RecipeIngredient extensions
```
### Files added by this session (Sprint 5)
```
frontend/src/hooks/useKeyboardShortcuts.ts # Sprint 5 F2: global keyboard handler
frontend/src/hooks/useFocusSearch.ts # Sprint 5 F2: focus-search CustomEvent bus
frontend/src/components/ShortcutHelpBanner.tsx # Sprint 5 F2: help dialog
```
```
---
## New session: 2026-05-24