From b9434967edb44f0b51ec3aee664425067305cad8 Mon Sep 17 00:00:00 2001 From: Peter Woolery Date: Mon, 4 May 2026 20:59:27 -0700 Subject: [PATCH] docs: add HANDOFF.md for new agent takeover --- docs/HANDOFF.md | 316 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 316 insertions(+) create mode 100644 docs/HANDOFF.md diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md new file mode 100644 index 0000000..a869a41 --- /dev/null +++ b/docs/HANDOFF.md @@ -0,0 +1,316 @@ +# MealPlanner - Agent Handoff Document + +**Project**: MealPlanner - Self-hosted meal planning system +**Last Updated**: 2026-05-04 +**Last Agent**: OpenCode (MealPlanner session) + +--- + +## Project Overview + +A self-hosted meal planning system for a family of 4 (2 adults, 2 children) that integrates with Lucky California grocery store. Key problem: replacing meal kit services (Blue Apron → EveryPlate → HungryRoot → Sunbasket) that suffer from 3x ingredient markup, repetitive meals, and no pantry integration. + +### Core Workflow +1. System generates 7-day meal plan based on Lucky California sales, family dietary constraints, budget, and home pantry items +2. Email sent to adults with meal proposals and approval links +3. Adults click email link → confirmation page → POST vote (Approve/Deny) +4. Per-voter tokens (single-use, 72h TTL) +5. Majority approve → meal confirmed; any deny → swap +6. Shopping list generated after approval + +### Family Constraints +- 3 of 4 family members do NOT like mushrooms +- No allergies +- Budget-conscious but wants tasty food + +--- + +## Architecture + +``` +User (email) ──► SendGrid ───────────────────────────────┐ +User (web) ───► React UI ──► nginx ──► FastAPI ──────────┼──► PostgreSQL + │ │ + └──► Lucky CA scraper ──┘ + (luckysupermarkets.com) +``` + +### Services (Docker Compose) +- **backend**: FastAPI Python app (port 8000, internal only via nginx) +- **frontend**: React + Tailwind (port 3000, internal only via nginx) +- **db**: PostgreSQL 15 (internal only) +- **nginx**: Reverse proxy with SSL (ports 80/443) + +### Tech Stack +- Backend: Python 3.11, FastAPI, SQLAlchemy 2.0, Alembic, Playwright, BeautifulSoup +- Frontend: React 18, TypeScript, Tailwind CSS, React Query, Vite +- Database: PostgreSQL 15 with ENUMs and CITEXT +- Email: SendGrid +- Hosting: Docker Compose, nginx + +--- + +## Current Git State + +``` +git log --oneline -10 +9458edf docs: update ORIENTATION.md with Phase 3/7 progress and current git state +27bca0e docs: update ORIENTATION.md phase table +08e196b feat: implement frontend Web UI pages +933a0cc feat: implement Lucky California scraper with Playwright + BeautifulSoup +c735d21 feat: implement Phase 2 - Alembic migrations, Pydantic schemas, and real API endpoints +e8706d3 docs: final ORIENTATION update +624b516 docs: update ORIENTATION.md for Phase 1 complete +1328ec3 feat: add Phase 1 infrastructure skeleton +0c5b0aa docs: add complete project documentation +``` + +--- + +## Implementation Phases + +| Phase | Description | Status | +|-------|-------------|--------| +| 1 | Infrastructure (Docker, PostgreSQL, FastAPI, React, nginx) | **Complete** | +| 2 | Database & Models (Alembic migrations, Pydantic schemas, API endpoints) | **Complete** | +| 3 | Lucky California Scraper (BeautifulSoup + Playwright, ScraperService) | **Complete** | +| 4 | Recipe Engine (CRUD, tagging, search) | Not Started | +| 5 | Meal Planner Engine (generation algorithm, substitutions) | Not Started | +| 6 | SendGrid Email Integration (meal proposal emails) | Not Started | +| 7 | Web UI - Core (Dashboard, Meal Detail, Pantry, Shopping List) | **Complete** | +| 8 | Web UI - Feedback (Feedback Portal, Learning) | Not Started | +| 9 | Meal Planner Generation Algorithm | Not Started | +| 10 | Image Strategy (scraped + AI fallback) | Not Started | +| 11 | Polish & Future (variety analysis, budget tracking) | Not Started | + +--- + +## Key Files and Locations + +### Backend Structure +``` +backend/ +├── alembic/ +│ ├── env.py # Alembic configuration +│ └── versions/ +│ ├── 0001_initial_migration.py # Full schema (enums, tables, indexes, constraints) +│ └── 0002_seed_data.py # Basic ingredients (70+), family profile, family members +├── app/ +│ ├── api/ +│ │ ├── admin.py # /api/admin/* (scrape trigger, logs, stats) +│ │ ├── meals.py # /api/meals/* (meal plans, voting, approval tokens) +│ │ ├── pantry.py # /api/pantry/* (CRUD for home pantry) +│ │ ├── profile.py # /api/profile/* (family profile, members) +│ │ ├── recipes.py # /api/recipes/* (CRUD, ingredients, filtering) +│ │ └── shopping_list.py # /api/shopping-list/* (aggregation, print HTML) +│ ├── config.py # Pydantic Settings (reads from .env) +│ ├── database.py # SQLAlchemy engine, SessionLocal, get_db +│ ├── models/ +│ │ └── __init__.py # All SQLAlchemy models (FamilyProfile, Recipe, MealPlan, etc.) +│ ├── schemas/ +│ │ └── __init__.py # All Pydantic schemas for API request/response +│ ├── scraper/ +│ │ ├── base.py # BaseScraper with rate limiting, retries, session management +│ │ ├── lucky_ca_scraper.py # LuckyCaliforniaScraper with BeautifulSoup + Playwright +│ │ └── __init__.py +│ └── services/ +│ └── scraper_service.py # ScraperService to save scraped items to grocery_item table +├── alembic.ini +├── Dockerfile +└── requirements.txt +``` + +### Frontend Structure +``` +frontend/ +├── src/ +│ ├── api/ +│ │ └── index.ts # mealPlannerApi wrapper for all endpoints +│ ├── pages/ +│ │ ├── Dashboard.tsx # Weekly meal plan grid view +│ │ ├── MealDetail.tsx # Recipe display with ingredients/instructions +│ │ ├── Pantry.tsx # Add/remove pantry items +│ │ └── ShoppingList.tsx # Grouped by aisle with sale highlighting +│ ├── types/ +│ │ └── index.ts # TypeScript interfaces for all models +│ ├── App.tsx # React Router with /, /meals/:id, /pantry, /shopping-list +│ └── vite-env.d.ts # Vite env types +├── Dockerfile +├── package.json +└── vite.config.ts +``` + +### Documentation +``` +docs/ +├── ARCHITECTURE.md # System architecture diagram +├── database-schema.md # Complete PostgreSQL schema reference +├── implementation-plan.md # Detailed phase-by-phase plan +├── ORIENTATION.md # First-stop guide for new agents (READ THIS) +├── RUNNING.md # Deployment guide +└── SPEC.md # Project specification +``` + +--- + +## Database Schema Highlights + +### Core Tables +- `family_profile` - Household with CHECK(household_size > 0) +- `family_member` - Individual members with email, role, mushroom preference +- `recipe` - Recipes with JSONB ingredients (not join table) +- `ingredient` - Master list with name_lower (CITEXT for case-insensitive matching) +- `meal_plan` - Weekly plan with ISO day_of_week (1=Mon, 7=Sun) +- `meal_plan_item` - Individual meal with approval_status enum +- `meal_plan_vote` - Per-member votes (one vote per member per meal) +- `approval_token` - Single-use tokens with TTL and status tracking +- `home_pantry` - Family's on-hand ingredients +- `feedback` - Ratings, denial reasons, never-suggest flags +- `grocery_item` - Scraped Lucky CA items with FK to ingredient +- `scrape_log` / `email_log` - Operation history + +### Key Enums +- `meal_plan_status_enum`: draft, pending_approval, approved, locked +- `meal_plan_item_status_enum`: pending, approved, denied, swapped +- `approval_token_status_enum`: active, used, expired +- `denial_reason_enum`: too_expensive, boring, disliked_ingredient, cultural, other + +### Approval Flow (REDESIGNED) +1. Email contains unique token per family member (not shared) +2. Token expires after 72 hours +3. Token can only be used once (marked USED after voting) +4. Email link → GET confirmation page (NOT auto-approve) +5. Vote submitted via POST + +--- + +## Configuration + +### Environment Variables (.env) +```bash +DATABASE_URL=postgresql://mealplanner:password@db:5432/mealplanner +SENDGRID_API_KEY=SG.xxx +FAMILY_EMAIL_1=you@example.com +FAMILY_EMAIL_2=spouse@example.com +LUCKY_CA_URL=https://luckysupermarkets.com +AI_IMAGE_ENABLED=false +LOG_LEVEL=INFO +SECRET_KEY=change-me-to-a-random-secret-key +``` + +### Key URLs +- Lucky California: https://luckysupermarkets.com (verified scrapeable) +- robots.txt: Allows all + +--- + +## Verification Commands + +```bash +# Docker build verification +docker compose config +docker compose build backend +docker compose build frontend + +# Backend import test +docker compose run --rm backend python -c "from app.main import app; print(app.title)" + +# Alembic migration test (requires running db) +docker compose run --rm backend alembic upgrade head + +# Frontend build test +docker compose run --rm frontend npm run build +``` + +--- + +## Known Issues / Open Questions + +1. **Lucky California scraping**: Site uses dynamic content (JS rendering). The scraper uses Playwright for browser automation, but actual scraping hasn't been tested with a live database yet. May need adjustment based on actual page structure. + +2. **AI image generation**: Config flag `AI_IMAGE_ENABLED=false`. Not implemented - just a placeholder for future. + +3. **WhatsApp integration**: Planned for future via Twilio. Out of scope for MVP. + +4. **Planned scheduler**: APScheduler with `--workers 1` to avoid duplicate fires. Not yet implemented. + +5. **Meal planner algorithm**: Not implemented. Need to create algorithm that: + - Filters out never_suggest ingredients/recipes + - Prioritizes home_pantry items + - Incorporates sale items from grocery_item + - Ensures variety (max 2 same protein/sauce per week) + - Respects mushroom preference (3 of 4 don't like) + +6. **SendGrid email integration**: Not implemented. Need: + - Email templates for meal proposals + - Approval email with per-voter tokens + - Reminder emails before deadline + - Confirmation emails after approval + +--- + +## Next Steps (Priority Order) + +### 1. Implement SendGrid Email Integration (Phase 6) +- Create `backend/app/services/email_service.py` +- Implement meal proposal email template +- Connect to meal plan creation flow +- Use approval tokens for email links + +### 2. Implement Meal Planner Generation Algorithm (Phase 9) +- Create `backend/app/services/meal_planner_service.py` +- Load constraints (family profile, dietary, budget) +- Filter never_suggest ingredients/recipes +- Prioritize home_pantry items +- Incorporate sale items +- Ensure variety requirements + +### 3. Implement Recipe Engine (Phase 4) +- Recipe CRUD already exists but needs testing +- Tag-based filtering implemented in API +- Search functionality needed + +### 4. Implement Web UI - Feedback (Phase 8) +- Feedback Portal page +- Rating submission (1-5 stars) +- "Never suggest this" flag +- Learning integration + +--- + +## Important Conventions + +### Code Style +- Python: Black formatter, isort for imports +- TypeScript: Prettier, ESLint +- No comments unless explaining non-obvious logic + +### Git Commits +- Conventional commits: `feat:`, `fix:`, `docs:`, `refactor:`, `test:` +- One logical change per commit + +### API Design +- RESTful endpoints with proper HTTP methods +- Pydantic schemas for request/response validation +- Email approval links use GET → confirmation page → POST +- Per-voter tokens, not shared household tokens + +### Database +- UUIDs for primary keys +- Timestamps with timezone (TIMESTAMPTZ) +- ENUMs for status fields (not loose VARCHAR) +- CITEXT or lowercase-on-write for name matching + +--- + +## Contacts + +- **Primary user**: Peter (tech-savvy, hosts the system) +- **Wife**: Non-technical, will use web UI and email +- **Children**: 2, eating habits vary (one OK with mushrooms) + +--- + +## File: ORIENTATION.md + +**IMPORTANT**: Read `docs/ORIENTATION.md` first before doing anything else. It contains the authoritative project state, phase table, and next steps. \ No newline at end of file