Migrations
The schema is a list of numbered migrations inlib/db/migrations.ts. Each one is recorded in the schema_migrations table once it has run.
- The pending migrations run once per server instance, in order, the first time any module needs the database (
ensureSchema()). npm run db:migrateruns them ahead of a deploy.- Every statement must be safe to run on a database that already has it, so two instances starting together are fine and a migration is recorded only once.
Add a migration
1
Append it
Add a new entry at the end of
MIGRATIONS with the next id, a short name and its statements. Never edit a migration that has already run.2
Make it idempotent
Use
IF NOT EXISTS and ADD COLUMN IF NOT EXISTS, so running it twice changes nothing.3
Test it
tests/migrations.test.ts builds a fresh database from every migration and checks that every table the code uses exists.What is stored where
Bookings, quotes, trips and saved travellers are stored as a JSON document per row, next to the columns used to find them (agency, reference, dates).
The search results cache is the one thing kept in each server’s memory, on purpose: it lasts five minutes and losing it only means asking the supplier again.
Agency scope
Every request that touches agency data runs insiderunForAgency. Every agency-owned query reads the agency id from that scope with currentAgencyId().
Commands run inside the caller’s agency automatically. A scheduled job loops over the agencies and runs once inside each one’s scope.
Transactions
withTransaction(fn) runs several writes as one. Every query made inside fn, from any module, joins the same transaction: it commits when fn returns and rolls back if it throws.
Outside a database (unit tests with in-memory stores), fn simply runs. Linking a booking to a trip is a typical use: the trip’s list and the booking’s trip id are written together, so one is never saved without the other.
Rebooking and switching to a cheaper rate work this way: the new booking is made with the supplier, then the writes that link the old and new bookings are saved together.