ADR-0007: The bank's definition is a module of its own

Status: Accepted Date: 2026-10-10, accepted 2026-10-11 Stage: ADR-0002 stage 8 (roadmap 1.8), stories 1.8.2, 1.8.4 and 1.8.5 (renumbered 2026-10-11: 1.8.3, 1.8.6 and 1.8.7)

Context

gobank is becoming a general banking solution: a ledger, a general ledger, customers, payments, users, a BFF and the product contract of ADR-0006. What makes the running demo this bank is scattered through it: the catalogue is a list in bank/products, the blurb for each product beside it, the name "Model Bank" in the demo, the base-rate series in the simulation. A second bank, a white label on the same capabilities, would be a fork.

Decision

One Go module per bank entity holds everything that makes the general solution this bank, as code. gobank holds the capabilities; a running bank is gobank opened with one definition; another bank is another definition module over the same capabilities.

In the definition In the capabilities (gobank)
The bank's name the ledger, the GL, customers, payments, users, the BFF and apps
The product versions it carries at one time, in catalogue order, each with the bank's blurb and whether it is withdrawn from sale: the catalogue and its migration data, release by release the product contract (gobank-products), the runner, the adoption record
Its policy: the savings and lending base rates derived from the market rate, their spreads and lags (ADR-0006, story 1.8.4, now 1.8.6) the parameters component that stores settings and resolves them
Its own products, once a product is the bank's rather than the library's (story 1.8.5, now 1.8.7) products a bank shares with others
Customisation that overrules defaults as it arises: data lifetime, security settings the defaults

The shape today is bank/definition.Bank (name, product listings) and the package modelbank in gobank that implements it for the Model Bank; bank.Open takes the definition and refuses to open without one. The package becomes the module modelbank, in its own repository, in story 1.8.4 (now 1.8.6) when the policy joins it: a module with one product list and no policy is not yet worth a repository.

Ownership and cadence

The definition module is a separate repository with a release cadence of its own, because it is the client bank's: its staff and engineers change it, not gobank's maintainers, and they change it on their timetable (a product launched, a policy revised) rather than gobank's. gobank is released by its maintainers and taken up by a bank when it chooses.

The interface

What the two repositories share is therefore a contract that must stay stable across many gobank releases:

Surface Lives in Used by the definition to
bank/definition.Bank and products.Listing gobank say what the bank is and carries
gbp.Version, Facts, Intents, Declaration (ADR-0006) gobank-products write the bank's own rules versions and policy
bank.Open and its options gobank run

Rules for it: a change is additive, a new field or method with a default, never a removal or a change of meaning in a minor release; a removal is deprecated for a release first and named in the changelog; the definition pins the gobank and gobank-products versions it was built against and declares the oldest it supports; gobank's own test suite builds against the Model Bank's definition at that oldest version, so a break is found by the maintainers, not the client. Anything the definition needs that is not on this surface is a change to gobank, released first, and a bank waits for it.

Release or setting

Not everything about the bank is a release. The parameter tree (ADR-0006) is run-time configuration: a rate, a spread, a lag, an allowance, a term is changed by a setting, decided for a day, with no release. Rules are code, and a change to rules is a tested release: a new rules version in gobank-products or in the bank module, and the definition carrying it. Between the two sits the product itself: a product is an instance of a tested rules version with its own name and its own parameter values. A new fixed-rate saver with a different term is the same rules with another term, and that is configuration, not a release: the bank creates it, names it, sets its parameters and later withdraws it through the parameters it already has.

Change How Who
A rate, a spread, a lag, an allowance, a term a setting, effective from a day the bank's staff, through the parameters
A new product on existing rules: another term, another rate, another name a product instance created in the catalogue, its parameters set the bank's staff
A product withdrawn from sale the instance withdrawn the bank's staff
New or changed rules: a new event answer, a new derivation, a new parameter a rules version, tested, released; the definition lists it engineers, a release
The definition's own contents: name, the rules it carries, the policy, the overrides the module, released engineers, a release

The definition therefore carries the bank's initial catalogue and the rules versions it is allowed to instantiate; what the bank has done with them since is in the database, as every other setting is.

Amendment, 2026-10-13 (story 1.8.9)

The definition carries the policy: definition.Bank.Policy, a gbp.Policy, which the bank refuses to open without. The Model Bank's is modelbank/policy/v1, and the bank is named the Isle of Alba Bank. The package modelbank is still in gobank at this story. The direction for its move, decided 2026-10-13: a bank is a top-level module that imports gobank (the capabilities: bank, bff, core) and gobank-products (the contract) and adds its definition and its wiring, so that most of this code is taken as a library and wrapped to make a bank. gobank-products stays the contract and the support for writing rules and policies, not the home of a definition. gobank's own tests build against test definitions of gobank's own, not the Model Bank's, so no module depends back on a bank.

The interface rules above ("a change is additive … never a removal or a change of meaning in a minor release") apply from version 1. While the code is pre-1.0 the interface may be restructured as the stories need; once it is stable and 1.0 is released, normal Go module rules apply and the contract stays stable until a major version change.

Consequences

Easier: a white label is a module; a product change is a diff in one place; the capabilities are tested against more than one definition (stage 9's scenario tests build a definition each).

Harder: an interface that must be kept stable and widened only additively, which slows gobank's own refactoring where it touches the definition's surface; a change that needs both repositories is released in order, gobank first, and the bank waits; the definition's module version becomes part of what a deployment names; ADR-0006's product identity moves out of the rules package into the catalogue (its amendment there).

Given up: a product list that can be read off the definition alone. The definition says what the bank started with and what it may build products from; the catalogue in the database says what it sells today.