imn@dev:~/oss/larder$ cat readme.md

gh://larder

WIP

household food hub · realtime cart + recipes

larder replaces the shared phone note a couple actually runs a kitchen on — the one where "tomatoes" sits bought at the bottom and un-bought at the top, because a note has no idea it is the same product. pick the week's dishes, fold every ingredient into one shared cart checked against the pantry, shop from the same realtime list, cook from a single recipe format.

read honestly: this is a two-commit repository. what is committed is the product vision, a full data model, a from-scratch design system with twelve screens spec'd, an 8-phase implementation plan, and a ci gate written to pass docs-only prs. there is no package.json and nothing under src/ yet — github's own language detector still calls the repo html.

what makes it worth reading before the code exists is how deliberately the pre-code decisions were made. realtime is sse over postgres listen/notify on a dedicated non-pooled connection rather than a hosted vendor — sized for two to five people, and the reason hosting has to be an always-on node process. the recipe-import cascade was costed against real bookmarked recipes first.

architecture blueprint: cart, pantry and recipes linked by sse — spec v1

imn@dev:~/oss/larder$ cat scheme.md

pwa client

optimistic mutations · offline queue

tRPC / SSE

always-on next.js process

railway · not serverless on purpose

LISTEN / NOTIFY

postgres

one active cart line per product — a db constraint

spec-complete · code landing in model-routed phases

// planned deploy: one always-on Railway process · Postgres plugin · $5-10/month

imn@dev:~/oss/larder$ cat services.md

Railway
the planned host — one always-on next.js process plus a postgres plugin; not serverless, since sse and a live LISTEN die on a cold start.
OpenAI
planned for vision parsing of recipe screenshots, icon picking, and the assistant's tool calls — every call metered into a cost column.
FireCrawl
planned as the last step of the recipe-import cascade, reached only when a url exposes neither json-ld nor microdata.
UploadThing
planned storage for dish photos and recipe screenshots, compressed client-side to roughly 300kb before upload.
Resend
planned for magic-link auth and household invite links; needs a verified custom domain before launch.
CodeRabbit
already live: automated review on every pull request, with every thread resolved or explicitly rejected with reasoning before merge.
GitHub Actions
already live: a ci gate written to pass docs-only prs until package.json exists, plus a docs-to-wiki sync on every merge to main.

imn@dev:~/oss/larder$ cat stack.md

Next.jsTypeScript stricttRPC v11TanStack QueryDrizzle ORMPostgresBetter AuthZodnext-intl

imn@dev:~/oss/larder$ cat highlights.md

CONSTRAINT
the core rule — one active cart line per product — is a postgres partial unique index (WHERE trip_id IS NULL), not an application check. duplicates are structurally impossible rather than merely discouraged.
REALTIME
sse over postgres listen/notify on a dedicated, non-pooled connection that re-listens after any drop. notify payloads are not persisted, so a reconnect just invalidates the household cache instead of replaying missed events.
IMPORT
the recipe cascade (json-ld → microdata → firecrawl → ai normalization) was validated against real bookmarked recipes and costed to roughly a cent each before any app code existed. instagram links skip straight to a screenshot prompt, since firecrawl cannot pass the login wall.
OFFLINE
the mutation queue persists to indexeddb rather than memory, specifically because ios pwas have no background sync api; conflicts resolve last-write-wins per row, which is safe for checkbox-shaped state.
BUDGET
every ai call is metered into a cost column from the very first ai feature, and the monthly cap throttles only the chat assistant — recipe import and icon picking keep working after it is hit.
PLAN
the build itself is model-routed: every row of the 8-phase plan is tagged fable, opus or sonnet, the board is a checked-in markdown file updated inside the same pr that does the work, and branch protection has been on since the first commit.