Every fintech prototype starts with a balance column. It is the obvious thing to do, it takes ten minutes, and it is correct right up until the first refund.
Why the single column fails
A mutable balance has no history. When it is wrong, you cannot tell when it became wrong, and you cannot tell which of the six code paths that write to it was responsible. You can only see the current, incorrect number.
It also has no atomicity across accounts. Moving money from A to B is two updates, and if the second fails you have destroyed value. You can wrap it in a transaction, and you should, but the model gives you no help — nothing about the schema tells you those two writes belong together.
What double-entry actually costs
Roughly a day. One table:
ledger_entries
id, transaction_id, account_id,
direction ('debit' | 'credit'),
amount_minor, currency, created_at
Plus one invariant, enforced in the database: for any transaction_id, debits must equal credits. Plus a rule you never break: entries are never updated or deleted. A mistake is corrected by writing a reversing entry, which means the mistake is still visible.
Balance becomes SUM(credits) - SUM(debits) for an account. If that query gets slow, you add a materialised snapshot with a periodic rebuild — but you add it as a cache, not as the truth.
The migration you avoid
Retrofitting this later means backfilling every historical transaction from whatever records still exist, running both models in parallel long enough to trust the new one, and discovering along the way that some of your history cannot be reconstructed at all. We have done that migration. It is not hard so much as it is long, and it is done under the pressure of knowing production numbers are currently wrong.
A day now, or six weeks later with an auditor waiting. That is the whole trade.
The one exception
If you are genuinely never going to hold, move, or owe money — if the numbers are display-only and sourced from somewhere else that already has a ledger — skip it. A read-only dashboard does not need double-entry. Almost everything else does.