System Context
The actors, organisations, and repositories the platform operates across, and the high-level relationships between the per-solution Orbit stacks and the Aurora control plane.
The platform in one paragraph
Orbit is MaxQ Labs’ implementation of the Trajectory methodology: it takes a customer system as-is → R2B (Refactor-to-Be) → to-be → iterations → release, producing a machine-readable solution tree (currently Trajectory v1.8). Each solution gets its own runtime stack — a read-only viewer, an authoring agent, and a Mission Control console — while Aurora, the portfolio control plane, manages the whole fleet of solutions across customers and tenants. The Customer → Tenant → Solution registry (three microservices on Postgres) is the system of record for what exists; GitHub holds the solution definitions; Azure Container Apps is the sole deployment target.
Actors
| Actor | Who | What they touch |
|---|---|---|
| MaxQ Labs maintainers | The platform team | Operate Aurora (MaxQ-internal — the portfolio across all customers and tenants), the platform repo, provisioning, and releases. |
| Customers | Client organisations (e.g. cronos) | The commercial identity that owns tenants. The customer id doubles as the org slug in solution naming. |
| Tenants | A customer’s environment (<customer>-<slug>, e.g. cronos-production) | The customer-facing scope: a tenant’s Orbit app manages that tenant’s solutions. Tenants carry kind (production, staging, poc, demo) and an org-per-tenant auth block. |
| AI agents | The per-solution maxq-orbit-agent and Aurora’s in-product agent chat | The per-solution agent is the single writer of that solution’s repo pair (plans and runs worker tasks, branch per request → commit per task → merge). Aurora’s chat agent can create and deploy solutions through confirm-gated tools. |
The governing principle is three layers, three managers:
- Aurora manages the portfolio — all customers and tenants (MaxQ-internal).
- A tenant’s Orbit app manages that tenant (customer-facing).
- Each solution’s agent authors that solution — single writer per repo pair.
Customer → Tenant → Solution
The portfolio hierarchy is a strict containment chain, with the portfolio registry as its system of record:
Customer (1) ──< Tenant (1) ──< Solution (registry record) ──── solution repos
│ │ │ ├─ customer repo (Trajectory tree)
│ │ │ └─ internal repo (agent IP + audit)
│ │ └─ deployment record ──────── deployed Orbit runtime
│ └─ orbit block: the tenant-manager Orbit app
│ └─ auth block: WorkOS Organization (org-per-tenant)
└─ commercial identity (contacts, status)The registry as system of record
The registry is implemented as three Hono microservices — customer-service,
tenant-service, solution-service (under implementation/, sharing
shared/registry-kit) — over one Postgres database with a Cosmos-shaped document
model: per service, one records table of id + JSONB document + version, with
If-Match optimistic concurrency and an append-only audit.events table written
on every mutation. The services are private infrastructure (internal-only
ingress); aurora-webapp is the BFF in front of them.
Key invariants (enforced cross-service, synchronously, fail-closed):
- A tenant belongs to exactly one customer (required, immutable).
- A solution belongs to at most one tenant — a single
tenantpointer on the solution record; attach/detach is a PATCH of that pointer (null= detach). customer.idis the org slug used in solution repo naming.- Deletes are refused while children exist (a customer with tenants, a tenant with solutions); solution records are archived, not deleted, while their repos exist.
- Single authority per field: every field is owned by exactly one of the
registry record, the customer repo’s
solution.yaml, or the live runtime. The joined Solution object Aurora serves surfaces drift, never silently resolves it.
The registry owns portfolio concerns (tenancy, lifecycle, repos, deployment);
the customer repo’s solution.yaml owns the methodology definition (name,
description, trajectory version, stages, owners). Aurora joins the two at read
time, keyed by customer-repo name. A reconciliation sweep compares the GitHub
org scan against the registry and reports unregistered repo pairs and orphaned
records — nothing silently disappears.
The registry went live in production on 2026-07-03: every existing solution was
registered, given a default <customer>-main tenant, and attached — final sweep
reported zero unregistered and zero orphaned records.
The GitHub organisation model
Solution definitions live on GitHub, split across two organisations with a deliberate visibility boundary:
| Org | Role | Contents |
|---|---|---|
maxq-labs-orbit-solutions | Customer org — the source of truth for solution definitions | One private repo per solution, named solution-<org>-<sol> (e.g. solution-cronos-wallonia), forked from solution-template. Customer-visible deliverables. |
maxq-labs-orbit-platform | Internal org — MaxQ Labs only | The platform repo (orbit), the two base templates (solution-template, solution-template-internal), and one private repo per solution named solution-<org>-<sol>-internal, holding agent IP and the audit trail. |
Naming rule: the inputs are an organisation name and a solution name, each
slugified (letters and hyphens only, max 20 chars, lowercased). The repo base is
solution-<org-slug>-<sol-slug>; the internal repo appends -internal. The
seeded solution.yaml identity is id: <org-slug>-<sol-slug> — the same id the
registry uses as the solution record key.
Repos are created as true GitHub forks with a rename (not template-generates), specifically to keep the “forked from” upstream link so every solution can pull future template and methodology updates via fork syncing.
Aurora reads both orgs live through one GitHub App per org (App JWT → installation token), with read-only permissions (Contents: read, Metadata: read):
- The customer org App lists
solution-*repos and reads each repo’sworkspace/solution-definition/solution.yaml— the methodology source of truth. - The internal org App lists
solution-*-internalrepos only to correlate the internal-repo-linked indicator; the internal repo has nosolution.yamlof its own.
The three-repo split per solution
A solution’s definition is spread across three repositories, separating the customer-visible deliverable, the MaxQ-internal supporting IP, and the global specification:
| Repo | Remote / visibility | What lives there | Why it is separate |
|---|---|---|---|
Customer repo (solution-<org>-<sol>) | maxq-labs-orbit-solutions, customer-visible | workspace/solution-definition/ (the solution root — the Trajectory tree the loader consumes), repositories/, and a vendored, version-pinned copy of the methodology (trajectory-methodology/, matching solution.yaml’s pinned version). Per-request branch → merge git lifecycle. | This is the deliverable. Vendoring the methodology makes the repo self-contained and reproducible at its pinned Trajectory version. |
Internal repo (solution-<org>-<sol>-internal) | maxq-labs-orbit-platform, MaxQ-only | agents/ (sub-agent personas), catalog/ (the registries: assessment-types, component-types, architecture-types, …), templates/, and .orbit/ (the full audit trail of agent runs). Linear commits on main, no per-request branches. | Supporting IP and the audit trail must not be customer-visible. The no-branch discipline keeps the live .orbit/ task state from being swapped out from under the running agent — which is what makes the audit trail safely trackable. |
Methodology repo (trajectory-methodology) | Global, standalone (open-source candidate) | The Trajectory master specification: base-format docs, JSON Schemas (08-schemas/), per-stage methodology, migrations, and frozen releases/v<X.Y>/ snapshots (current: v1.8). | One spec, many solutions. It is read-only for solutions and mounted only for the upgrade operation — normal authoring resolves the vendored copy inside the customer repo. |
The per-solution agent is the sole owner of the repo mounts: the customer repo
at /repo (read-write), the internal repo at /repo-internal (read-write), and
the global methodology at /methodology (read-only, upgrade flow only). Since
2026-07-02 the reader webapp has no repo mount at all — it fetches solution
data from the agent over HTTP.
Deployment context
Azure is the sole deployment target — the earlier Vercel path was retired on 2026-07-02. Everything runs on Azure Container Apps (ACA) with images in a shared Azure Container Registry, provisioned via managed identity (no stored service-principal secret).
- Aurora is a singleton ACA app at
aurora.maxqlabs-orbit.com, alongside the three registry services (svc-customer,svc-tenant,svc-solution— internal-only ingress) and an Azure Database for PostgreSQL Flexible Server with Entra-only authentication (no database password exists anywhere). - Per-solution Orbit stacks are provisioned automatically on solution
creation: three ACA apps per solution — the reader
orbit-<h>, the writer agentagent-<h>(capped at one replica: single writer), and Mission Controlmc-<h>— wherehis a deterministic hash of the solution id. Two Azure Files shares hold working clones of the customer and internal repos, mounted into the agent; images are shared per release, not per solution — a stack is just apps + shares + env pinning an image tag. - Per-solution subdomains for the two public apps: the reader and Mission
Control each get a Cloudflare front door under the platform zone, flat
one-level for the wildcard certificate —
<solution-id>.maxqlabs-orbit.com(reader) and<solution-id>-mc.maxqlabs-orbit.com(Mission Control). Since 2026-07-03 the agent is internal-only (ACA internal ingress, no subdomain — requests from outside the environment are rejected); in-env callers address it ashttp://agent-<h>. Origin isolation per public app is deliberate; Mission Control reaches the agent through a runtime-injectedAGENT_URL(its browser traffic goes through Mission Control’s same-origin/agentproxy), never a baked-in URL. - After deployment, the public URLs are written back to the solution’s registry
record (
deploymentblock: mode, state, the reader and Mission Control URLs, the Azure name hash — noagentUrlsince the agent went internal), so the registry — not a naming convention — is what Aurora and the tenant Orbit apps resolve at read time. - Releases are tracked per component in the platform repo’s
releases/registry; container records are written by the image build tooling.
Context diagram
Boundaries worth remembering
- The registry, not GitHub, answers “what exists” — the GitHub org scan survives only as the reconciliation sweep. The registry services themselves stay GitHub-credential-free; only Aurora’s BFF holds the GitHub App credentials.
- One writer per solution. All mutation of a solution’s repo pair flows through that solution’s agent; the reader and Aurora only read.
- The customer never sees the internal repo. The visibility split between the two GitHub orgs is the platform’s confidentiality boundary.
- The methodology is consumed vendored. Solutions pin a Trajectory version and carry their own copy; the global repo is touched only when upgrading.