Engineering
Reconciliation without a nightly batch
A nightly batch is a bet that nothing will go wrong overnight, and that if it does, someone will be awake. It is a bet worth getting out of.
Make the ledger the source of truth
The move that made everything else possible was giving up on mutable balances. Every event appends a row; the balance is a fold over those rows. Recomputing is cheap, replays are safe, and correcting a mistake becomes another append rather than an UPDATE nobody can audit.
export async function replay(accountId: string, upTo: Date) {
const events = await db.query.ledgerEvents.findMany({
where: (e, { and, eq, lte }) => and(eq(e.accountId, accountId), lte(e.occurredAt, upTo)),
orderBy: (e, { asc }) => [asc(e.sequence)],
})
// Folding is pure, so the same inputs always produce the same balance —
// which is what makes a replay safe to run in production.
return events.reduce(applyEvent, emptyBalance(accountId))
}Idempotency keys everywhere
Every write carries a key derived from the upstream event. Re-delivering a message is then a no-op rather than a double charge — which means the pipeline can be replayed from any point without a human deciding whether it is safe.
The month-end close stopped being a computation and became a read. It now takes about forty minutes, most of which is waiting on a third-party export.