Files
Meal-Planner/Review/sprint7-verification.md
MealPlanner 09c7525a12 fix(ui): align 'this week' to upcoming Monday (Sprint 7)
User report 2026-06-05: 'webui Meal Planner page is empty' on Friday
morning after the Friday email went out. Root cause: the orchestrator
keyed plans by the most-recent-Friday while the frontend's isoMonday()
returned the most-recent-Monday — a 7-day mismatch on Fridays.

Fixes (one semantic across the stack):
- runner._current_week_start() returns the upcoming Monday (today if
  Mon, else the next Mon). The Friday email subject
  ('Meal plan for week of <date>') automatically picks up the new
  value via run.week_start_date.
- frontend isoMonday -> upcomingMonday (same logic; renamed for
  intent). isoMonday kept as a deprecated alias.
- New WeekRangeNav component (Dashboard + ShoppingList share it).
  Renders [<]  Jun 8 - Jun 14  [>] with clickable chevrons and a
  clickable range label that jumps to the upcoming week. Replaces
  the Sprint 5 inline segmented control on both pages.
- New formatWeekRange(mondayIso) helper (UTC-stable; uses
  timeZone: 'UTC' so the rendered date matches the stored ISO date
  regardless of viewer TZ; closes a latent bug in formatIsoDate too).
- New SQL fix script that retargets the user's 3-pending-items plan
  from 2026-06-05 (Friday-keyed) to 2026-06-08 (upcoming Monday).
  Idempotent + transaction-wrapped. Optional block for 2026-05-29.

No backend migration. No new dependencies. Deploy is git pull +
run the SQL fix + docker compose up -d --build backend frontend.
See Review/sprint7-verification.md for the full deploy + smoke flow.

Files:
- backend/app/services/orchestrator/runner.py:20-35
- backend/scripts/fix_2026_06_05_to_2026_06_08.sql (new)
- frontend/src/lib/utils.ts:43-130
- frontend/src/components/WeekRangeNav.tsx (new)
- frontend/src/pages/Dashboard.tsx (3 call sites + 1 segmented control)
- frontend/src/pages/ShoppingList.tsx (5 call sites + 2 segmented controls)
- Review/{sprint7-verification,ui-nielsen-audit,handoff-ui-audit}.md
- fix-ui-audit.md
- docs/HANDOFF.md
- .agent/{plan,context}.md
2026-06-05 07:46:55 -07:00

158 lines
8.3 KiB
Markdown

