Payment Domain Model
Overview
This document defines the core domain entities, their relationships, value objects, and invariants that govern the v2 payment system. Every engineer modifying payment logic must understand these boundaries.
Entity-Relationship Diagram
Aggregate Root: Payment
The Payment entity is the aggregate root. All state transitions and business rule enforcement flow through it.
Invariants
| # | Invariant | Enforcement Point |
|---|---|---|
| 1 | SUM(allocation.amount) == payment.amount | Request validation (controller) |
| 2 | payment.allocations.length ∈ 2 | Request validation (controller) |
| 3 | Split-tender only allows CARD + CARD | Service layer |
| 4 | merchantTransactionId is unique per merchant | Repository layer (unique index) |
| 5 | Retry count ≤ 4 (5 total attempts) per merchantTransactionId | Service layer (idempotency check) |
| 6 | authorizeCard: true requires partialAuthorization: true | Request validation |
| 7 | partialAuthorization: true requires authorizeCard: true | Request validation |
| 8 | Only CARD allocations support authorizeCard | Service layer |
| 9 | BANK_ACCOUNT requires valid consent | Service layer |
| 10 | Capture amount ≤ authorized amount per allocation | Service layer |
Value Objects & Enums
PaymentStatus (Payment-level)
| Status | Terminal? | Description |
|---|---|---|
INITIATED | No | Payment created, processing not yet started |
PENDING | No | Payment request queued for processing |
PENDING_FOR_CUSTOMER_CREATION | No | Waiting for customer record resolution |
PENDING_FOR_PAYMENT_METHOD_CREATION | No | Waiting for payment method validation |
PROCESSING | No | Actively being processed with vendor |
PROCESSING_DEDUP_CHECK | No | Pay-and-save dedup check in progress |
AUTHORIZED | No | Pre-auth hold placed, awaiting capture |
ACCEPTED | No | ACH accepted by processor, awaiting settlement |
COMPLETED | Yes | Payment fully processed and settled |
FAILED | Yes | Payment permanently failed |
CANCELLED | Yes | Payment cancelled by merchant or system |
AllocationStatus
| Status | Terminal? | Description |
|---|---|---|
PENDING | No | Allocation queued |
AUTH_REQUIRED | No | 3DS challenge required |
CONFIRMATION_INITIALIZED | No | Confirmation in progress post-3DS |
AUTHORIZED | No | Funds held |
CAPTURE_INITIALIZED | No | Capture in progress |
ACCEPTED | No | ACH accepted |
CANCEL_INITIALIZED | No | Cancellation in progress |
CANCELED | Yes | Successfully cancelled |
ROLLED_BACK | Yes | System-initiated reversal (split-tender failure) |
COMPLETED | Yes | Successfully settled |
FAILED | Yes | Processing failed |
PaymentMethodType
CARD | BANK_ACCOUNT
PaymentCancellationReason
| Value | Description |
|---|---|
DUPLICATE | Duplicate payment detected |
FRAUDULENT | Suspected fraud |
REQUESTED_BY_CUSTOMER | Customer initiated cancellation |
ABANDONED | Customer did not complete (e.g., 3DS timeout) |
CCG_AUTOMATED_CANCEL | System-initiated (split-tender rollback, partial capture remainder) |
CurrencyCode
USD (only supported value)
Customer Identification Priority
When multiple identifiers are provided, the system resolves the customer in this order: