July 28, 2026 · Architecture · Data
What a financial ledger API actually needs: auditability over cleverness
Debt and credit tracking looks like a simple CRUD problem until someone asks "why does this balance say what it says." That question is the whole design spec.
05 From building UMSA debt-tracking system — replacing the notebook-and-memory approach most informal credit runs on — looks, on paper, like a CRUD app: create a transaction, update a balance. The part that actually matters isn't the happy path, it's what happens when someone (rightly) asks why a balance is what it is, six months later.
That question is the real design constraint on a financial ledger, and it changes how you'd normally build a REST API for something that otherwise looks simple.
What the requirement actually implies
- Never overwrite a balance directly — a balance is a derived value, computed from the full transaction history, not a field you mutate
- Every transaction is append-only and immutable once written; a correction is a new, linked transaction, not an edit to the old one
- Store enough context on each transaction (who, when, why, from what state) that the history alone answers an audit question without needing a person's memory
- Design the API around transactions as the primary resource, not balances — the balance endpoint is a read model built from the transaction log, not the source of truth
Why this isn't over-engineering
It's tempting to treat append-only, immutable records as premature rigor for something that starts as a small internal tool. But the failure mode of the simpler version — a mutable balance field, updated in place — is silent and only shows up the first time two people disagree about a number and there's no record of how it got there. By then, retrofitting an audit trail onto history that was never captured is not possible; the information is just gone.
The REST layer built from scratch on UMS followed exactly this shape: transactions in, durable and auditable records out, with the balance always a computed view rather than a stored fact. It's more work than the naive version on day one, and it's the only version that survives someone asking a hard question about it later.