How BDI fits together
Three small services, a handful of shared packages, and one strictly-enforced rule about which way dependencies are allowed to point. This page is the visual sketch — for the long-form deep-dive, head to docs/ARCHITECTURE.
§1The fastest way to look around
If you'd rather click through the system than read about it, the interactive explorer is the better starting point. You can run animated flows for member onboarding, BVAD / BVOD issuance, webhook delivery, and cross-association federation, and see exactly which messages cross which boundary.
§2ASR — the membership office
The ASR governs who is allowed to participate. Two core aggregates carry the weight:
Member— onboarding, KvK / KBO / GLEIF / VIES verification, signing-representative eHerkenning check, 4-eyes approval, and the full status state machine.Connector— registration, kid/JWK binding, X.509 certificate-thumbprint pinning, and status transitions.
The ASR issues the BVAD (Bewijs van Associatie-Deelname) to connectors against RFC 7523 client assertions, signs the trustlist for the association, and performs RFC 8693 token exchange with federated peer associations.
§3ORS — the choreographer
The ORS governs what's happening right now in a chain. Its single aggregate is:
ChainContext— identifiers (BOL, AWB, …), parties and their roles, delegations, and role-bound natural persons (stored as SHA-256 pseudonyms; never as PII).
It issues the BVOD (Bewijs van Orkestratie-Deelname), scoped to a specific (context, subject connector) pair, and pushes events to subscribed connectors via Valkey Streams.
§4CON — the doorman at each member
The connector runs alongside each member's application. It handles a full token-verification pipeline on inbound traffic, dispatches outbound webhooks with backoff, acts as a reverse proxy for legacy upstreams, and supports pluggable PDP adapters (Cedar / OPA / Keycloak-Authz). Critically, every allow/deny decision happens locally — neither register sees payloads.
§5Shared packages
The shared packages aren't just utility code — they're where the protocol itself lives. Anything that has to look identical between services goes here, so it can never drift.
| Package | Responsibility |
|---|---|
@transportial/kernel | Result, branded types, EUID/LEI/VAT/KvK parsers, JWK & thumbprint helpers. |
@transportial/contracts | Wire schemas for BVAD, BVOD, trustlist, member descriptor. |
@transportial/crypto | BDI JWS profile, RFC 7523 verifier, key generation, HSM/PKCS#11/step-ca. |
@transportial/crypto-ca | RFC 8555 ACME server + client, CSR parser, X.509 issuer, OCSP, CRL. |
@transportial/identity | Keycloak OIDC verifier, eHerkenning SAML broker, AuthnPort. |
@transportial/events | Typed events, Valkey Streams consumer, rate limiter, scheduler. |
@transportial/policy | PDP port + embedded Cedar-like engine + external adapters. |
@transportial/config | Env parsing, *_FILE secrets, SIGHUP hot-reload, migrations, RLS, YAML. |
@transportial/observability | Structured logs, metrics registry, trace context, OTLP exporter. |
@transportial/openapi | OpenAPI 3.1 document builder used by scripts/generate-openapi.ts. |
§6Three planes, one mental model
A useful way to keep all of this in your head: think of BDI as three horizontal bands. The interactive explorer draws them exactly this way.
- Trust plane — the ASR and its satellites (IdP, registries, CA, peer ASR). This is where identities are established.
- Orchestration plane — the ORS and its subscriptions. This is where chain contexts are set up.
- Data plane — connector-to-connector traffic plus the outbound upstreams. This is where actual payloads flow.
Tokens issued in the trust plane (BVAD) and the orchestration plane (BVOD) are what the data plane verifies. The runtime data plane stays ignorant of identity providers and registries — all it needs is the ASR's trustlist and the ORS's public keys.