Architecture

Overview


A modular monolith, sized to be operated without an ops team.

The architecture answers three constraints: accounting rigour, an unstable network, and an operator who is not an IT specialist. Every component we do not add is an outage you will not have.

End-to-end architecture

AiO · end-to-end architecture

/ 01 · CLIENTSConsumption surface
CounterPWA · offline-capable
Back-officeReact · TypeScript
Supervisormobile · read + approve
/ 02 · EDGEProximity & shield
CDNPoP Central/West Africa
TLS 1.3Hardened headers
WAFRate-limit · anti-abuse
/ 03 · API — GoSingle entry, sealed
Auth 2FAJWT · refresh
RBACroles × agencies
Idempotencyone key, one entry
/ 04 · DOMAINE — modular monolithBusiness core
Ledgerappend-only · balance = 0
Cash & floatsessions · forecast
Commissionsrates · rounding account
Partner connectorsAPI · file · assisted
/ 05 · DATAState of record
PostgreSQL 16ledger · RLS · deferred checks
Redisidempotency · locks
Riverdurable jobs, on Postgres
Object storageencrypted receipts · ID docs
/ 06 · CLOUD & OPSRun & prove
CI/CD3 environments
Monitoring 24/7SLO · alerting
PITRWAL · timed restore drill
Rollbackone click

< 3s on 4G  ·  99,5%  ·  2 000 concurrent users

AiO · modular monolith · live traffic

ClientsGatewayAPIModulesData
ReactBack-office
TypeScriptCounter PWA · offline
TraefikTLS · routage · LB
Go · chisingle API
Ledgerappend-only
Cash & floatGo
CommissionsGo
Connectorspartners
ComplianceKYC · AML
PostgreSQLACID · RLS
Redisidempotency · locks
MinIOencrypted receipts

Docker · GitHub Actions (CI/CD, security scan) · PostgreSQL WAL + point-in-time recovery. One unit to deploy, one to operate — no message bus, no orchestrator. Dots are requests in flight.

Why a modular monolith, not micro-services

This is a deliberate choice, and it runs against what you will be offered elsewhere.

Your need is measured in tens of operations per minute, not tens of thousands per second. A properly tuned PostgreSQL handles 10,000 to 30,000 transactions per second: the database will never be your bottleneck. Micro-services, on the other hand, would force a message bus, orchestration, distributed monitoring and cross-service tracing on you — that is three times the operating cost, for capacity you have no use for.

So we keep the module boundaries — they structure the code and the Git repository — but one deployment to operate. The day a module has to be extracted, the boundary already exists.

Clients
Gateway
API
Ledger core
Data
Cloud / Ops

Six layers, one deployment

The ledger is the centre

Everything else derives from it. Balances, trial balance, reports, accounting and regulatory statements are not separate tables to keep in sync: they are reads of the journal. That is what makes the classic gap between “what the screen says” and “what accounting says” impossible.

Ready to be resold

Your §3.2 creates a publisher profile responsible for managing licences; your chapter 25 asks for multi-company administration. Module boundaries and isolation are therefore drawn with that future in mind: a second company is onboarded without a rewrite, and rate cards, thresholds, charts of accounts, currencies and roles are data, not code.

Version 1 is deployed for one legal entity. Isolation is delivered and usable; support for opening a second entity is quoted separately.