Skip to content

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 DecisionModule contract
  • 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:

interface DecisionModule<I, O> {
    fun execute(request: ModuleRequest<I>): ModuleResponse<O>
}

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.