
Introduction
A FinTech Platform is not a simple monolithic application — it is a complex system with many different domains that need to be clearly separated. In this article, we will design the overall architecture using Microservices and Domain-Driven Design (DDD).
1. High-Level Architecture
1.1 System overview
┌─────────────────────────────────────────────────────────┐
│ CLIENT LAYER │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐ │
│ │Mobile App│ │ Web App │ │Merchant │ │Partner │ │
│ │ │ │ │ │Dashboard │ │ API │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └───┬────┘ │
└───────┼──────────────┼─────────────┼────────────┼───────┘
│ │ │ │
┌───────▼──────────────▼─────────────▼────────────▼───────┐
│ API GATEWAY LAYER │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ API Gateway (Kong/Envoy) │ │
│ │ ├── Rate Limiting ├── Authentication │ │
│ │ ├── Request Routing ├── SSL Termination │ │
│ │ └── API Versioning └── Request/Response Transform │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────┬───────────────────────────────┘
│
┌─────────────────────────▼───────────────────────────────┐
│ SERVICE MESH │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────┐ │
│ │ Payment │ │ Wallet │ │ Ledger │ │ Risk │ │
│ │ Service │ │ Service │ │ Service │ │ Service │ │
│ └──────────┘ └──────────┘ └──────────┘ └────────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────┐ │
│ │ Identity │ │ Merchant │ │Reporting │ │Notification│ │
│ │ Service │ │ Service │ │ Service │ │ Service │ │
│ └──────────┘ └──────────┘ └──────────┘ └────────────┘ │
└─────────────────────────┬───────────────────────────────┘
│
┌─────────────────────────▼───────────────────────────────┐
│ DATA LAYER │
│ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────────┐│
│ │PostgreSQL│ │Redis │ │Kafka │ │ S3 │ │Elasticsearch││
│ └───────┘ └───────┘ └───────┘ └───────┘ └───────────┘│
└─────────────────────────────────────────────────────────┘
1.2 Design principles
- Domain-first: Divide services by domain, not by technical layer
- Database per service: Each service owns its own data
- Event-driven communication: Async communication for cross-domain
- API-first design: Contract-first approach with OpenAPI
- Defense in depth: Security at every layer
2. Domain-Driven Design for FinTech
2.1 Strategic Design — Bounded Contexts
┌─────────────────────────────────────────────────────────────┐
│ FINTECH PLATFORM │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ IDENTITY │ │ PAYMENT │ │ WALLET │ │
│ │ Context │ │ Context │ │ Context │ │
│ │ │ │ │ │ │ │
│ │ • User │ │ • Payment │ │ • Account │ │
│ │ • KYC │ │ • Refund │ │ • Balance │ │
│ │ • Auth │ │ • PSP │ │ • Transaction │ │
│ │ • Session │ │ • Checkout │ │ • Transfer │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ LEDGER │ │ RISK │ │ MERCHANT │ │
│ │ Context │ │ Context │ │ Context │ │
│ │ │ │ │ │ │ │
│ │ • Journal │ │ • Fraud │ │ • Merchant │ │
│ │ • Account │ │ • AML │ │ • Settlement │ │
│ │ • Posting │ │ • KYC │ │ • Fee │ │
│ │ • Balance │ │ • Scoring │ │ • Contract │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ LENDING │ │ REPORTING │ │ NOTIFICATION │ │
│ │ Context │ │ Context │ │ Context │ │
│ │ │ │ │ │ │ │
│ │ • Loan │ │ • Report │ │ • Template │ │
│ │ • Credit │ │ • Dashboard │ │ • Channel │ │
│ │ • Schedule │ │ • Export │ │ • Preference │ │
│ │ • Offer │ │ • Audit │ │ • History │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
2.2 Context Mapping
Identity ──[U/D]──► Payment (Identity upstream, Payment downstream)
Payment ──[Pub]──► Ledger (Payment publishes events, Ledger subscribes)
Payment ──[Pub]──► Risk (Payment publishes for fraud check)
Payment ──[ACL]──► PSP (Anti-corruption layer for external PSPs)
Wallet ──[Pub]──► Ledger (Wallet changes reflected in Ledger)
Merchant ──[Pub]──► Reporting (Merchant events feed Reporting)
Risk ──[U/D]──► Payment (Risk provides scoring to Payment)
Usage Patterns:
- Published Language: Events use the same schema (Avro/Protobuf)
- Anti-Corruption Layer (ACL): Wrap external PSP APIs
- Upstream/Downstream (U/D): Clear dependency direction
- Shared Kernel: Common types (Money, Currency, Address)
2.3 Shared Kernel — Common Value Objects
// Shared across all bounded contexts
public record Money(BigDecimal amount, Currency currency) {
public Money {
if (amount.scale() > currency.getDefaultFractionDigits()) {
throw new IllegalArgumentException("Invalid precision");
}
}
public Money add(Money other) {
requireSameCurrency(other);
return new Money(amount.add(other.amount), currency);
}
}
public record TransactionId(String value) {
// UUID v7 for time-ordered IDs
public static TransactionId generate() {
return new TransactionId(UUIDv7.generate().toString());
}
}
3. Microservice Architecture
3.1 Service Topology
┌──────────────┐
│ API Gateway │
└──────┬───────┘
│
┌────────────────┼────────────────┐
│ │ │
┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
│ Payment │ │ Wallet │ │ Identity │
│ Service │ │ Service │ │ Service │
│ │ │ │ │ │
│ PostgreSQL │ │ PostgreSQL │ │ PostgreSQL │
│ Redis │ │ Redis │ │ Redis │
└──────┬──────┘ └──────┬──────┘ └─────────────┘
│ │
└────────┬───────┘
│
┌──────▼──────┐
│ Kafka │ Event Bus
└──────┬──────┘
│
┌─────────────┼─────────────┐
│ │ │
┌────▼────┐ ┌─────▼─────┐ ┌────▼────┐
│ Ledger │ │ Risk │ │Reporting│
│ Service │ │ Service │ │ Service │
│ │ │ │ │ │
│PostgreSQL│ │PostgreSQL │ │ClickHouse│
└─────────┘ │ Redis │ └─────────┘
│ ML Model │
└───────────┘
3.2 Communication Patterns
| Pattern | Use Case | Example |
|---|---|---|
| Sync (REST/gRPC) | Real-time queries | Check balance, get payment status |
| Async (Events) | State changes | Payment completed → update ledger |
| Command | Action requests | Process payment, create refund |
| Query | Read-only | Get transaction history |
3.3 Database per Service
Payment Service ──► payment_db (PostgreSQL)
├── payments
├── payment_methods
├── payment_attempts
└── refunds
Wallet Service ──► wallet_db (PostgreSQL)
├── accounts
├── balances
├── transactions
└── holds
Ledger Service ──► ledger_db (PostgreSQL)
├── journal_entries
├── postings
├── accounts
└── balances
Risk Service ──► risk_db (PostgreSQL + Redis)
├── fraud_rules
├── risk_scores
├── blacklists
└── ml_features (Redis)
4. Event-Driven Architecture
4.1 Domain Events
Payment Domain Events:
├── PaymentInitiated
├── PaymentAuthorized
├── PaymentCaptured
├── PaymentFailed
├── PaymentRefunded
└── PaymentSettled
Wallet Domain Events:
├── AccountCreated
├── BalanceCredited
├── BalanceDebited
├── TransferInitiated
├── TransferCompleted
└── HoldPlaced
Risk Domain Events:
├── FraudCheckRequested
├── FraudCheckCompleted
├── RiskScoreCalculated
├── TransactionBlocked
└── AlertRaised
4.2 Event Schema (Avro)
{
"type": "record",
"name": "PaymentCompletedEvent",
"namespace": "com.fintech.payment.events",
"fields": [
{"name": "eventId", "type": "string"},
{"name": "eventType", "type": "string"},
{"name": "timestamp", "type": "long"},
{"name": "paymentId", "type": "string"},
{"name": "amount", "type": {"type": "record", "name": "Money", "fields": [
{"name": "value", "type": "string"},
{"name": "currency", "type": "string"}
]}},
{"name": "merchantId", "type": "string"},
{"name": "customerId", "type": "string"},
{"name": "paymentMethod", "type": "string"},
{"name": "status", "type": "string"}
]
}
4.3 Event Flow — Payment Processing
Customer ─── Initiate Payment ───► Payment Service
│
├──► Risk Service (Fraud Check)
│ │
│ ◄──┤ (Approved/Rejected)
│
├──► PSP (Authorize)
│ │
│ ◄──┤ (Auth Response)
│
├──► Event: PaymentAuthorized
│ │
│ ├──► Wallet Service (Debit)
│ ├──► Ledger Service (Record)
│ ├──► Notification Service
│ └──► Reporting Service
│
└──► Response to Customer
5. API Gateway Design
5.1 Gateway Responsibilities
API Gateway Configuration:
authentication:
- JWT validation
- API key verification
- mTLS for service-to-service
rate_limiting:
default: 100 req/min
premium: 1000 req/min
merchant_api: 5000 req/min
routing:
/api/v1/payments/* → payment-service
/api/v1/wallets/* → wallet-service
/api/v1/merchants/* → merchant-service
/api/v1/reports/* → reporting-service
security:
- CORS policies
- Request validation
- IP whitelisting (for merchant APIs)
- PCI-DSS compliant headers
5.2 API Versioning Strategy
/api/v1/payments ← Current stable
/api/v2/payments ← Next version (beta)
Header-based: Accept: application/vnd.fintech.v1+json
6. Cross-cutting Concerns
6.1 Observability Stack
┌──────────────────────────────────────┐
│ OBSERVABILITY STACK │
├──────────────────────────────────────┤
│ Metrics: Prometheus + Grafana │
│ Logging: ELK Stack / Loki │
│ Tracing: OpenTelemetry + Jaeger │
│ Alerting: PagerDuty / OpsGenie │
└──────────────────────────────────────┘
6.2 Security Layer
Defense in Depth:
├── Network: VPC, Security Groups, WAF
├── Transport: TLS 1.3, mTLS
├── Application: JWT, OAuth2, RBAC
├── Data: Encryption at rest (AES-256)
├── Payment: Tokenization, HSM
└── Audit: Immutable audit logs
Summary
FinTech Platform architecture needs:
- DDD to divide complex domains into clear bounded contexts
- Microservices with database per service for isolation
- Event-Driven for loose coupling and eventual consistency
- API Gateway for security, routing, rate limiting
- Defense in Depth for security at every layer
Next article: We will deep-dive into Regulatory Compliance — PCI-DSS, PSD2, and State Bank of Vietnam regulations — and how to design a system to meet compliance requirements.