Ctrl Plane

Architecture

How Ctrl Plane's packages fit together, from providers to the HTTP API.

Ctrl Plane is organized as a set of Go packages, each responsible for one concern. There is no central god object. The app.CtrlPlane struct wires the packages together, but you can also use any package independently.

Package map

github.com/xraph/ctrlplane/
    id/            TypeID wrapper (prefix-qualified identifiers)
    auth/          Authentication and authorization interface
    provider/      Cloud provider abstraction + implementations
    instance/      Instance lifecycle management
    deploy/        Deployments, releases, and strategies
    health/        Health checking subsystem
    network/       Domains, routes, and TLS certificates
    secrets/       Secret management and vault interface
    telemetry/     Metrics, logs, traces, resource snapshots
    admin/         Tenant management, quotas, audit
    event/         Event bus and webhooks
    worker/        Background task scheduler
    store/         Persistence layer (postgres, sqlite, memory)
    api/           HTTP handlers and middleware
    app/           Root orchestrator
    extension/     Forge extension adapter
    cmd/           Reference binary

Layered design

The library is structured in layers. Lower layers know nothing about higher layers.

Layer 1: Foundation

The root ctrlplane package and the id package. These define the base Entity type, sentinel errors, configuration, and the TypeID identity system. Every other package depends on these.

Layer 2: Interfaces

Each subsystem package (instance, deploy, health, network, secrets, telemetry, admin, event) defines its own Service interface, Store interface, and domain entities. These packages depend only on the foundation layer and each other where necessary.

Layer 3: Infrastructure

The provider package defines the Provider interface that abstracts over cloud orchestrators. The store package composes all subsystem store interfaces into a single aggregate interface. The auth package defines the authentication abstraction.

Layer 4: Wiring

The app package creates a CtrlPlane struct that instantiates all service implementations, registers background workers, and connects the event bus. The api package mounts HTTP handlers. The extension package adapts everything for Forge.

Data flow

A typical request flows through these layers:

HTTP Request
    -> api.AuthMiddleware (extracts tenant from token)
    -> api.Handler (parses request, calls service)
    -> instance.Service (business logic, state validation)
    -> provider.Provider (talks to Docker/K8s/AWS)
    -> instance.Store (persists state change)
    -> event.Bus (publishes lifecycle event)

Key interfaces

Every subsystem follows the same pattern: a Service interface for business logic, a Store interface for persistence, and domain-specific extension interfaces.

InterfacePackageRole
provider.Providerprovider/Cloud orchestrator abstraction (15+ methods)
instance.Serviceinstance/Instance CRUD and lifecycle actions
deploy.Servicedeploy/Deployment orchestration and release management
deploy.Strategydeploy/Pluggable deployment strategy (rolling, blue-green, canary, recreate)
health.Servicehealth/Health check configuration and execution
health.Checkerhealth/Individual check type implementation
network.Servicenetwork/Domain, route, and certificate management
network.Routernetwork/External traffic routing abstraction
secrets.Servicesecrets/Secret lifecycle and injection
secrets.Vaultsecrets/Backend secret storage abstraction
telemetry.Servicetelemetry/Metrics, logs, and trace querying
telemetry.Collectortelemetry/Custom telemetry data source
admin.Serviceadmin/Tenant, quota, and audit management
event.Busevent/Publish/subscribe event dispatch
auth.Providerauth/Authentication and authorization
store.Storestore/Aggregate persistence (composes all subsystem stores)
worker.Workerworker/Background periodic task

Usage modes

Standalone library

Import the packages you need, create a CtrlPlane with app.New(), and serve the HTTP API with api.New(). You own the process.

cp, _ := app.New(
    app.WithStore(postgresStore),
    app.WithProvider("k8s", kubernetesProvider),
    app.WithAuth(myAuthProvider),
)
cp.Start(ctx)
http.ListenAndServe(":8080", api.New(cp).Handler())

Forge extension

Wrap Ctrl Plane in the extension adapter and mount it into a Forge application. Forge manages the HTTP server and process lifecycle.

forgeApp := forge.New()
forgeApp.Use(cpext.New(
    cpext.WithProvider("k8s", kubernetesProvider),
    cpext.WithAuthProvider(authsomeAdapter),
))
forgeApp.Run()

Individual packages

You can use any subsystem package on its own. For example, the health package works independently if you provide a store and a set of checkers.

Background workers

The worker.Scheduler manages five built-in workers that run on configurable intervals:

WorkerPurposeDefault interval
ReconcilerDetects drift between stored state and provider state60s
HealthRunnerExecutes configured health checks30s
TelemetryCollectorCollects metrics and resource snapshots from providers10s
GarbageCollectorCleans up old deployments, health results, and audit entries5m
CertRenewerRenews TLS certificates approaching expiry1h

Workers are started by cp.Start(ctx) and stopped by cp.Stop(ctx).

On this page