Celiq
v0.12Open app โ†—
Docs/Developer/Platform Architecture

Platform Architecture

A technical overview of how Celiq's layers โ€” Physical, Semantic, and Runtime โ€” work together to serve analytics queries.

LuminaryWeaverUpdated June 2026 ยท 8 min read
โœฆ
In this section
Part of Celiq's semantic layer platform. Connect your warehouse, model your data once, query it everywhere.
๐Ÿ“
Note

This page is for platform builders and administrators who need to understand Celiq's internals. End users building analytics should start with Quick Start instead.

Celiq is a self-hosted semantic analytics platform. It has three layers: the Physical Layer connects to your warehouse, the Semantic Layer defines what data means, and the Runtime Layer executes queries. This page describes each layer and how they interact.

Three-layer architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                   RUNTIME LAYER                       โ”‚
โ”‚  Discover  ยท  Orion AI  ยท  Mosaics  ยท  Scheduling    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                       โ”‚ resolves
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                  SEMANTIC LAYER                       โ”‚
โ”‚  Nodes  ยท  Domains  ยท  Reveals  ยท  Metrics  ยท  CML   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                       โ”‚ maps to
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                  PHYSICAL LAYER                       โ”‚
โ”‚  Datasets  ยท  Deployments  ยท  Mappings               โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                       โ”‚ queries
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                     WAREHOUSE                         โ”‚
โ”‚  Snowflake  ยท  BigQuery  ยท  Postgres  ยท  Redshift     โ”‚
โ”‚  DuckDB  ยท  MySQL  ยท  SQL Server  ยท  Databricks       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Physical Layer

The Physical Layer resolves abstract dataset names to physical tables at query time. It has three concepts:

Datasets โ€” Logical table definitions. A dataset is a schema: a name plus a list of column definitions (name, type, nullable). It doesn't live in any one warehouse. Deployments โ€” Target environments (Production, Development, Staging). Each workspace has one default deployment; all end-user queries run through it. Dataset Mappings โ€” Bindings that say "in deployment X, dataset Y maps to connection Z, table W." Celiq validates mappings by comparing dataset column definitions against the physical table schema and computes a compatibility score. What it resolves: dataset name + active deployment โ†’ (connection, physical table) Storage: PostgreSQL tables datasets, dataset_columns, deployments, dataset_mappings

Semantic Layer

The Semantic Layer defines what data means: metric calculations, dimension taxonomies, join logic, and security rules. It is authored in CML files inside Forge.

Nodes โ€” Map to datasets. Each node defines dimensions (group-by columns) and measures (aggregations). Written in CML. Domains โ€” Join multiple nodes together. A domain defines which nodes can be combined in a query, and with what join logic. Reveals โ€” Named, certified query configurations exposed to end users. A Reveal defines which node/domain to start from, which metrics and dimensions are surfaced, and AI context for Orion. Metrics โ€” Named measures promoted to first-class status. A metric has a canonical definition, a business owner, and usage tracking. Storage: PostgreSQL; CML source files in Forge (Git-backed). A compiled model cache is maintained per workspace. Compile/validate flow: Forge runs a validation pass (Check & Save) before any semantic change goes live. Validation checks SQL parse, fanout risk, join integrity, and field reference correctness.

Runtime Layer

The Runtime Layer is everything that actually runs queries and serves results.

Query execution

  1. Field resolution โ€” Discover sends a query spec (dimensions, measures, filters, grain). The backend resolves field names against the compiled semantic model.
  2. SQL generation โ€” buildSQL() generates warehouse-specific SQL via applyDialect(). It handles type casting, date truncation, CASE expressions, and window functions per warehouse dialect.
  3. Deployment resolution โ€” The active deployment is determined (workspace default, or Mosaic-pinned deployment). The dataset โ†’ (connection, physical_table) mapping is looked up.
  4. Execution โ€” SQL is sent to the warehouse via the appropriate driver (pg, @google-cloud/bigquery, snowflake-sdk, duckdb).
  5. Post-processing โ€” Table calculations (window functions, running totals, rank) that can't be expressed as SQL are applied client-side after results arrive.

Security enforcement

Every query passes through two security guards before results are returned:

  • dataSecurityEnforce โ€” Applies row-level security (Data Keys) and column-level security (Data Gates) based on the requesting user's role and attributes. This guard is fail-closed: any error blocks the query rather than returning unredacted data.
  • Tenant isolation โ€” All database queries include workspace_id in WHERE clauses, enforced by tenantRls.js. A user in workspace A cannot access workspace B's data regardless of the query.

Orion AI

Orion is the AI layer that translates natural language into Reveal configurations. It uses Claude (Anthropic) via the workspace's configured API key. The key is stored encrypted per workspace in the database โ€” never as environment variables.

Orion resolves node/domain/metric references using the semantic model via resolveReveal (DISTINCT ON with domain priority โ€” the node that most closely matches the intent is selected, preferring nodes within the active domain).

Scheduling and delivery

Scheduled reports and Mosaic snapshots run via a background job queue. Each scheduled item runs a query through the normal runtime path and delivers results via configured channels (email, Slack).

Stack

ComponentTechnology
BackendNode.js / Express
DatabasePostgreSQL (Railway managed)
FrontendReact 18 + Vite (dist committed to git)
AIAnthropic Claude โ€” model configurable per workspace
Warehouse driverspg (Postgres/Redshift), @google-cloud/bigquery, snowflake-sdk, better-sqlite3 (DuckDB)
DeploymentRailway (auto-deploy on push to main)

Authentication

  • Session tokens โ€” JWT-based, issued on login. No session storage in the database.
  • API keys โ€” Workspace-scoped keys for programmatic access to /api/* endpoints.
  • Workspace AI key โ€” Anthropic API key stored encrypted per workspace, accessed via getWorkspaceApiKey(workspaceId). Never queried from workspace_ai_config directly.

Multi-tenancy

Celiq is a single-instance, multi-tenant deployment. Tenant isolation is enforced at:

  1. Auth middleware โ€” req.workspaceId is set from the authenticated session. All route handlers use req.workspaceId, never req.user.workspace_id.
  2. Database queries โ€” All queries include workspace_id = $1 filters. The tenantRls.js module enforces this pattern.
  3. Credential encryption โ€” Warehouse credentials are encrypted with AES-256-GCM using a per-deployment encryption key (ENCRYPTION_KEY env var). Decryption happens in backend/lib/crypto.js.