09c7525a12afe4b41efeac3cd3c971533cab6d38
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
Meal Planner
Self-hosted meal planning system that integrates with Lucky California grocery store, sends weekly meal proposals via email to family members, generates shopping lists, and learns from feedback.
Background
This project was born out of frustration with meal kit services (Blue Apron → EveryPlate → HungryRoot → Sunbasket) that:
- Escalate costs to 3x ingredient markup
- Fall into repetitive meal rhythms
- Force users to log into apps to manage selections
- Don't integrate with home pantry items
Features
- Grocery Integration: Scrapes Lucky California weekly ads and sales
- Family Approval Workflow: Email proposals with approve/deny; one denial swaps the meal
- Shopping List Generation: Weekly list grouped by store aisles, highlighting sales, with interactive checkboxes to track purchased items
- Pantry Integration: Specify home items to incorporate into suggestions
- Web UI: Modern interface for the whole family
- Learning: Feedback-based meal recommendations, with weekly auto-discovery of new recipes from external APIs when family preferences are signaled
- Recipe Images: Scraped from public recipe sites, AI fallback available
- Unit Conversion: Converts recipe quantities (cups, tbsp, lb) to grocery units for accurate cost estimates
Architecture
- Backend: Python/FastAPI
- Database: PostgreSQL
- Frontend: React + Tailwind CSS
- Email: SendGrid
- Hosting: Docker Compose with nginx reverse proxy
Documentation
Quick Start
# Clone and start
docker-compose up -d
# View logs
docker-compose logs -f
# Stop
docker-compose down
Family Profile
Household: 2 adults, 2 children
- One adult likes mushrooms, one child OK with them
- Three family members do NOT like mushrooms
- No allergies
- Calorie, budget, and health conscious eating
Approval Workflow
- System generates 7-day meal plan based on sales, dietary constraints, budget, variety
- Email sent to both adults with meal previews
- One denial = meal swapped; no denials = auto-approved
- Shopping list generated after approval
Tech Stack
| Component | Technology |
|---|---|
| Backend | Python 3.11, FastAPI |
| Database | PostgreSQL 15 |
| Frontend | React 18, TypeScript, Tailwind |
| Scraping | Playwright, BeautifulSoup |
| SendGrid | |
| Hosting | Docker Compose, nginx |
Languages
Python
72.5%
TypeScript
25.9%
JavaScript
0.5%
PLpgSQL
0.4%
CSS
0.3%
Other
0.2%