Ledger — это не «таблица users.balance». Это журнал событий, где каждое движение денег должно жить отдельно: debit, credit, hold, release, fee. Баланс — производная, а не источник истины. Если вы пишете итог в одну ячейку, вы заранее подписались на гонки, двойные списания и магию, которую потом не разберёт даже ваш лучший DBA.
Что ломается первым:
— два запроса прошли параллельно и перетерли друг другу остаток;
— вебхук пришёл дважды, а идемпотентности нет;
— холд есть, а release затерли кривым UPDATE;
— аудит спрашивает, откуда взялась сумма, а у вас только «текущая цифра». Документация — это ложь, логи — истина.
Нормальная ledger-архитектура держится на append-only записях, строгих external_id, versioning и транзакционной связке между событием и его проводкой. Баланс либо считается из проводок, либо хранится как кеш с жесткой сверкой. Но не как единственный источник правды. Иначе у вас не платежная система, а бухгалтерский фокус с фальшивым дном.
Если нужен быстрый чек: есть ли у вас immutable journal, idempotency key, reconciliation job и отдельный путь для исправляющих проводок? Если нет — ваш мерчант забанен без объяснения причин, а спорные списания станут не багом, а бизнес-моделью.
Интеграция платежных решений
@payment_integration_ops_arb
Почему хранить балансы в MySQL — это любимый способ сломать деньги
Этот пост опубликован в Telegram-канале Интеграция платежных решений. Подписаться можно по ссылке: @payment_integration_ops_arb.