Plan: CreatorTrack meals AI logging engine (phase 2)¶
URL: https://mkdocs.justinsforge.com/memory/plans/creatortrack-meals-ai-logging-engine-2026-07-08/
Date: 2026-07-08
REVISED 2026-07-08 after discovery: The AI logging engine ALREADY EXISTS. lib/chat.ts +
app/api/chat/route.ts give the workspace assistant log_food_batch/search_food/log_food/
update_food/delete_food tools AND photo support (system prompt already logs food from photos).
So text + photo logging are done. The shared "food-JSON" is the existing FoodSearchResult
(what Composer.pickDb consumes). Building new vision/assistant endpoints would DUPLICATE the
engine (violates single-source-of-truth). Real remaining gaps only:
- Barcode scanning (BarcodeDetector) — missing
- Open Food Facts data (branded/UPC) — missing (USDA-only today)
- The chat surfaced ON the food log (Day view), not just the workspace sidebar
Behavior (Justin 2026-07-08): existing chat stays auto-log; barcode + photo-button stage
into the Composer for a confirm tap (reuse pickDb prefill + setDbBase scaling base). Build on
branch feat/meals-quickwins-contacts (cumulative; quick-wins already committed ee4f6fe).
Out of scope: Google Contacts two-way sync (separate plan); rebuilding the chat engine.
Repo/paths: ~/creatortrack; meals app components/apps/meals/; food search route
app/api/apps/meals/foodsearch/route.ts; chat infra components/workspace/Chat*; sub per
reference_creatortrack_chat_agents. Reuse Composer dbBase scaling + pickDb staging path.
Task list (revised — shared shape = existing FoodSearchResult)¶
Task 1: Open Food Facts client¶
- Files:
lib/openfoodfacts.ts(new) - What:
offByBarcode(upc)(GETworld.openfoodfacts.org/api/v2/product/<upc>?fields=...) +offSearch(q); mapproduct.nutriments(per-serving whenserving_quantitypresent, else per 100 g) →FoodSearchResult(syntheticfdcId = upcnumber). Fail loud: null + reason on non-200/status:0, never a fabricated food. - Verification:
npx tsx -e "import('./lib/openfoodfacts').then(m=>m.offByBarcode('737628064502').then(r=>console.log(r?.name, r?.calories)))". - Commit:
feat(meals): Open Food Facts client -> FoodSearchResult
Task 2: Barcode lookup endpoint¶
- Files:
app/api/apps/meals/barcode/route.ts(new) - What:
GET ?upc=→offByBarcode→{ok,result}(aFoodSearchResult) or{ok:false,reason}. Session-authed viacurrentUser(), same asfoodsearch/route.ts. - Verification:
curl -fsS "http://127.0.0.1:<devport>/api/apps/meals/barcode?upc=737628064502" | jq .result.name. - Commit:
feat(meals): barcode lookup API (Open Food Facts)
Task 3: Composer staging prop¶
- Files:
components/apps/meals/Composer.tsx,components/apps/meals/DayView.tsx,components/apps/meals/MealsClient.tsx - What: Composer accepts
staged?: FoodSearchResult; on mount it runs the existingpickDbprefill (sets fields +dbBase). DayView holds astaged+stagedMealstate; a stage handler opens a pre-filled Composer under the chosen meal, confirmed with Add. No auto-commit. - Verification:
npx tsc --noEmit; dev-drive: stage a fixture, Composer opens pre-filled, qty edit rescales. - Commit:
feat(meals): stage a FoodSearchResult into the Composer
Task 4: Barcode scanner UI¶
- Files:
components/apps/meals/BarcodeScanner.tsx(new),components/apps/meals/DayView.tsx,components/apps/meals/meals.css - What: Scan button in DayView → modal with
BarcodeDetectorcamera loop →/barcode→ stage (Task 3). Feature-detectBarcodeDetector; clear fallback message when unsupported. - Verification: Dev-drive on Venus (phone): scan a real barcode, Composer stages it.
- Commit:
feat(meals): in-browser barcode scanner
Task 5: Chat box on the food log (surface existing chat)¶
- Files:
components/apps/meals/DayView.tsx,components/apps/meals/meals.css, likelycomponents/workspace/WorkspaceShell.tsx(expose an "open chat" hook to apps) - What: Compact launcher pinned above
ml-calcardthat opens the EXISTING workspace chat (ChatProvider/ChatThread), optionally seeding the input. Reuse, do not rebuild the engine. - Verification: Dev-drive: tap the box on the food log, the existing chat opens; "add a banana" logs it.
- Commit:
feat(meals): food-log entry point to the AI chat
Task 6: Photo-stage button (optional; photo already works via chat auto-log)¶
- Files:
app/api/apps/meals/vision/route.ts(new),components/apps/meals/DayView.tsx - What: ONLY the staging variant is new (chat photo already auto-logs). Image → one vision call
(reuse the model/sub path in
lib/chat/lib/llm/anthropic) →FoodSearchResult[](no logging) → stage. Build last; if descoped, photo logging still works through the chat. - Verification:
curl -fsS -X POST .../vision -F [email protected] | jq '.results[0].name'. - Commit:
feat(meals): photo-to-stage vision endpoint + button
Task 7: Register and document¶
- Files:
MEMORY.md(Claude project index),memory/general/reference_creatortrack_meals_ai_logging.md(new) - What: Topic file (endpoints, food-JSON shape, sub usage, OFF/USDA split, BarcodeDetector notes); MEMORY.md index line. Run the eval harness.
- Verification:
bash /home/justinwieb/forge/scripts/forge_eval_run.sh. - Commit:
docs(meals): register AI logging engine + reference file