A cut list is a woodworker's todo list.
This one is the Millroom billing example: shared auth, an org per shop, row-level security between shops, optimistic updates, and a paid tier that runs entirely in Stripe test mode.
Free carries 1 project of 20 pieces. Pro is $5 a month and drops both caps.
Workbench top
Free plan, up to 20 pieces
- Top lamination, 1500 x 90 x 6014
- End cap, 620 x 90 x 602
- Leg, 850 x 90 x 904
- Long rail, 1240 x 120 x 322
- Short rail, 460 x 120 x 322
- Shelf slat, 1240 x 140 x 205
What it demos, and where to read it
- Auth, once
The shared sign-in card, the shared callback, the shared MFA step-up. Nothing here is cutlist's.
src/lib/auth
- An org per shop
The first authed load provisions one, through a race-safe RPC. No signup wizard, no team setup.
src/app/(cutlist)/lib/org.ts
- Row-level security
A project id from another shop reads back as null and 404s, even though the id is valid.
supabase/migrations/20260803100800_cutlist_schema.sql
- Optimistic writes
Cut, add and delete land instantly. A refused write toasts and pulls the server's rows back.
src/app/(cutlist)/components/project-board.tsx
- A paid tier
One shared Stripe webhook, one entitlement check, and caps the pricing page and the gate both read.
src/app/(cutlist)/billing.ts
This example is deliberately small. The chassis is the point.
Left out on purpose: blog, teams, custom domains, API keys, profile settings.
The chassis carries every one of those. cutlist does not need them, so it does not ship them. Everything this product adds sits in one route group, src/app/(cutlist), plus two lines on the product roster. That is the whole footprint.