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
This commit is contained in:
MealPlanner
2026-06-05 07:46:55 -07:00
parent a616138e7c
commit 09c7525a12
13 changed files with 679 additions and 96 deletions
@@ -0,0 +1,77 @@
-- Sprint 7 — One-time data fix: retarget Friday-keyed plan(s) to the
-- equivalent upcoming Monday.
--
-- Background: pre-Sprint 7, the orchestrator's `_current_week_start()`
-- returned the most recent Friday. The Friday email was sent for that
-- date, and the plan was keyed by it. Sprint 7 changes the convention
-- to "upcoming Monday" (Mon-Sun week). Existing plans keyed by a
-- Friday are migrated to the equivalent upcoming Monday so:
--
-- 1. The user's just-voted-on plan (3 pending items, week of
-- 2026-06-05) lives under the same date the new code will use.
-- 2. The webui default (upcoming Monday) and the plan key line up.
--
-- This script is idempotent: re-running it is a no-op once 2026-06-05
-- has no rows. The transaction wraps both the count and the UPDATE so
-- a partial run can't leave the table in an inconsistent state.
--
-- Run on the deployment host (db is in a container, no host psql):
--
-- 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
-- id | week_start_date
-- ------------------------------------+-----------------
-- <uuid-for-2026-05-15-plan> | 2026-05-11
-- <uuid-for-2026-05-22-plan> | 2026-05-18
-- <uuid-for-2026-05-29-plan> | 2026-05-25
-- <uuid-for-2026-06-05-plan-NOW-2026-06-08> | 2026-06-08
--
-- COMMIT
BEGIN;
-- (1) How many rows will be migrated? A count of 1 is the expected
-- outcome for the 2026-06-05 plan. Zero is also safe (nothing to do).
SELECT COUNT(*) AS rows_to_migrate
FROM meal_plan
WHERE week_start_date = DATE '2026-06-05';
-- (2) The actual migration. Single-row target; safe under concurrent
-- readers (the row stays visible under the default REPEATABLE READ).
UPDATE meal_plan
SET week_start_date = DATE '2026-06-08'
WHERE week_start_date = DATE '2026-06-05';
-- (3) Verify. Lists all plans ordered by week, so the operator can
-- eyeball that the migration took effect and that the date keys are
-- all Mondays (or Fridays, if a pre-2026-05-15 plan was missed).
SELECT id, week_start_date
FROM meal_plan
ORDER BY week_start_date;
COMMIT;
-- ---------------------------------------------------------------------
-- Optional: also migrate the 2026-05-29 plan (and any other Friday-keyed
-- plan) to the equivalent Monday. The 2026-05-29 plan contains 3
-- approved items the family has already acted on; migrating it is
-- cosmetic (the plan keeps the same items, just under a Monday key so
-- the webui's "current calendar week" view -- if anyone navigates to
-- it -- agrees with the calendar). Comment out the block below if
-- you do NOT want to migrate older plans.
--
-- BEGIN;
-- SELECT COUNT(*) AS rows_to_migrate_0529
-- FROM meal_plan
-- WHERE week_start_date = DATE '2026-05-29';
-- UPDATE meal_plan
-- SET week_start_date = DATE '2026-06-01'
-- WHERE week_start_date = DATE '2026-05-29';
-- COMMIT;