Appearance
Bounded contexts
This is the domain-model family of the Explanation quadrant. Each page explains a single bounded context — its ubiquitous language, aggregates, invariants, state machines, and the seams it exposes to other contexts — so you understand why the model is shaped the way it is. For the wire shape of a context's HTTP surface see reference; for a task against it see how-to. The layout under internal/<context>/ mirrors this tree page-for-page, and the depguard rules in .golangci.yml enforce that one context does not reach into another except through the documented seams.
Context groups
- Identity — bootstrap tokens, registration, tenancy (
Domain → Project → Resource → Node), IdP bindings, ReBAC, invitations, and groups. Start with tenancy for the aggregate model, thenbootstrap-tokens,registration,idp,rebac,invitations, andgroups. The dual-control approvals sub-context layers a generic approval-workflow gate on top — propose → approve / reject / break-glass / expire — keyed on a per-Domain ApprovalPolicy. - Mesh — peer manager, per-Node reachability, the reconciliation pull surface, the signed event bus, and the per-Node node-state store. Start with peers, then
reachability,reconciliation-pull, andsse. The Node State Service owns the per-Node key/value State Entry aggregate — the platform-ownedmetadataanddataentries that fan out anode_state_updatedevent and the upstream, NSK-authenticatedreportentries a workload on the Node pushes back — and is the source the reconciliation pull projects itsstateandreportssnapshot blocks from. - Policy — the Network Policy Engine authoring surface, the per-Node Policy Compiler, the closed two-event outbox set and the per-Node SSE fan-out, and the per-Node Capability Manifest ingest pipeline that captures the agent-side snapshot of "what binary am I running, what hooks do I advertise, what host key am I presenting" and emits the diff downstream consumers correlate against. Start with
modelfor the Policy aggregate and L3/L4 rule grammar, thencompilerfor the per-Node projection,eventsfor the publisher-side dispatch table and per-Node fan-out, andcapabilitiesfor the agent-side manifest ingest surface, its NSK-authenticated transport, the exhaustive Problem code catalogue, and the single-transaction diff & event contract,integrityfor the agent-side IntegrityViolation ingest surface, the three-by-three violation taxonomy (binary_checksum/hook_checksum/ssh_host_key×startup_scan/inotify/pre_dispatch), the batched persist-and-alert contract, and theintegrity_alertoutbox event that fans out per-Domain through the denormalised(Node, Resource, Project, Domain)quartet, andhooksfor the discovery-only projection of Kubernetes PlexdHook custom resources onto the Node'splexd_hookscapability-manifest list (name, image digest, parameters, timeout, sandbox) — read-only, so plexsphere never writes them back, resolves no registry digest, and never schedules or executes a hook — plus the hook-integrity gate layered on the advertised-hook catalog: a trust-on-first-use known-good baseline pinned per(Node, hook)at capability ingest, the driftintegrity_alert(kinds["hook_checksum"], recommended actionquarantine_node), and theVerified/Drift/Uncataloguedverdict the Action Orchestrator consults to refuse a drifted or uncatalogued hook dispatch with a409 hook_integrity_violation. - Bridge — the Bridge Orchestrator: the orchestrator configuration a Resource of kind
bridgecarries, modelled as four independent aggregates rather than one mega-aggregate so each invariant stays inside its own transaction boundary and the four lifecycles operators manage separately stay decoupled.BridgeRelayis the singleton relay configuration of a bridge Resource (keyed on the Resource alone, no surrogate id);UserAccessProvideris a named WireGuard-family mesh-ingress provider end users dial in through;PublicIngressRuleis an SNI-routed public ingress termination forwarding to a target Node; andSiteToSiteTunnelis a directional tunnel to a remote endpoint carrying its allowed-subnets list. Every mutation first reads the target Resource and refuses unless its kind isbridge, and the context emits a closed set of seven past-tense outbox events (*Configured/*Removed, the singleton relay having only a configured form) pinned by an AST gate; every auth secret a provider or tunnel consumes is held as an opaque reference, never as material. Seebridgefor the aggregate model, the invariants, the event set, and the secret-reference posture, andbridge/validationfor the cross-aggregate validation pipeline (host-port, subnet-overlap, and ACME-feasibility refusals). - Actions — the Action Orchestrator: one dispatch of a named action (a
builtinshipped with the Node agent, or a user-declaredhook) across a cohort of Nodes, modelled as a singleExecutionaggregate whose per-NodeActionInvocationentities each advance independently along the closed status state machine (pending → ack → started →one ofsucceeded/failed/cancelled, with atimeoutedge from every non-terminal status). A dispatch resolves its cohort from a singlenode_idor an opaque labelselector, applies per-node domain-isolation / ReBAC-act/ capability / hook-integrity gates (refusing a drifted or uncatalogued hook with a409 hook_integrity_violation), and fans out to one invocation per surviving Node, persisting the header, the N targets, and the N outbox events in one transaction. The collected output rides a two-tier contract — bounded inline bytes (≤ 16 KiB) stored in the control plane, or a presigned object-store PUT for an over-ceiling body. A per-Domain live-execution cap, a background timeout reconciler, and a closed single-member outbox set (actions.ActionDispatched, pinned by an AST gate) round out the model. Seeactionsfor the aggregate, the invocation state machine, the two-tier output contract, the survivor-precedence rules, the ReBACactmatrix, the audit contract, and the Problem-code catalogue, andactions/eventsfor the closed-outbox-vs-wire-literal split, theaction_requestpayload, and the per-Node SSE fan-out. The context is one of the four sanctioned consumers of the Label Registry'sSelectorPortseam — it expands "dispatch to every Node matching<selector>" into the concrete Node set ataction_requesttime (seelabels). - Access — the Access Orchestrator: it mints short-lived, signed session credentials (EdDSA JWTs) for
ssh/k8s/tcpaccess to a Resource's Nodes, modelled as a singleSessionaggregate that carries the kind, a per-KinddiscriminatedSessionTarget(an sshuser+ optional command allow-list, a k8suser+ optional impersonation groups, or a protocol-opaque tcphost:port), the issuing Domain / Project, the target Resource, the requesting Identity, and the TTL / idle / expiry envelope, with the per-Sessionjtipinned to the SessionID so revoking the Session revokes its token. Issuance runs aresource#actReBAC check as a hard gate, enforces the per-DomainSessionPolicy(clamping the requested TTL to the Domain's MaxTTL, applying the three concurrency caps and the issuance rate limit, and running the step-up acr/amr/freshness gate), signs the deterministic canonical-claims JWT through the per-Domain Signing Service key, and persists the metadata-only aggregate plus its outbox event in one transaction — the assembled token never rests in the control plane. Revocation is instant: it appends a row to thejtirevocation list and fans out the revoke rather than waiting for the token to expire, and a background sweeper revokes expired and idle Sessions through the same path. The two domain events route onto the closedsession_setup/session_revokedSSE wire literals so a target plexd provisions or tears down a session immediately, and the per-kindaccess_session_eventcallbacks (sshcommand_executed/command_exited, k8sapi_request, tcpsession_started/session_ended) reset the idle timer from the authenticated target. Seeaccessfor the Session aggregate invariants, the per-Kind SessionTarget, the JWT canonical-bytes contract and its alg-confusion-proof verifier, the SessionPolicy snapshot, the issuance state machine, the audit relations, and the step-up contract. - Secrets — the Secret Store: the real-time NSK-rewrap proxy that delivers Project-scoped secret material to Nodes over
GET /v1/nodes/{id}/secrets/{name}without ever exposing plaintext. It is the platform's only meet-and-rewrap point between the OpenBao backend and the per-Node Node Secret Key (NSK): the read path reconstructs the NSK plaintext, reads the backend, rewraps the payload under AES-256-GCM in-process with a fresh nonce, and returns only NSK-wrapped ciphertext — plaintext is never persisted, logged, or placed on the event bus. Every read runs a ReBAC hard gate onsecret:<id>#read, is audited on grant and denial, and is throttled by per-Node and per-Domain token buckets; the companionnode_secrets_updatedevent fans a names-and-versions-only inventory delta out over the Signed Event Bus so a Node re-fetches changed values without the bus ever carrying secret bytes. Seesecretsfor the Secret aggregate, the rewrap pipeline and its plaintext-never-persists invariant, the audit contract, the rate-limit policy matrix, and the threat model. The read side pairs with the write-side OpenBao Credential Broker underprovisioning/credentials. - Observability — the Observability Ingest pipeline: the per-Node front door for plexd telemetry over three NSK-authenticated batch-ingest endpoints under
/v1/nodes/{id}— metrics routed to Grafana Mimir, structured logs and normalised audit events routed to Grafana Loki. The front door admits each batch (structure, encoding, size, and per-batch record caps), quota-gates it against a byte-weighted per-Node and per-Domain budget, and hands the survivor onto a per-signal JetStream buffer stream where the Domain, Project, and Node identity rides the subject and a header rather than the record body. Records are tagged server-side and de-personalised — the wire body never carries an identity subject or email, so dashboards and alerts scope through the platform label model and PII a record inadvertently carries stays the customer's ingest-side responsibility. Seeingestfor the ingest aggregate, the admission and quota gates, the buffer-stream subject grammar, the auditednode_id_mismatchself-check, and the Problem-code catalogue. The egress half drains the three per-Domain JetStream buffer streams and fans each batch to its downstream sink — Grafana Mimir (metrics, Prometheus remote-write), Grafana Loki (logs + audit), and the audit SIEM — through five durable consumers with deterministic capped redelivery backoff. Seeroutingfor the sink mapping, the consumer topology, the error classification, and the routing metrics. - Artifacts — the Artifact Registry: indexed plexd release records the control plane verifies before serving. It consumes the upstream OCI release stream (one image index per version, one image per architecture carrying the binary checksum and a Sigstore bundle), runs every artifact through a staged gate pinned to the upstream Fulcio SAN and OIDC issuer, indexes only whole-version-verified records, and serves them over two read endpoints (
GET /v1/artifacts/plexd/{version}and its.sigstorecompanion). Seeartifactsfor the PlexdRelease aggregate, the verify-or-reject invariant, the verdict-as-timestamp persistence, and the seed + refresh reconcilers that gate/readyzunder theartifacts-seedsandartifacts-refreshprobes. - Audit — the platform audit log: hash-chained Postgres primary with object-store mirror, per-Domain residency, and the erasure flow. See
audit/. - Signing — Ed25519 custody, deployment-scoping rules, and the rotation contract. See
signing/. - Labels — definitions, assignments, the selector grammar, and the
SelectorPortseam consumed by policy and provisioning. Seelabels/. - Provisioning — bootstrap-driven enrolment surfaces, the OpenBao Credential Broker that owns project-scoped secret material, the Cloud Credentials Custodian that owns cloud-scoped secret material, the Management Fleet that owns the Kubernetes clusters hosting the provisioning substrate, the Blueprint Catalog that owns the curated provisioning recipes a Project can request, and the Provisioning Broker that turns a Project's resource declaration into running, mesh-enrolled substrate. See
provisioning/credentialsfor the Credential aggregate, the four lifecycle events, the deterministic KV-v2 path, and the Sweeper. Seeprovisioning/credential-poolfor the CloudCredential aggregate, the four lifecycle events, the deterministic KV-v2 path keyed on(cloud_id, credential_id), and the Sweeper that gates/readyzunder thecloud-credentials-sweeperprobe. Seeprovisioning/management-fleetfor the ManagementCluster and ProjectClusterAssignment aggregates, the per-Project namespace-phase state machine, the verify-only readiness gate, and the reconcile loop that gates/readyzunder themanagement-fleet-reconcileprobe. Seeprovisioning/blueprintsfor the Blueprint and BlueprintVersion aggregates, the ProviderKind and InjectionStrategy closed enums, the typed parameter-schema model, the five-blueprint platform seed catalog, and the seed reconcile that gates/readyzunder theblueprint-catalog-seedsprobe. Seeprovisioning/brokerfor the ProvisionedResource aggregate, the eight-phase status state machine (Pending → Provisioning → Enrolling → Readyon the converge arm,Faileda sticky terminal sink, and the orderedDeregistering → Deprovisioning → Deletedteardown machine), the render-and-apply pipeline that turns a blueprint into a Crossplane v2 namespaced Composite Resource, and the reconcile loop that gates/readyzunder theprovisioning-broker-reconcileprobe. Seeprovisioning/cloud-init-daemonsetfor the broker's bootstrap-injection half — the cloud-init user-data document contract and its metadata-service delivery model, the Kubernetes plexd DaemonSet bundle with its embedded-Secret and External-Secrets-Operator token-delivery modes, the per-strategy injected-XR field map (spec.userData/ thehelmValuestriple / the unchangedproviderSecretleaf), and the force-apply preservation rule. Seeprovisioning/label-propagationfor how the broker projects a tenancy Resource's opted-in labels onto cloud-provider tags — theplexsphere:key prefix, the per-provider constraint profiles, the deterministic count cap, and the skip-observability contract. Seeprovisioning/cloudfor the Cloud Inventory aggregate, its closedaws/azureprovider enum, the per-provider validator family, and the three Cloud lifecycle events. Seeprovisioning/adoptionfor the how-to that brings a pre-existing Kubernetes cluster under management with the ExternalSecrets pattern. Seeprovisioning/deletionfor the graceful-deletion teardown ordering and the node-before-substrate invariant. Seeprovisioning/rebacfor the Credential Assignment sub-context and the request / approve / reject / revoke ReBAC workflow that binds a cloud credential to a Project.
When to read this section
- You are about to add or change code inside
internal/<context>/and need to know which invariants the existing aggregates enforce. - You are reviewing a cross-context change and want to confirm the seam it uses is the documented one.
- You are debugging an event flow and need the canonical envelope shape.
For the higher-level system map, see architecture. For operator-facing tasks, see how-to.