1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
# Food — Meal Planning System
A custom Django app for pantry tracking, meta-recipes, and meal planning. Built for Tom, operated primarily through Caine (OpenClaw AI assistant) via Matrix chat, with Django admin as the web UI.
## Architecture
- **Django 5.2** (latest LTS) with SQLite backend
- **Django REST Framework** for API with token auth
- **HTMX** frontend planned (Phase 4)
- **App name:** `kitchen`
### Core Concept: Meta-Recipes
Instead of rigid recipes, the system uses **templates with swappable slots**:
```
"Stir Fry" = protein (chicken OR pork) + carb (noodles OR rice) + veg (any combo) + sauce
```
This matches how Tom actually cooks — same method, different ingredients depending on what's in the pantry.
## Models
| Model | Purpose |
|-------|---------|
| `Tag` | Flexible ingredient tags (protein, carb, veg, etc.) |
| `Ingredient` | Master ingredient list with aliases and shelf life |
| `PantryItem` | Current kitchen inventory with location and expiry |
| `MetaRecipe` | Cooking template with swappable slots |
| `Slot` | A category in a meta-recipe (protein, carb, veg) |
| `SlotOption` | An ingredient that can fill a slot, with qty/serving |
| `MetaRecipeBase` | Always-needed ingredients (onion, garlic, oil) |
| `Recipe` | Traditional fixed-ingredient recipe |
| `RecipeIngredient` | Ingredient in a fixed recipe |
| `CookLog` | What was cooked and when |
| `ShoppingListItem` | Shopping list with reasons and checkboxes |
## Setup
```bash
cd /var/lib/food
source venv/bin/activate
# Run migrations
python manage.py migrate
# Seed initial data (ingredients, pantry, meta-recipes)
python manage.py seed
# Create superuser (if not already done)
python manage.py createsuperuser
# Run dev server
python manage.py runserver 0.0.0.0:8042
```
## Access
- **Admin UI:** `http://localhost:8042/admin/`
- **Browsable API:** `http://localhost:8042/api/`
- **cgit:** `https://git.jihakuz.xyz/food/`
## API
All endpoints require auth. Token auth for Caine, session auth for browser.
### Key Endpoints
| Method | Endpoint | Purpose |
|--------|----------|---------|
| GET | `/api/what-can-i-cook/?servings=2` | Match pantry vs recipes |
| POST | `/api/log-cook/` | Log a cooked meal, optionally deduct from pantry |
| GET | `/api/pantry/` | List all pantry items |
| GET | `/api/pantry/expiring/` | Items expiring within 3 days |
| GET | `/api/pantry/restock/` | Staples needing restocking |
| CRUD | `/api/ingredients/` | Ingredient master list |
| CRUD | `/api/meta-recipes/` | Meta-recipes with nested slots |
| CRUD | `/api/recipes/` | Fixed recipes |
| CRUD | `/api/shopping-list/` | Shopping list |
| CRUD | `/api/cook-log/` | Cooking history |
### Auth
- **Token:** `Authorization: Token <token>` header
- **Session:** Log in via admin or `/api-auth/login/`
- **API users:** `tom` (admin), `caine` (API-only)
## File Structure
```
/var/lib/food/
├── food_project/ # Django project config
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── kitchen/ # Main app
│ ├── models.py # All 11 models
│ ├── admin.py # Admin config with inlines
│ ├── serializers.py # DRF serializers
│ ├── views.py # ViewSets + what-can-i-cook + log-cook
│ ├── urls.py # API router
│ ├── management/
│ │ └── commands/
│ │ └── seed.py # Initial data seeder
│ └── migrations/
├── venv/ # Python virtual environment (gitignored)
├── db.sqlite3 # SQLite database (gitignored)
├── manage.py
├── requirements.txt
└── README.md
```
## Pantry Business Rules
- **Freezer items** → no expiry date (frozen = indefinite)
- **Fridge items** → expiry date set from ingredient's `shelf_life_days` if available
- **Staples** (onions, frozen chips, salt, etc.) → auto-flag for restocking when quantity = 0
- **Onions** are a permanent staple — always restock
- **Chicken skin** → remove before cooking (noted in slot option notes)
- **Tom prefers pork** to chicken — pork mince over loins
- **Cooked chicken** — 3 day max fridge life
- **Defrosted sausages** — 2-3 days max
## Implementation Phases
- [x] **Phase 1:** Django project + models + admin + seed data
- [x] **Phase 2:** DRF API + token auth + "what can I cook?" + log-cook with pantry deduction
- [ ] **Phase 3:** Recipe import (URL scraping + cookbook extraction)
- [ ] **Phase 4:** HTMX frontend (pantry view, recipe browser, shopping list)
- [ ] **Phase 5:** Systemd service + nginx reverse proxy + production hardening
## Caine Integration
OpenClaw skill file at `~/.openclaw/workspace/skills/food/SKILL.md` teaches Caine the API each session. Natural language interface via Matrix:
- "What can I cook?" → calls `/api/what-can-i-cook/`
- "Add 6 eggs to the fridge" → POST to `/api/pantry/`
- "Made stir fry with pork and noodles" → POST to `/api/log-cook/` with deduction
- [Photo of shopping] → identify items, bulk add to pantry
## Design Doc
Full design document: `Obsidian Vault/Tom Net/Meal Planning System.md`
|