summaryrefslogtreecommitdiff
path: root/requirements.md
diff options
context:
space:
mode:
authorTom Flux <tom@tomflux.xyz>2026-06-23 19:55:16 +0100
committerTom Flux <tom@tomflux.xyz>2026-06-23 19:55:16 +0100
commite34081ce36d1993912dad514127924440437a2e9 (patch)
tree01efff278699e0fbf38e77a2000bef0fc71fb6ad /requirements.md
parentcdbfabf0ea855df854b2357dc124df03f18d0514 (diff)
Add planning docs: research, requirements, redesign plan
Research of current state, requirements for the web-first pivot (pantry polish -> auth -> MCP), and the phased implementation plan. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'requirements.md')
-rw-r--r--requirements.md260
1 files changed, 260 insertions, 0 deletions
diff --git a/requirements.md b/requirements.md
new file mode 100644
index 0000000..6c71a97
--- /dev/null
+++ b/requirements.md
@@ -0,0 +1,260 @@
+# Food App — Requirements (pivot to web-first)
+
+> Written 2026-06-22, after reviewing `research.md` and interviewing Tom.
+> This supersedes the Caine-centric design. Pairs with `research.md` (current
+> state) — this doc is the *target*.
+
+## The pivot, in one line
+
+Caine (the Matrix LLM assistant) was never really used — it cost too much per
+call. **The web UI becomes the primary interface.** An LLM can come back later
+as an MCP server riding on the existing claude.ai subscription (no per-call
+cost), but that's a later phase, not now.
+
+## The one constraint that wins
+
+**Ease of use beats everything.** This is a single-user personal app, low
+stakes. When a requirement trades correctness, completeness, or robustness for
+less friction, friction wins. Specifically: fewer fields, fewer taps, fewer
+decisions, nothing that nags, and updating the pantry should feel like nothing.
+
+**Mobile-first, not mobile-also.** The pantry is used standing in the kitchen
+or at the shop, on a phone — that's the primary device, and it's fiddly today.
+Design for a one-handed phone screen first; desktop is the afterthought.
+Concretely: big tap targets (state changes and add are thumb-sized, not
+table-cell links), no tiny number inputs or cramped rows, single-column
+layouts, no horizontal scroll, controls reachable in the lower half of the
+screen. If something works on the phone it'll be fine on desktop; the reverse
+is what's been failing.
+
+Everything below is judged against that.
+
+---
+
+## Priorities (Tom, 2026-06-22 — current call)
+
+In value order:
+
+1. **Pantry: make it a bit nicer in the web UI.** Not a ground-up rebuild —
+ incremental polish (the In/Low/Out state + fast add from §2), enough that
+ keeping it accurate isn't a slog. It needs to be *reasonably* accurate
+ precisely because of #3.
+2. **Add some auth** (§1) — login once, long session.
+3. **MCP server with claude.ai — the highest-value piece.** The whole point:
+ stop hand-reciting "here's what's in my pantry" every time. Claude reads the
+ pantry directly in cooking mode. Almost certainly also the *lowest-friction
+ update path* — say "I used the last of the noodles" and Claude writes it
+ back — which is the real answer to the pantry-is-tedious problem.
+
+Everything else in this doc (web what-can-i-cook, shopping rethink, web
+cook-logging, fixed recipes, §4.1 substitutions) is **deferred** — nice, not
+now. Detailed below for when we get there.
+
+**The synergy that justifies the order:** #3 is *why* #1 only needs to be "a
+bit nicer" rather than perfect. If Claude can both read and update the pantry
+conversationally, the web UI becomes the glanceable / manual fallback, not the
+primary data-entry surface. So don't over-invest in pantry UI — invest in
+making the data MCP can serve trustworthy and easy to nudge.
+
+---
+
+## 1. Auth — log in once, then forget it
+
+Decision: **a simple login page + a very long-lived session** (≈1 year cookie).
+Log in once per device; never get prompted again on that device.
+
+- Standard Django session auth (`login_required`) on all `/app/` views — no
+ HMAC, no signed requests, no per-request secret. (The HMAC idea was heavier
+ than needed for one user.)
+- Set `SESSION_COOKIE_AGE` long (~1 year) and `SESSION_EXPIRE_AT_BROWSER_CLOSE
+ = False` so the session survives restarts.
+- One user account is enough. `/api/` keeps its existing token auth for the
+ future MCP client.
+- This also lets us drop the `@csrf_exempt` hacks — a logged-in session has a
+ real CSRF token, so HTMX POSTs can be protected normally.
+
+Security is explicitly *not* the top priority, but this gives a real baseline
+(no more wide-open `/app/`) at near-zero friction.
+
+## 2. Pantry — the redesign (this is the heart of it)
+
+Today the pantry is "all just frustrating": adding is slow, quantities drift
+out of date the moment you cook, expiry dates are fiddly to set and chase, and
+it's a separate chore that's easy to forget. The fix is to **stop tracking the
+pantry like a spreadsheet and track it like a fridge you glance into.**
+
+### 2.1 Track presence, not precise amounts
+
+Replace exact decimal quantities as the primary signal with a simple state:
+
+> **In stock · Running low · Out**
+
+- One tap to change state (e.g. cycle In → Low → Out, or three buttons).
+- Quantity becomes *optional metadata* (a free note like "½ bag", "3 left"),
+ never required, never the thing the app reasons about.
+- This kills the "quantities drift after cooking" problem outright — you don't
+ maintain a number, you flip a flag when you notice.
+
+> **Open decision:** some items genuinely want a rough count (eggs, noodle
+> nests). Proposal: keep the optional quantity note for those, but the matcher
+> and shopping logic only ever look at the In/Low/Out state. Confirm before
+> building.
+
+### 2.2 Fast add
+
+- A single search box: type → autocomplete against known ingredients (and
+ aliases) → tap to add. Defaults its unit/location from the `Ingredient`
+ record, state defaults to "In stock". Zero further fields needed.
+- If the name isn't known, add it inline in the same flow (it auto-creates the
+ ingredient, like the API already does).
+- **Quick-add chips** for staples and recently-used items — one tap, no typing.
+- On mobile this is the make-or-break screen: the search box and chips sit near
+ the bottom (thumb reach), adding an item is one tap, and the In/Low/Out
+ control on each row is a proper button, not a fiddly inline link. The current
+ table-of-tiny-actions layout is exactly what's being replaced.
+
+### 2.3 Expiry stops nagging
+
+- Expiry dates become fully optional and de-emphasised. No required date entry.
+- Instead of chasing exact dates, a lightweight **"use soon"** flag you can tap
+ on an item (and an optional date if you actually care for something specific).
+- Keep the existing freezer rule (frozen = no expiry). Defrosting (freezer →
+ fridge) can set a soft "use soon" instead of computing a hard date.
+
+### 2.4 Updating the pantry as a by-product, not a chore
+
+The biggest win against "I forget to update it": make other actions update the
+pantry for you, so the standalone chore mostly disappears.
+
+- **Logging a cook** optionally flips the ingredients it used toward Low/Out
+ (replaces the brittle decimal-deduction logic).
+- **Checking off a shopping item** marks that ingredient back to "In stock" in
+ the pantry — closing the buy → restock loop automatically.
+
+## 3. Recipes & "what can I cook" — keep it, but make it one implementation
+
+Decision: **keep meta-recipes and the what-can-i-cook matcher** — it's the part
+Tom actually wants. But:
+
+- There are currently **two separate matchers** (`views.what_can_i_cook` JSON
+ and `views_htmx.recipes_page` HTML) that have already drifted. Collapse to
+ **one shared function**; both the page and any API/MCP call use it. (This is
+ also the "two implementations hanging around" Tom flagged.)
+- The matcher moves to **presence-based**: a required slot is satisfied if any
+ of its options is In (or Low) — no quantity comparison. Simpler, and matches
+ the new pantry model.
+- Servings is currently hardcoded to 2 in the web page; with a presence-based
+ matcher, servings stops mattering for "can I cook this", so we can just drop
+ the servings input from that view.
+- Fixed `Recipe`s: keep the model, but **de-scope the URL import for now** — it
+ never links ingredients (see `research.md` §7), so imported recipes are
+ half-broken. Cooking ideas live in claude.ai cooking mode anyway. Don't
+ invest here until the MCP phase, if ever.
+
+## 4. Shopping list — rethink the flow
+
+Tom was explicitly unhappy with the current flow. Requirements:
+
+- Generation stays smart (staples that are Out, "use soon" items, gaps for
+ required recipe slots) but should be **additive and forgiving** — generating
+ again shouldn't wipe manual additions or duplicate.
+- Checking an item off should (a) cross it out and (b) restock it in the pantry
+ (see §2.4).
+- Needs a clear "done shopping" action that tidies the list.
+- Keep it dead simple — a phone checkbox list, grouped by aisle/section.
+
+### 4.1 "Can't find it at the shop" — substitutions (important to Tom)
+
+A recurring real pain: Tom goes to the shop to buy something and it's not
+there, and then he's stuck. He wants help *in the moment* knowing what else
+works.
+
+- **Partial fix available now, no LLM needed:** the meta-recipe slot model
+ *is* a substitution table — a protein slot already lists pork mince OR
+ chicken, etc. So a shopping-list item that came from a recipe slot can show
+ "alternatives that fit the same slot" inline. If you can't find pork mince,
+ the list shows the other proteins that recipe accepts.
+- **Richer substitutions need the LLM/MCP (Phase 2):** general swaps the app
+ has no data for ("no fresh basil → dried is fine", "no crème fraîche → use
+ yoghurt") require world knowledge. That's a claude.ai-via-MCP job: it reads
+ the shopping item + recipe context and suggests a real-world substitute.
+- So: ship slot-based alternatives in the web UI now; treat "smart, open-ended
+ substitution at the shop" as a headline use case for the MCP phase.
+
+## 5. Cook log — make it usable from the web
+
+- Add a **web UI way to log a cook** (currently API/admin only): pick a
+ meta-recipe, tap the slot choices you used, optional rating + note, save.
+- `log-cook` must accept and store `rating` (the model field exists; the
+ endpoint ignores it today).
+- Route cook-logging through model validation so the "exactly one recipe link"
+ rule is actually enforced (today's `log_cook` bypasses `clean()`).
+
+## 6. Cleanup / housekeeping (do first)
+
+- **Run `/simplify` first**, before feature work, to clear the obvious cruft
+ (duplicate matcher, dead `filterset_fields`/`search_fields` with no
+ django-filter installed, the freezer-first deduction bug if deduction
+ survives the redesign).
+- Production baseline: `DEBUG = False`, real `SECRET_KEY` from env. Low
+ priority but cheap.
+
+## 7. Later — MCP (Phase 2, optional)
+
+Once the web UI is solid, wrap the existing API in an **MCP server** so
+claude.ai "cooking mode" can read the pantry and (maybe) log cooks. This is the
+integration Tom actually wanted from Caine, without the per-call cost. Explicit
+non-goal for now — listed so the API stays MCP-friendly in the meantime.
+
+Two things this phase unlocks (and why it's worth keeping the API clean):
+
+- **Cooking blocks still work.** MCP only *feeds data into* the claude.ai
+ conversation — it gives Claude tools to read the pantry. It does not change
+ how claude.ai renders cooking mode. So Claude pulling ingredients from the
+ food app and Claude producing its nice formatted cooking blocks are
+ independent: you get the blocks *and* they're grounded in your actual pantry.
+- **Smart shop-floor substitutions** (see §4.1) — the open-ended "this isn't on
+ the shelf, what else works?" question is the main thing MCP buys over the
+ built-in slot alternatives.
+
+---
+
+## Build order (current)
+
+1. `/simplify` pass (running) — behavior-preserving cleanup of the existing
+ code so the next steps build on something tidy.
+2. **Pantry polish** — In/Low/Out state + fast add in the web UI (§2). Scoped
+ to "a bit nicer", not the full redesign.
+3. **Auth** — login page + ~1-year session, drop `@csrf_exempt` (§1). Fold the
+ cheap production baseline (DEBUG off, real SECRET_KEY) in here since we're
+ touching settings anyway.
+4. **MCP server** — the goal. Expose pantry **read and update** to claude.ai
+ cooking mode, so Claude can both see what's in stock and write changes back.
+ Reuses the existing `/api/` + token auth.
+
+Deferred until after the above (still wanted, just not now): web
+what-can-i-cook, §4.1 slot-based substitutions, shopping flow rethink, web
+cook-logging.
+
+## Open decisions to confirm before building
+
+- **Quantity**: drop exact decimals entirely in favour of In/Low/Out + an
+ optional free-text note? (§2.1) — recommended yes.
+- **Fixed recipes**: park the URL-import feature rather than fix it? (§3) —
+ recommended yes.
+- Anything here that's actually *more* friction than today — call it out.
+
+---
+
+## Original notes (Tom, preserved)
+
++ interface: never really ended up using caine due to cost issues. was a nice idea though.
++ if we went down the route of llms again, maybe a mcp. could claude.ai connect with it
++ current food flow is using claude.ai and its "cooking mode", issue is that it doesnt integrate with my pantry
++ pantry was tedious to update, not sure the best approach here. might just have to tough it out
++ webui interface was generally clunky
++ security not the highest prio but would be good to have some basic auth
++ lets run the /simplify skill firstly
++ tagging recipes never really worked, feels like theres two implementations of it hanging around
++ auth just scares me, i want the least friction way of doing this. a hmac secret or something might be nice for fe <> be and a simple log in page would be good. although i really dont want to have to log in every time
++ pantry: it's all just frustrating at the moment (adding slow, quantities drift, expiry fiddly, easy to forget)