ADR-035: Snowflake account configuration and data residency¶
| Status | Superseded |
| Date | 2026-04-10 |
| Deciders | CTO, Head of Architecture |
| Affects repos | bank-risk-platform, bank-aml, bank-credit, bank-platform |
| Superseded by | ADR-054 |
⚠️ This ADR has been superseded by ADR-054.
Superseded. This ADR has been superseded by ADR-054 (DCM Projects for Snowflake DDL management). The SQL DDL script approach described here has been replaced by DCM Projects for new modules. Existing modules (MOD-038, MOD-085, MOD-098) are pending migration.
ADR-035: Snowflake account configuration and data residency¶
Status¶
Superseded — 2026-05-03 (by ADR-054). Supplements ADR-002 (Snowflake as analytics platform) and ADR-023 (cloud region strategy) with explicit data residency configuration.
Context¶
ADR-002 selected Snowflake as the analytics and risk compute platform. ADR-023 established ap-southeast-2 (Sydney) as the bank's cloud region and confirmed NZ customer data may reside in Sydney under contractual DPA. Neither ADR specified the Snowflake account region, account isolation model, or network access controls. For APRA, RBNZ, and AUSTRAC compliance the data residency posture of the analytics platform must be explicitly documented.
Decision¶
Account region: Single Snowflake account in AWS AP-SOUTHEAST-2 (Sydney). No
cross-region replication at launch.
NZ data residency: NZ customer data in the Sydney Snowflake account is acceptable under the same contractual DPA basis as ADR-023. This is consistent with the position RBNZ has accepted for cloud-hosted banks operating without a local AWS region. When an AWS NZ region becomes available, the data migration trigger follows ADR-023 — an operational decision, not a platform rebuild.
Domain database structure: One Snowflake database per system domain, consistent with AP-010. Ownership and RBAC boundaries follow system domain boundaries (SD), not business domain boundaries.
| Database | System domain | Repo | Business domain owner |
|---|---|---|---|
CORE |
SD01 Core Banking | bank-core | BD02 Finance |
CUSTOMER |
SD02 KYC Platform | bank-kyc | BD01 Customer |
FINCRIME |
SD03 AML Monitoring | bank-aml | BD07 Financial Crime |
PAYMENTS |
SD04 Payments | bank-payments | BD06 Payments |
CREDIT |
SD05 Credit | bank-credit | BD05 Credit |
RISK |
SD06 Risk Platform | bank-risk-platform | BD08 Risk |
PLATFORM |
SD07 Data Platform | bank-platform | BD09 Technology |
SD08 (App / bank-app) does not produce data products in Snowflake and has no database.
Schema governance within each database¶
Each Snowflake database uses a layered schema structure. Schema names are lowercase.
Layer 1 — Raw data products (raw_<module_slug>)
One schema per source Neon module that produces data. Named after the module slug. These are the raw data products — append-only Iceberg tables written by the CDC pipeline (ADR-003). Ownership belongs to the team responsible for the source module.
Examples:
| Schema | Source module | Source tables |
|---|---|---|
CORE.raw_accounts |
MOD-001 Account ledger | accounts, postings |
CORE.raw_transactions |
MOD-002 Transaction store | transactions |
CUSTOMER.raw_onboarding |
MOD-006 Customer onboarding | customers, onboarding_events |
CUSTOMER.raw_kyc |
MOD-009 eIDV & document verification | kyc_checks, identity_documents |
PAYMENTS.raw_domestic |
MOD-021 Domestic payment execution | payments, payment_events |
FINCRIME.raw_aml_cases |
MOD-013 AML transaction monitoring | aml_cases, aml_alerts |
CREDIT.raw_applications |
MOD-030 Credit application | credit_applications, bureau_responses |
The full raw schema map is maintained in each module's YAML (raw_snowflake_schema field — to be added when modules reach In progress status). This section documents the pattern; module-level detail lives with the module.
Layer 2 — Analytical data products (domain schema)
Snowflake Dynamic Tables that derive from raw data products. Named by analytical concern, not by source module.
| Schema | Database | Purpose |
|---|---|---|
CORE.intelligence |
CORE | Spend analytics, balance trends, idle cash signals |
PAYMENTS.intelligence |
PAYMENTS | Payment predictions, FX signals |
FINCRIME.typology |
FINCRIME | AML typology models, SAR decision inputs |
CREDIT.decisions |
CREDIT | Affordability models, pre-approval signals |
RISK.capital |
RISK | Capital and liquidity positions (CET1, RWA, LCR, NSFR) |
RISK.customer_risk |
RISK | Customer risk scores, fraud model outputs |
PLATFORM.regulatory |
PLATFORM | Regulatory returns, cross-domain aggregations |
Layer 2 schemas may read from raw schemas in other databases — but only via a documented cross-domain data contract (see access controls below).
Layer 3 — Reporting views (reporting schema in each database)
Snowflake views or Dynamic Tables serving the Snowflake read API (ADR-038 Tier 3). Named reporting within the relevant domain DB. These are the surfaces the API layer queries — they never expose raw Iceberg columns directly.
Data product ownership rule¶
A data product is owned by the system domain that writes it. The owning domain team controls schema evolution, partition strategy, and access grants. No other team may write to a raw schema they do not own. Analytical schemas (Layer 2) may be written by the risk/analytics team using data from multiple raw schemas, provided cross-domain data contracts are in place.
Access controls: - Snowflake RBAC — one functional role per system domain; no cross-domain SELECT without a documented data contract - Column-level masking on all PII fields — unmasked access requires elevated role, all access logged to audit trail - Network policy restricts connections to Lambda NAT Gateway IPs (ap-southeast-2) and authorised engineer IPs via VPN only — no public account URL access
Compute isolation: One dedicated virtual warehouse per domain. Auto-suspend after 5 minutes idle. No shared warehouses — cost and performance isolated per domain.
IaC approach¶
Snowflake objects are managed as versioned SQL DDL scripts, not via Pulumi, Terraform,
or the Snowflake Terraform provider. SQL is the native IaC for Snowflake — it is idempotent
(CREATE OR REPLACE), human-readable, diffable in code review, and requires no external
state file.
MOD-102 (bank-platform) owns account-level objects: warehouses, databases, RBAC roles,
storage integrations (S3, SNS, GitHub), network policy, PII tag taxonomy, and column-level
masking policies. These are applied once at account bootstrap by CI from versioned scripts
in bank-platform/snowflake/setup/.
Domain repos (bank-risk-platform and future domain repos) own domain-specific objects
within their assigned database — schemas, tables, Dynamic Tables, and grants. Scripts live
in each repo's infra/snowflake/ directory and are applied by domain CI. A manifest.yml
in that directory declares the ordered script list.
Deployment rule: MOD-102 must be applied before any domain module's Snowflake scripts run — it provisions the databases and roles that domain scripts reference.
Migration path¶
When an AWS NZ region is available: NZ customer databases are cloned to a new Snowflake account in the NZ region, traffic is cut over, and the Sydney account retains AU customer data only. Application layer is unaffected — connection strings updated via Secrets Manager (ADR-030).
Rejected alternatives¶
| Option | Reason rejected |
|---|---|
| US East or US West Snowflake region | AU/NZ data residency obligations not satisfied |
| AP-NORTHEAST-1 (Tokyo) | Outside AU/NZ data residency boundary |
| Separate Snowflake accounts per domain | Operational overhead; cross-account Secure Data Sharing adds complexity without benefit at launch scale |
Signoff record¶
| Date | Name | Role | Status |
|---|---|---|---|
| 2026-04-10 | Ross Millen | CTO | Approved |
| 2026-04-10 | Ross Millen | Head of Architecture | Approved |
| 2026-04-10 | Ross Millen | Head of Data | Approved |
Capabilities¶
| Capability | Description | Relationship |
|---|---|---|
| CAP-030 | Regulator evidence portal | enabled — Snowflake Secure Data Sharing enables regulator account access |
| CAP-033 | Tenant data isolation | enabled — one Snowflake DB per system domain with RBAC isolation |
| CAP-034 | Jurisdiction configuration layer | enabled — NZ/AU data residency formalised; migration trigger defined |
| CAP-035 | Per-jurisdiction regulatory report profiles | enabled — PLATFORM.regulatory schema holds jurisdiction-specific returns |
Related decisions¶
| ADR | Title | Relationship |
|---|---|---|
| ADR-002 | Snowflake as the analytics and risk compute platform | this ADR supplements ADR-002 with residency and account config |
| ADR-003 | CDC pipeline — Neon Postgres to Snowflake via Firehose and Apache Iceberg | raw schemas receive CDC data |
| ADR-023 | Cloud provider and region strategy | same region constraint (ap-southeast-2) |
| ADR-038 | Data access tier policy — Snowflake as the reporting and insight layer | reporting schemas (Layer 3) serve the Tier 3 read API |
All ADRs
Compiled 2026-05-22 from source/entities/adrs/ADR-035.yaml