BB MotherShip
Restaurant operations, front and back of house
The only build on this floor made for somebody else's business — which is why the numbers are here and the commit messages are not.
- 93 commits
- 2026-06-07 → 2026-08-03
- TypeScript 94.7%
- private repository
A working restaurant with a kitchen, a floor, stock, shifts, food-safety obligations and a second location coming. Software for that either costs more than the business can justify or arrives as five tools that do not know about each other.
This dossier is deliberately thinner than the others. It is a client's operation, and the split that governs this whole wing applies twice over: the method can be public, the business cannot.
5 decisions
What the constraint forced.
Each of these is a choice with a reason attached. The reason is the part worth reading — a stack list tells you what was used, and nothing at all about the judgment that put it there.
- 01
Let the database compute compliance, so it cannot be miscalculated.
Whether a fridge temperature reading is within its safe range is a generated stored column, evaluated by Postgres from the reading and the range. Application code cannot get it wrong and cannot be persuaded to write a different answer. For a food-safety audit trail the authority has to sit at the lowest layer that a human cannot reach past.
is_in_range GENERATED ALWAYS AS ( temperature_c >= min_safe_c AND temperature_c <= max_safe_c ) STORED - 02
Make the daily forms idempotent by making them upserts.
Stock entries are unique on location, date, shift window and type, so re-submitting the form updates rather than duplicates. Anything filled in by a person under time pressure will be submitted twice; the choice is whether that produces a duplicate row or nothing at all. Sell-through is then computed on read rather than stored, so it cannot disagree with the entries it comes from.
- 03
Use a null scope to mean "everywhere".
A null location id marks a record as chain-wide, so one master set of menu items, recipes and suppliers is visible at every location while each site can still hold its own. Reads take the union of the current location and the global scope. The pattern is old and worth naming, because the alternative — copying the master set per location — is correct on the day it is written and wrong every day after.
- 04
Derive the forecast from tables that already exist.
The revenue outlook is a weighted confidence score over shifts, checklist completions and calendar events — three tables already being written for other reasons, no new migration, no new storage. Before adding a data source, check whether the signal is already in the building.
- 05
Write tests for the pure functions that have already caused bugs.
The first suite deliberately targets the utilities with a history: timezone conversion behind past off-by-a-day and wrong-hour bugs, rank thresholds and progress caps, PIN hashing round-trips and malformed input. Not coverage for its own sake — the specific pure functions whose failures had already cost something. Integration tests against row-level security still need a test database, and that is written down as an open gap rather than quietly skipped.
The part that survives the build.
Put the invariant in the strongest layer that can hold it.
Generated columns, unique constraints and row-level security are all the same move — take a rule that application code is currently promising to keep, and make the database keep it instead. Every rule moved down is a class of bug that cannot be written.
The typed client will let you read a table it will not let you write.
Reading from an unregistered table can be cast past. Inserting cannot — the client validates the payload against the registered insert type and rejects excess properties. That asymmetry is easy to hit late, when the read path has been working for weeks and the first write fails.
"Zero tests" is a finding, not a confession.
Writing it down as a gap with a first suite against it is the useful response. A build journal that only records successes is a marketing document with timestamps.
Built with
- Next.js App Router
- TypeScript
- Supabase / Postgres (RLS, generated columns)
- Vitest
- Server actions
- Vercel
Measured
- commits
- 93
- last commit
- 2026-08-03
- journal sections
- 62
- nights logged
- 12
Written from BB MotherShip build journal — diary + dossier, 95 sections. The dossier is composed from the journal rather than quoted out of it — the raw sections stay behind the review gate described in docs/THE_FORGE.md §4, and every figure above is read from the GitHub API at build time.
