Public Access
docs: refresh HANDOFF + ORIENTATION for Phase 5 completion
This commit is contained in:
+35
-17
@@ -15,13 +15,18 @@ Constraint that drives the design: 3 of 4 members do not like mushrooms; family
|
||||
## Architecture (current)
|
||||
|
||||
```
|
||||
email ─► SendGrid (R3-C, not yet wired) ──┐
|
||||
web ─► nginx :80/:443 ─► React/Vite ────┼─► FastAPI ──► PostgreSQL 15
|
||||
│ │
|
||||
│ └─► Swiftly JSON API
|
||||
│ (prod.swiftlyapi.net)
|
||||
│
|
||||
└─► /api/admin/scrape (BackgroundTasks)
|
||||
email ─► SendGrid (Phase 6, not yet wired) ──┐
|
||||
web ─► nginx :80/:443 ─► React/Vite ───────┼─► FastAPI ──► PostgreSQL 15
|
||||
│ │
|
||||
│ └─► Swiftly JSON API
|
||||
│ (prod.swiftlyapi.net)
|
||||
│
|
||||
└─► /api/admin/scrape (BackgroundTasks)
|
||||
|
||||
scheduler ─► APScheduler (America/Los_Angeles)
|
||||
Fri 02:00 scrape → 05:00 generate → 06:00 email
|
||||
Fri 17:00 deadline → 18:00 finalize+shopping-list
|
||||
(same backend image; command: python -m app.scheduler)
|
||||
```
|
||||
|
||||
- **backend** (FastAPI 0.109, SQLAlchemy 2.0, Alembic) — internal only, `expose: 8000`
|
||||
@@ -31,7 +36,7 @@ web ─► nginx :80/:443 ─► React/Vite ────┼─► FastAPI ─
|
||||
|
||||
---
|
||||
|
||||
## Phase status (2026-05-06)
|
||||
## Phase status (2026-05-07)
|
||||
|
||||
| # | Phase | Status |
|
||||
|---|---|---|
|
||||
@@ -39,7 +44,7 @@ web ─► nginx :80/:443 ─► React/Vite ────┼─► FastAPI ─
|
||||
| 2 | DB & models (Alembic, Pydantic schemas, API endpoints) | **Complete** (real, verified) |
|
||||
| 3 | Lucky California ingestion (Swiftly JSON API) | **Complete** — 17 categories, ~10k products live |
|
||||
| 4 | Recipe engine (CRUD, search, tagging, never-suggest filter) | **Thin slice complete** — recipe + ingredient CRUD, ingredient↔grocery match layer (rapidfuzz, manual override), NeverSuggest CRUD, 30-recipe seed. Ingestion source decision deferred (see spec). |
|
||||
| 5 | Meal planner orchestration (generate → email → vote → finalize) | Not started |
|
||||
| 5 | Meal planner orchestration (generate → email → vote → finalize) | **Complete** — Friday Pacific cadence; APScheduler container; `weekly_run` state table; idempotent steps; stale-data fallback; configurable deadline policy. |
|
||||
| 6 | SendGrid email integration (proposal/reminder/confirmation) | Stub only — `app/services/email.py::SendGridEmailBackend` raises NotImplementedError |
|
||||
| 7 | Web UI core (Dashboard / Meal Detail / Pantry / Shopping List) | **Complete** (no auth UI yet) |
|
||||
| 8 | Web UI feedback portal | Not started |
|
||||
@@ -47,7 +52,7 @@ web ─► nginx :80/:443 ─► React/Vite ────┼─► FastAPI ─
|
||||
| 10 | Image strategy (scraped + AI fallback) | Not started |
|
||||
| 11 | Polish (variety analysis, budget tracking, APScheduler) | Not started |
|
||||
|
||||
Verification gate (current, 2026-05-06): **92/92 pytest green**; alembic upgrade→downgrade→upgrade clean; frontend `npm run build` clean; live scrape persists **9,980 grocery_item rows in 44 s** with auto-minted JWT (no env var); 29,779 ingredient_grocery_match rows produced; email approval round-trip (approve/deny/single-use) verified end-to-end.
|
||||
Verification gate (current, 2026-05-07): **115/115 pytest green**; alembic upgrade→downgrade→upgrade clean; frontend `npm run build` clean; live scrape persists **9,980 grocery_item rows in 44 s** with auto-minted JWT (no env var); 29,779 ingredient_grocery_match rows produced; email approval round-trip (approve/deny/single-use) verified end-to-end; scheduler container starts with all 5 Friday jobs registered.
|
||||
|
||||
---
|
||||
|
||||
@@ -69,7 +74,7 @@ Conventions: UUID PKs everywhere, `TIMESTAMPTZ`, Postgres ENUMs (with `values_ca
|
||||
|
||||
Key relationships: `family_profile`→`family_member`; `family_member`→`meal_plan_vote` (per-voter); `recipe.ingredients` JSONB (no recipe-ingredient join table); `grocery_item.(source, external_id)` is the upsert key for scrape ingestion.
|
||||
|
||||
Migrations applied: 0001 initial, 0002 seed (idempotent via `ON CONFLICT DO NOTHING`), 0003 grocery_item.description, 0004 family_profile.calorie_target, 0005 grocery_item.external_id + source + composite index, 0006 thin Phase 4 (ingredient.aliases, recipe.calories_per_serving, ingredient_grocery_match), 0007 seed canonical ingredients (50) + 30 starter recipes.
|
||||
Migrations applied: 0001 initial, 0002 seed (idempotent via `ON CONFLICT DO NOTHING`), 0003 grocery_item.description, 0004 family_profile.calorie_target, 0005 grocery_item.external_id + source + composite index, 0006 thin Phase 4 (ingredient.aliases, recipe.calories_per_serving, ingredient_grocery_match), 0007 seed canonical ingredients (50) + 30 starter recipes, 0008 Phase 5 (`weekly_run` table + `family_profile.pending_approval_policy`).
|
||||
|
||||
Full schema: `docs/database-schema.md`.
|
||||
|
||||
@@ -89,7 +94,11 @@ SESSION_PASSWORD=... # family-shared password for /api/auth/login
|
||||
|
||||
# Email
|
||||
EMAIL_BACKEND=console # 'console' (default) or 'sendgrid'
|
||||
SENDGRID_API_KEY=... # only when EMAIL_BACKEND=sendgrid (R3-C)
|
||||
SENDGRID_API_KEY=... # only when EMAIL_BACKEND=sendgrid (Phase 6)
|
||||
|
||||
# Phase 5 orchestration
|
||||
ADMIN_EMAIL=... # alert destination; empty = alerts dropped silently
|
||||
APP_BASE_URL=http://localhost # base URL for vote links in emails
|
||||
|
||||
# Lucky / Swiftly
|
||||
LUCKY_STORE_ID=757 # Lucky California — San Pablo
|
||||
@@ -110,10 +119,18 @@ The Swiftly bearer JWT is auto-minted at request time via Firebase REST anon-sig
|
||||
## Verification commands
|
||||
|
||||
```bash
|
||||
# Full local stack
|
||||
docker compose --env-file .env.test up -d db backend
|
||||
# Full local stack (include scheduler for Phase 5)
|
||||
docker compose --env-file .env.test up -d db backend scheduler
|
||||
docker compose --env-file .env.test exec backend alembic upgrade head
|
||||
docker compose --env-file .env.test exec -e TEST_DATABASE_URL=postgresql://mealplanner:${POSTGRES_PASSWORD}@db:5432/mealplanner backend pytest -q tests/ # → 92 passed
|
||||
docker compose --env-file .env.test exec -e TEST_DATABASE_URL=postgresql://mealplanner:${POSTGRES_PASSWORD}@db:5432/mealplanner backend pytest -q tests/ # → 115 passed
|
||||
|
||||
# Verify scheduler
|
||||
docker compose --env-file .env.test logs scheduler | grep Registered
|
||||
# Expected: 5 lines — scrape/generate/email/deadline/finalize
|
||||
|
||||
# Manual step trigger (useful for testing without waiting for Friday)
|
||||
curl -X POST http://localhost:8000/api/admin/orchestrate/scrape \
|
||||
-H "Authorization: Bearer ${ADMIN_TOKEN}"
|
||||
|
||||
# Frontend
|
||||
cd frontend && npm ci && npm run build
|
||||
@@ -132,7 +149,7 @@ A `.env.test` template lives in the repo root (gitignored) for local stack runs.
|
||||
- API paths: no trailing slash, no `/list`/`/planned` suffixes.
|
||||
- Tests: pytest; `requires_postgres` marker auto-skips locally without `TEST_DATABASE_URL`.
|
||||
- Migrations: Alembic only. Never `Base.metadata.create_all()` at runtime.
|
||||
- Background work: FastAPI `BackgroundTasks` (current). APScheduler with `--workers 1` planned for Phase 11.
|
||||
- Background work: FastAPI `BackgroundTasks` for on-demand scrape. APScheduler `BlockingScheduler` in the `scheduler` container for the weekly cycle (Phase 5 complete).
|
||||
|
||||
---
|
||||
|
||||
@@ -146,9 +163,10 @@ A `.env.test` template lives in the repo root (gitignored) for local stack runs.
|
||||
- `docs/RUNNING.md` — local dev workflow.
|
||||
- `docs/specs/2026-05-05-meal-planner-algorithm-design.md` — Phase 9 + thin Phase 4 design.
|
||||
- `docs/specs/2026-05-06-swiftly-token-auto-mint.md` — Swiftly JWT auto-mint design (Implemented 2026-05-06).
|
||||
- `docs/superpowers/plans/2026-05-07-phase5-orchestration.md` — Phase 5 implementation plan (executed 2026-05-07).
|
||||
- `.agent/plan.md`, `.agent/context.md`, `.agent/phase-summaries/` — recovery decisions and per-phase summaries from the R1+R2+R3-0 work.
|
||||
- `Review/reviewconcensus.md` — the adversarial review that drove the recovery.
|
||||
|
||||
---
|
||||
|
||||
Last updated: 2026-05-06 — Swiftly auto-mint shipped (AM-1..AM-6); 92/92 pytest green; live scrape verified end-to-end with no `SWIFTLY_BEARER_TOKEN` env var. Next pickup: Phase 5 weekly orchestration.
|
||||
Last updated: 2026-05-07 — Phase 5 weekly orchestration shipped; 115/115 pytest green; scheduler container live with 5 Friday Pacific jobs. Next pickup: Phase 6 SendGrid.
|
||||
|
||||
Reference in New Issue
Block a user