Все проекты

Платёжное ядро

Независимое от фреймворка TS-ядро платежей для банков Литвы — защищённые webhook и суммы.

TypeScriptBank integrationsCrypto
01

Задача

Логику оплаты переписывали под каждый продукт и путали с его фреймворком и базой — именно там и прячутся платёжные баги.

02

Что делали

Чистое TypeScript-ядро с доменными правилами оплаты без импортов фреймворка или БД; каждый литовский банк или PSP это тонкий провайдер-адаптер, а ядро усилено там, где деньги реально ломаются: проверки подписи и свежести webhook, защита от переполнения суммы и лишних знаков, валидация redirect-целей и потоки ручной проверки, когда ссылка или сумма из callback не совпадают.

03

Результат

Новый продукт подключает оплату, дописывая адаптеры вокруг одного протестированного, проверенного на безопасность ядра, а не реализуя банковские потоки и состояния ошибок заново.

Dev-story статья

Платёжное ядро: как создавался проект

Возврат из банка через редирект браузера означает лишь то, что пользователь вернулся на сайт — но не то, что деньги ушли, и всё же множество интеграций помечают заказ оплаченным именно по этому сигналу. Это ядро построено на обратном допущении: редирект ничего не доказывает, а единственное надёжное состояние приходит из подписанного колбэка или серверной перепроверки статуса. Всё время напряжение создавало то, что каждый банковский протокол, карточный агрегатор и API кошелька подписывают, кодируют и сообщают суммы по-разному, поэтому укрепление должно было быть общей логикой, а не копипастом под каждого провайдера.

Разделы

05

Модули

05

Стек

TypeScript + Bank integrations

01

Почему появился проект

Логику оплаты переписывали под каждый продукт и путали с его фреймворком и базой — именно там и прячутся платёжные баги.

Возврат из банка через редирект браузера означает лишь то, что пользователь вернулся на сайт — но не то, что деньги ушли, и всё же множество интеграций помечают заказ оплаченным именно по этому сигналу. Это ядро построено на обратном допущении: редирект ничего не доказывает, а единственное надёжное состояние приходит из подписанного колбэка или серверной перепроверки статуса. Всё время напряжение создавало то, что каждый банковский протокол, карточный агрегатор и API кошелька подписывают, кодируют и сообщают суммы по-разному, поэтому укрепление должно было быть общей логикой, а не копипастом под каждого провайдера.

02

Что было создано

Чистое TypeScript-ядро с доменными правилами оплаты без импортов фреймворка или БД; каждый литовский банк или PSP это тонкий провайдер-адаптер, а ядро усилено там, где деньги реально ломаются: проверки подписи и свежести webhook, защита от переполнения суммы и лишних знаков, валидация redirect-целей и потоки ручной проверки, когда ссылка или сумма из callback не совпадают.

Это пакет на TypeScript, содержащий только правила платёжной предметной области — подпись запросов, валидацию колбэков, нормализацию статусов, проверки суммы и валюты, обработку повторных колбэков и безопасные для аудита нормализованные события. Ядро не импортирует никакого фреймворка, HTTP-рантайма или клиента базы данных: оно принимает простую структуру PaymentHttpRequest, так что один и тот же код провайдеров работает из нашего реактивного бэкенда, Node-воркеров или тестов. Реализовано несколько реальных литовских банков и провайдеров; банки без официальных мерчант-материалов поставляются как строгие скелеты, которые бросают ошибку, а не гадают.

03

Основные модули и путь пользователя

M01

Проверка подписанных колбэков и вебхуков по каждому протоколу (RSA-SHA512/SHA1/SHA256, отсоединённый JWS, hex HMAC-SHA256) по точным сырым байтам запроса, а возвратные редиректы моделируются как provesPayment:false, чтобы поддельный URL успеха никогда не мог завершить заказ

M02

Защита от повтора через опциональные окна свежести: недатированные колбэки или те, чья метка времени/JWS iat выходит за допуск, отклоняются как недоверенные; по умолчанию выключено, чтобы законно запоздавшие колбэки всё же доходили

M03

Денежные проверки как общие хелперы: decimalAmountToCents, возвращающий undefined за пределами Number.MAX_SAFE_INTEGER, и отклонение сумм с более чем двумя знаками после запятой вместо тихого округления 12.999 до 1300 центов

M04

Маршрутизация на ручную проверку при расхождении: когда ссылка, сумма или валюта вебхука не совпадают с авторитетным заказом, полученным с сервера, событие уходит в requires_manual_review как сигнал вмешательства, а не слепо доверяет одной из сторон

M05

Независимое от фреймворка ядро плюс тонкие адаптеры, со строгими скелетами провайдеров, которые бросают явные ошибки «требуется реализация», пока не появятся реальные эндпоинты, поля, подписи и сертификаты

04

Архитектура и технологические решения

Сделано на TypeScript, Bank integrations, Crypto.

Чистый TypeScript с подключаемыми адаптерами Web Crypto и Node crypto, без импортов фреймворка в точке входа ядра, и CI-гейт, удерживающий 100% покрытие по операторам, ветвям, функциям и строкам в рантайм-коде.

05

Результат и выводы

Новый продукт подключает оплату, дописывая адаптеры вокруг одного протестированного, проверенного на безопасность ядра, а не реализуя банковские потоки и состояния ошибок заново.

Один и тот же код провайдеров работает без изменений на разных бэкендах и в тестах, а каждый путь, завершающий платёж, ломается безопасно — переполненная сумма, повторный колбэк или несовпадающая ссылка выдают отсутствие платежа или флаг проверки, а не неверный результат.

Читать дальше

Эти проекты близки по техническим или продуктовым решениям и показывают, как тот же принцип работает в другом контексте.

Есть похожая идея?

Обсудить проект