Documentation

Deploy, connect & operate InsightViz

Everything runs on the shared VerticalServe platform: FastAPI on Postgres for metadata, DuckDB over Parquet for data, a React console, and the identity and connection registry every Insight product shares.

Architecture at a glance

One engine, three runtimes, one query contract. The React app never talks to DuckDB directly: it sends a logical query and gets rows back through the gateway, which compiles it against the semantic model with the caller’s policies applied.

# the query path React console → POST /api/query {model_id, query} → compiler: semantic model + row/column policies → DuckDB SQL (params bound) → engine: read_parquet(s3://bucket/{org}/{datasource}/{version}/<table>/**) → rows → query_log: who, what, rows, ms, refused/failed
ComponentWhat it holds
Postgres (schema viz)workspaces, datasources, extracts, semantic models, dashboards, conversations, policies, query log, jobs — plus the platform’s identity and connection tables
Object storethe extracts: partitioned Parquet + manifest.json per version, and uploads awaiting import
DuckDBin-process in the API; reads Parquet on file://, s3://, gs://, az:// through httpfs; result cache keyed on the immutable extract
Workerin-process by default (VIZ_WORKER=1); a Postgres queue with SKIP LOCKED, so a second container is safe
Model providerthe platform’s chat model: Bedrock, Azure OpenAI, Vertex, OCI or an OpenAI-compatible endpoint

Quick start

The API and the console run from two directories; the platform packages come from the private insight-platform repository.

# API — Python 3.12 cd insightviz-api && python3.12 -m venv .venv && source .venv/bin/activate pip install -r requirements.txt cp .env.example .env # INSIGHT_DATABASE_SCHEMA=viz, VIZ_STORE_EXTRACTS=… PYTHONPATH=. python scripts/init_platform.py --admin you@company.com PYTHONPATH=. uvicorn app.main:app --port 8119 # Console — Node ≥ 20 cd insightviz-ui && npm install && npm run dev # http://localhost:5219, /api proxied to 8119

Docker. docker compose up in the product directory builds both images. The API image takes INSIGHT_PLATFORM=aws|azure|gcp|oci to pick the cloud SDKs, and a read-only git_token build secret for the platform packages.

Configuration reference

