The constraints
Three regulators; three overlapping rule sets:
- ADGM (Abu Dhabi Global Market) Data Protection Regulations 2021. Personal data of UAE residents stays in UAE territory unless explicit transfer mechanism (consent + safeguards).
- DIFC (Dubai International Financial Centre) DP Law 5/2020. Similar; with its own list of approved transfer destinations.
- SAMA Cybersecurity Framework 2017. Saudi banking data stays in Saudi Arabia. Period. No “transfer mechanism” loophole.
A platform serving customers in both jurisdictions has to keep Saudi data in Saudi territory AND honour UAE-specific transfer rules for UAE customer data.
The architecture
Two parallel deployments:
┌─ UAE customers ──► UAE deployment (Bahrain region)
│
Bancnet front-end ────┤
│
└─ Saudi customers ──► Saudi deployment (Riyadh region)
Per-deployment:
- Postgres + RLS (data physically in-region)
- LLM inference on-prem or in-region cloud
- Audit logs in-region
- Backups in-region
The front-end is the only shared layer. It serves both jurisdictions and routes based on the user’s residency claim (validated against the bank’s KYC data, not self-asserted).
The router
A user logs in. The platform reads their residency from KYC and routes:
func routeRequest(claims auth.Claims, req Request) (deployment string, err error) {
residency := claims.Residency // "UAE" or "SAU", validated at KYC
switch residency {
case "UAE":
return "uae-bahrain", nil
case "SAU":
return "saudi-riyadh", nil
default:
return "", ErrUnsupportedResidency
}
}
The router is the only place residency is enforced. The downstream deployments are blind to each other — they don’t know the other exists. This is by design: a code bug in one can’t leak data from the other because the connection doesn’t exist.
The data flows you’d think work but don’t
Cross-deployment analytics. A “show me transactions across both jurisdictions” report runs nowhere — there’s no joined view. Reports are per-jurisdiction. Aggregate insights (counts, anonymous patterns) are computed by hand on per-jurisdiction outputs and combined off-platform.
Cross-deployment LLM context. A user’s chat history doesn’t follow them across jurisdictions because there’s no cross-jurisdiction store. If a UAE user moves to Saudi, they start fresh.
Backups across regions. Tempting: store UAE backups in a redundant Saudi region for resilience. Not allowed — Saudi region might house UAE data; UAE region might house Saudi data; both regulators object.
The discipline: design every data path with “in which jurisdiction does this data live, in transit and at rest” answered explicitly. Anything cross-jurisdiction is either explicitly approved (rare) or refactored to per-jurisdiction (default).
The audit shape
Each jurisdiction has its own audit log. The hash chain doesn’t cross jurisdictions. Audit reads are per-jurisdiction; auditors get scoped credentials.
When a Saudi auditor inspects, they see only Saudi data. The UAE deployment doesn’t exist from their perspective. Same in reverse.
What this cost in engineering
About 20% more infrastructure cost (two deployments instead of one). About 15% more engineering effort (per-jurisdiction config, per-jurisdiction testing, per-jurisdiction monitoring).
What it saved: not having a regulator letter. The cost of getting this wrong dwarfs the cost of getting it right by 100×.
What transfers
For any platform serving multiple jurisdictions with strict data-residency rules:
- Treat data residency as physical, not logical. The data lives in a place; you can prove where.
- Cross-jurisdiction flows need explicit approval, default-denied.
- Reports are per-jurisdiction unless aggregated insights are computed off-platform.
- Each jurisdiction has its own audit; auditors are scoped to their jurisdiction.
The Bancnet pattern works at three jurisdictions. The same shape extends to N. The cost is linear; the safety is constant.