Rebuilding a payments ledger no one wants to touch
How we take a brittle, mutate-in-place ledger and turn it into an append-only event log behind a type-safe Go service, migrated against live traffic, with no big-bang cutover.
- Every balance derived from an immutable event log
- A type-safe contract no other service can write a bad entry through
- A live migration with no big-bang cutover
A representative example: the kind of problem we solve and how we approach it, not a specific client engagement.
The problem
A payments ledger almost always starts the same innocent way: one table, updated in place, with a little reconciliation logic spread across a few services. It works, right up until it doesn't. Month-end close turns into a manual, nervous ritual, and a slow drip of reconciliation mismatches starts wearing down the trust of the banking partner you can least afford to lose it with.
How we approach it
We make an append-only event log the source of truth, and rebuild the balance table as a projection off it. History is never overwritten, and any balance can be recomputed and audited down to the entry that moved it. The ledger service is Go behind a Protobuf-defined API, so every other service gets a type-safe client and could not write a malformed entry if it tried.
The migration runs in the background, against live traffic. The new system shadows the old one, the two are compared continuously, and the cutover is a single config flag, flipped only after the ledgers have agreed to the cent for weeks. No big-bang, no maintenance window, no held breath.
Why it holds up
Once every balance is derived from an immutable log, reconciliation stops being a recurring fire and month-end close becomes a report that simply runs. And when something does look off, the event history shows exactly what happened, in order, so you are debugging facts instead of arguing about guesses.
Working on something like this?