Matelotdocs
Operating a cell

Endpoints of a cell

Every cell exposes exactly three public hostnames, all TLS, no ports:

Surface Hostname Used by
Web app + API (/api/v1) https://<slug>.<domain> browsers, runners (RUNNER_URL=https://<slug>.<domain>/api/v1), CI (SECOPS_URL), webhooks
Container registry https://registry-<slug>.<domain> docker login/push/pull, runners scanning images, clusters pulling environment images
Identity (Keycloak) https://auth-<slug>.<domain> browser login (OIDC), the API (JWKS)

<slug> is the customer (acme), <domain> the operator's cell domain (secops.example.com). One wildcard certificate *.secops.example.com (or cert-manager per host) covers all three, because every name is a single level under the domain. The Helm chart derives all URLs from tenant.slug and tenant.domain: token realm, registry notifications, OIDC issuer, WEB_BASE_URL, GitHub App callback.

On the app host, /api/* and /.well-known/* (OAuth/OIDC discovery for matelot login and MCP clients) go to the API, everything else to the web app; a Docker Compose cell serves Keycloak under /auth on the same host and the registry on registry.<domain> (or localhost:5000). Unauthenticated endpoints an operator can probe: GET /api/v1/health/live, GET /api/v1/health/ready (database reachable) and GET /api/v1/version ({"name":"matelot","version":"0.1.0"} — what matelot doctor shows before login).

Provisioning a cell therefore needs from the operator: three DNS records (or a wildcard), a TLS issuer, and helm install (M12 automates this in the cell provisioning flow). Nothing about ports or hostnames is configured by teams: the UI, the CI snippets and the CLI print the cell's real URLs.

Local development

make dev / make web / docker compose use http://localhost:3000 (API), :5173 (web), :8080 (Keycloak) and localhost:5000 (registry, insecure-registries in Docker Desktop). These never appear in a deployed cell.