Client type
Regional insurance startup
Markets
Ghana · Nigeria
Engagement
Long-term product engineering
Status
In production · Live traffic
Java 21
Spring Boot 3.4
JHipster
PostgreSQL
Liquibase
React 18
TypeScript
The problem
The client operated an insurance business in Ghana and needed to expand into Nigeria — a fundamentally different regulatory environment, currency, and integration landscape. Their existing core system had been built for a single market and couldn't cleanly separate tenant-level configuration from shared business logic.
The specific technical problem was that motor and non-motor policy issuance depended on hard-coded assumptions about the Ghanaian regulator's data model, the local KYC providers, and the payment rails. Copying the platform for Nigeria would have doubled the maintenance burden overnight and created two divergent codebases within twelve months.
Rebuild the platform on a multi-tenant architecture that could serve Ghana and Nigeria from one core — without breaking any of the live Ghanaian traffic, and without a rewrite that would freeze feature delivery for six months.
The approach
We came in as the lead engineering team on the migration and rebuild. The approach had three components:
1. Tenant model refactor, in-place
Rather than a big-bang rewrite, we refactored the existing codebase in-place to introduce a tenant abstraction. Every table got a tenant discriminator column via Liquibase migrations that ran zero-downtime against live Ghanaian data. Every service query got a tenant-scoped filter, enforced at the repository layer rather than sprinkled throughout the business logic.
2. Insurer-integration layer rewrite
The direct-to-insurer integrations (motor pricing, policy issuance, claim settlement) had been coded against specific Ghanaian insurers' APIs. We rewrote this layer as a pluggable adapter pattern — each insurer became a self-contained adapter implementing a common interface, with retry, circuit-breaker, and observability built into the base class. Adding a Nigerian insurer became a matter of writing one new adapter, not modifying the pricing engine.
3. Renewals subsystem — the hardest piece
Renewals were the subsystem where the two markets diverged the most. Ghanaian regulations require specific notice periods and formats; Nigerian regulations require different ones. Rather than fork the code, we rewrote renewals as a state machine driven by tenant-configured rules. The state machine handles both markets' regulations from one codebase, and adding a third market means adding rows to a rules table — not writing code.
What shipped
- Multi-tenant core, live in production across two markets on a single deployment
- Pluggable insurer-integration layer with adapters for both markets' primary insurers
- Rewritten renewals subsystem, now handling both regulatory regimes without code changes
- Zero downtime for Ghanaian users throughout the migration
- Nigerian launch completed on the target date
What made the release own-able
The reason this worked wasn't the specific architectural choices — plenty of firms could have made the same calls. It was that one person owned the release end-to-end: the merge queue, the CI pipeline, the migration rollouts against live data, the coordination with the local Ghanaian insurance regulator's technical team, the go/no-go call on the Nigerian launch date.
Multi-market platform migrations don't fail because of tech choices. They fail because nobody is explicitly on the hook for the release. Polymit is on the hook for every release we ship.
Stack details
- Backend: Java 21, Spring Boot 3.4, JHipster scaffolding, Liquibase migrations, Hibernate ORM
- Database: PostgreSQL with tenant-scoped row-level security
- Frontend: React 18, TypeScript, Vite, custom design system
- Infrastructure: AWS ECS + RDS, GitHub Actions CI/CD, blue-green deployment
- Observability: structured logging, Prometheus metrics, distributed tracing
Have a similar problem?
If your team is planning a multi-market expansion, or trying to introduce multi-tenancy into a single-tenant codebase without a rewrite, we've been there. Talk to us.
Talk to us →