Control Plane
The control plane manages multi-tenant brand configuration, event ingestion, and reliable dispatch into Temporal.Multi-tenancy
Auth runs in one of three modes via
CONTROL_PLANE_AUTH_MODE: required (the default),
optional, or disabled.
Outbox and DLQ
Events flow through a transactional outbox so delivery survives crashes and Temporal outages:- Event ingested, validated, inserted into
workflow_dispatch_outbox. - Dispatcher claims a batch of pending rows using
SELECT FOR UPDATE SKIP LOCKED. - For each, it generates a deterministic workflow ID (SHA-256) and dispatches to Temporal.
- On success, the row is marked
dispatched. - On failure,
attempt_countincrements and the row retries with backoff. - After
max_attempts(default 20), the row moves toworkflow_dispatch_dlq. - Operators can list, retry, or resolve DLQ items via the API.
The deterministic workflow ID is what makes redelivery safe: a duplicate event resolves to the
same Temporal workflow ID, so it dedupes rather than starting a second run.
SELECT FOR UPDATE SKIP LOCKED lets multiple dispatcher instances coexist without
double-claiming β though the deployment runs a single dispatcher with a maxUnavailable: 0
disruption budget.
Progressive migration
Brands move from legacy systems to the engine through routing modes rather than a cutover:
Stable hashing by
brand_id means a given brand stays on the same side of a canary split
between runs, rather than flapping.
Brand configuration API
Brand config is versioned, with draft/evaluate/apply rather than direct mutation:Brand lifecycle
Billing endpoints cover contracts, periods, rated outcomes, reconciliation, and sync under
/v1/brands/{id}/billing.
Task queue and workflow scoping
Two allow-list pairs constrain what a brand binding may target:
Without an explicit allow-list, the workflow name must match the bindingβs
template_key.
Database schema
PostgreSQL, with migrations undermigrations/control-plane/. The initial migration creates
tenants, brands, workflow_templates, policy_sets, connector_bindings,
brand_workflow_bindings, brand_policy_bindings, brand_config_versions,
idempotency_keys, event_ingestion_log, and brand_migration_ledger; later migrations add
workflow_dispatch_outbox and the DLQ.
Run migrations with: