Как мы разрабатываем финтех-платформы и платёжные системы

Почему финтех — это отдельная инженерная дисциплина
Разработка платёжной системы или финтех-платформы только внешне похожа на создание обычного веб-приложения. Под капотом действуют другие правила. Если в маркетинговом сайте баг приводит к кривой вёрстке, то в финтехе ошибка в одной строке кода может означать двойное списание, потерянную транзакцию или расхождение в балансе на миллионы. И это уже не вопрос репутации в стиле «извините, поправим» — это прямые финансовые потери клиента, претензии регулятора и подорванное доверие пользователей, которое в деньгах не восстанавливается.
Поэтому в OneDev мы относимся к финтех-проектам как к отдельной инженерной дисциплине. Здесь нельзя «сначала запустить, потом допилить»: фундаментальные решения — модель учёта денег, обработка ошибок, безопасность, аудит — должны быть заложены правильно с первого дня. Переписать архитектуру платёжного ядра на работающей системе, через которую уже идут реальные деньги, в разы дороже и опаснее, чем спроектировать её верно сразу.
Деньги нельзя хранить как обычные данные
Первое, что отличает зрелую платёжную систему от наспех собранной, — это то, как в ней представлены деньги и операции. Начинающие команды часто хранят баланс пользователя как одно изменяемое число в таблице: пришёл платёж — прибавили, ушёл — отняли. Это путь к катастрофе. При любом сбое, гонке запросов или повторной обработке вы получаете баланс, который невозможно объяснить и невозможно восстановить.
Мы строим учёт на принципах двойной записи (double-entry ledger), как в настоящей бухгалтерии. Каждая операция — это не изменение числа, а неизменяемая запись о движении средств между счетами. Баланс не хранится как факт, а выводится как сумма проводок. Это даёт ключевое свойство: в любой момент можно доказать, откуда взялась каждая копейка.
- Только целые числа. Деньги храним в минимальных единицах (тийины, копейки) как целые числа. Тип
floatдля денег недопустим — округление двоичной дроби рано или поздно даст расхождение. - Неизменяемость операций. Проводку нельзя отредактировать или удалить — только создать компенсирующую (сторно). История остаётся полной и аудируемой.
- Явные статусы. Транзакция проходит через чёткий жизненный цикл: создана, в обработке, подтверждена, отклонена, возвращена. Никаких «зависших» промежуточных состояний без определённого исхода.
Идемпотентность и борьба с двойными списаниями
Главный технический враг любой платёжной системы — ненадёжная сеть. Пользователь нажал «Оплатить», запрос ушёл, а ответ не вернулся: соединение оборвалось, приложение зависло, мобильный интернет моргнул. Деньги списались или нет? Никто не знает. Пользователь нажимает ещё раз — и вот вам потенциальное двойное списание.
Решение — идемпотентность. Каждая платёжная операция получает уникальный ключ, и сервер гарантирует: сколько бы раз ни пришёл запрос с одним и тем же ключом, деньги спишутся ровно один раз, а в ответ вернётся один и тот же результат. Это касается и взаимодействия с внешними платёжными провайдерами, и приёма вебхуков от них: один и тот же вебхук может прийти несколько раз, и система обязана обработать его единожды.
Интеграция с местными платёжными системами Узбекистана
В контексте Узбекистана финтех-проект почти всегда означает интеграцию с локальной платёжной инфраструктурой: Payme, Click, Uzum, эквайринг банков, а для части сценариев — взаимодействие с системами вроде HUMO и UZCARD. У каждого провайдера свой протокол, своя модель статусов, свои правила подтверждения и отмены платежа, свои форматы вебхуков и свои требования к таймаутам.
Мы изолируем каждую такую интеграцию за внутренним слоем-абстракцией. Бизнес-логика приложения не должна знать, через какого провайдера прошёл платёж — она работает с единой моделью «платёж». Это даёт два практических преимущества: можно добавить нового провайдера, не переписывая ядро, и можно безопасно тестировать интеграции на песочницах, не задевая боевые деньги.
Отдельно отметим работу с протоколами Payme и Click: они построены на сценарии, где провайдер сам опрашивает ваш сервер (check, create, perform, cancel). Это значит, что ваша система должна корректно отвечать на эти запросы в строго определённом порядке состояний — и здесь любое отклонение от спецификации приводит к зависшим или несведённым платежам.
Безопасность, соответствие требованиям и защита данных
Финтех — это зона повышенного внимания и злоумышленников, и регуляторов. Безопасность здесь не функция, которую можно добавить в конце, а сквозное свойство всей системы.
- Не храним то, что не обязаны. Полные данные карт (PAN, CVV) не должны попадать на ваши серверы — для этого существуют токенизация и платёжные шлюзы. Чем меньше чувствительных данных вы храните, тем меньше поверхность атаки и нагрузка по требованиям PCI DSS.
- Разделение прав и ролей. Доступ к платёжным операциям и финансовым отчётам должен быть строго разграничен. Любое действие, меняющее деньги, фиксируется в аудит-логе с указанием, кто, когда и что сделал.
- Шифрование и защита каналов. Чувствительные данные шифруются и в покое, и при передаче; вебхуки от провайдеров проверяются по подписи, а не принимаются на доверии к источнику.
- Соответствие локальному законодательству. Хранение персональных данных граждан Узбекистана регулируется требованиями локализации, и это нужно учитывать при выборе размещения инфраструктуры ещё на этапе проектирования.
Сверка, аудит и наблюдаемость
Даже идеально написанная система живёт в неидеальном мире: провайдер может задержать вебхук, банк — провести возврат вне вашего интерфейса, сеть — потерять ответ. Поэтому в финтехе обязателен механизм автоматической сверки (reconciliation): система регулярно сравнивает свой внутренний реестр операций с данными платёжных провайдеров и выявляет расхождения до того, как их заметит пользователь или бухгалтер.
Сюда же относится наблюдаемость. Мы закладываем подробное логирование платёжных потоков, метрики по доле успешных и отклонённых операций, алерты на аномалии — например, на всплеск отказов конкретного провайдера или на «зависшие» в обработке транзакции. В платёжной системе вы не можете позволить себе узнавать о проблеме из жалоб клиентов — она должна быть видна на мониторинге раньше.
Сравнение подходов к учёту средств:
- Изменяемый баланс одним числом. Просто и быстро на старте. Но: невозможно восстановить историю, баланс «уплывает» при сбоях и гонках, аудит и сверка практически невозможны. Не подходит для реальных денег.
- Двойная запись с неизменяемым реестром. Сложнее в реализации, требует продуманной модели данных. Зато: любая операция доказуема, баланс всегда выводим и проверяем, сверка с провайдерами и аудит — штатная процедура. Единственно приемлемый вариант для финтеха.
Как мы ведём финтех-проект в OneDev
Мы начинаем не с кода, а с проектирования денежных потоков: какие сущности участвуют, какие операции возможны, какие статусы и переходы допустимы, что происходит при каждом виде сбоя. На этом этапе мы вместе с заказчиком проговариваем сценарии возвратов, частичных оплат, отмен и спорных ситуаций — потому что именно они, а не «счастливый путь», определяют сложность системы.
Дальше мы строим платёжное ядро с двойной записью и идемпотентностью, изолируем интеграции с местными провайдерами, закрываем безопасность и с самого начала закладываем сверку и мониторинг. Тестируем не только нормальные сценарии, но и обрывы связи, повторные вебхуки, частичные сбои — то, что в проде случается обязательно. Такой подход стоит дороже наивной реализации на старте, но он избавляет бизнес от куда более дорогих инцидентов с реальными деньгами в будущем.
Вывод
Финтех не прощает срезанных углов: модель учёта денег, идемпотентность, безопасность, сверка и аудит — это не опции, а фундамент, который нужно заложить правильно с первого дня. Правильно спроектированная платёжная система не только защищает деньги пользователей, но и даёт бизнесу спокойствие: каждую копейку можно объяснить, каждую операцию — доказать. Если вы планируете платёжный сервис, кошелёк, маркетплейс с расчётами или интеграцию с Payme, Click и Uzum — расскажите нам о задаче. Команда OneDev поможет спроектировать архитектуру так, чтобы вам не пришлось переписывать её под давлением первого же серьёзного инцидента.
С чего начать разработку платёжной системы?
Можно ли хранить данные банковских карт у себя на сервере?
Что такое идемпотентность и зачем она в платежах?
С какими платёжными системами вы интегрируетесь в Узбекистане?
Почему нельзя хранить деньги в виде дробного числа?
Зачем нужна автоматическая сверка, если система работает корректно?
Нужна похожая система или хотите обсудить проект?
Опишите задачу — предложим архитектуру, технический подход и план работ. Часто для старта достаточно короткого звонка.
Обсудить проект