Case study · PickBits product · live

PantryPlan
meal planning
that starts in your kitchen.

Most recipe apps ask what you feel like eating. PantryPlan asks what you already own. Pantry inventory, AI recipes built from your actual shelves, a week plan the whole household can edit, and a shopping list that only contains the gaps. Built end-to-end by PickBits; live at pantryplan.me.

PantryPlan — meal planning for modern households, built by PickBits.AI
Product
PickBits, in-house
Category
Household / meal planning
AI
OpenAI GPT-4.1 + gpt-image-1
Licence
MIT
Status
Live in production
Stack
React + Express + Postgres

The challenge.

Dinner is a coordination problem wearing a cooking problem's clothes. The recipe app doesn't know what's in your cupboard, so it suggests a meal that needs three things you don't have. The pantry drifts out of date the moment someone shops without telling anyone. And the shopping list gets a second bag of rice because nobody checked.

Three constraints shaped the build:

  • Pantry first, recipe second. Any planner that starts from a recipe catalogue has the arrow backwards. The question is "what can I make with this," which means inventory is the primary object, not a feature.
  • A household is multi-user by definition. Two people editing the same pantry from two phones is the normal case, not an edge case — so tenancy and isolation had to be in the database, not in the UI.
  • The list has to actually add up. "2 tsp black pepper" from one recipe and "1 tsp black pepper" from another is 3 tsp of one line item — not two lines. Get this wrong and every downstream promise breaks.

The approach.

The boring engine is the whole product

The AI writes the recipes; the unit-conversion and ingredient-aggregation engine is what makes the app trustworthy. It merges the same ingredient across recipes, converts across volume (tsp/tbsp/cups) and weight (oz/lbs), groups by store department, and scales with servings. It is the single most-tested unit in the codebase — 16 of the 58 tests point at it alone — and it's exposed as a first-class package export rather than buried in a route handler. Unglamorous, and the reason a shopping list is worth opening.

A canonical recipe, and everyone's fork of it

Recipes needed to be both curated and personal: one master copy that improves for everyone, and a user's own edits that survive. That's a gold copy reference model — a canonical recipe kept in sync while users fork their own versions — and it earned a set of dedicated migration and sync scripts of its own. It's the kind of problem that looks like a database question and turns out to be a product question.

Isolation at the database, not the query

Household separation runs on Postgres row-level security, applied as a deliberate, rehearsed operation: back up, enable RLS, run the security test suite section by section, then verify legitimate users still have access. Doing this in the database instead of in the application means a forgotten WHERE household_id = ? in some future route can't leak another family's groceries.

Treat the model like a metered utility

AI calls cost money per request, so the limits are asymmetric on purpose: the general API allows 300 requests/minute per IP, while AI endpoints allow 5 per 15 minutes per user. Usage is logged to its own table and responses are cached. Generated recipe images had a second, sharper failure mode — the provider's image URLs expire — so images are synced into Supabase storage rather than hot-linked, which is a bug you only find in production, months later, as a wall of broken thumbnails.

The stack.

A pnpm + Turborepo monorepo — one app, three shared packages (schema/types, a generated API client, and shared config):

React 18
Vite
TypeScript
Express 5
Drizzle ORM
PostgreSQL
Supabase Auth
OpenAI
TanStack Query
Tailwind + Radix
dnd-kit
pnpm + Turborepo
Sentry + PostHog
Vitest + Playwright

Drizzle because the schema is genuinely relational and deserves types that don't drift. dnd-kit because dragging a meal onto a day is the one interaction the whole planner rests on. Deploys to Railway via Nixpacks, with Docker as the alternative path. The API client is generated from an OpenAPI spec, so the front end can't quietly disagree with the server about a payload.

The results.

Live in production and MIT-licensed. These are build numbers, counted from the repository — we don't publish user counts we can't show you.

88
API route handlers across 65 distinct paths.
18
Postgres tables — households, inventory, recipes, plans, lists.
73
Recipes in the seeded catalogue, across nine categories.
51
Active build days, across 437 commits.

What it looks like.

What the work looks like.

PantryPlan is a PickBits product, built with the same patterns taught in the University tracks — used here first, on something with a real database and a real bill. If you want that pointed at your build, scope it on a free 30-minute call.

Want this for your business?

Built in Phoenix.
Shipped to production.

One operator, end-to-end — design, build, ship, hand off. PantryPlan went from an idea to a live household planner with 18 tables behind it. Yours could be the next one on this page.