Architecture

Security & compliance


Tamper-evident audit trail, split of duties, KYC/AML — the level your trade requires.

Security is designed into the data model, not bolted on at the end. In a financial system the question is not only “who can get in”, but “what can be proven six months later”.

Immutability enforced by the database, not by discipline

REVOKE UPDATE, DELETE ON journal_entries, postings FROM amtm_app;

An entry cannot be modified or deleted. Not because the code refrains — because the database refuses. An application bug, a mishandled operation or a malicious action physically cannot corrupt history. A correction is a reversal: both the error and its correction stay visible.

Hash-chained audit trail

Every audit row embeds the hash of the previous one:

hash = sha256( prev_hash ‖ seq ‖ timestamp ‖ actor ‖ action ‖ payload )

Any after-the-fact modification of a row breaks the chain and becomes detectable. An external auditor can verify the integrity of the whole history without trusting us, and without asking us for anything.

Split of duties

  • Granular RBAC: role × branch × ceiling. A teller only sees their own till.
  • Whoever enters does not approve. Above a configurable threshold, dual approval is mandatory.
  • Every account is named. No shared logins, ever — that is the first weakness in this kind of operation.
  • Expiring sessions, remote forced logout, login log.

Isolation lives in the database

ALTER TABLE postings ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON postings
  USING (tenant_id = current_setting('app.tenant_id')::uuid);

Even if the application code gets it wrong, the database will not return another tenant's rows. That is what makes reselling to other sub-agents defensible to a third party.

KYC / AML

  • Secondary identifiers mandatory at entry: a name alone is not enough. Date of birth, nationality and identity document are what let you confirm or clear a candidate, with a documented basis.
  • Fuzzy matching on sanctions lists: phonetic, transliteration, aliases — exact-name matching misses too many true hits.
  • Automatic rescreening of the existing base on every list update, not just a check at onboarding.
  • Monitoring: threshold rules, structuring detection, risk corridors, suspicious activity reports generated and tracked.

Continuity

TLS everywhere, encryption at rest for identity documents, secrets kept out of the code, WAL backups with point-in-time recovery.

These objectives are not intentions — they are quantified and committed in the proposal:

CommitmentValueWhat it means
RPOunder 5 minutesHow much data is lost at worst in a disaster. The standard for critical banking systems sits between one and five minutes.
RTOunder 1 hourTime before service resumes. Measured in a real drill, with the stopwatch handed to you.
Availability99.5 %That is 3 h 39 of downtime tolerated per month. It is an error budget: it is spent, it is measured, and when exhausted we stop shipping features to restore reliability.
A backup never restored is not a backup. The restore drill is tested and timed before go-live, and the result is handed to you in writing.

What we prove before launch

  • Penetration test report (OWASP methodology)
  • Load test report
  • Restore report: measured duration, verified data
  • Audit-chain integrity verification on an acceptance dataset