Database schema
The schema lives in packages/infra/db/src/schema/. One file per
entity bundle; schema/index.ts is the barrel. Migrations live in
packages/infra/db/src/migrations/ and are registered in
meta/_journal.json.
Every relevant concept also has its own page in Concepts. This page is the dense schema-only summary.
Users & sessions
Section titled “Users & sessions”Institutions & accounts
Section titled “Institutions & accounts”Tokens & prices
Section titled “Tokens & prices”Holdings & ledger
Section titled “Holdings & ledger”Vaults & groups
Section titled “Vaults & groups”Portfolio rollup
Section titled “Portfolio rollup”Async jobs & cloud
Section titled “Async jobs & cloud”Foreign-key semantics
Section titled “Foreign-key semantics”The schema uses three ON DELETE behaviours deliberately:
Append-only tables
Section titled “Append-only tables”These are never updated, never deleted in normal operation:
holding_transactions(one documented exception: the synthesisedopening_balancerow, updated in place by the reconciliation flow — at most one per holding per cycle).holding_balance_observations.token_price_edit_history.admin_audit_log.cloud_usage_events.
See Why an append-only ledger.
Drizzle types are inferred
Section titled “Drizzle types are inferred”Every table file exports its row type via Drizzle’s inference:
export type Holding = typeof holdings.$inferSelect;export type NewHolding = typeof holdings.$inferInsert;These are the types you reach for in services and repositories. The codebase deliberately never hand-writes a row interface.
Where to look in code
Section titled “Where to look in code”packages/infra/db/src/schema/— all schema files + theindex.tsbarrel.packages/infra/db/src/migrations/— generated and hand-written SQL.packages/infra/db/src/migrate.ts— the runner.packages/infra/db/src/connection.ts— postgres.js client setup.packages/infra/db/src/BaseRepository.ts— shared repository helpers.