Architecture
Prices quotes from each office's price book.Saved lines keep their price.
Coordinators build options in a workspace, and the pricing engine prices every line from the office's published price book. The save writes the price, tier, label and book version onto each line, and the PDF, the Excel and every total read those back.
14.5 hours
from the first commit to v1.0.0
4 fields
frozen on every saved line: price, tier, label and price book version
5 min
from a 4:58 AM fix for a coordinator's ask to shipping it as v1.14.0
3 offices
each with its own versioned price book; only an admin can publish a change
New York --:-- simulated
Hover a part to trace what it touches. Click it for its notes.
- Built by me
- Managed by Google
- Outside system
- Main data path
- On demand
- Credentials cross
When it breaks
What each failure does, and what it does not do.
-
A release goes bad
Traffic moves back to the previous revision in about ten seconds. The prior revision stays warm for exactly this.
docs/runbook/incidents.md:40
-
The CDF is slow or unset
After 8 seconds the coordinator gets their screen back with an empty day and a reason. Production never fills it with sample names.
lib/schedule/registry.ts:83
-
The database zone fails
Restore to a new instance from point in time recovery, point the secret at it, redeploy. The runbook's target is 5 to 10 minutes.
docs/runbook/incidents.md:286
What I tuned
Small choices that keep it fast and cheap.
-
Code for flow, rows for prices
The decision tree is TypeScript with tests. Each office's prices are versioned rows with their own approval, so an office can change a price without a deploy.
docs/architecture/0001-stack-decisions.md:182
-
Scale to zero
Cloud Run runs zero to five instances and bills per request. October 1 to 28 cost 14 cents of Cloud Run.
.github/workflows/deploy-prod.yaml:141
-
The arch follows the options
Nobody picks Upper, Lower or Both anymore. The arch is set from the options inside every save and delete transaction.
lib/summary/archSync.ts
Guards
Rules the code enforces, not rules people remember.
-
Prices frozen on each line
Four columns on every saved line: price, tier, label and price book version. Totals, PDF and Excel read those back, never the live book.
lib/db/schema/estimate.ts:138
-
Reopen moves, never copies
Reopening moves the live rows to the next revision, so payments still point at the right lines. The update is guarded on status and revision, so two clicks cannot both move them.
app/_actions/estimate.ts:672
-
No grant means read only
A new account lands as a viewer and can write nothing until someone grants a role. It fails closed.
lib/auth/guards.ts:29
What it costs
Measured from the Google Cloud billing export, October 1 to 28, net of credits. The always on database is almost all of it, $23.45 of that for the instance alone. The app itself scales to zero between consults.
$34in October
- $33.20 Cloud SQL, always on
- $0.39 Secret Manager
- $0.15 Image registry
- $0.14 Cloud Run, per request
