Architecture overview
Constellation OS is two cooperating systems: a tenant-scoped platform API with physically separated data planes, and a browser console that does its own physics and analysis client-side. This page is the map; the deeper console pages cover rendering and determinism.
Platform
The request path, top to bottom:
| Layer | Role |
|---|---|
| API gateway and TLS termination | Public hostnames per environment (api.constellation.space and friends), certificate management |
| FastAPI application | The whole customer surface: /health*, /topology, /telemetry, /predictions, plus the operator-only /rules* |
| Middleware stack | Tracing, then metrics, then body-size enforcement, then per-IP rate limiting, then authentication, then per-tenant rate limiting, then tenant context resolution, then the handler |
| Tenant registry | Environment-provided registry mapping each tenant to its data plane, secrets, and encryption key; no control-plane database |
| Per-tenant data planes | One dedicated Timestream-for-InfluxDB instance per tenant, with a dedicated KMS key and scoped read/write token |
| Prediction serving | The snr model family, served cached or live (sagemaker, local, or registry backends) |
| Weather worker | A central worker that ingests weather observations and fans them out into every tenant's data plane as weather telemetry |
The middleware order is worth memorizing when debugging: a 413 fired before auth means the body never reached your tenant context, and a locked-out IP gets 429 before its key is even checked. See Errors and limits.
Environments are separate deployments (prod, stage, dev, sandbox, GovCloud dev, and dedicated tenant stacks), each with its own keys and registry. See Environments and Enterprise.
Console
The console is a Vite single-page application with no router: one scene, panels as overlays. Its heavy lifting is client-side by design, so the operator's what-ifs never load the platform:
| Piece | Role |
|---|---|
| Cesium globe engine | The persistent scene: earth styles, entities, transitions, camera choreography |
| Fleet propagation worker | A Web Worker that runs SGP4 over every TLE-bearing asset and hands sampled position windows to the renderer |
| Unified asset registry | One store for operator fleet, catalog constellations, uploads, chat imports, and synthetic assets, persisted in the browser |
| Deterministic engines | Fleet statistics, link budgets, coverage and passes, outage and rain scenarios, siting and beam optimizers |
| Chat service | The assistant backend: a proxied Lambda in production, a dev middleware locally; tools execute in the console against the live scene |
| Billing service | Stripe-backed plan and entitlement handling behind its own Lambda |
| Platform API client | Topology-projection reads and prediction fetches against the platform, keyed per environment |
Static assets ship to S3 behind CloudFront under the /app/ base path, per environment. Console hosts and buckets are listed in URLs and hosts.
Data flow, end to end
- Gateways and pipelines write
TelemetryRecordbatches toPOST /telemetry; the platform stamps the tenant and writes to that tenant's own InfluxDB instance. - The console and integrations read fleet state via
GET /topology, a latest-sample-per-entity projection over that telemetry. - Predictions are fetched per link via
GET /predictions, cached or live with provenance. - Inside the console, the propagation worker and deterministic engines compute everything geometric and analytical locally, against the same registry the globe renders.
- Analyses capture into reports; scenarios save with everything needed to reproduce them.
Design consequences
- Isolation is structural. A tenant's data lives in its own database instance under its own key; cross-tenant reads have no path to exist. See Tenant isolation.
- The platform stays small. No webhooks, streaming, or pagination; polling integrations against a stable, flat surface. See API overview.
- The console degrades honestly. No API key means demo and replay modes with a labeled baseline for SNR; a stale feed is marked stale rather than rendered as quiet.