CRUMB a card from devarno-cloud

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

RepoRoleStack
so1-roverControl plane UINext.js 16 App Router, TanStack Query
so1-control-plane-apiBFF serviceHono, Node.js
so1-sharedContracts & typesZod 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:#f0ece6

Dependency 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| shared

so1-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. rover never holds a third-party token.
  • rover is 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