# breakpilot-control Control plane. Single VM (`vm-control`). Becomes its own Gitea repo `platform/breakpilot-control` at migration time. ## Services (7) | Service | Purpose | |---|---| | [`customer-portal.toml`](./services/customer-portal.toml) | Next.js 15 customer-facing portal | | [`erpnext.toml`](./services/erpnext.toml) | Internal-only ERP (sales, invoices, fulfillment) | | [`frappe-hd.toml`](./services/frappe-hd.toml) | Helpdesk on the Frappe stack | | [`mariadb.toml`](./services/mariadb.toml) | DB for ERPNext + Frappe HD | | [`redis-erpnext.toml`](./services/redis-erpnext.toml) | ERPNext cache + queue Redis | | [`stalwart.toml`](./services/stalwart.toml) | Outbound mail relay; per-stage accept-rule blocks real customers from receiving stage mail | | [`tenant-registry.toml`](./services/tenant-registry.toml) | Tenant glue: orgs, entitlements, API keys, audit. M7.3's `TENANT_REGISTRY_URL` resolves here. | ## SLA targets (per `INFRASTRUCTURE.md §6`) ``` Owns: RPO (tenant) — tenant registry & compliance schemas RPO ≤ 6h RPO (ERPNext) — sales orders, invoices RPO ≤ 6h AUDIT_TRAIL — all portal actions (invites, IdP changes, impersonations) AVAILABILITY — portal ≥ 99.5%; ERPNext ≥ 99% (internal) RTO (portal) — ≤ 10 min RTO (ERPNext) — ≤ 60 min ``` ## Co-tenant note ERPNext + Portal + Stalwart on one VM. Orca resource limits per `§6`: | Service | Memory cap | |---|---| | customer-portal | 1 GB | | erpnext | 6 GB | | mariadb | 3 GB | | stalwart | 1 GB | | tenant-registry | 500 MB | ## Stage callers Stage workloads in `breakpilot-app/services/stage/` call the **prod** tenant-registry here under `tenant.kind = "stage"` rather than running a duplicate. Isolation is by tenant kind, not by replicating the control plane.