Источник
System Design Interview
Классический подход к payment architecture: orchestration, ledger и интеграция с PSP.
Payment System - это не просто API для списания денег. Это распределённая система, где критичны корректность состояний, идемпотентность, устойчивость к частичным сбоям и безопасность обработки чувствительных данных. Базовый принцип: exactly-once на практике заменяется at-least-once + idempotency + reconciliation.
Требования
Функциональные
- Создание payment intent для заказа (authorization/capture flow).
- Поддержка карт и альтернативных платёжных методов через PSP.
- Идемпотентные операции списания и возврата (refund/partial refund).
- Webhooks от PSP для статусов: authorized, captured, failed, chargeback.
- История платежей и прозрачный audit trail для support/finance.
Нефункциональные
Доступность: 99.99%
Платежи - критичный revenue path, простои напрямую бьют по бизнесу.
Латентность: p95 < 300ms
Checkout должен оставаться отзывчивым и предсказуемым для пользователя.
Корректность: No double charge
Система не должна дважды списывать при retry и сетевых сбоях.
Безопасность: PCI DSS scope control
Минимизируем обработку card data внутри платформы.
High-Level Architecture
Payment Platform: High-Level Map
sync checkout path + async settlement/reconcile pathSync Plane
Async Plane
Платежная платформа разделена на синхронный checkout-контур и асинхронный settlement/reconcile контур.
Ключевой паттерн — разделение синхронного checkout path и асинхронного settle/reconcile path. Это повышает устойчивость, снижает latency для пользователя и делает финансовые статусы проверяемыми.
Critical Flows
Payment Flow Explorer
Сценарии в формате read/write-style explorer: sync checkout и async settlement.
Sync payment path: operational notes
- Payment API создаёт intent и фиксирует idempotency key для безопасных retry.
- Orchestrator управляет переходами INITIATED -> AUTHORIZED -> CAPTURED.
- PSP adapter изолирует provider-specific логику от core домена.
- Синхронный ответ checkout не ждёт полного settle/reconcile цикла.
- Промежуточные статусы записываются в payment db для recoverability.
Async settle/reconcile path: operational notes
- Webhooks обрабатываются как at-least-once события с дедупликацией.
- Ledger/outbox фиксируют финансовые эффекты в immutable-проводках.
- Reconcile jobs сверяют внутренние статусы с отчетами PSP.
- Расхождения (missing capture/refund mismatch) идут в remediation queue.
- Finance и support получают события через outbox без прямой связи с PSP.
Data model (упрощённо)
payment_transactions
- payment_id (UUID), order_id, customer_id
- amount, currency, status, psp_reference
- idempotency_key, created_at, updated_at
ledger_entries
- entry_id, payment_id, account_id
- direction (debit/credit), amount, currency
- entry_type (auth/capture/refund/chargeback)
Надёжность и консистентность
Обязательные паттерны
- Idempotency key для всех mutating операций (authorize/capture/refund).
- Transactional outbox для публикации событий без потери и дублей.
- Retry с exponential backoff + jitter и circuit breaker на PSP вызовы.
- State machine со строгими переходами (INITIATED -> AUTHORIZED -> CAPTURED/FAILED/REFUNDED).
- Ежедневная reconciliation между внутренним ledger и отчётами PSP.
Опасные anti-patterns
- Считать webhook единственным источником истины без регулярной сверки.
- Не хранить idempotency key или делать его короткоживущим.
- Писать финстатус в одной таблице без immutable журнала изменений.
- Смешивать бизнес-логику checkout и gateway-specific код в одном модуле.
- Обрабатывать PAN/CVV в своей системе без строгой необходимости.
Security и compliance минимум
- Card data tokenization: PAN/CVV не должны попадать в ваш core сервис.
- mTLS/service identity между внутренними сервисами платежного контура.
- Строгий RBAC для операций refund/manual capture.
- Непрерывный audit trail для финансовых и операционных действий.
- Границы PCI DSS scope: чем меньше зона, тем ниже операционные риски.
Reference
Payment Intents
Практический пример stateful payment flow с authorization/capture.
