C4 — component view: ControlPlaneApi¶
Target
This page describes intended behaviour or structure. No implementation is claimed unless a section is explicitly marked Current implementation or Evidence.
Rewritten 2026-10-09
One host is shown as the pattern. Components are the module-of-host services of the Control Plane platform (model/services/_registry.yaml); the first fully designed one is RunControlService.
C4Component
title ControlPlaneApi — components (level 3)
Container_Boundary(cp, "ControlPlaneApi (.NET 10, BaseTemplate project model)") {
Component(api, "API boundary", "ServiceModel.RestApi + ServiceModel.Grpc", "Scope from the authenticated context; REST public, gRPC internal")
Component(proj, "Project & Environment module", "BC-01", "Projects, environments, module metadata, scope ids")
Component(pub, "Asset Publication module", "BC-04", "Release manifests, dependency closure, agent cards (A2A)")
Component(run, "Run Control module", "BC-03", "Runs, steps, attempts, leases, approvals, recovery journal; sole transition authority")
Component(usage, "Usage Accounting module", "BC-05", "Reservations, usage records, pricing revisions, reconciliation")
Component(ten, "Factory Tenancy & Entitlements module", "BC-33", "Editions, quotas, entitlement checks (canonical ADR-0100)")
Component(com, "Factory Commercial module", "BC-34", "Subscriptions, invoices, meters on the SaaS templates")
Component(persist, "Persistence port", "PersistenceModel.NHibernate + Saas tenant filter", "Row-filtered access; outbox in the same transaction")
Component(msg, "Messaging port", "MessagingModel + profile adapter", "Outbox dispatch; inbox dedup")
Component(grains, "Run grains", "ActorModel.Orleans", "Serialise run transitions; reminders for expiry")
}
ContainerDb(sql, "control-sql", "Azure SQL", "Runs … ApprovalRequests; releases; projects; usage")
ContainerQueue(bus, "Messaging transport", "Profile per ADR-0012")
Container_Ext(gov, "GovernanceHost", "Policy decisions, approval eligibility")
Container_Ext(worker, "AgentRuntimeWorker", "Leases, outcomes")
Container_Ext(idp, "Identity Platform", "Tokens, roles")
Rel(api, run, "Submit, cancel, decide")
Rel(api, proj, "")
Rel(api, pub, "Validate, publish")
Rel(api, ten, "Entitlement checks")
Rel(run, pub, "Resolve release alias")
Rel(run, usage, "Reserve, settle")
Rel(run, gov, "Policy revision, approver rule", "gRPC")
Rel(run, grains, "Transitions")
Rel(run, persist, "")
Rel(usage, com, "Meters")
Rel(persist, sql, "NHibernate")
Rel(persist, msg, "Outbox")
Rel(msg, bus, "")
Rel(worker, api, "AcquireLease, ReportAttemptOutcome, RequestApproval", "gRPC")
Rel(api, idp, "Validate token")
UpdateLayoutConfig($c4ShapeInRow="3", $c4BoundaryInRow="1")
Hold "Alt" / "Option" to enable pan & zoom
The pattern for every host¶
- One API boundary per host; modules never expose their own transports.
- Modules own their aggregates and tables (schema per module) in the host's store; cross-module reads go through the module's application port, cross-host reads through APIs or events.
- The persistence port enlists the outbox writer of the selected messaging profile so that a state change and its event commit together.
- Grains, workers and sagas are declared per module in the model and rendered on the platform's workers page.