Microservices Framework¶
| Field | Value |
|---|---|
| Status | Draft |
| Owner | Platform Engineering |
| Last Updated | 2026-04-03 |
| Applies To | All backend services |
1. Overview¶
Simpaisa processes 270M+ transactions annually across Pakistan, Bangladesh, Nepal, Iraq and Egypt. This document defines the microservices architecture that underpins all product lines — Pay-Ins, Pay-Outs, Remittances and Cards — ensuring consistent service design, communication patterns and operational readiness.
2. Service Decomposition¶
2.1 Product Services¶
| Service | Responsibility | Owner |
|---|---|---|
pay-in-svc |
Charge initiation, OTP validation, callback handling | Pay-In Squad |
pay-out-svc |
Disbursements, batch payouts, settlement reconciliation | Pay-Out Squad |
remit-svc |
Cross-border quotes, AML screening, corridor routing | Remit Squad |
cards-svc |
Authorisation, capture, void, refund, 3DS orchestration | Cards Squad |
2.2 Shared Services¶
| Service | Responsibility |
|---|---|
merchant-svc |
Merchant onboarding, API key lifecycle, configuration |
notification-svc |
Webhooks, SMS, email dispatch via NSQ consumers |
fx-svc |
Real-time FX rate fetching, spread calculation, caching |
fraud-svc |
Rule engine, velocity checks, ML scoring |
recon-svc |
End-of-day reconciliation against channel statements |
settlement-svc |
Net settlement calculation, ledger posting |
3. Inter-Service Communication¶
3.1 Synchronous — gRPC¶
All service-to-service synchronous calls use gRPC with Protocol Buffers v3. Protobuf definitions live in a shared simpaisa-proto repository.
- Timeouts: 3 s default, 10 s for channel adapter calls.
- Retries: Automatic with exponential back-off (max 3 attempts).
- Load balancing: Client-side round-robin via K8s headless services.
3.2 Asynchronous — NSQ¶
Event-driven workflows use NSQ topics. Each service publishes domain events; downstream services subscribe via dedicated channels.
| Topic | Publisher | Subscribers |
|---|---|---|
txn.payin.completed |
pay-in-svc | notification-svc, recon-svc |
txn.payout.initiated |
pay-out-svc | fraud-svc, settlement-svc |
txn.remit.aml.cleared |
remit-svc | pay-out-svc |
txn.cards.authorised |
cards-svc | notification-svc, fraud-svc |
4. Service Discovery¶
Service discovery uses Kubernetes DNS. Each service is addressable as <service>.<namespace>.svc.cluster.local. No external service registry is required.
Environment-specific routing:
pay-in-svc.payin-prod.svc.cluster.local
pay-out-svc.payout-prod.svc.cluster.local
5. Health Checks¶
Every service must expose two HTTP endpoints on a dedicated health port (default :9090):
| Endpoint | Purpose | K8s Probe |
|---|---|---|
/health |
Liveness — process is running | livenessProbe |
/ready |
Readiness — dependencies are healthy | readinessProbe |
The /ready check must verify connectivity to SurrealDB, Redis, and NSQ before returning 200 OK.
6. Resilience Patterns¶
6.1 Circuit Breakers¶
All outbound calls to external channel partners use circuit breakers implemented via the sony/gobreaker library.
| Parameter | Default |
|---|---|
| Failure threshold | 5 |
| Success threshold | 3 |
| Timeout (half-open) | 30 s |
6.2 Bulkhead Isolation¶
Each channel adapter runs in its own goroutine pool with a bounded semaphore. A misbehaving channel (e.g. Easypaisa timeout spike) cannot exhaust resources for other channels (e.g. JazzCash, bKash).
// Per-adapter concurrency limit
sem := make(chan struct{}, cfg.MaxConcurrent) // e.g. 200
6.3 Graceful Degradation¶
- If
fraud-svcis unavailable, pay-in transactions below the risk threshold (PKR 5,000) proceed with a flag for deferred screening. - If
fx-svcis unavailable,remit-svcreturns the last cached rate with a staleness indicator. - If
notification-svcis down, events remain on the NSQ topic and are processed on recovery.
7. Security — mTLS via Caddy Sidecar¶
Every pod runs a Caddy sidecar that terminates and originates mTLS. Certificates are issued by ControlPlane.com's built-in CA and rotated automatically every 24 hours.
# K8s pod spec excerpt
containers:
- name: caddy
image: caddy:2-alpine
ports:
- containerPort: 443
volumeMounts:
- name: certs
mountPath: /etc/caddy/certs
8. Configuration¶
All runtime configuration is injected via environment variables, sourced from Kubernetes ConfigMaps and Secrets. No configuration files are baked into container images.
| Variable | Example |
|---|---|
SURREAL_DSN |
ws://surrealdb:8000/rpc |
NSQ_LOOKUPD_ADDR |
nsqlookupd:4161 |
OTEL_EXPORTER_ENDPOINT |
otel-collector:4317 |
POSTHOG_API_KEY |
phc_xxxxx |
9. Feature Flags¶
Feature flags are managed via PostHog Feature Flags. Services evaluate flags at runtime using the PostHog Go SDK.
Use cases:
- Rolling out a new channel adapter (e.g. enable_alfa_wallet_pk).
- Toggling async vs sync charge flow per merchant.
- A/B testing fraud rule thresholds.
10. Service Template¶
All new services are scaffolded from the simpaisa-go-template repository, which provides:
- Standard project layout (
/cmd,/internal,/pkg,/api). - gRPC server and client boilerplate.
- NSQ publisher/subscriber wiring.
- Health check endpoints.
- OpenTelemetry tracing and metrics instrumentation.
- Dockerfile with multi-stage build.
- Helm chart with Caddy sidecar.
- CI pipeline definition for Bitbucket Pipelines.
# Scaffold a new service
cookiecutter [email protected]:simpaisa/simpaisa-go-template.git \
--no-input service_name=new-svc
11. Architectural Decision Records¶
Changes to this framework require an ADR in /Standards/ADR/. See ADR/ADR-TEMPLATE.md.