ADR-060: Tenant extension fields — runtime-extensible custom entity attributes¶
| Status | Proposed |
| Date | 2026-05-09 |
| Deciders | CTO, Head of Architecture, Head of Data |
Status: Proposed — 2026-05-09
Context¶
The bank platform is designed as a multi-tenant SaaS product (ADR-040, ADR-042). Different tenant configurations — including the bank's own NZ and AU regulatory contexts — will require custom attributes on core entities (party/customer, account, product) that are specific to that context and not universally applicable across all tenants.
Today, every custom field on any entity requires a Flyway migration deployed to the Neon Postgres instance for every environment. This is appropriate for structural, long-lived schema changes but is a disproportionate mechanism for tenant-specific configuration fields such as:
- Regulatory fields specific to one jurisdiction (e.g., AU-only tax residency fields beyond those already in
regulatory.party_regulatory_profiles) - Tenant-specific customer profiling fields required by the tenant's own internal reporting (e.g., internal customer segment codes)
- Product configuration extension fields needed by a specific product launch without being applicable platform-wide
- Operational tagging fields used by a specific back-office workflow
Apache Fineract's datatables pattern was studied as a design reference (see fineract-design-reference.md). Fineract allows institutions to define arbitrary additional tables linked to any core entity at runtime without forking or redeploying the platform. This pattern provides meaningful precedent for how a bank platform handles extensibility without sacrificing schema discipline.
Two positions were evaluated:
(a) No extension fields — all entity attributes are defined in fixed Flyway migrations. Custom fields require a code release.
(b) Runtime extension field registry — a governed module (MOD-169) provides a JSON-Schema-validated custom field registry per entity type. Field definitions are registered by authorised operators; field values are stored, validated, and queryable without a code deployment.
This ADR proposes option (b) and raises the open questions that must be resolved before MOD-169 is built.
Proposal¶
MOD-169 — Tenant extension fields module¶
MOD-169 will be a new module providing:
- A field definition registry: operators define custom fields per entity type (party, account, product) with a JSON Schema fragment for validation, a display label, a data type (string, number, boolean, date, enum), and a jurisdiction or tenant scope.
- A field value store: entity-keyed custom field values stored in a dedicated schema. Values are validated against the registered schema on write.
- A query API: consumers retrieve extension fields for an entity alongside the core entity response without needing to know the field definitions in advance.
- Audit trail: all field definition changes go through MOD-168 (maker-checker) given the potential regulatory implication of adding PII or categorisation fields to customer records. Field value writes are logged to MOD-047.
Open questions to resolve before build¶
This ADR is Proposed rather than Accepted because the following questions are material to the module design and have not yet been resolved:
Q1 — Storage location (SD01 vs SD07): Should the extension field store live in the core database (bank-core / SD01) alongside the entities it extends, or in a separate platform database (bank-platform / SD07) as a cross-cutting concern? SD01 co-location gives referential proximity; SD07 separation keeps the core schema clean and avoids a SD07 → SD01 dependency direction.
Q2 — CDC and Snowflake treatment: How should extension field values flow to Snowflake? If stored in SD01, they are captured by the existing CDC pipeline (ADR-003). If stored in SD07, a separate CDC configuration is needed. Extension fields that become analytically important (e.g., a new risk classification field) may need promotion to a proper schema column in Snowflake rather than landing as a generic JSON blob.
Q3 — Privacy and data classification: Custom fields on the party entity may carry PII. The privacy-by-design standard (ADR-004, PRI-* policies) requires that PII fields are identified and handled with appropriate retention, access control, and DSAR coverage. Field registration in MOD-169 should require a data classification tag; PII-classified fields should trigger additional controls.
Q4 — Scope boundary: The v1 scope proposed is party entity only. Account and product entity extension deferred to v2. Is this the right boundary, or should product extension fields be included in v1 given the product launch use case?
Next step¶
This ADR advances to Accepted once the four open questions are resolved with a decision recorded in the Consequences section. The CTO, Head of Architecture, and Head of Data are the decision-makers.
Consequences (to be completed on acceptance)¶
- MOD-169 is added to the delivery plan in the system domain to be determined.
- The entity schema (
schema.py) gains anextension_fieldsfield onModuleSpecto allow modules to declare which entity types they extend. - PRI-* policies are reviewed to ensure DSAR and retention coverage applies to extension field values.
- Snowflake schema conventions (ADR-054) are updated to address CDC treatment of extension field tables.
All ADRs
Compiled 2026-05-22 from source/entities/adrs/ADR-060.yaml