Database Migrations
The SDK does not ship its own migration runner — the old
applyPatches()/DatabasePort helpers were deleted. Database migrations
are owned by the dal-pg engine (runMigrations +
primebrick-db CLI), documented in the dal-pg dev-guide → Database
migrations page.
This page covers what the SDK does around that engine: the boot wiring
inside createMicroservice.
Boot ordering
createMicroservice accepts a dbPatches option. When present, the
engine runs before any domain traffic is served — HTTP routes,
NATS subscriptions and the registry heartbeat only come up after the
migration step completes. The script scripts/database-patch-apply.ts
in each microservice invokes the same runMigrations code path for
manual runs (pnpm db:migrate).
The migration step needs a raw pg.Pool handle — this is the one
sanctioned getPool() seam in service code:
Code
Degraded mode
runMigrations returns { mode, degraded, applied[], failed[], pendingReview[], skipped[], securityEvents[] }. A failed patch does
not stop the service from booting — the boot continues degraded and
domain routes return 503 until an admin remediates through the FE
/system/migrations page (retry / approve / resolve). Later patches in
the module are not executed after a failure (ordering is mandatory).
The reload invariant
The migration engine is the only component allowed to read DB state
before itself — and whatever it reads, it re-reads after applying ≥1
patch. Concretely today: the engine re-reads db_migration.mode from
<schema>.config_entries post-apply (a patch may have changed it) and
logs the effective next-run mode. Everything else (ConfigLoader, shield
registries, translations) runs after the step and sees fresh state by
construction.
Any future boot-stage read added before the migration step must implement the same reload — otherwise it can observe pre-patch schema or config.