Files
Meal-Planner/Review/sprint7-verification.md
T
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

8.3 KiB

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 isoMondayupcomingMonday (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):

# 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)

# (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.