Skip to main content

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.
disabled removes tenant scoping from API requests. It exists for local development β€” never set it on anything reachable from outside your machine.

Outbox and DLQ

Events flow through a transactional outbox so delivery survives crashes and Temporal outages:
  1. Event ingested, validated, inserted into workflow_dispatch_outbox.
  2. Dispatcher claims a batch of pending rows using SELECT FOR UPDATE SKIP LOCKED.
  3. For each, it generates a deterministic workflow ID (SHA-256) and dispatches to Temporal.
  4. On success, the row is marked dispatched.
  5. On failure, attempt_count increments and the row retries with backoff.
  6. After max_attempts (default 20), the row moves to workflow_dispatch_dlq.
  7. 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:
evaluate-golden runs a draft against a known-good case set before you apply it. Use it as the gate on config changes β€” it’s the difference between finding a regression in evaluation and finding it in production traffic.

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 under migrations/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: