summaryrefslogtreecommitdiff
path: root/CLAUDE.md
diff options
context:
space:
mode:
Diffstat (limited to 'CLAUDE.md')
-rw-r--r--CLAUDE.md43
1 files changed, 43 insertions, 0 deletions
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..5da8209
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,43 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
+
+## Commands
+
+```bash
+# Install dependencies
+pip install -r requirements.txt
+
+# Run dev server (auto-reload)
+uvicorn main:app --reload
+
+# Run on a specific port
+uvicorn main:app --reload --port 8080
+
+# Explore the API interactively
+open http://localhost:8000/docs
+```
+
+There are no tests. The SQLite database (`chef.db`) is auto-created on first startup via `Base.metadata.create_all()` in the lifespan handler — no migrations needed.
+
+## Architecture
+
+Single-process FastAPI app. All state lives in SQLite. Ollama runs as a separate local process on port 11434.
+
+**Request flow for AI endpoints:**
+1. Router calls `pantry_service.build_pantry_context(db)` to snapshot the current pantry + recent meal history into a plain dict
+2. That dict is passed to an `ai_service` function which builds a prompt and calls Ollama synchronously via `run_in_executor` (keeps the async event loop unblocked during the 15–120s generation)
+3. Ollama always returns JSON (`format="json"` is set on every call); the response is `json.loads()`'d and returned directly — no intermediate parsing layer
+4. The router saves AI output into the DB and returns both the DB record and the raw AI response to the frontend
+
+**Route registration order matters:** `app.include_router(...)` calls happen before `app.mount("/", StaticFiles(...))`. Reversing this breaks all API routes — the static catch-all intercepts them first.
+
+**JSON columns:** `recipes.ingredients`, `menu_plans.plan`, and `grocery_lists.items` are stored as JSON strings in `Text` columns. Always `json.dumps()` before saving and `json.loads()` before using.
+
+**`menu_plans.plan` structure:** `{"monday": {"breakfast": <recipe_id>, "lunch": <recipe_id>, "dinner": <recipe_id>}, ...}`. The `POST /api/menus/generate` response also includes `week_plan` with full recipe details (name, ingredients, instructions) — the frontend uses this for display without a second fetch. On page reload only the plan with IDs is available, so `GET /api/recipes` is needed to look up names.
+
+**`meal_ingredients.ingredient_name` is denormalized** — it stores a copy of the name string rather than a FK to `ingredients`. This preserves meal history when pantry items are deleted.
+
+**`grocery.py` exports two routers:** `router` (prefix `/api/grocery`) and `ai_router` (prefix `/api/ai`). Both are included in `main.py`.
+
+**Config** is loaded from `.env` via `pydantic-settings`. Key vars: `OLLAMA_HOST`, `MODEL_NAME`, `DATABASE_URL`. Change `MODEL_NAME` to switch Ollama models (e.g. `mistral`, `llama3.1`).