Architectural Design — Overview¶
Validated against PRD v1.0
Executive Summary¶
The FEC Platform is built as a modular monolith — a single deployable application with 10 bounded contexts separated by strict module boundaries. This delivers the business value first, avoids premature distributed complexity, and enables mechanical extraction to services when needed.
Stack: Kotlin + Spring Boot 3, TypeScript + React, PostgreSQL, Temporal, Docker Compose.
Key architectural properties:
- Configuration over code (business rules change without deployment)
- Immutable audit trail from day one
- Human-in-the-loop via Temporal signals
- Pluggable intelligence modules via standard
DecisionModulecontract - Architecture fitness tests in CI prevent boundary violations
1. Technology Stack¶
| Layer | Choice | Key Rationale |
|---|---|---|
| Backend | Kotlin + Spring Boot 3 | Null safety, coroutines, enterprise ecosystem |
| Frontend | TypeScript + React + MUI | Type safety, rich component library |
| Database | PostgreSQL | ACID, JSONB, recursive CTEs for graph |
| Workflow | Temporal | Workflow-as-code, versioning, retry, human-in-the-loop |
| Internal Messaging | Spring Application Events | Zero infrastructure for modular monolith |
| Audit Streaming | Deferred: Kafka | PostgreSQL audit table sufficient for MVP |
| Auth | Spring Security → Keycloak | Built-in for MVP, SSO when needed |
| Containers | Docker Compose | Single deployment for MVP |
| Testing | JUnit 5 + TestContainers + Playwright | Unit, integration, E2E |
See: Technology Evaluation for full trade-off analysis and divergences from client suggestions.
2. Bounded Contexts¶
flowchart TB
CE[Config Engine] -->|reads| WF[Workflow Orchestrator]
WF -->|creates| CM[Case Management]
WF -->|invokes| NS[Name Screening]
WF -->|invokes| RR[Risk Rating]
WF -->|invokes| NA[Network Analysis]
subgraph Modules[Decision Modules]
NS
RR
NA
end
subgraph CC[Cross-Cutting]
AUDIT[Audit Service<br/>ALL write]
IAM[Identity & Access<br/>ALL check]
end
10 bounded contexts: 1. Configuration Engine — workflow templates, thresholds, rules, versioning 2. Workflow Orchestration — state machines, task management, SLA enforcement 3. Customer Onboarding — intake, classification, data capture, UBO, documents, decision 4. Name Screening — sanctions/PEP matching, adjudication 5. Customer Risk Rating — rules-based scoring, factor traceability 6. Case Management — lifecycle, queue, evidence, notes, escalation, decisions 7. Network Analysis — ownership graph, linked entity discovery 8. Notification — in-platform alerts, reminders 9. Audit & Governance — immutable event log, deterministic replay 10. Identity & Access — authentication, RBAC, sessions
See: Bounded Contexts for full domain model, aggregates, entities, value objects, domain events.
3. System Topology¶
MVP: Single Deployment¶
flowchart TB
subgraph DC[Docker Compose]
APP[Spring Boot App<br/>Temporal Worker<br/>React SPA<br/>Spring Security<br/>All 10 Bounded Contexts]
DB[(PostgreSQL<br/>Schema per Context)]
TS[Temporal Server]
APP --> DB
APP --> TS
end
Communication Patterns¶
| Pattern | When | How |
|---|---|---|
| Sync (in-process) | Caller needs result | Direct method call through shared.contract interface |
| Async (events) | Fire and forget | Spring Application Events (audit, notifications) |
| Long-running | Workflows with retries, timers, human tasks | Temporal (orchestration layer) |
Extraction Path¶
When a module needs independent deployment: 1. Module already has a clean interface → no caller code changes 2. Create new Spring Boot app with module's domain + infra 3. Replace in-process call with HTTP client 4. Replace Spring Events with Kafka topics
This works because the modular monolith enforces boundaries from day one.
See: System Topology for package structure, API gateway design, cross-cutting concerns, and security topology.
4. Data Architecture¶
PostgreSQL — Schema per Bounded Context¶
flowchart TB
subgraph PG[PostgreSQL]
ONB[(onboarding<br/>customer, individual<br/>legal_entity, ownership<br/>document)]
SCR[(screening<br/>request, result<br/>adjudication)]
RR[(riskrating<br/>risk_assessment<br/>risk_factor)]
CM[(casemanagement<br/>case, note, decision)]
CFG[(configuration<br/>config_version<br/>workflow_template)]
NA[(networkanalysis<br/>entity_graph<br/>linked_entity)]
NT[(notification)]
AUD[(audit<br/>audit_event<br/>immutable)]
AUTH[(auth<br/>user, role, session)]
end
Key Design Decisions¶
- UUIDs as primary keys — no auto-increment. Supports future service extraction.
- Append-only for audit-critical tables (audit_event, decision, adjudication, risk_assessment, config_version).
- JSONB for flexible config data — no schema migrations for rule changes.
- Recursive CTEs for ownership graph traversal (UBO identification).
- Application-level PII encryption for sensitive fields (DOB, ID numbers).
- Flyway for sequential, immutable migrations per bounded context.
See: Data Architecture for full DDLs, indexing strategy, and encryption design.
5. Module Contract (Intelligence Modules)¶
Every intelligence module implements the standard DecisionModule interface:
This is how Name Screening, Risk Rating, and Network Analysis plug into workflows. When v2 adds Adverse Media or Transaction Monitoring, they implement the same contract — no workflow code changes.
6. Audit Architecture¶
Every bounded context writes to the Audit Service. The audit event table is:
- Immutable — no UPDATE, no DELETE
- Append-only — new events create new rows
- Partitioned by month — retention management (7 years)
- BIGSERIAL event IDs — sequential ordering within partitions
- JSONB payload — full event data for reconstruction
The audit log supports NFR-C02: reconstruct any decision within 5 minutes, from up to 7 years ago.
7. Security Architecture¶
flowchart LR
B[Browser] -->|TLS| JWT[JWT Auth Filter]
JWT --> RBAC[RBAC Filter]
RBAC --> RATE[Rate Limiting]
RATE --> CORR[Correlation ID]
CORR --> CTRL[Controller]
- 8 predefined roles mapped to platform capabilities
- Segregation of duties enforced at the application layer (not just DB)
- Session timeout: 30 minutes idle
- Lockout: 5 failed attempts = 15-minute lock
- PII encryption: Application-level AES-256-GCM for sensitive fields
See: System Topology §8 for full security topology.
8. Architecture Fitness Tests¶
CI enforces boundary integrity with ArchUnit:
// No cross-module internal imports
onboarding must not import screening.internal
// No circular dependencies between modules
all modules must be free of cycles
// Audit module must not depend on any domain module
audit must not depend on onboarding, screening, riskrating, etc.
These tests run on every build. They prevent the modular monolith from degrading into a ball of mud.
9. Key Risks & Mitigations¶
| Risk | Mitigation |
|---|---|
| Modular monolith becomes tightly coupled | ArchUnit tests in CI. Bounded context module structure enforced from day one. |
| Temporal learning curve | PoC before full onboarding workflow. Temporal provides excellent docs. |
| PostgreSQL recursive CTEs become slow | Define performance threshold. If UBO traversal > 1s at 10+ levels, evaluate Neo4j. |
| Configuration engine complexity | Start with minimal viable config (thresholds + templates). Add features incrementally. |
| External integrations unstable | Adapter + fallback pattern. Mock providers for development. Test with real providers early. |
10. Document Map¶
| Document | Contents |
|---|---|
| Architecture Overview | This document — executive summary of all architectural decisions |
| Technology Evaluation | Full trade-off analysis for every technology choice |
| Bounded Contexts | Domain model, aggregates, entities, domain events per context |
| System Topology | Package structure, communication patterns, deployment, cross-cutting |
| Data Architecture | Schemas, DDLs, indexing, encryption, migration strategy |
Architecture validated against PRD v1.0. Re-evaluate if PRD scope or NFRs change materially.