================================================================================ RODMENA PLATFORM TOPOLOGY ================================================================================ Last verified : 2026-08-21 Scope : the nine first-party services and the data tier behind them Audience : engineers integrating with, operating, or auditing the platform This document describes architecture. It deliberately omits operational coordinates (host addresses, database endpoints, role names, storage bucket names, internal ports, filesystem paths). See NOTES ON DISCLOSURE at the end. ================================================================================ 1. AT A GLANCE ================================================================================ 10 services 9 PostgreSQL databases 4 database hosts 3 countries Every service is a separate application with its own database. No two services share a schema, and no service reads another's tables. All cross-service communication is over HTTPS APIs. Applications and data are deliberately in different places: applications are redeployable, data is not. APPLICATION TIER DATA TIER CONSENSUS TIER London, UK United Kingdom / United Kingdom / (2 hosts) France / Germany France / Germany (4 hosts, 3 regions) (3 members, 3 regions) ================================================================================ 2. SERVICES ================================================================================ Each entry: what it does, where its data lives, and what it calls at runtime. "Region" refers to the datacenter holding that service's database. -------------------------------------------------------------------------------- AUTH https://auth.rodmena.co.uk -------------------------------------------------------------------------------- Role Role-based access control and authorization for the platform Database Region FR Depends on (nothing) Depended on by futex, mail_api, agentbus, red9, runflow The root of the trust tree. It calls no other first-party service, which is deliberate: an authorization service that depends on its own consumers cannot be recovered independently. -------------------------------------------------------------------------------- TOKENGATE https://tokengate.rodmena.co.uk -------------------------------------------------------------------------------- Role Quota management, rate limiting and usage metering as a service Database Region FR Depends on (nothing) Depended on by mail_api, identity, agentbus Also stateless-recoverable: its hot-path counters live in a cache, and are rebuilt from the database of record if that cache is lost. -------------------------------------------------------------------------------- IDENTITY https://identity.rodmena.co.uk -------------------------------------------------------------------------------- Role OpenID Connect identity provider for end users; issues and rotates signing keys, manages sessions and consent Database Region FR Depends on mail_api, tokengate Depended on by red9 Distinct from AUTH: identity authenticates *people*, auth authorizes *services*. They are separate systems in separate databases. -------------------------------------------------------------------------------- FUTEX https://futex.rodmena.co.uk -------------------------------------------------------------------------------- Role Human-in-the-loop approvals: pauses automated work pending a human decision, with policies and audit Database Region UK Depends on auth, mail_api, runflow Depended on by agentbus, red9 -------------------------------------------------------------------------------- RUNFLOW https://runflow.rodmena.app -------------------------------------------------------------------------------- Role Workflow and pipeline engine; scheduled and event-driven execution in isolated containers Database Region UK Depends on auth, mail_api Depended on by futex, mail_api By transaction volume this is the busiest database on the platform. -------------------------------------------------------------------------------- MAIL API https://mailserver.rodmena.co.uk -------------------------------------------------------------------------------- Role Transactional and campaign email: sending, delivery tracking, inbound routing, suppression and complaint handling Database Region UK Depends on auth, runflow, tokengate Depended on by identity, futex, agentbus, red9, runflow, ledger The most depended-upon service after auth. Attachments are stored on the application host, not in the database. -------------------------------------------------------------------------------- AGENTBUS https://agentbus.rodmena.co.uk -------------------------------------------------------------------------------- Role Inter-platform message bus: addressed, threaded messaging between autonomous agents, with delivery guarantees and audit Database Region UK Depends on auth, futex, mail_api, tokengate Depended on by (operational tooling) Runs as eight coordinated processes: two API instances behind a load balancer, plus egress, ingest, webhook, janitor and synthetic-check workers. -------------------------------------------------------------------------------- RED9 https://api.red9.app -------------------------------------------------------------------------------- Role Multi-tenant task and conversation platform Database Region UK Depends on auth, identity, futex, mail_api, and an external model provider Depended on by (none) The only service that enforces tenant isolation inside the database itself, using row-level security keyed on a per-request tenant identifier. Its application role cannot bypass those policies. -------------------------------------------------------------------------------- LEDGER https://ledger.rodmena.co.uk -------------------------------------------------------------------------------- Role Double-entry accounting ledger: assets, postings, balances Database Region UK Depends on mail_api Depended on by (none) Enforces per-tenant isolation with row-level security and separates the application, maintenance and reporting roles so that ordinary request handling cannot perform maintenance operations. -------------------------------------------------------------------------------- CONSENSUS https://consensus.rodmena.co.uk -------------------------------------------------------------------------------- Role Distributed strongly-consistent key-value store and coordination primitive (leader election, distributed locks, watches) Database None. It IS the datastore -- a Raft cluster, not a PostgreSQL consumer Depends on (nothing) Depended on by (available to any service; no first-party consumer yet) Three voting members in three regions -- UK, FR, DE -- forming a Raft quorum of two. It therefore survives the loss of any one member INCLUDING that member's entire region, and continues to accept reads and writes. This replaced a three-member cluster whose members all ran on one host. That arrangement tolerated a process restart but not the host failure it existed to survive; the distinction matters, and the earlier documentation said so plainly rather than claiming redundancy it did not have. Verified by deliberately killing the leader: the surviving two elected a new leader, kept serving reads and writes, and the recovered member reconciled the writes it had missed on rejoining. Peer traffic between members is mutually authenticated with TLS against a private certificate authority -- a Raft peer can commit entries, so an unauthenticated peer port would be a write path into the cluster. Client access is TLS with per-user authentication and role-based authorization. What it does not survive: the simultaneous loss of two members. With one member there is no quorum, so it stops accepting writes rather than risk divergence. It is then unavailable, not corrupted, and recovers when a second member returns. ================================================================================ 3. DEPENDENCY GRAPH ================================================================================ Arrows point from a service to the services it calls at runtime. +------------------+ | AUTH | (no dependencies) +------------------+ ^ +----------+-----------+-----------+----------+ | | | | | +-------+ +--------+ +--------+ +-------+ +------+ | FUTEX | | MAIL | |AGENTBUS| | RED9 | |RUNFLOW| +-------+ | API | +--------+ +-------+ +------+ | +--------+ | | | | ^ ^ | | | | | | | | | +----------+ +----------+----------+----------+ | +--------------+ | TOKENGATE | (no dependencies) +--------------+ ^ | +--------------+ +-----------+ | IDENTITY |<---------| RED9 | +--------------+ +-----------+ Read in dependency order, lowest first: tier 0 auth, tokengate depend on nothing tier 1 identity, runflow depend on tier 0 (+ mail_api) tier 2 mail_api, futex mutually reference runflow tier 3 agentbus, red9, ledger consume the tiers below Practical consequences: - auth unavailable -> authorization fails platform-wide - mail_api unavailable -> no outbound email; six services degrade - tokengate unavailable -> quota decisions degrade, not authorization - agentbus unavailable -> inter-agent messaging stops; user-facing services are unaffected ================================================================================ 4. DATA TIER ================================================================================ PostgreSQL 18.4 on FreeBSD 15, one dedicated host per group of databases. Every cluster: data-page checksums on, locale provider "builtin" with a C.UTF-8 collation (immune to libc collation drift across upgrades). HOST GROUP REGION DATABASES ---------------- -------------------- ----------------------------- Primary A United Kingdom futex, ledger, runflow Primary B France auth, tokengate, identity Primary C United Kingdom agentbus, red9, mail_api Standby Germany live replicas of all nine Total data volume is small; capacity is not a constraint at any tier. The design constraint is isolation and recoverability, not scale. Note that primaries A and C are in the same UK facility. That is a known concentration; it is mitigated by the German replica set below rather than by pretending the two hosts are independent. ================================================================================ 5. ACCESS CONTROL AT THE DATABASE LAYER ================================================================================ No database on this platform accepts a password alone from the network. Every remote connection must present three independent factors: 1. TLS 1.2 minimum (TLS 1.3 with AES-256-GCM in practice), verified against a publicly trusted server certificate 2. A client certificate issued by a private certificate authority, whose subject common name must equal the database role being used 3. A SCRAM-SHA-256 password A connection lacking any one of these is refused before authentication completes. Unencrypted connections from the network are rejected outright. Isolation is enforced by host-based access rules, not only by grants: each service's role has no rule permitting any other service's database, so a cross-database connection is refused at connect time even with valid credentials. This is verified continuously rather than assumed. The certificate authority's private key is held offline, never on any database host, so compromising a database server cannot mint new identities. Additionally, two services (red9 and ledger) enforce row-level security inside the database for per-tenant isolation, with application roles that are explicitly unable to bypass those policies. ================================================================================ 6. REPLICATION ================================================================================ Every primary cluster streams to a physical standby in Germany, giving a continuously current copy of all nine databases outside both the UK and French facilities. Region UK (futex, ledger, runflow) --\ Region FR (auth, tokengate, identity) ---> Region DE : 3 standby clusters Region UK (agentbus, red9, mail_api) --/ Properties: - Physical (block-level) replication, not logical. It is exact, and it cannot silently diverge when a schema changes. - Asynchronous, so a replica can never slow down or block a primary. - No replication slots are used. A standby that falls behind recovers from archived write-ahead logs in object storage instead of forcing its primary to retain them, so a lagging replica cannot exhaust a primary's disk. - Replicas are read-only and are configured never to influence maintenance behaviour on their primary. - Promotion is a deliberate manual operation. There is no automatic failover and no consensus layer in the database tier, a considered trade: at this data volume, split-brain and consensus faults are harder to diagnose and recover from than the hardware failure they would guard against. (The consensus service in section 2 is a separate product with its own Raft cluster. It takes no part in database failover, and no database depends on it.) Replica health is checked automatically every ten minutes. The check fails on: instance down, unexpected promotion, replication not connected, replica connected but not streaming, or staleness beyond a threshold. It has been validated by deliberately severing replication and confirming the check reports the fault while the replica is still running and answering queries. IMPORTANT: replication is not a backup. A destructive or erroneous statement reaches every replica within milliseconds. Recovery from logical error is the job of the backup system below. ================================================================================ 7. BACKUP AND RECOVERY ================================================================================ Every primary cluster is backed up continuously to off-site object storage in a separate facility, independent of any database host. Full backup daily Incremental backup hourly Write-ahead log archived continuously Recovery point (RPO) 5 minutes or better Encryption AES-256-CBC, encrypted before leaving the host Retention 7 full, 4 differential Point-in-time recovery is supported to any moment within retention, either in place or into a separate cluster, so a restore can be verified without disturbing production. Restore has been exercised end to end, not assumed: a known dataset was written, captured by an incremental backup, restored from object storage into a separate cluster, and compared by both row count and content checksum. Every service additionally retains a pre-migration logical dump, held in two independent locations. Recovery objectives: Loss of one database host replica promotion, minutes Loss of an entire facility unaffected services continue; affected services recover from the German replica set or from object storage Logical error (bad statement) point-in-time recovery to just before it ================================================================================ 8. OPERATIONAL POSTURE ================================================================================ Database hosts - Default-deny firewall; only the ports required to operate are reachable - Administrative access by public key only; password authentication is disabled entirely - Automated intrusion blocking on repeated authentication failures, with blocks that expire automatically so no lockout can become permanent - Base operating system patched on a schedule, with security advisories audited weekly - Server certificates renew automatically and reload the database without operator action; renewal is tested, not assumed Verification - A single re-runnable probe exercises every host: per-role connectivity, refusal without a client certificate, refusal of a wrong password, refusal of cross-database access, refusal of unencrypted connections, rejection of a certificate from an untrusted authority, negotiated TLS version and cipher, and remaining certificate lifetime. - Checks are designed so they can fail. Each is validated against a known good case before being trusted to report a bad one. Change management - Schema changes are applied by a migration tool whose state is stored inside the database it manages, so it survives restore intact - Every service repository carries an operational runbook describing where its database lives, how to connect, how to run migrations, how to restore, and how to roll back ================================================================================ 9. NOTES ON DISCLOSURE ================================================================================ This document is published deliberately, and just as deliberately omits: - host addresses and database endpoint names - database role and user names - object storage bucket names, regions and endpoints - internal service ports and filesystem paths - any credential, key, certificate or fingerprint Nothing above is required to integrate with the platform's public APIs, and publishing it would provide no benefit to a legitimate integrator while materially assisting an attacker in targeting infrastructure. Security issues may be reported to security@rodmena.co.uk. Reports affecting data integrity or isolation are treated as highest priority. ================================================================================ Rodmena Limited generated 2026-08-09 (UTC) ================================================================================