{
  "schema": "leumas.docs.page/1",
  "id": "arch:CONTROL-PLANE",
  "slug": "architecture/control-plane",
  "kind": "pages",
  "bucket": "architecture",
  "title": "Control plane",
  "name": "Control plane",
  "eyebrow": null,
  "chip": null,
  "summary": "Identity, money, licences, the install fleet, the app-store review queue and moderation — everything Leumas does to or about its customers.",
  "keywords": [
    "leumas control plane",
    "licensing and entitlements",
    "app store review",
    "fleet management",
    "release feed",
    "how leumas licences an install"
  ],
  "audience": "both",
  "funnel": {
    "product": "leumas-studio",
    "cta": "See the control plane in Studio"
  },
  "body": "# Control plane\n\n**What Leumas does TO or ABOUT its customers.**\n\nIdentity, money, licences, the install fleet, the app-store review queue, the release feed, and\nmoderation of what customers publish to Leumas-hosted services. If it is Leumas acting *on* a\ncustomer, it is here.\n\nCompanions: [PLATFORM.md](PLATFORM.md) · [APPLIANCES.md](APPLIANCES.md)\nExecution: [ops/todos/leumas-consolidation-roadmap.md](ops/todos/leumas-consolidation-roadmap.md)\n\n---\n\n## Two things, not one\n\nThis is the distinction that matters, because getting it wrong produces a console customers have to\ntalk to:\n\n| | **Central services** | **The console** |\n|---|---|---|\n| Host | `api.leumas.tech` | `admin.leumas.tech` |\n| Role | `LEUMAS_ROLE=platform` | `LEUMAS_ROLE=control` |\n| Who reaches it | everyone — every Studio, iOS, leumas.tech, every browser | **Leumas staff only** |\n| What it is | login, memberships, app store, relay, analytics ingest, release feed | a **window over the same data** |\n| Exposure | public | edge-restricted |\n\nSame binary, same database, different `LEUMAS_ROLE`. The console stores nothing of its own.\n\n> **A customer's browser or Studio never contacts `admin.leumas.tech`.**\n> When a flow needs a customer to visit a Leumas page, that page is on `leumas.tech` and it calls\n> `api.leumas.tech`.\n\nStaff-only is a *second axis*, not a bigger role: `admin` means \"administrator of an instance\",\n`leumas_staff` means \"works for Leumas\". A customer who is an admin of their own Studio is not staff.\n`pnpm check:staff` enforces the split.\n\n---\n\n## What it owns\n\n| Job | Why it must be central |\n|---|---|\n| **Leumas identity** | one account across leumas.tech, iOS, and every self-hosted Studio |\n| **Memberships & Stripe** | one billing relationship per customer |\n| **Licences** | what an appliance is entitled to run, revocable |\n| **The install fleet** | every Studio that has phoned home — version, health, activity |\n| **The app store** | submissions, review, signing, distribution |\n| **Releases** | the feed every appliance polls to update itself |\n| **Ecosystem analytics** | rollups across installs |\n| **Social & marketplace moderation** | content on Leumas infrastructure, under Leumas terms |\n\nAn appliance's only phone-home is a licence heartbeat carrying a key and an instance id. **It stays\nthat way.** The lever against a bad self-hoster is revoking their licence, not watching their machine.\n\n---\n\n## How it relates to the other two\n\n```\n CONTROL ── issues licences, bills, reviews apps, publishes releases ──-> APPLIANCES\n      │                                                                          │\n │ <-──────────────── licence heartbeat (key + instance id) ─────────────────┘\n      │\n      └── serves the identity + money API that PLATFORM's public pages call\n```\n\nThe control plane is the only plane that is **not** a product anyone else can run. Everything else\nships; this stays home.\n\n---\n\n## The boundary rule\n\n> Things *Leumas* does **to or about** its customers → **control plane**.\n> Anything a *customer* does on their own instance → **Studio** ([APPLIANCES.md](APPLIANCES.md)).\n\nIf a tenant admin would legitimately use it on their own appliance, it is not a control-plane surface.\n\n---\n\nDetail — topology, security posture, the console's domains, per-job design:\n[ops/reference/control-plane-detail.md](ops/reference/control-plane-detail.md)\n",
  "source": {
    "path": "CONTROL-PLANE.md",
    "blobSha": "",
    "commit": "",
    "committedAt": "",
    "provenance": "no-git",
    "bytes": 3968,
    "hash": "e054099c336a9e4424359204f38272e7f345f057"
  },
  "urls": {
    "html": "/p/architecture/control-plane",
    "json": "/docs/architecture/control-plane.json",
    "md": "/docs/architecture/control-plane.md"
  },
  "links": {
    "composes": [],
    "usedBy": [],
    "product": [],
    "howTo": [],
    "skills": []
  }
}
