Skip to content

ADR-042: Single-stack deployment with jurisdiction as runtime context

Status Accepted
Date 2026-04-15
Deciders CTO, Head of Architecture, Head of Engineering
Affects repos bank-core, bank-kyc, bank-aml, bank-payments, bank-credit, bank-risk-platform, bank-platform, bank-app

Status: Accepted — 2026-04-15

Context

The bank operates in New Zealand and Australia under separate regulatory regimes (RBNZ/FMA and APRA/AUSTRAC). A decision was needed on how to express this jurisdictional difference in the system architecture.

Two options were evaluated:

Option A — Separate stacks per jurisdiction: Two independent deployments per environment (bank-nz-{env} and bank-au-{env}), each with their own Cognito user pools, Lambda functions, EventBridge buses, and Neon branches. Jurisdiction separation is enforced by infrastructure.

Option B — Single stack, jurisdiction as runtime context: One deployment per environment serves both NZ and AU customers. Jurisdiction is an attribute on the party and account, flowing through the system as a JWT claim and a data column. Jurisdiction-specific behaviour is handled in code.

Decision

Option B — single stack.

Rationale

The compliance obligations for NZ and AU differ in regulatory detail (which act, which regulator, which report format) but not in technical architecture. The underlying platform capabilities — KYC checks, payment processing, account management, AML screening — are structurally identical. Maintaining two parallel stacks doubles infrastructure cost, operational overhead, and deployment complexity without providing a corresponding technical benefit.

Jurisdiction-specific logic (which AML/CFT rules apply, which report to file, which KiwiSaver vs superannuation products to offer) is a configuration and code concern, not an infrastructure topology concern. The same Lambda function that processes a payment handles both NZ and AU payments; it branches on the account's jurisdiction field.

Separate Cognito user pools for NZ and AU customers were also evaluated and rejected. A customer's jurisdiction is an attribute (custom:jurisdiction) stored on their Cognito user profile and emitted as a JWT claim. Both NZ and AU customers authenticate identically. Splitting the pool would add operational complexity (two pool IDs, two client IDs, two token issuers) with no security or compliance benefit.

Data residency is satisfied at the regional level (ap-southeast-2), not the pool or deployment level.

Consequences

  • One Cognito customer pool per environment. custom:jurisdiction is a custom user attribute and flows as a JWT claim on every request.
  • Every Lambda that applies jurisdiction-specific logic reads jurisdiction from the request context (JWT claim) or from the account/party record for background operations.
  • accounts.accounts.jurisdiction and banking.customer_relationships.jurisdiction are the data-layer source of truth for which rules apply to a given account or relationship.
  • Regulatory report generation (RBNZ, FMA, AUSTRAC, APRA) is driven by querying on jurisdiction, not by which deployment produced the data.
  • A customer who holds accounts in both NZ and AU (future capability) has a single user identity with a primary jurisdiction and account-level jurisdiction on each account.
  • The single-stack constraint must be considered when adding jurisdiction-specific infrastructure (e.g., a NZ-specific payment rail). That integration lives in the same stack, gated by jurisdiction at the call site.

All ADRs Compiled 2026-05-22 from source/entities/adrs/ADR-042.yaml