Scaling and deployment
PartialOmniglass is one Go binary, and that is a packaging decision, not a scale ceiling. The same artifact runs an all-in-one container on a laptop and a horizontally-scaled fleet on Kubernetes; you scale by topology, not by swapping products.
Two run modes, one binary
Section titled “Two run modes, one binary”The binary is a modular monolith: one codebase, one artifact, modules behind clean seams (the Storage Gateway is the only path to the database, coordination rides NATS, collection runs at the edge). It runs two ways, no fork:
- All-in-one (the modular monolith). One process runs every role, with Postgres and NATS embedded (below), against nothing external. The small-fleet case: download, run, done.
- Split by run mode (Kubernetes). The same binary launched per mode as separate Deployments, against an external Postgres and an external NATS cluster. A Helm chart wires it up, and each role scales independently.
Splitting a mode onto its own pods is a deployment choice, not a rewrite: the modules already talk over NATS and the gateway. The roles:
- server: the public HTTP API (API) and the views read path; it serves the
SPA embedded in the binary (
go:embed), so the web UI is not a separate service. Stateless.
- node: collection; runs at the sites (outside the cluster) and connects back, plus a central
nodefor cloud-API and SaaS sources (placement: central, nodes).
Embedded services (single-binary mode)
Section titled “Embedded services (single-binary mode)”In all-in-one mode the binary brings its dependencies up in-process, so an operator runs one container, zero external setup:
- NATS + JetStream, embedded as a library (
nats-serverin-process, file-backed). The app is always a NATS client; embedded versus external is a config flag, not a code path.
Coordination: NATS moves, Postgres remembers
Section titled “Coordination: NATS moves, Postgres remembers”Postgres is the relational system of record (entities, samples, events and alarms, audit, and the queries the cascade, fusion, views, and scope need). NATS (JetStream) is the nervous system: work distribution, the durable command queue, the telemetry buffer, and fan-out.
Platform configuration
Section titled “Platform configuration”Configuration is two tiers, and platform settings are deliberately centralized:
- Bootstrap (env, optional). The irreducible minimum needed before the database exists: the Postgres
DSN, the NATS embed-or-external choice and address, the
SecretProviderkey, the run mode, and the listen address. In all-in-one mode these have working defaults, so a desktop run needs no configuration at all; env vars override. - The platform settings store (one place). Everything else lives in the single, audited
settings engine: feature flags, buffer and retention defaults, CDC routing,
integration settings, UI defaults, official-registry overrides, resolved most-specific-wins down the
principal hierarchy. An operator settings file (
settings.jsonor YAML) is the GitOps layer, read into memory at boot and mounting cleanly as a Kubernetes ConfigMap (and a future operator); only the override an operator sets through the API is persisted in Postgres (audited), while the file and the embedded defaults are recomputed each boot, so restore is a delete and the file never drifts into a second authoritative copy (ADR-0033).
This is distinct from fleet config and variables, which describe the fleet and resolve down the cascade; the settings store describes the platform itself.
Multi-tenancy: per database, per account, per deployment
Section titled “Multi-tenancy: per database, per account, per deployment”Tenant isolation is physical, not a row predicate: a tenant is one database, one NATS account, and
one deployment. There is no tenant_id column anywhere, no shared row store, and no shared subjects, so
per-database isolation (storage) and per-account isolation (messaging) are the same boundary. The data
model stays single-tenant-shaped; multi-tenancy lives at the orchestration layer (CNPG-per-tenant). One
noisy or compromised tenant cannot reach another: there is nothing shared to reach across
(identity and access).