VariableMeaning
INSIGHT_DATABASE_URL / _SECRET / _SCHEMAthe platform Postgres; the password is a secret ref (aws-sm://…, azure-kv://…, gcp-sm://…), never a value
VIZ_STORE_EXTRACTSa store ref for extracts: s3://bucket/prefix, gs://…, az://…, file:///…
VIZ_STORE_UPLOADSwhere dropped files and Tableau workbooks wait for the worker
VIZ_EXTRACT_TTL_DAYShow long a client may use an extract before it must re-authenticate (default 7)
VIZ_LOCAL_EXTRACT_MAX_MBextracts at or under this size may be served to a browser / desktop runtime (default 400)
VIZ_QUERY_MAX_ROWS, VIZ_DUCKDB_THREADS, VIZ_DUCKDB_MEMORYengine limits per query
VIZ_AI_ENABLED, INSIGHT_LLM_PROVIDER, INSIGHT_CHAT_MODELthe assistant, and which model answers
INSIGHT_JWT_KEY_REFthe token-signing key shared across Insight products

Datasources & extracts

A datasource is a named source inside a workspace: a platform connection plus the tables or queries to pull, a refresh schedule, and whether its extract may be served to a local runtime. A refresh writes a new extract under a new prefix; when it is ready the datasource’s pointer moves, so readers never see a half-written extract and the previous version stays for rollback until it expires.

s3://bucket/insightviz/extracts/{org}/{datasource}/{version}/ manifest.json # format, written_at, expires_at, tables, lineage orders/year=2025/month=09/part-000.parquet customers/part-000.parquet

Postgres and MySQL are attached natively by DuckDB and copied straight to Parquet; other SQL dialects stream through Arrow batches. CSV and Parquet drops become an extract of kind upload. Partition with order_date:month or a plain column.

Semantic models

The model is the contract between the data and everything that asks it. It names dimensions, metrics and joins with business labels, descriptions and synonyms; the compiler and the AI read nothing else. A model is derived on a datasource’s first extract and refined from there — by hand in the JSON editor, or by the AI (“Enrich”) for labels, descriptions and synonyms.

{"base_table": "orders", "tables": {"orders": {"source": "orders"}, "customers": {"source": "customers"}}, "joins": [{"table": "customers", "type": "left", "on": "orders.customer_id = customers.id"}], "dimensions": [{"name": "region", "label": "Region", "sql": "orders.region", "type": "string", "synonyms": ["territory"]}, {"name": "order_date", "sql": "orders.order_date", "type": "time"}], "metrics": [{"name": "net_revenue", "label": "Net revenue", "sql": "SUM(orders.amount - orders.discount)", "format": "currency"}]}

The logical query

What the console, the dashboard document and the AI produce. None of them write SQL.

{"dimensions": ["region", "order_date.month"], "metrics": ["net_revenue", "orders"], "filters": [{"field": "region", "op": "in", "values": ["West"]}, {"field": "net_revenue", "op": ">", "value": 100}], "order_by": [{"field": "net_revenue", "desc": true}], "limit": 500}

Operators: = != > >= < <= in not_in between contains starts_with is_null not_null. Time grains: year quarter month week day hour. Every name must be a dimension or metric of the model — nothing else is accepted, which is how the catalogue is the whole attack surface. Values are bound as parameters, never spliced.

Dashboards

A dashboard is a document: {layout, widgets: [{id, title, x, y, w, h, query, chart}], filters, parameters}. Chart specs are declarative — {type: bar|line|area|scatter|pie|table|kpi, x, y, series} — and rendered by the console with Vega-Lite. Publishing snapshots the definition as a version with a note; any version can be restored into the draft. POST /api/dashboards/{id}/run executes every widget with the page’s filters in one call.

AI Ask

The assistant is given the catalogue (names, labels, synonyms — never SQL) and two tools: run_query and draw_chart. It iterates — query, look, refine — then answers in words. The message carries the logical query, the SQL, the chart, a result sample and the tool trace, so “how was this computed” is a click. Answers can be kept as saved queries or added to a dashboard as widgets.

Tableau import

Drop a .twbx, .tdsx, .twb, .tds or .hyper. Every table in the Hyper extract becomes Parquet; the workbook XML becomes the semantic model (captions, roles, aggregations, hierarchies, calculated fields translated to SQL) and the dashboards (sheets → widgets, zones → grid). The fidelity report lists every sheet and calculation as converted, translated-verify or manual — LOD expressions and table calculations are always manual. A workbook with a live connection and no extract is reported with the connection details so the datasource can be created against your own connection.

Security & policies

  • Identity — OIDC/SAML through the platform identity service; roles map from your directory; API keys for services.
  • Workspaces — owner, editor, viewer per workspace; an organisation-visible workspace is viewable by anyone signed in.
  • Row policies{dimension, op, values} for a principal (an email, role:<name> or *), added to WHERE by the compiler.
  • Column policies — dimensions hidden from a principal disappear from the catalogue; a query naming them is refused.
  • Local runtimes — a datasource marked server-only never issues presigned URLs. Data served to a client is data that person may see.
  • Query log — every compiled query with who, source, rows, milliseconds and outcome, refusals included.

API

Every response is the envelope {status: SUCCESS|FAIL, data, error_message}. A bearer token from /api/auth/login or an API key authenticates. Interactive docs at /docs on the API host.

RouteWhat
/api/workspacesworkspaces and members
/api/datasourcesdatasources, /refresh, extracts (/activate, /tables/{t}/preview, /presign), policies, /upload
/api/modelssemantic models, /publish, /enrich, /suggest, /values/{dim}, saved queries
/api/querythe gateway; /compile for the SQL without running it; /log
/api/dashboardsdocuments, /publish, /versions, /run, /clone
/api/chatconversations, /ask, /messages/{id}/save
/api/imports/tableau, jobs and their SSE events
/api/connections, /api/user, /api/auditthe platform’s connection registry, identity admin and audit trail

Want a hand with the deployment?

We deploy InsightViz into your AWS, Azure or GCP account with your identity provider and your model endpoint, and migrate the first workbooks with you.

Talk to us