Part 4 · 2 chapters · ~20 min
Regulatory Variance
The adapter pattern for regulators: one core interface per regulated concern (identity, limits, reporting, consent, inspection) with an adapter per country and a boundary the tooling enforces, and KYC per market as one journey: a closed vocabulary of step kinds, adapter declarations, what stays core, reason-code mapping and the tests per fixture.
9
The regulator lives in an adapter
one interface per regulated concern
- Identity verification: the core's interface is the Trust course part 2's state machine (start, submit a step, get state); the adapter talks to the country's provider and declares its steps, including an optional in-person stage the core's state machine supports.
- Limits and thresholds: the core asks the rules engine (part 2) with the country's rule set; a regulator's limit is data with an effective-from date, authored by the country team with compliance. No number like 5,000,000 lives in the core.
- Reporting: the core emits events (the CBA module's event log); a reporting adapter per country applies thresholds and formats and files with the regulator; the client shows the user only what the regulation requires.
- Consent and disclosures: the config names them, the catalogue holds the text per locale, the core renders a disclosure step whenever one is listed for the action, the audit records what was shown and agreed (the Trust course part 0). A new disclosure is a config and catalogue change.
- Inspection: every config and rule-set version with effective dates, the disclosure and authorisation audit per action, the event log; an adapter formats the inspection response. A platform that cannot answer "what rules applied on 3 March" fails the inspection.
- The boundary, enforced: a lint and a dependency rule (the Architecture course part 0) forbid the core importing an adapter or containing a regulator's, country's or provider's name; adapters are selected by config; a country-specific branch in a core PR fails review (part 7). Mechanical, because the deadline is always one country's.
THE REGULATOR LIVES IN AN ADAPTER
one core interface per regulated concern, an adapter per country, and the core never knowing a regulator's name
swipe the figure sideways, or tap expand for full screen
1/6
identity
Identity verification: the core's interface is startJourney(tier), submitStep(step, data), getState(): the Trust course part 2's state machine. The Nigerian adapter talks to a provider that verifies a national ID number against the registry and does liveness; the Kenyan adapter uses a different provider and documents; the Egyptian adapter requires an in-person step the others do not (an optional stage the core's state machine supports). The core renders the journey from the adapter's declared steps.
10
KYC per market, one journey
three countries, one component
- A closed vocabulary of step kinds the core supports: personalDetails, document (with a type list), selfie (active or passive liveness), addressProof, sourceOfFunds, inPerson, additionalId, consent. An adapter composes its journey from these; a missing kind is a core change through design review.
- Three compositions: Nigeria (details, document from NIN/passport/licence, active selfie, consent; automatic review); Kenya (details, document, a KRA PIN for tier 3, passive selfie, consent); Egypt (details, document, selfie, an agent visit for tier 2 and above, consent; manual review always). Different journeys, the same code.
- The adapter's declaration: steps, documents with capture modes, the liveness method, tiers with their requirements and limit rule ids, review expectations. The core renders the picker, the capture flow, the liveness prompt, the tier screen and the review copy from it; the provider calls live behind the adapter's submit.
- What stays core: the state machine and resumability, the capture UI and on-device checks, the honest review states, the rejection-to-action mapping, the tier screen, the telemetry: the hard parts of KYC UX (the Trust course part 2), shared by every country for free.
- Reason codes: each provider's rejection codes mapped by the adapter to the core's vocabulary (DOC_BLUR, DOC_EXPIRED, NAME_MISMATCH, LIVENESS_FAIL, SANCTIONS_HIT), which the core maps to an action and a step, with copy from the catalogue. A new provider is a new mapping, not new screens.
- Testing the variance: a fixture per adapter with every reason code; the journey rendered per fixture in the component suite asserting steps, documents, copy and rejection paths; visual tests per country and locale; contract tests against each provider's sandbox (the Architecture course part 2), because providers change APIs without telling anyone.
the exercise
Write the step list for your product's verification journey in a second country you do not serve yet. Every step kind you need that the vocabulary lacks is a core change to make now; every provider call that is not behind an adapter is a fork.
KYC PER MARKET, ONE JOURNEY
how three countries' verification requirements become one state machine with declared steps
swipe the figure sideways, or tap expand for full screen
1/6
the vocabulary
The vocabulary of steps the core supports: personalDetails, document (with a document-type list), selfie (with a liveness method: active or passive), addressProof, sourceOfFunds, inPerson (an appointment or an agent visit), additionalId (a second number: a tax id, a social security id), consent. An adapter composes its journey from these; a step kind the vocabulary lacks is a core change (rare, and a design review).