argent-checkout
A pure-Kotlin payment-checkout state machine (three MVI reducers) from a production fintech app — centralized type config, runtime SIP bank-switch resolution, zero Android/Compose deps.
KotlinMVIState Machine
High-level design
Three reducers (checkout, processing, status) drive every UPI flow as reduce(state, intent) -> Pair<state, effects>.
CheckoutStateMachine
UPI app/QR/collect selection, VPA validation, and runtime SIP bank-switch resolution
↓
ProcessingStateMachine
timer + progress, UPI-app launch/return lifecycle, poll-result handling
↓
StatusStateMachine
countdown → navigation, TPV sheet, SIP-creation overlay, analytics/meta events
Low-level design
Type-specific behavior lives in one CheckoutTypeConfigFactory; 9 unit tests; JVM module, Apache-2.0, CI.
- –A when(checkoutType) that was scattered across 50+ places collapses into a single config object the reducers only read, never branch on
- –For a SIP bank switch the reducer re-derives the flow from the selected bank's mandates — reuse only a valid, sufficient mandate, else create/upsize