# Meal Planner - Implementation Plan

## Overview

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.

---

## Phase 1: Infrastructure & Foundation

### 1.1 Project Setup
- [ ] Initialize Git repository with `.gitignore` (Python, Node, Docker)
- [ ] Create `docker-compose.yml` with: backend (FastAPI), frontend (React), PostgreSQL, nginx
- [ ] Create `backend/` directory structure
- [ ] Create `frontend/` directory structure
- [ ] Set up Alembic for database migrations
- [ ] Create initial database migration with full schema

**Verify**: `docker-compose up -d` starts all services; `docker-compose ps` shows all running

### 1.2 Backend Skeleton
- [ ] Create FastAPI app with directory structure:
  ```
  backend/app/
    __init__.py
    main.py
    config.py
    database.py
    models/
    schemas/
    api/
    services/
    scraper/
  ```
- [ ] Create SQLAlchemy models matching database schema
- [ ] Create Pydantic schemas for API requests/responses
- [ ] Set up database connection with session management
- [ ] Create health check endpoint `GET /health`

**Verify**: `curl localhost:8000/health` returns `{"status": "ok"}`

### 1.3 Frontend Skeleton
- [ ] Create React app with TypeScript (`npx create-react-app` or Vite)
- [ ] Install dependencies: Tailwind CSS, React Router, React Query, Axios
- [ ] Create basic directory structure:
  ```
  frontend/src/
    components/
    pages/
    hooks/
    api/
    types/
  ```
- [ ] Set up React Query provider and routing
- [ ] Create basic layout with navigation

**Verify**: Frontend builds without errors; `docker-compose up` serves frontend on port 3000

### 1.4 Reverse Proxy (Nginx)
- [ ] Create `nginx.conf` with routing rules:
  - `/api/*` → backend:8000
  - `/*` → frontend:80
  - SSL configuration for remote access
- [ ] Create Caddyfile alternative for easier Let's Encrypt setup

**Verify**: Nginx starts without config errors; routing works correctly

---

## Phase 2: Database & Models

### 2.1 SQLAlchemy Models
- [ ] Create `backend/app/models/__init__.py` with all model imports
- [ ] Implement `FamilyProfile` model
- [ ] Implement `Ingredient` model
- [ ] Implement `Recipe` model with JSONB ingredients column
- [ ] Implement `MealPlan` model
- [ ] Implement `MealPlanItem` model
- [ ] Implement `HomePantry` model
- [ ] Implement `Feedback` model
- [ ] Implement `NeverSuggest` model
- [ ] Implement `GroceryItem` model
- [ ] Implement `ScrapeLog` model
- [ ] Implement `EmailLog` model

### 2.2 Pydantic Schemas
- [ ] Create request/response schemas for each model
- [ ] Create nested schemas for related objects (e.g., `MealPlanWithItems`)
- [ ] Create pagination schemas for list endpoints

### 2.3 Database Migrations
- [ ] Create Alembic configuration
- [ ] Create initial migration from SQLAlchemy models
- [ ] Add seed data migration (basic ingredients, sample recipes)

**Verify**: `alembic upgrade head` runs without errors; tables created in PostgreSQL

---

## Phase 3: API Endpoints

### 3.1 Core CRUD Endpoints
- [ ] `GET/PUT /api/profile` - Family profile management
- [ ] `GET/POST /api/ingredients` - Ingredient list
- [ ] `GET/POST /api/recipes` - Recipe management
- [ ] `GET /api/recipes/{id}` - Single recipe with full details
- [ ] `GET /api/pantry` - Home pantry items
- [ ] `POST/DELETE /api/pantry/{id}` - Add/remove pantry items

### 3.2 Meal Plan Endpoints
- [ ] `GET /api/meals/planned` - Current week's meal plan
- [ ] `POST /api/meals/{id}/approve` - Approve a meal
- [ ] `GET /api/deny/{token}` - Denial form (for email links)
- [ ] `POST /api/deny/{token}` - Process denial with reason

### 3.3 Shopping List Endpoints
- [ ] `GET /api/shopping-list` - Current week's shopping list
- [ ] `GET /api/shopping-list/print` - Printable format (PDF-ready HTML)

### 3.4 Feedback Endpoints
- [ ] `POST /api/feedback` - Submit feedback for a meal
- [ ] `GET /api/feedback` - View feedback history

### 3.5 Admin Endpoints
- [ ] `POST /api/admin/scrape` - Trigger Lucky California scrape
- [ ] `GET /api/admin/logs` - View scrape and email logs

**Verify**: All endpoints return expected status codes and data shapes

---

## Phase 4: Lucky California Scraper

### 4.1 Scraper Infrastructure
- [ ] Create `backend/app/scraper/base.py` with base scraper class
- [ ] Create `backend/app/scraper/playwright_setup.py` for browser automation
- [ ] Implement retry logic with exponential backoff
- [ ] Create logging for scrape operations
- [ ] Implement rate limiting (respect Lucky California's limits)

### 4.2 Weekly Ad Scraper
- [ ] Scrape Lucky California homepage for weekly ad link
- [ ] Parse weekly ad page for sale items
- [ ] Extract: product name, sale price, regular price, image URL, product URL
- [ ] Map products to existing ingredients or create new ones
- [ ] Store in `grocery_item` table

### 4.3 Product Catalog Scraper (Future)
- [ ] Scrape product search results for specific ingredients
- [ ] Parse product detail pages for pricing and availability
- [ ] Implement pagination handling

### 4.4 Scrape Scheduling
- [ ] Create scheduler service (APScheduler or similar)
- [ ] Schedule weekly scrape (Sunday night before meal planning)
- [ ] Schedule ad-hoc scrape via admin endpoint

### 4.5 Error Handling
- [ ] Log all scrape failures with full context
- [ ] Create alert if scrape fails 3 consecutive times
- [ ] Store failed URLs for manual review

**Verify**: Scraper successfully pulls 10+ sale items from Lucky California website

---

## Phase 5: Recipe Engine

### 5.1 Recipe Database
- [ ] Create recipe CRUD service
- [ ] Implement tag-based filtering (cuisine, dietary, protein)
- [ ] Create search functionality (name, ingredients)
- [ ] Store recipe images (URL reference)

### 5.2 Recipe Importing
- [ ] Create basic recipe input form in web UI
- [ ] Support manual recipe entry (name, ingredients, instructions)
- [ ] Support pasting recipe URL for future scraping

### 5.3 Ingredient Mapping
- [x] Create ingredient matching service
- [x] Map recipe ingredients to `ingredient` table entries
- [x] Handle unit conversions (cups → oz, lb → g, etc.)
  - Implemented in `app/utils/units.py`: normalization, within-family (weight/volume/count), cross-family via density tables for ~30 canonical ingredients, fallback to dimensionless
  - Integrated into `planner/cost.py` for accurate cost calculation
  - Orchestrator email and shopping list use converted quantities

**Verify**: Can add a recipe manually and retrieve it via API

---

## Phase 6: Meal Planner Engine

### 6.1 Plan Generation Algorithm
- [ ] Create `MealPlannerService` with generation logic
- [ ] Load constraints: family profile, dietary restrictions, budget
- [ ] Filter out `never_suggest` ingredients and recipes
- [ ] Prioritize ingredients from `home_pantry`
- [ ] Select meals based on variety (max 2 same protein/sauce per week)
- [ ] Incorporate sale items from `grocery_item`
- [ ] Generate 7-day plan (dinner only for MVP)

### 6.2 Substitution Logic
- [ ] When meal denied, find similar substitute
- [ ] Criteria: same protein, similar cuisine, within budget
- [ ] Avoid previously denied meals

### 6.3 Cost Calculation
- [ ] Calculate per-serving cost using grocery prices
- [ ] Sum total weekly meal cost
- [ ] Flag meals exceeding budget

### 6.4 Plan Persistence
- [ ] Save generated plan as `draft` status
- [ ] Generate unique approval tokens per meal
- [ ] Set approval deadline (48h from email send)

**Verify**: Plan generation produces valid 7-day plan respecting all constraints

---

## Phase 7: SendGrid Email Integration

### 7.1 SendGrid Setup
- [ ] Create SendGrid API key (if not already done)
- [ ] Create `backend/app/services/email_service.py`
- [ ] Implement email sending via SendGrid API
- [ ] Create HTML email templates

### 7.2 Meal Proposal Email
- [ ] Create email template with:
  - Week overview
  - All 7 meals listed with images
  - Each meal: name, day, image, ingredients list, cost estimate
  - Approve/Deny links with tokens
  - Deadline reminder
- [ ] Send to both adult email addresses

### 7.3 Reminder Email
- [ ] Send reminder 2 days before deadline
- [ ] Include current approval status
- [ ] Include link to web UI for approval

### 7.4 Confirmation Email
- [ ] Send after all meals approved
- [ ] Include link to shopping list
- [ ] Include link to recipes

**Verify**: Emails sent and received; links work correctly

---

## Phase 8: Web UI - Core Features

### 8.1 Dashboard
- [ ] Create `Dashboard` page
- [ ] Show current week's meal plan
- [ ] Show approval status for each meal
- [ ] Quick action buttons (approve/deny)
- [ ] Show shopping list summary

### 8.2 Meal Detail Page
- [ ] Create `MealDetail` page
- [ ] Show full recipe with ingredients and instructions
- [ ] Display meal image
- [ ] Show nutritional hints (calories, protein)
- [ ] Print recipe button

### 8.3 Approval Center
- [ ] Create `ApprovalCenter` page
- [ ] List pending approvals
- [ ] Approve/Deny buttons with reason selection
- [ ] Show denial history and reasons

### 8.4 Pantry Manager
- [ ] Create `PantryManager` page
- [ ] Add items with quantity and unit
- [ ] Remove items
- [ ] Set expiration dates for perishables

**Verify**: All pages render correctly; actions update database

---

## Phase 9: Web UI - Feedback & Learning

### 9.1 Feedback Portal
- [ ] Create `FeedbackPortal` page
- [ ] Rate completed meals (1-5 stars)
- [ ] Select "Never suggest this" option
- [ ] Free-text feedback field

### 9.2 Learning Integration
- [x] Update meal planner weights based on feedback (family-level planner_config JSONB)
- [ ] Block denied recipes from future proposals
- [ ] Block denied ingredients from future proposals

### 9.3 Recipe Discovery
- [ ] Create `RecipeBrowser` page
- [ ] Filter by cuisine, protein, dietary tags
- [ ] Search by name or ingredient
- [ ] "Surprise me" random recipe button

**Verify**: Feedback submitted and reflected in future meal plans

---

## Phase 10: Shopping List & Print

### 10.1 Shopping List Generation
- [ ] Aggregate all ingredients from week's meals
- [ ] Subtract home pantry items
- [ ] Group by Lucky California aisle
- [ ] Highlight sale items
- [ ] Show estimated total cost

### 10.2 Printable Shopping List
- [ ] Create print-optimized CSS
- [ ] Generate clean HTML for printing
- [ ] Include checkbox squares for manual marking
- [ ] Show aisle location for each item

### 10.3 Web UI Shopping List View
- [ ] Create `ShoppingList` page
- [ ] Show items grouped by aisle
- [ ] Show sale price vs regular price
- [ ] Show total estimated cost
- [ ] Print/export button

**Verify**: Shopping list accuracy (matches meal plan ingredients minus pantry)

---

## Phase 11: Image Strategy Implementation

### 11.1 Scraped Images
- [ ] Store image URLs in `recipe.image_url`
- [ ] Implement graceful fallback if image unavailable
- [ ] Lazy-load images in web UI

### 11.2 AI Image Generation (Fallback)
- [ ] Create AI image service abstraction
- [ ] Implement DALL-E or similar API integration
- [ ] Generate images only when scraped image unavailable
- [ ] Cache generated images in database
- [ ] Add config flag to enable/disable AI generation

### 11.3 Email Image Handling
- [ ] Embed images via CDN URL or inline base64
- [ ] Provide alt text for blocked images
- [ ] Include link to web UI for full image gallery

**Verify**: Meals display appropriate images in both web UI and email

---

## Phase 12: Polish & Future Features

### 12.1 Variety Analysis
- [ ] Track sauce/ingredient usage per week
- [ ] Warn if meals are too similar
- [ ] Suggest diverse alternatives

### 12.2 Budget Tracking
- [ ] Track actual spending vs estimated
- [ ] Show cost per serving over time
- [ ] Alert if significantly over budget

### 12.3 WhatsApp Integration (Future)
- [ ] Set up Twilio WhatsApp Business API
- [ ] Create WhatsApp message templates
- [ ] Implement approval/denial via WhatsApp

### 12.4 Recipe Scraping (Future)
- [ ] Implement recipe site scraper
- [ ] Parse recipe structured data (JSON-LD)
- [ ] Auto-import recipes from web

---

## Verification Commands

### Backend Tests
```bash
# Health check
curl localhost:8000/health

# API tests
curl localhost:8000/api/profile
curl localhost:8000/api/recipes
curl localhost:8000/api/shopping-list
```

### Frontend Tests
```bash
# Build test
cd frontend && npm run build

# Dev server
cd frontend && npm run dev
```

### Full Stack Tests
```bash
# Start all services
docker-compose up -d

# Check all services running
docker-compose ps

# View logs
docker-compose logs -f

# Stop all services
docker-compose down
```

---

## File Structure

```
mealplanner/
├── docker-compose.yml
├── docker-compose.override.yml
├── .env.example
├── .gitignore
├── README.md
├── RUNNING.md
├── docs/
│   ├── SPEC.md
│   ├── ARCHITECTURE.md
│   ├── database-schema.md
│   └── implemenation-plan.md
├── nginx/
│   ├── nginx.conf
│   └── ssl/
├── backend/
│   ├── Dockerfile
│   ├── requirements.txt
│   ├── alembic.ini
│   ├── alembic/
│   │   ├── env.py
│   │   └── versions/
│   └── app/
│       ├── __init__.py
│       ├── main.py
│       ├── config.py
│       ├── database.py
│       ├── models/
│       │   ├── __init__.py
│       │   └── [model files]
│       ├── schemas/
│       │   ├── __init__.py
│       │   └── [schema files]
│       ├── api/
│       │   ├── __init__.py
│       │   └── [endpoint files]
│       ├── services/
│       │   ├── __init__.py
│       │   ├── email_service.py
│       │   ├── meal_planner_service.py
│       │   └── [other services]
│       └── scraper/
│           ├── __init__.py
│           ├── base.py
│           ├── lucky_ca_scraper.py
│           └── [other scrapers]
└── frontend/
    ├── Dockerfile
    ├── package.json
    ├── vite.config.ts
    ├── tailwind.config.js
    └── src/
        ├── App.tsx
        ├── main.tsx
        ├── index.css
        ├── components/
        ├── pages/
        ├── hooks/
        ├── api/
        └── types/
```

---

## Dependencies

### Backend (Python 3.11+)
- fastapi
- uvicorn
- sqlalchemy
- alembic
- psycopg2-binary
- pydantic
- sendgrid (sendgrid-python)
- playwright
- beautifulsoup4
- apscheduler
- python-dotenv
- pytest (dev)

### Frontend (Node 18+)
- react
- react-dom
- react-router-dom
- @tanstack/react-query
- axios
- tailwindcss
- postcss
- autoprefixer
- typescript
- vite
- @types/react
- @types/node

---

## Environment Variables

```bash
# Backend
DATABASE_URL=postgresql://mealplanner:password@db:5432/mealplanner
SENDGRID_API_KEY=SG.xxx
RECIPES_EMAIL=you@example.com
FAMILY_EMAIL_1=wife@example.com
FAMILY_EMAIL_2=you@example.com
AI_IMAGE_ENABLED=false
AI_IMAGE_PROVIDER=openai

# Frontend
VITE_API_URL=http://localhost:8000

# Docker
POSTGRES_PASSWORD=secure_password_here
```

---

## Notes

- All code commits should follow conventional commit format
- Test at each phase before proceeding to next
- Document any deviations from this plan
- Keep ORIENTATION.md updated as implementation progresses
