Skip to content

feat: base food catalog (v1 phases 1-2) — schema, admin CLI, online endpoints, picker + barcode UI#247

Open
OrellBuehler wants to merge 18 commits into
mainfrom
feat/base-food-catalog
Open

feat: base food catalog (v1 phases 1-2) — schema, admin CLI, online endpoints, picker + barcode UI#247
OrellBuehler wants to merge 18 commits into
mainfrom
feat/base-food-catalog

Conversation

@OrellBuehler
Copy link
Copy Markdown
Owner

Summary

Ships v1 Phases 1-2 of the access-gated base food catalog (Swiss retail data). Lays the durable foundation users can pick from instead of hand-entering foods OFF lacks.

  • Schema — 3 new tables (catalog_datasets, catalog_foods, catalog_access) in migration 0037 with hand-appended pg_trgm GIN; drift-guard test enforces three-way equality with foods and ALL_NUTRIENTS.
  • Dataset contract — Zod JSONL schema (header + product, fail-closed). Shared with the future crawler.
  • Admin CLI (scripts/catalog.ts) — import (batched insert + GIN drop/recreate + upsert-by-key, grants survive re-import), grant / revoke / list.
  • Server queries (src/lib/server/catalog/queries.ts) — catalogSearch, catalogByBarcode, instantiateCatalogFood. Access enforced authoritatively via SQL INNER JOIN catalog_access; copy-on-use goes through createFood (refactored to accept an optional dbOverride).
  • API endpointsGET /api/catalog/search, GET /api/catalog/barcode/{code}, POST /api/catalog/{id}/save. Declared in openapi.ts, regenerated docs/openapi.json + src/lib/api/generated/schema.d.ts. CI's api:check gate is clean.
  • UIFoodPicker surfaces online catalog results with a source badge below local Dexie results; AddFoodModal handles the new catalog PickerSelection variant (pick → save → log); DayLog barcode scan now checks personal → catalog → OFF.
  • Guardrails.gitignore (data/catalog/, tests/fixtures/catalog/bad.jsonl) + a local prek hook rejecting committed data/catalog/*.jsonl.
  • Refactor — extracted pure nutrient-extraction logic into src/lib/server/nutrient-extract.ts; OFF now uses it (behavior-preserving).
  • i18n — en + de strings for the catalog picker.

Catalog rows are reached only through /api/catalog/* and never enter /api/foods or the Dexie offline mirror; an isolation integration test regression-locks this invariant.

Out of scope (follow-on PRs)

  • OFF adapter (Phase 3) and Migros adapter (Phase 4) — separate plans; data files are produced offline.
  • Coop adapter — deferred to v1.1.
  • MCP catalog parity — additive; spec §9 mentions it; not required for the web UX delivered here.
  • Security CVE bumpsbun run security flags 3 transitive HIGHs (fast-uri 3.1.0, kysely 0.27.6, minimatch). This branch added zero dependencies; these predate main. Handle in a dedicated deps-bump PR.

Spec & plan

  • Spec: docs/superpowers/specs/2026-05-18-base-food-catalog-crawler-design.md
  • Plan: docs/superpowers/plans/2026-05-18-base-food-catalog-foundation-and-integration.md

Test plan

  • bun run check exits 0
  • bun run test — 1775/1775 passing
  • bun run test:integration-db — 40/40 passing (catalog: schema 3, import/grant/revoke/list 4, endpoints + isolation 4)
  • bun run api:check exits 0 (CI's OpenAPI drift gate)
  • Dev server boots cleanly; migration applies
  • Manual smoke (post-merge): import a real Migros JSONL on the server, grant a test user, verify picker shows the catalog section, pick + save + log a product, scan a known barcode and confirm catalog wins over the OFF fallback

OrellBuehler and others added 18 commits May 18, 2026 22:51
13-task plan covering Phase 1 (schema, dataset JSONL Zod, import/grant CLIs,
pg_trgm GIN, drift guard, fixture) and Phase 2 (online search/barcode/save
endpoints, picker source-badge, AddFoodModal pick-to-log, DayLog barcode flow).
Proves end-to-end against a JSONL fixture; OFF/Migros adapters are follow-on
plans, Coop is v1.1.
…og instantiate through it

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

Playwright E2E Results

✅ All tests passed

Download screenshots & report

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant