Skip to main content

The DFE Control-Plane Layer

The control-plane layer is the small set of repos that own the DFE control plane - configuration, RBAC, schema, the operator UI, and the deploy target. When a doc says "the control-plane layer" it means exactly these repos. Anything that interacts directly, or one level removed, with the dfe-engine API or what it does is reasoning about this layer.

The layer​

RepoRole in the layer
dfe-engineThe config control plane + the sole authorisation PDP. Hosts the FastAPI API and the generated dfe CLI. Everything else in the layer keys off its API.
dfe-schemasThe schema SSoT (common event header, hunt-results DDL, profiles). The engine reads it (the version-pinned dfe-schemas wheel) and auto-creates from it.
dfe-uiThe operator console. A window over the engine API - it holds no authority of its own; it verifies the engine-minted JWT.
dfe-infraThe GitOps SSoT and deploy vehicle (Argo CD). Deploys the suite; never a config authority.
dfe-deployThe per-deployment read-write gitops repo the running engine commits to. We own only its initial state; after handover the deployment owns it.

The controlling SSoTs​

The layer is organised around a handful of single sources of truth. The SSoTs are how everything works: each holds one kind of authoritative state, every other component reads from it (or from a generated artefact of it), and each has exactly ONE write path - so a change is auditable and consumers can never diverge.

SSoTLives inConsumed byOnly written by
API surface - openapi.jsondfe-engine openapi-spec/dfe CLI, dfe-ui types, dfe-ai, contract mock, reference docsthe FastAPI routes via generate.py (never hand-edited)
Schema - event header, hunt-results DDL, profilesdfe-schemas (the dfe-schemas wheel, pinned in uv.lock)the engine (auto-creates the CH objects at startup), the CLI, dfe-uidfe-schemas commits
Deployment shape - Helm charts + valuesdfe-infra helm/ (base charts) + the deploy-repo overlaysArgo CD, the clusterbase charts by dfe-infra; the overlays by the engine, one values/<service>-<instance>-values.yaml per app instance, each write a gitops commit. Where no chart runs (Compose), appmgmt/appconfig.py merges an overlay's config: over the deployment's base config into the app's config file
Deployed state - the gitops YAMLdfe-deploy (per deployment)Argo CD (syncs to the cluster), the engine (reads current state)the engine API - every mutation is a git commit (governed ops); dfe local break-glass when the daemon is down
AuthZ - RBAC roles + scopesdfe-engine auth/ (YAML)the API (require_action), the CLIthe engine (governed writes)

To change any of them you go through its one writer: edit the API routes and regenerate the spec, commit to dfe-schemas, turn the engine's dials (which writes Helm values + gitops state as commits), or edit the RBAC YAML. Never hand-edit a generated artefact (openapi.json, compiled Helm values) - change the source and let it regenerate. The next section walks the openapi.json case in full as the worked example.

dfe-engine, never "dfe-api"​

The API is the dfe-engine API. dfe-api was the old server entry-point name and is retired: the daemon binary is now dfe-engine (dfe-engine run), the human CLI is dfe. Anything talking to the API is talking to the dfe-engine API -- do not call it "the dfe-api". (The DFE_API_* env prefix stays, purely to keep settings resolution and the Helm chart stable.)

openapi.json is the API SSoT​

openapi-spec/openapi.json is the single source of truth for the API surface. It is generated from the FastAPI app (uv run python openapi-spec/generate.py) and committed. Every consumer keys off it, never off a hand-maintained copy:

The spec is the hub; everything radiates out of it. The FastAPI routes feed it, and every downstream consumer keys off it - never off a hand-kept copy:

  • The dfe CLI generates its whole command tree from the spec at runtime - add an endpoint and the CLI grows a command, with no CLI code. An endpoint opts out via the x-cli extension.
  • dfe-ui generates its TypeScript types from the same spec.
  • dfe-ai (the peer service) reads the spec for its client + MCP tool schemas.

So when the API changes: change the routes, regenerate openapi.json, and every consumer follows. Never edit openapi.json by hand or let a consumer drift from it.

What is NOT in this layer​

  • dfe-ai is a peer service, not control-plane - a single modular service (all AI capability + an MCP layer in one deployable, sharing the scalo foundation with the engine). It is a compute peer the control plane orchestrates; it owns no config and calls the engine API for data. See the dfe-ai service spec.
  • The data-plane repos (receivers, loaders, transforms, fetchers, archiver, hunt-runner) are downstream services the control plane configures - not part of it.

Documents in this area​

DocCovers
governed-ops-design.mdGitCrud + governance layer + curated actions
gitops-commit-standard.mdmachine-commit conventions for gitops repos
oidc-rbac-architecture.mdOIDC + RBAC SSoT - auth model, the two RBAC planes, provider registry + adapters, management API, infra requirements, test emulation
rbac.mdauth paths, RBAC model, multi-tenant ClickHouse, stores
rbac-sign-in.mdidentity resolution, the sign-in allowlist, first login and password changes
rbac-groups.mdIdP group sync, linking a group to an IdP group, the checks on a link
rbac-engine-reads.mdthe engine's own ClickHouse reads and how they bind to a caller's orgs
idp-setup/ -- google.md, entra.md, okta.mdone-time setup for a customer's IdP admin -- sign-in client, groups, the values to send the operator
rbac-vocabulary.mdSSoT for role + group names and terms across engine, ui, infra, deploy, schemas and test envs
synthetic-data.mdsynthetic data generation - reference packs, lookalike scrub, standing demo streams
ui-api-guide.mdfrontend integration guide (endpoint reference)
type-safety-sync.mdOpenAPI + RBAC-scope typegen sync to dfe-ui
dfe-cli-design.mdthe dfe client CLI design (AWS CLI v2 model)

The system map is ../architecture.md.