ADR-0025: Control-plane co-location and migration trigger¶
- Status: Accepted
- Date: 2026-08-17
- Deciders: El, Lachlan
- Supersedes: ADR-0014 §1 (in part — the control-plane/tenant split, deferred there, is now bounded)
Context¶
ADR-0014 co-located the shared core and tenant stacks and deferred the control-plane/tenant split without saying what would end the deferral. An open-ended deferral is not a decision; it is a thing that gets rediscovered during an audit or a sales conversation.
The control plane is the one component whose compromise crosses tenants. Everything else fails inside a single client's blast radius; the registry does not. At two clients, dedicated control-plane hardware is infrastructure paid for ahead of the risk it mitigates.
There is a parallel question of whether the first client gets a dedicated box. A dedicated box isolates them from our own provisioning learning curve, but sets a precedent that must be walked back, and leaves the multi-tenant path untested until client two — when a gap in it is more expensive to find.
Decision¶
- Shared by default. Dedicated only on client request or compliance requirement.
Client-zero comes first. Tenant zero is Octopodia's own inbox, proven on the shared host for roughly a month before any paying client (docs/provisioning-build-order.md). Greenhills is the first client tenant, not tenant one — we do not learn tenant provisioning on a client who is paying.
2. The control plane runs on the same host as tenant stacks at current scale, with the trust boundary enforced inside the box rather than by separate hardware:
- Control-plane Postgres runs in its own container with its own credentials.
- It sits on a separate Docker network that tenant containers cannot reach.
- Tenant stacks reach the brain over its API. They never connect to the registry directly.
- The control plane keeps its own AU-resident backup and reconciliation pass (ADR-0006, ADR-0026).
These are not optional hardening. They are the condition of the decision. 3. Migration trigger — the control plane moves to its own host at whichever comes first: 1. the first compliance-bound client (healthcare, finance, legal), or 2. the first dedicated-box tenant, or 3. tenant count reaching the point where the shared host is resized rather than extended.
Consequences¶
Infrastructure spend stays proportionate to revenue, and the multi-tenant provisioning path is exercised from tenant zero — on ourselves — so gaps in the playbooks surface with no client to apologise to at all.
Co-location is a real, named compromise: a container escape or a mishandled n8n credential on a tenant stack sits closer to the registry than it would on separate hardware. Because the trigger is written down, moving the control plane later is planned work rather than an emergency.
Alternatives considered¶
- Dedicated control-plane host from day one — rejected: spending ahead of the risk at two clients, given the network and credential isolation available within one host.
- Dedicated box for the first client — rejected: leaves the multi-tenant path untested until tenant two and sets a precedent that is awkward to reverse. Client-zero removes most of the risk this would have mitigated.
- Continuing to defer without a trigger — rejected: that is what this ADR exists to correct.