Vantage Docs
Self-hosting

Architecture

What runs where: web app, dataplane, StarRocks, Cube, n8n, Zitadel?

A standalone Vantage is one web app, one ingest service, a warehouse and a semantic layer, with its own Zitadel, deployed as Nomad jobs on a Consul and Vault cluster (vantage-deployment), or as one Docker Compose project on a laptop. n8n is not part of a standalone deployment: the Nomad jobs and the compose file have none. Platform n8n exists only when Vantage runs inside a Norims cluster; a workspace can still point at its own n8n, Airbyte or OpenFN from Integrations.

What runs where

How data reaches a tenant's dashboard in Norims Vantage: client databases (through n8n CDC sync), file uploads and norims-backend feed the dataplane, which stages files in RustFS, loads them into StarRocks (one tenant_<slug> database per workspace) and runs schedules on Temporal. Cube with CubeStore serves metrics over a tenant JWT. The Vantage web app proxies every data-plane call, keeps its control plane in Postgres with row-level security, budgets queries in Valkey, signs users in with Zitadel, reads per-tenant credentials from Vault and packs from the pack registry in norims-backend.

The picture shows Vantage inside a Norims cluster. norims-backend, its pack registry and the platform n8n come from Norims; a standalone deployment has none of them.

Hosts and ports

ComponentJob (Nomad)HoldsPersistent
analytics-webanalytics-webUI, server functions, control plane, OIDC sessions, MCP endpointno; state in Postgres
dataplanedataplaneUploads, batch loads, DDL, warehouse users, modeled datasets, the Temporal workerno
StarRocksstarrocks (FE, BE), starrocks-bootstrapEvery workspace's data, one database eachstarrocks-meta, starrocks-storage volumes
CubecubeMetrics REST API; pre-aggregations in a CubeStore sidecarcubestore-data volume
PostgresCloud SQL (GCP) or the database hostanalytics, zitadel, temporal, temporal_visibilityyes
Zitadelzitadel, zitadel-loginUsers, organisations (one per workspace), OIDCin Postgres
Vaultsystemd on control-plane nodesJob secrets; per-workspace read-only credentials; dbt credential markersRaft
ValkeyvalkeySQL editor budgets, Cube cache, MCP rate limitsvalkey-data volume
RustFSrustfs, rustfs-bootstrapvantage-parquet-staging bucketrustfs-data volume
TemporaltemporalIngestion schedules and runsin Postgres
oauth2-proxyoauth2-proxySign-in gate for uploads., monitoring., logs.no
backupbackup (periodic, 02:30 UTC)Postgres dumps and the staging bucket, mirrored to B2backups volume
Observabilityotel-collector, victoriametrics, victorialogs, perses, node-exporterMetrics, logs, dashboardsvolumes on the monitoring worker

Consul, Vault and Nomad servers run on three control-plane nodes; jobs run on three workers. Each stateful job is pinned to the worker that carries its host volume, so a reschedule never restarts it on an empty disk.

Request paths

PathHops
Sign-inbrowser → auth.<d> (Zitadel, PKCE, no client secret) → analytics.<d>/auth/callback; the session is held server-side behind an encrypted __Host-sid cookie (8 hours)
Dashboard widgetbrowser → analytics-web server function → Cube REST with a JWT the server mints for the session's workspace → StarRocks as ro_<slug>
SQL editorbrowser → analytics-web → StarRocks as the project's p_<project id> user, SELECT/WITH only, budget-checked in Valkey
File uploadbrowser asks analytics-web for a 5-minute ticket → posts the file to uploads.<d> → dataplane stages it in RustFS → StarRocks reads it with FILES() into raw_<source>
Scheduled syncTemporal schedule → dataplane worker → the n8n workflow's webhook (N8N_WEBHOOK_URL) → the workflow reads cdc-plan, extracts, and posts batches to load-batch → stream load into the BE. A standalone cluster runs no n8n, so this needs one you provide
Cube schemaCube → analytics-web /api/internal/cube/* with CUBE_SERVICE_TOKEN, per workspace
MCPagent → analytics.<d>/api/mcp with a vmcp_ token → same server functions as the UI

The browser never holds a Cube, StarRocks or Vault credential; everything data-bearing goes through analytics-web server functions, except the file upload, which carries only its ticket.

Tenant boundary

A workspace is a Zitadel organisation. Its id is the tenant_id everywhere: the urn:zitadel:iam:user:resourceowner:id claim, the control-plane row key, the Cube security context, and the tenant_id column on every warehouse row. Its slug names the warehouse database (tenant_<slug>) and its StarRocks users. How each hop enforces it is Tenant isolation.

Prod and preview on one cluster

SharedPer environment
Postgres server, Temporal server, StarRocks, RustFS, Valkey, oauth2-proxy, Caddy, Vault, Consul, backup, observabilitydatabases (analytics / analytics_preview), Nomad namespace, Vault tree (secret/preview/…), bucket (…-preview), warehouse prefix (preview_tenant_<slug>), hostnames (*.preview.<d>), Zitadel, analytics-web, cube, dataplane

Local compose

vantage-deployment/compose/vantage.sh runs the same services as the compose project vantage, plus Mailpit for mail, without Caddy, oauth2-proxy, backup or observability. Ports are in Deploy and upgrade.

Next

On this page