Engineering note · records
Decision records
Four architecture decisions in classic ADR form, published because the rejected alternatives say more about a team than the chosen ones. Dates are when the decision was recorded in our internal log.
One Postgres schema per operating system
Context
Nineteen vertical products share one platform (identity, tenancy, push, jobs) and are rebuilt in parallel lanes that seed and truncate test data simultaneously.
Decision
Each OS owns a schema; genuinely shared tables live in a dedicated platform schema that always migrates first. Row-level security ships in the migration that creates each table.
Alternatives rejected
- Tenant column in shared tables — every query must remember the filter forever; parallel lanes collide in the same tables.
- Database per OS — nineteen migration streams, and the shared platform tables become a federation problem.
Costs accepted
Schema selection must be structural (bound once per OS module, never per query), and migrations need namespace and ownership rules — both enforced by CI guards. Full reasoning: One database, nineteen worlds.
Media binaries never enter version control
Context
The brand estate generates heavy media: renders, film plates, licensed stock, editing projects. Some single files exceed a git host's hard size limit outright, and a repo that carries media history stops being cloneable on island bandwidth.
Decision
Binaries stay out of git, blocked by extension. Every asset carries a JSON sidecar — prompt, source, licence, generation parameters — and the sidecars are tracked. The sidecar is the source of truth; the binary is a cache that can be re-pulled or regenerated from it.
Alternatives rejected
- Large-file extensions to git — adds infrastructure and cost to solve a problem the sidecar model dissolves.
- A separate asset server as truth — splits provenance from the repo where decisions live.
Costs accepted
Regeneration is a step, not a checkout; a fresh machine starts from sidecars. We consider that a feature: it keeps provenance honest.
Guided tours are load-bearing, and CI enforces them
Context
Every OS ships a guided tour for a new operator's first day. Tours rot silently: rename a module and every test still passes while the tour points at nothing.
Decision
Tours are a required, permanent part of every OS — and a UI change is not finished until its tour updates in the same commit. A CI guard verifies every OS declares a tour, every step is readable, and every selector matches something that exists.
Alternatives rejected
- Tours as optional onboarding polish — rejected; for a solo restaurateur there is no training department. The tour is the training department.
- Reviewing tours by hand — rejected; the failure mode is precisely the one hand review misses.
Costs accepted
Every UI change costs a little more. That tax is the point — it prices in the operator's first day.
Rebuild the fleet on a fresh shell rather than refactor in place
Context
The first-generation platform proved the products but grew nineteen diverging dashboard forks. Its disease was architectural — per-OS pages owning shell code — not cosmetic.
Decision
Build a fresh shared shell and rebuild each OS onto it, one lane at a time, while the legacy platform keeps running frozen. A parity ledger per OS defines done; nothing is dropped without the founder's recorded sign-off.
Alternatives rejected
- Incremental refactor in place — rejected; the fork disease was the architecture, and each increment would have had to survive inside it.
- Big-bang cutover — rejected; a beta serving real islanders cannot stop while a rewrite lands.
Costs accepted
A long mid-flight period where one OS is across and the rest are not — publicly visible on /geek as amber dots. We chose to show the flight rather than pretend it landed.
