Three-Repo Control Plane Architecture
so1 beginner 4 min read
ELI5
The control plane is split into three boxes like a restaurant: a dining room (so1-rover) where users sit, a kitchen (so1-control-plane-api) where the cooking happens, and a recipe binder (so1-shared) both sides read so the order matches the dish.
Technical Deep Dive
Repo Roles
| Repo | Role | Stack |
|---|---|---|
so1-rover | Control plane UI | Next.js 16 App Router, TanStack Query |
so1-control-plane-api | BFF service | Hono, Node.js |
so1-shared | Contracts & types | Zod schemas, error & job models |
Component Map
---title: "so1 Control Plane"---flowchart TD user(("<b>Operator</b><br/>@devarno.cloud user")):::person subgraph so1 ["**so1 platform**"] rover["<b>so1-rover</b><br/>Next.js 16 SSR UI"]:::system api["<b>so1-control-plane-api</b><br/>Hono BFF"]:::system shared["<b>so1-shared</b><br/>Zod contracts"]:::system end github["<b>GitHub</b><br/>REST API"]:::ext n8n["<b>n8n</b><br/>REST API"]:::ext mcp["<b>MCP servers</b><br/>stdio/SSE"]:::ext user -- "HTTPS" --> rover rover -- "same-origin /api/bff/*" --> api api -- "REST" --> github api -- "REST" --> n8n api -- "stdio/SSE" --> mcp rover -- "imports types" --> shared api -- "imports types" --> shared
classDef person fill:#1c1c24,stroke:#e85d3e,color:#f0ece6 classDef system fill:#1c1c24,stroke:#d4a574,color:#f0ece6 classDef ext fill:#141419,stroke:#8b7e74,color:#f0ece6,stroke-dasharray: 4 3 classDef db fill:#1c1c24,stroke:#d4a574,color:#f0ece6 classDef container fill:#1c1c24,stroke:#d4a574,color:#f0ece6Dependency Direction
flowchart LR shared["so1-shared (types only)"] rover["so1-rover (UI)"] api["so1-control-plane-api (BFF)"] rover -->|HTTP| api rover -->|imports| shared api -->|imports| sharedso1-shared has zero runtime deps on either end. Both rover and api import its Zod schemas (JobSchema, ErrorEnvelope) so request and response shapes match. The arrow from rover to api is HTTP only — no in-process import.
Boundaries
- All business logic for GitHub, n8n, MCP lives in
api.rovernever holds a third-party token. roveris intentionally a single Next.js app, not a workspace monorepo (deferred per README).
Key Terms
- BFF → Backend-for-Frontend, a server tailored to one client UI.
- Control plane → the management surface for organisational resources (repos, workflows, jobs).
- Same-origin → frontend and BFF share a hostname so cookies and CORS are simple.
Q&A
Q: Why is so1-shared a separate repo rather than a folder in rover?
A: Both rover and api need its Zod schemas at runtime; sharing via package install keeps the contract symmetric and version-pinned.
Q: Where does Clerk vs BetterAuth confusion come from?
A: ADR-001 specifies Clerk; the current so1-rover middleware uses BetterAuth (so1.session_token cookie). The ADR predates the migration — implementation is authoritative.
Q: Can so1-rover call GitHub directly?
A: No. Per ADR-002, every external integration is brokered through so1-control-plane-api.
Examples
A “list workflows” click in the UI: rover → /api/bff/workflows (same-origin) → BFF auth check → BFF n8n adapter → upstream n8n REST → response normalised against so1-shared types → JSON back to rover.
neighbors on the map
- purr-api Layered Architecture adding a new feature to purr-api
- LORE Architecture Overview learning LORE for the first time
- Two-Service Architecture onboarding to the chronicle-hq monorepo