~2~Engineering Details
~3~Staged migration and backward compatibility
~p~The migration was organized around business capabilities rather than a mechanical split of the original application. Teams rebuilt services for transaction history, savings products, customer offers, credit applications, authorization and other customer journeys. The new API entry layer selected the legacy or microservice destination according to the mobile client version. This mattered because not every customer updated the app at the same time, and old clients still needed to complete familiar transactions.
~3~Database and release engineering
~p~New services used PostgreSQL alongside existing Oracle-backed functionality. Liquibase managed schema changes, while type-safe SQL access helped developers work with new service data models. Container deployment on Kubernetes separated deployment and scaling decisions by service. Automated builds and tests covered multiple testing environments, and feature availability could be enabled for a small cohort before a full rollout.
~p~The team prepared realistic load profiles for banking operations, then investigated bottlenecks in service behavior and data access. This was essential for login, account history and other functions that cannot be paused for a platform migration.
~3~Implementation specifics
~p~The migration was organised around business domains: authentication, transactions, payments, deposits and customer offers moved into independent services while older client versions still used the monolith.
~p~NGINX routed requests between the legacy and modern environments. The implementation uses Kubernetes, GitLab CI/CD, Java 17, Spring Boot, PostgreSQL, Liquibase and Kafka.
~p~Feature flags enabled limited releases and rollback before functionality was enabled for all customers.
~2~The Outcome
~p~New banking functionality that previously took roughly four to five weeks to reach users could be released in one to two weeks. Teams gained independent deployment paths, controlled feature rollouts and the ability to route modern clients to new services while supporting older versions. A failure in one service no longer had to interrupt unrelated parts of the banking platform. Just as importantly, the bank could test and reverse a customer-facing change without redeploying the entire monolith.