Home kitchen management — inventory, recipes, and meal plans.
Built on Next.js 16 (App Router) and Supabase. See AGENTS.md for coding conventions and architectural rules.
- Node.js 20+
- Docker (for the local Supabase stack)
npm install
npm run db:start # generates the JWT signing key, then boots local Supabase
cp .env.example .env # then fill in from `npx supabase status -o env`
npm run devOpen http://localhost:3000. If port 3000 is taken, Next picks the next free port; Google OAuth is allowlisted for 3000–3009, so sign-in keeps working on any of those — but not above 3009, where it silently no-ops.
After any schema change, regenerate types:
npm run db:types| Command | What it does |
|---|---|
npm run dev |
Start the Next.js dev server |
npm run build |
Production build |
npm run start |
Serve the production build |
npm run lint |
ESLint |
npm run typecheck |
TypeScript (no emit) |
npm run format / format:check |
Prettier write / check |
npm run test:unit |
Vitest (unit + integration) |
npm run test:e2e |
Playwright (E2E) |
npm run test:db |
pgTAP database tests |
npm run db:start / db:stop |
Start / stop local Supabase |
npm run db:reset |
Reset the local database |
npm run db:types |
Regenerate types/database.types.ts |
npm run db:advisors |
Run Supabase security/performance advisors |
npm run worktree:init |
Link shared dev files into a linked worktree |
All git worktrees of this repo share one local Supabase stack — the CLI keys its Docker containers by project_id, so there's a single database, auth instance, and JWT signing key across every checkout. A few consequences:
- Link shared dev files into a new worktree. After creating a worktree, run
npm run worktree:init: it symlinks.env(edits propagate to every worktree) andsupabase/signing_keys.jsonfrom the primary checkout so the worktree boots against the shared stack. Keep per-worktree overrides in.env.local, which is deliberately not linked. The signing key is symlinked, not copied — a divergent key silently invalidates every session. - Destructive DB commands are guarded outside the primary checkout.
db:resetanddb:stoprefuse to run from a linked worktree, since they'd disrupt every checkout. Run them from the primary, or setFORCE_SHARED_SUPABASE=1to override. - The primary checkout must stay put. Linked worktrees symlink into it, so moving, renaming, or removing the primary leaves them with dangling links (missing
.env, invalidated sessions). Re-runnpm run worktree:initin each worktree after relocating the primary. - DB-touching commands serialize across worktrees.
db:start,db:reset,db:stop,test:db(pgTAP), andtest:e2eoperate on the shared stack, so each takes an exclusive lock — a concurrent run (from any worktree, or the same one) waits rather than clobbering it. Locking needsflock, present on Linux and CI; on stock macOS it's absent —brew install flockto enable it. Withoutflockthese commands refuse to run, since an unserialized run can corrupt the shared stack; if you use only a single worktree, setALLOW_UNSERIALIZED_SUPABASE=1to run without locking.test:unitis safe regardless — Supabase is mocked. - Each dev server takes its own port. With several worktrees running
npm run dev, Next falls back through3001+, and OAuth is allowlisted only for3000–3009(see Setup). If Google sign-in does nothing — no error, just a silent no-op — check the port in your address bar. A server above3009(an 11th concurrent one, or one bumped past the range because lower ports are taken) gets a redirect URL that isn't allowlisted; free a port in range and restartnpm run dev.
See docs/DEPLOY.md for the production setup checklist.