docs: add HANDOFF.md for new agent takeover

This commit is contained in:
2026-05-04 20:59:27 -07:00
parent 9458edfb45
commit b9434967ed
+316
View File
@@ -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.