DLT is the engine. It defines how data gets in, how it's reshaped, and how it's surfaced — through a single, declarative template model. Customers get isolated workspaces; we get a single codebase that powers all of them.

The mental model

A template is a blueprint. A workspace is its instance. Same template → many workspaces.

Template
blueprint
Workspace
isolated instance
Dashboards
customer view

one template can power many customers · each gets its own tables, configs, and data

How data moves through DLT

Think medallion architecture: bronze (raw) → silver (derived) → gold (predicted). Metrics sit on top and can pull from any layer.

bronze silver gold analytics Source SCADA · APIs · S3 Datastore raw timeseries Featurestore derived / aggregated ML Models train + serve Inferencestore predictions · scores Metrics SQL / Python · cross-layer Dashboards Alerts Reports data layers automation cross-cutting view layer

ML models read from bronze + silver, write to gold. Metrics sit on top of all three layers.

Template components — click to drill down

Every template is built from these six lego pieces.

D

Datastores

Raw incoming data — sensor readings, events, logs.
data layer
+
F

Featurestores

Derived / aggregated data, pre-shaped for analytics & ML.
data layer
+
I

Inferencestores

ML predictions, scored back into the same DB.
data layer
+
M

Metrics

SQL or Python — KPIs and aggregations that power charts & alerts.
analytics
+
B

Dashboards

Customer-facing layout of charts & controls.
analytics
+
L

ML Models

Training pipelines + serving config for inference.
ml / auto
+

Datastores

Raw incoming data. Schemas are defined as JSON Schema, validated on write, stored as TimescaleDB hypertables under {key}_wid{workspace_id}.

  • One datastore = one logical "stream" of data (e.g. sensor_data, events)
  • Per-workspace isolation — same template, different physical tables per customer
  • Powers all downstream layers (metrics, features, dashboards)

Featurestores

Derived data — rolled-up timeseries, computed metrics, joins. Used to keep dashboards fast and feed ML models.

  • Example: pump_metrics_10min_wid1 — 10-min aggregates of raw sensor data
  • Refreshed on schedule by the scheduler service

Inferencestores

Where ML model outputs land — predictions, anomaly scores, classifications — written back into the platform so dashboards and alerts can use them like any other data.

Metrics

The "view layer" of the platform. SQL or Python transforms that take store data and produce numbers/series for charts and alerts.

  • Reference stores with datastore:key, featurestore:key, inferencestore:key
  • Bind params support filters & user inputs
  • Drive charts on dashboards and conditions for alerts

Dashboards

Layouts of charts & controls. Most complex component — supports time-series, bars, pies, geospatial, tables, alerts, and cross-dashboard redirects.

ML Models

Training pipelines and serving config. Operate on featurestores, write to inferencestores. (Example: XRI's pump-metrics-transform model.)

What plugs into DLT

Out-of-the-box connectors and notifiers.

Data connectors (in)

PostgreSQL
core
Ignition / SCADA
core
MongoDB
v1
MySQL
v1
S3 / Azure Blob
v1
Snowflake
v1
Airtable
v1
Shalestone
v1

Notifiers (out)

Email (incl. PDFs)
core
Slack
v1
SMS
v1
Microsoft Teams
v1

Alerts and scheduled reports route through these. Email is the workhorse — PDFs, CID-inline images, all supported.

Deployment shape

Stack

  • Backend: Python · FastAPI · SQLAlchemy
  • Frontend: React + TypeScript
  • DBs: TimescaleDB (Postgres 16)nixdb + nixdatadb
  • Container runtime: Docker Compose
  • Scheduler: internal · cron-like
  • CLI: nix · hatch-managed

Service split

  • nixapi — main backend (REST + UI server)
  • nixdb — app DB (workspaces, templates, configs)
  • nixdatadb — data sink (customer timeseries)
  • scheduler — featurestore + inference jobs
  • alertserver — runs alert checks
  • metricserver — metric computation
  • mlserver — model training & serving
The split between nixdb (control plane) and nixdatadb (data plane) is deliberate — it lets us scale customer data independently and keeps platform metadata small & portable.
See the full architecture diagram →