# Sprint 7 — Verification
**Sprint:** Fix webui "empty meal plan" (date-semantics mismatch)
**Status:** code complete, awaiting deploy.
**Approach:** Option C — align orchestrator + frontend on "this week" = upcoming Monday; migrate the existing Friday-keyed plan to its equivalent Monday.
**Date of handoff:** 2026-06-05.
---
## What changed (recap)
| Layer | File | Change |
|---|---|---|
| Backend | `backend/app/services/orchestrator/runner.py:20-35` | `_current_week_start()` returns the **upcoming Monday** (today if Mon). |
| Frontend | `frontend/src/lib/utils.ts:43-83` | `isoMonday``upcomingMonday` (new logic). `isoMonday` kept as a deprecated alias. New `formatWeekRange(mondayIso)` helper. |
| Frontend | `frontend/src/components/WeekRangeNav.tsx` (NEW) | Shared component. Renders `[<] Jun 8 — Jun 14 [>]` with clickable chevrons + a clickable range label (jump home) + an optional `This week` chip. |
| Frontend | `frontend/src/pages/Dashboard.tsx` | Import + 3 call-site updates. Replaces inline segmented control with `<WeekRangeNav>`. |
| Frontend | `frontend/src/pages/ShoppingList.tsx` | Same: import + 5 call-site updates, replaces both inline segmented controls (header + empty-state) with `<WeekRangeNav>`. |
| Data | `backend/scripts/fix_2026_06_05_to_2026_06_08.sql` (NEW) | Guarded `UPDATE meal_plan SET week_start_date='2026-06-08' WHERE week_start_date='2026-06-05';` with a `SELECT COUNT(*)` and a final verification `SELECT`. Optional commented-out block for 2026-05-29. |
| Docs | `Review/ui-nielsen-audit.md` + `fix-ui-audit.md` + `Review/handoff-ui-audit.md` + `docs/HANDOFF.md` + `.agent/plan.md` + `.agent/context.md` | All updated with Sprint 7 status blocks. |
**No new dependencies. No backend migration. Frontend + backend rebuild only, plus the one-time SQL data fix.**
---
## Deploy commands
Run on the deployment host (`100.108.224.12`):
```bash
# 1. Pull
cd ~/MealPlanner
git pull
# 2. SQL data fix (the user's 3-pending-items plan moves to 2026-06-08)
docker compose exec -T db psql -U mealplanner -d mealplanner \
-f /dev/stdin < backend/scripts/fix_2026_06_05_to_2026_06_08.sql
# Expected output:
# rows_to_migrate
# ----------------
# 1
# UPDATE 1
# COMMIT
# If you also uncomment the 2026-05-29 block, you'll see another UPDATE 1.
# 3. Rebuild backend + frontend
docker compose -f docker-compose.yml up -d --build backend frontend
# 4. (Optional) Verify the new function on the running backend
docker compose exec backend python -c "
from datetime import date
from app.services.orchestrator.runner import _current_week_start
print('_current_week_start() →', _current_week_start())
"
# Should print the upcoming Monday's date (e.g. 2026-06-08 if today is Fri 2026-06-05).
```
**Order matters.** Pull → SQL fix → rebuild. The SQL fix is idempotent (re-running is a no-op once 2026-06-05 has no rows), so it's safe to retry.
---
## Smoke checklist (browser, on `http://100.108.208.56:8082/`)
| # | Action | Expected |
|---|---|---|
| 1 | Open `/` (Dashboard) with no `?week=` query param. | URL is just `/`. Header shows the new week-range nav: `[<] Jun 8 — Jun 14 [>]` for week 2026-06-08. Three meal cards visible (Chicken Fajitas Mon, Garlic Shrimp Scampi Wed, Breakfast-for-Dinner Veggie Scramble Fri). Plan status badge: `draft`. Total cost ~$188.98. |
| 2 | Click the range label (`Jun 8 — Jun 14`). | URL is still `/` (jump home goes to the default week). The `This week` chip is **not** visible (we're already on the upcoming week). |
| 3 | Click the right chevron (`[>`). | URL becomes `/?week=2026-06-15`. Header shows `Jun 15 — Jun 21`. Empty state appears (no plan for next-next week). |
| 4 | Click the left chevron (`[<`). | URL becomes `/?week=2026-06-08`. Header shows `Jun 8 — Jun 14`. Three meal cards reappear. |
| 5 | Click the `This week` chip (visible only when off the upcoming week). | URL clears the `?week=` param. Header shows the upcoming week again. |
| 6 | Open `/shopping-list` (no `?week=`). | Header shows the same `[<] Jun 8 — Jun 14 [>]` nav. The "Add N to pantry" + "Reset" + "Print List" buttons are still in their normal positions. |
| 7 | Click a checkbox in the shopping list. The "Add N to pantry" button shows. | Button works as in Sprint 6 (no regression). |
| 8 | Open `/shopping-list?week=2026-06-15`. | Empty state: "No plan for that week. Go to the Dashboard and generate one, or pick a different week." The week-nav is still clickable. |
| 9 | Open `/` with `?week=2026-06-01` (a Mon that has no plan). | Empty state with "Plan the week" dropdown (F4). The week-nav shows `Jun 1 — Jun 7` with the `This week` chip visible (because we're not on the upcoming week). |
| 10 | Reload the page after each navigation. | URL is preserved; the same week is shown. (F5 URL persistence still works.) |
| 11 | Press `g d` (Sprint 5 keyboard shortcut). | Navigates to `/` with the default (upcoming) week. |
| 12 | Press `?` (Sprint 5 help shortcut). | ShortcutHelpBanner slides down with the keyboard help text. (No regression.) |
If any item fails, **stop and report** with the URL you were on, the action you took, and the observed vs expected behavior.
---
## API smoke (curl, on the deployment host)
```bash
# (a) The user's just-migrated plan lives at the upcoming Monday's key
curl -s "http://100.108.208.56:8082/api/meals?week_start=2026-06-08" | python3 -m json.tool | head -30
# Expect: 3 items, all status=pending, total ~$188.98
# (b) The old Friday-keyed date now returns null (post-migration)
curl -s "http://100.108.208.56:8082/api/meals?week_start=2026-06-05"
# Expect: null
# (c) The current calendar week has no plan (was always the case)
curl -s "http://100.108.208.56:8082/api/meals?week_start=2026-06-01"
# Expect: null
# (d) The shopping list is also keyed by the upcoming Monday now
curl -s "http://100.108.208.56:8082/api/shopping-list?week_start=2026-06-08" | python3 -c "
import sys, json
d = json.load(sys.stdin)
print('items:', len(d.get('items', [])))
print('week:', d.get('week_start_date'))
print('total:', d.get('total_estimated_cost'))
"
# Expect: items around 20, week=2026-06-08, total ~$27.35
```
---
## Things to look for
- **The webui is no longer empty.** This is the user's original complaint.
- **The week-range label is scannable.** The header shows `Jun 8 — Jun 14` (or whatever the upcoming week is) — the user requested this format.
- **The chevron brackets are clickable.** Mouse or keyboard, they step the week by 7 days.
- **The `This week` chip appears only when off the upcoming week.** Clean visual signal.
- **URL persistence still works.** `?week=YYYY-MM-DD` in the URL is respected.
- **Keyboard shortcuts (Sprint 5) still work.** `g d`, `g r`, `g p`, `g s` navigate; `/` focuses search; `?` shows help.
- **Plan-the-week (Sprint 6) still works.** The "Plan the week" button is at the same position with the same dropdown.
- **Bulk pantry add (Sprint 6) still works.** The "Add N to pantry" button on the shopping list is unchanged.
---
## Rollback (if needed)
The Sprint 7 change is small and easy to revert:
1. Revert `runner._current_week_start()` to return the most recent Friday (the original 5-line body).
2. Revert `upcomingMonday()` to return the current calendar week's Monday.
3. Revert the frontend `WeekRangeNav` swap (put the inline segmented control back in Dashboard and ShoppingList).
4. Re-run the SQL in reverse: `UPDATE meal_plan SET week_start_date='2026-06-05' WHERE week_start_date='2026-06-08';` (and similarly for 2026-05-29 if you migrated it).
5. `git revert` is also clean — all Sprint 7 work is in one or two commits if squashed.
The pre-Sprint 7 behavior is what the user reported as broken. Only revert if a regression appears that wasn't there before Sprint 7.
---
## Verification log
(Filled in by the operator after deploy + smoke.)
- [ ] `git pull` on deployment host → success
- [ ] SQL fix script ran → expected row count
- [ ] Backend rebuild → success
- [ ] Frontend rebuild → success
- [ ] Browser: `/` shows 3 meals on the upcoming week
- [ ] Browser: `[<]` and `[>]` chevrons step the week
- [ ] Browser: `This week` chip is visible only when off the upcoming week
- [ ] API: `/api/meals?week_start=2026-06-08` returns 3 items
- [ ] API: `/api/meals?week_start=2026-06-05` returns null
- [ ] No regression in Sprints 1-6
---
**Last updated: 2026-06-05** — code complete, awaiting deploy.