Platform

Architecture

Kaveon is a pnpm monorepo with two applications — a Next.js frontend and a FastAPI backend — over a two-plane database (a small control + context store and a data warehouse) plus your registered data sources. The browser only ever talks to the frontend.

The two applications

AppPathRuntime
kaveon-webapps/kaveon-webNext.js 15 · React 19 · TypeScript
kaveon-apiapps/kaveon-apiFastAPI · Python 3.11

Shared TypeScript types live in packages/types.

Request flow

text
Browser
  │  session cookie (same-origin)
  ▼
kaveon-web  (Next.js — App Router, RSC by default)
  │  /api/kaveon/[...path]  — the only ingress to the API
  │  stamps X-User-Email, X-User-Name, X-User-Role, X-Proxy-Secret
  ▼
kaveon-api  (FastAPI)
  ├── kaveonmeta   (Azure PG — control + context: datasets, charts, dashboards,
  │                 roles, history, and the DLM tables dlm_* / context_*)
  ├── kaveon       (Azure PG — the data warehouse: the actual rows)
  └── Data Sources (Fabric SQL · Azure SQL · PostgreSQL · MySQL · StarRocks)
The API is never exposed to the browser. All traffic hits Next.js; the proxy route forwards it server-side with the identity headers and a shared secret the API validates. See Auth & RBAC for that contract.

Frontend — kaveon-web

Next.js 15 App Router, React Server Components by default, with client components for the interactive builders.

text
app/
  page.tsx            — Homepage / NL→SQL chat
  lab/                — SQL Lab (Monaco)
  charts/  datasets/  — builders + lists
  dashboards/         — react-grid-layout canvas
  data-sources/       — connection management
  docs/               — this documentation (public)
  api/kaveon/[...]/   — API proxy (route.ts)
  api/auth/           — NextAuth (Auth.js v5)
Key utilityPurpose
utils/nlToSql.tsTemplate-based NL→SQL engine — the fallback path (the DLM is primary)
components/ContextBanner.tsxHomepage banner: what the DLM can answer, with hover detail
components/DatasetContextPanel.tsxDataset page: last-generated, duration, indexed dims/metrics, Regenerate
utils/echartsTheme.tsDark/light theming for ECharts
utils/querySemaphore.tsClient-side query concurrency limit
components/charts/ChartBuilderContext.tsxChart registry, SQL generation, builder state
components/dashboards/DashboardCanvas.tsxGrid-layout dashboard canvas

Backend — kaveon-api

FastAPI with a routers/services/middleware split: one router per domain, business logic in services (query_generator, the dlm / context_* engine, auth/role resolution), and cross-cutting concerns in middleware. Identity is established by the frontend proxy, not the API: middleware reads the X-User-* headers and trusts them only when X-Proxy-Secret matchesKAVEON_PROXY_SECRET — there is no bearer token or JWT verification in the request path. A per-database connection pool is warmed at startup and kept alive with a 5-minute heartbeat; the smallkaveonmeta pool is sized independently from the warehouse pools.

Query paths — the DLM

The homepage’s primary NL→SQL engine is the DLM (Data Language Model) — a per-dataset compiled context artifact built with no hosted LLM. It resolves a question deterministically and, for the common cases, answers from precomputed context with no database scan at all. Only novel slices fall through to a single live query. Every answer is labelled honestly:

  • ⚡ From context · no DB scan — a totals / by-dimension / single-dimension-filter answer served from an in-memory cache warmed from the precomputed dlm_answers store.
  • Live query · Xs — a year-slice or multi-filter combination assembled into one warehouse query, then cached.

Because the kaveonmeta control + context plane is physically separate from the kaveonwarehouse, context answers never contend with a multi-million-row scan. The in-browser template parser (utils/nlToSql.ts) remains as the fallback for shapes the DLM does not yet build (mainly time-series trends). See the NL→SQL page for details.

Generating a DLM is a one-time encode step (read the warehouse’s statistics and precompute answers), not per-dataset model training. The dataset page shows when context was last generated, how long it took, and which dimensions and metrics are indexed.

Theming

Every color is a CSS variable — no hardcoded values in components — so light/dark and per-user themes apply instantly. ECharts options are passed through applyChartTheme(option, isDark) so charts match.

css
var(--accent)        /* #4A9EE8 — brand blue */
var(--bg-surface)    /* cards / panels */
var(--text-primary)  var(--text-muted)  var(--border)