Event-sourced ledger

A fintech needs an audit-grade ledger. Regulators can demand the exact balance of any account at any historical timestamp. A normal relational table does not remember what it used to be. Event sourcing does.

The idea is simple. Never update records. Only append events: AccountCreated, MoneyDeposited, MoneyWithdrawn, MoneyTransferred. The current balance is a function of all the events so far. To get a historical balance, replay events up to that timestamp. To undo a bad deploy, reverse the bad events without data loss.

Events plus projections

Events are the source of truth. Projections are rebuilt on demand.

ledger.ts
typescript
type Event =
  | { type: 'Deposited'; accountId: number; amount: number; at: Date }
  | { type: 'Withdrew'; accountId: number; amount: number; at: Date };

async function balanceAt(accountId: number, at: Date): Promise<number> {
  const events = await db.events.find({
    accountId,
    at: { $lte: at },
  });
  return events.reduce((sum, e) => {
    if (e.type === 'Deposited') return sum + e.amount;
    if (e.type === 'Withdrew')  return sum - e.amount;
    return sum;
  }, 0);
}

Append events. Compute balance by folding the log.

Quiz: Quiz

Loading practice…