Files
dbis_core/db/migrations

Database Migrations

This directory contains SQL migrations that enforce ledger correctness boundaries.

Migration Order

Run migrations in this order:

  1. 001_ledger_idempotency.sql - Add unique constraint for idempotency
  2. 002_dual_ledger_outbox.sql - Create outbox table
  3. 003_outbox_state_machine.sql - Enforce state machine constraints
  4. 004_balance_constraints.sql - Enforce balance integrity (apply after data cleanup)
  5. 005_post_ledger_entry.sql - Create atomic posting function
  6. 006_sal_positions_fees.sql - SAL extension: positions (asset x chain), fees, reconciliation snapshots

Running Migrations

Option 1: Direct SQL execution

# Set your database connection
export DATABASE_URL="postgresql://user:password@host:port/database"

# Run migrations in order
psql $DATABASE_URL -f db/migrations/001_ledger_idempotency.sql
psql $DATABASE_URL -f db/migrations/002_dual_ledger_outbox.sql
psql $DATABASE_URL -f db/migrations/003_outbox_state_machine.sql
psql $DATABASE_URL -f db/migrations/004_balance_constraints.sql
psql $DATABASE_URL -f db/migrations/005_post_ledger_entry.sql
psql $DATABASE_URL -f db/migrations/006_sal_positions_fees.sql

Option 2: Prisma migrate (if using Prisma migrations)

These SQL files can be added to a Prisma migration:

npx prisma migrate dev --name add_ledger_correctness_boundaries

Then copy the SQL into the generated migration file.

Important Notes

Column Naming

These migrations assume snake_case column names in the database (Prisma default).

If your database uses camelCase, adjust the SQL accordingly:

  • ledger_idledgerId
  • debit_account_iddebitAccountId
  • etc.

Balance Constraints

The balance constraints in 004_balance_constraints.sql will fail if you have existing inconsistent data.

Before applying:

  1. Audit existing balances
  2. Fix any inconsistencies
  3. Then apply the constraints

Testing

After applying migrations, verify:

-- Check idempotency constraint exists
SELECT constraint_name 
FROM information_schema.table_constraints 
WHERE table_name = 'ledger_entries' 
  AND constraint_name LIKE '%reference%';

-- Check outbox table exists
SELECT COUNT(*) FROM dual_ledger_outbox;

-- Test posting function
SELECT * FROM post_ledger_entry(
  'Test'::TEXT,
  'account1'::TEXT,
  'account2'::TEXT,
  100::NUMERIC,
  'USD'::TEXT,
  'fiat'::TEXT,
  'Type_A'::TEXT,
  'test-ref-123'::TEXT,
  NULL::NUMERIC,
  NULL::JSONB
);

Rollback

These migrations are designed to be additive. To rollback:

  1. Drop the function: DROP FUNCTION IF EXISTS post_ledger_entry(...);
  2. Drop the outbox table: DROP TABLE IF EXISTS dual_ledger_outbox CASCADE;
  3. Remove constraints: ALTER TABLE ledger_entries DROP CONSTRAINT IF EXISTS ledger_entries_unique_ledger_reference;
  4. Remove balance constraints: ALTER TABLE bank_accounts DROP CONSTRAINT IF EXISTS ...;