Skip to content

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) (GET world.openfoodfacts.org/api/v2/product/<upc>?fields=...) + offSearch(q); map product.nutriments (per-serving when serving_quantity present, else per 100 g) → FoodSearchResult (synthetic fdcId = upc number). 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} (a FoodSearchResult) or {ok:false,reason}. Session-authed via currentUser(), same as foodsearch/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 existing pickDb prefill (sets fields + dbBase). DayView holds a staged + stagedMeal state; 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 BarcodeDetector camera loop → /barcode → stage (Task 3). Feature-detect BarcodeDetector; 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, likely components/workspace/WorkspaceShell.tsx (expose an "open chat" hook to apps)
  • What: Compact launcher pinned above ml-calcard that 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