Skip to Content
ArchitectureSystem Context

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

ActorWhoWhat they touch
MaxQ Labs maintainersThe platform teamOperate Aurora (MaxQ-internal — the portfolio across all customers and tenants), the platform repo, provisioning, and releases.
CustomersClient organisations (e.g. cronos)The commercial identity that owns tenants. The customer id doubles as the org slug in solution naming.
TenantsA 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 agentsThe per-solution maxq-orbit-agent and Aurora’s in-product agent chatThe 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:

  1. Aurora manages the portfolio — all customers and tenants (MaxQ-internal).
  2. A tenant’s Orbit app manages that tenant (customer-facing).
  3. 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 microservicescustomer-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 tenant pointer on the solution record; attach/detach is a PATCH of that pointer (null = detach).
  • customer.id is 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:

OrgRoleContents
maxq-labs-orbit-solutionsCustomer org — the source of truth for solution definitionsOne private repo per solution, named solution-<org>-<sol> (e.g. solution-cronos-wallonia), forked from solution-template. Customer-visible deliverables.
maxq-labs-orbit-platformInternal org — MaxQ Labs onlyThe 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’s workspace/solution-definition/solution.yaml — the methodology source of truth.
  • The internal org App lists solution-*-internal repos only to correlate the internal-repo-linked indicator; the internal repo has no solution.yaml of 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:

RepoRemote / visibilityWhat lives thereWhy it is separate
Customer repo (solution-<org>-<sol>)maxq-labs-orbit-solutions, customer-visibleworkspace/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-onlyagents/ (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 agent agent-<h> (capped at one replica: single writer), and Mission Control mc-<h> — where h is 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 as http://agent-<h>. Origin isolation per public app is deliberate; Mission Control reaches the agent through a runtime-injected AGENT_URL (its browser traffic goes through Mission Control’s same-origin /agent proxy), never a baked-in URL.
  • After deployment, the public URLs are written back to the solution’s registry record (deployment block: mode, state, the reader and Mission Control URLs, the Azure name hash — no agentUrl since 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.