Modernizing a High-Volume Financial Transaction Platform
Strangler-fig migration behind an API façade, with exactly-once posting guarantees.
1 Context & Problem
A high-volume financial transaction platform at a global bank had accumulated years of change inside a tightly coupled core. Posting logic, business rules and integration code had grown together, so every change carried blast radius across the whole platform, and the pace of safe delivery had slowed to a crawl.
In practice this was a retail and wholesale posting / settlement path that had lived for well over a decade on a Java monolith with synchronous fan-out to downstream consumers. The programme was triggered by a combination of rising operational-incident cost (duplicate posting and timeout retries) and a cloud / platform mandate that made a big-bang rewrite politically and operationally untenable.
The brief was not "rewrite it". Money movement cannot pause for a re-platforming programme, and a big-bang cut-over on a transaction system is an unacceptable risk. The problem was how to move the platform to a modern, independently deployable architecture while it stayed continuously in service, with the ability to reverse any step if a cut-over misbehaved.
A second, sharper problem sat underneath: duplicate postings. Retries, timeouts and at-least-once delivery between systems meant the platform could post the same financial transaction more than once. In a ledger, that is not a glitch — it is a correctness failure with a manual remediation cost attached to every occurrence. Before the change, duplicate-posting incidents were a recurring ops class rather than a rare edge case.
2 Scale & Constraints
The constraints, not the technology menu, drove every decision that follows. Figures below are industry-typical for mid-to-large bank posting platforms of this class (neobank / regional-bank core ranges sit far below Visa-scale peaks of 8k–20k+ TPS). Exact client volumes are withheld under engagement confidentiality.
The non-negotiable constraints were:
- Zero downtime. The platform had to remain continuously available throughout migration. No maintenance window was available for cut-over.
- Every cut-over reversible. Any migrated slice had to be revertible to the legacy path quickly, without data reconciliation drama.
- Exactly-once financial effect. At-least-once transport is a given in distributed systems; the business outcome still had to happen exactly once.
- Regulated-environment controls. Data classification, field-level masking, and four-eyes / segregation-of-duties approvals applied to privileged actions and to what operators could see.
- Hybrid cloud footprint. Workloads spanned on-premise and cloud, so the design could not assume a single network or a single control plane.
3 Architecture Decisions & Tradeoffs
Four decisions carried the programme. Each one bought something specific and cost something specific; the cost is stated because that is what makes a decision reviewable.
Put a façade in front of the legacy core and route traffic through it, then move capability out slice by slice. Consumers keep calling one stable contract while the implementation behind it changes.
A parallel-run rewrite with a single big-bang cut-over weekend, or replacing the core with a packaged vendor payments suite. Both were evaluated and rejected: a parallel rewrite doubles cost without reducing cut-over risk, and a vendor package would have forced a multi-year product-fit programme on top of the migration itself.
It makes migration incremental and, critically, reversible. Each slice is a small bet with a defined rollback, so the programme never depends on one high-stakes weekend.
You run two systems at once for an extended period. That means duplicated operational surface, routing logic that is itself a component to test and monitor, and the discipline to actually finish — strangler migrations that stall leave you permanently worse off than when you started.
Give every posting request a business-meaningful idempotency key, deduplicate on it at the application layer, and write the state change and the outbound event in a single local transaction via an outbox table, relayed to Kafka afterwards.
Relying on broker-level "exactly-once" semantics or on distributed (XA) transactions spanning the database and the message broker.
Broker exactly-once guarantees do not extend across a database write and an external publish; the dual-write problem stays. The outbox collapses the two writes into one atomic local commit, and idempotency keys make retries safe by construction rather than by hope. Together they eliminated duplicate posting as a class of defect.
Extra write amplification and an outbox relay to operate and monitor; events are eventually rather than instantly published; and deduplication state has to be retained long enough to cover the realistic retry window, which is a storage and housekeeping commitment.
Extracted services publish domain events to Kafka; downstream consumers (reconciliation, dashboards, audit) subscribe rather than calling back synchronously into the posting path.
Synchronous REST fan-out from the transaction path to every interested consumer.
It keeps the money-movement path short and independent of consumer availability. A reporting consumer being slow or down must never be able to fail a financial transaction, and a log-structured broker gives replay for recovery and for onboarding new consumers.
Consumers see eventual consistency and must be idempotent themselves. Event schemas become long-lived public contracts requiring versioning discipline, and debugging shifts from a single stack trace to correlated traces across hops.
RBAC on privileged operations, mTLS for service-to-service traffic, envelope encryption for sensitive data, and immutable WORM audit logs. Operator-facing React and Angular dashboards were delivered under data-classification, field masking and four-eyes / segregation-of-duties controls.
Perimeter-only trust, with internal service calls treated as implicitly safe and audit added late for compliance sign-off.
Decomposing a monolith multiplies the number of network hops and the number of places privileged data can surface. In a regulated environment the audit trail is part of the product, and retrofitting immutability is far more expensive than designing for it.
Certificate lifecycle and key rotation become standing operational work, mTLS adds handshake overhead, four-eyes approval deliberately slows some operator actions, and WORM storage grows monotonically and must be budgeted.
Publish every domain mutation as a fine-grained event immediately after the local commit, hoping consumers would reconstruct the business view themselves.
Coarser, business-meaningful events with explicit versioned schemas, and a short aggregation window in the relay so consumers are not flooded by intermediate states that never mattered to them.
The first design looked elegant on a whiteboard and produced noisy topics, brittle consumer logic and harder replay. Staff-level work includes killing a design you are attached to when production evidence disagrees.
Slightly higher latency to first publish, and the need to document which intermediate states are intentionally never emitted.
4 Architecture Diagram
© sanjeevk.net — All rights reserved
5 Outcome & Results
Beyond the numbers, the durable outcome was structural. Duplicate posting stopped being an incident category and became an invariant enforced by the design. Reversible cut-overs meant migration risk was priced per slice instead of concentrated in one event. And the patterns established here — idempotency keys, the outbox, versioned API contracts — were packaged as reusable libraries and reference patterns that other squads adopted as the path of least resistance.
Delivered as Technical Architect at Wipro. Client-identifying detail and proprietary design artefacts are deliberately withheld. The ~35% incident reduction and zero-downtime migration are from the engagement record; throughput, latency budgets and the deployment-frequency / latency lifts are industry-typical for platforms of this class and are labelled as such above.
Want the deeper version?
I am happy to walk through the migration sequencing, the failure modes we designed against, and the parts that did not go to plan.