ADR-043: Standardised repository and module directory layout¶
| Status | Accepted |
| Date | 2026-04-24 |
| Deciders | CTO, Head of Platform |
| Affects repos | bank-core, bank-kyc, bank-aml, bank-payments, bank-credit, bank-risk-platform, bank-app, bank-platform |
Status: Accepted — 2026-04-24
Context¶
Eight code repositories implement the platform. Each maps to one system domain (SD01–SD08). As the first modules were built independently, three structural inconsistencies emerged that will cause CI/CD failures and confuse Claude Code sessions:
- Test runner: bank-platform uses Jest; bank-core and bank-kyc use Vitest.
- Test directory naming:
__tests__/(bank-platform),tests/(bank-core),test/(bank-kyc) — three different conventions in three repos. - SST configuration scope: bank-platform and bank-core use per-module
sst.config.ts; bank-kyc uses a single rootsst.config.tsthat imports all module infra, creating a single shared stack for the entire repo.
Additional inconsistencies: bank-kyc uses npm; bank-platform and bank-core use pnpm. bank-kyc's root SST app is named bank-kyc rather than per-module.
These inconsistencies break the reusable CI/CD workflows (MOD-156, FR-733/FR-734), which assume pnpm install, pnpm test:unit, and pnpm run deploy run inside the module directory. They also mean Claude Code sessions in each repo receive different implicit conventions, leading to sessions inventing their own structure rather than following a consistent one.
Decision¶
Standardise all eight code repositories on a single layout. The canonical structure is documented in full at Repo and module structure.
Key decisions:
1. One repo per system domain, multiple modules as top-level directories.
Each module occupies a MOD-NNN-{slug}/ directory at the repository root. There is no further nesting (no modules/ parent directory). This is already consistent across all three existing repos and is confirmed as the convention.
2. pnpm as the package manager, with pnpm workspaces.
pnpm is used by bank-platform and bank-core. bank-kyc is on npm and must migrate. pnpm-workspace.yaml at the repo root declares packages: ["MOD-*"]. The root package.json declares "packageManager": "pnpm@9.12.0". This is required by reusable-lambda.yml and reusable-iac.yml, which run pnpm/action-setup and pnpm install --frozen-lockfile.
3. Vitest as the test runner.
Vitest is used by bank-core and bank-kyc. bank-platform's existing built modules (MOD-043 through MOD-097) keep Jest and are not migrated. All new modules in all repos use Vitest. Each module owns a vitest.config.ts that scopes coverage to unit-testable files.
4. tests/ as the per-module test directory, with four standard subdirectories.
The canonical layout is tests/unit/, tests/integration/, tests/policy/, tests/contract/. tests/unit/ and tests/integration/ are required for all Lambda and hybrid modules. tests/policy/ is required for any module with policies_satisfied entries; one test file per policy row. tests/contract/ is required for any module that publishes or consumes EventBridge events; one test per event schema. IaC-only modules require tests/integration/ only.
5. Per-module sst.config.ts inside the module directory.
Each module is an independent SST app. The SST app name follows the pattern {repo}-mod-{NNN} (e.g. bank-core-mod-001, bank-kyc-mod-009). This isolates deployment blast radius: deploying MOD-002 cannot affect MOD-001's stack. bank-kyc's root sst.config.ts must be split into per-module configs as each module is built.
6. infra/ for IaC code, src/ for Lambda handler code.
Application modules keep Lambda handler and service logic in src/, with subdirectories src/handlers/, src/services/, src/lib/, src/types/. Infrastructure (SST resources, Pulumi components) lives in infra/, with subdirectories infra/index.ts, infra/api.ts, infra/functions.ts, infra/ssm-outputs.ts. bank-platform's existing modules use src/stacks/ for IaC; new bank-platform modules use infra/.
7. docs/design/MOD-NNN.md at the repo root.
Required by reusable-iac.yml, which reads this file to extract and verify SSM output paths after deploy. All modules produce this file. IaC modules must include an SSM outputs table. Lambda modules document handler contracts and observability schema.
8. docs/handoffs/MOD-NNN-complete.handoff.md at the repo root.
The standard handoff path. The wiki's handoff processor expects this location.
Alternatives considered¶
Option A — bank-platform defines the standard and hands off. Rejected. bank-platform is one of eight peer repos. Designating it as a governance authority over the others creates a dependency chain: every structure change routes through bank-platform first, then propagates to seven other repos. The CI/CD tooling (MOD-156) should implement the convention, not own it.
Option B — leave repos inconsistent, rely on per-repo CLAUDE.md.
Rejected. Three repos already have three different test runner conventions after only one module each was built. The reusable-lambda.yml workflow hardcodes pnpm install and pnpm test:unit; bank-kyc's npm and its root SST config would silently fail in CI. Inconsistency is already causing damage; it compounds with every new module.
Option C — migrate bank-platform's existing Jest modules to Vitest. Not adopted for existing modules. bank-platform's built modules (MOD-043 through MOD-097) are working and their test suites are complete. Migrating them from Jest to Vitest provides no functional benefit and risks introducing regressions. The standard applies to new modules. The inconsistency is documented and bounded.
Consequences¶
Immediate:
- bank-kyc must migrate to pnpm and per-module sst.config.ts before the next module (MOD-010) is built. The existing MOD-009 module should be migrated as part of that setup.
- generate-workflows.py (bank-wiki, FR-735) uses pnpm as the assumed package manager. No change needed.
- reusable-lambda.yml comment references jest.config.js — this should be updated to be test-runner-agnostic (the step calls pnpm test:unit --coverage which works for both runners via the module's package.json scripts).
Ongoing:
- Every new module in every repo must follow the layout in Repo and module structure.
- Claude Code sessions in each repo read CLAUDE.md at startup. Each repo's CLAUDE.md references this ADR and the structure page. Sessions that invent their own structure violate the ADR.
- New system domains (SD03–SD06, SD08) start with the pnpm + Vitest + per-module SST layout from day one. No migration debt.
All ADRs
Compiled 2026-05-22 from source/entities/adrs/ADR-043.yaml