Skip to content
MCP server built inHow that works

Architecture

The platform services sit behind a single reverse proxy. The Compose stack also includes a dedicated backup service. Only that proxy is reachable; everything else stays on the internal network.

On this page

The shape of it

Path of a query
                       ┌──────────── nginx gateway (:8080) ────────────┐
 browser  ───────────▶ │  /  → console    /api/agent → agent   /auth → KC │
                       └──────────────────────────────────────────────────┘
                                    │                 │
                             Console (React/Vite)     Agent (Fastify/TS)
                                                       │  delegated token (RFC 8693)
                                                       ▼
   Keycloak (OIDC)   PostgreSQL + pgvector   Trino ── Iceberg ── Nessie   SeaweedFS (S3)
   identity          platform state,         SQL engine  tables   catalog  object store
                     vectors
                                                       │
                                              Ollama (local embeddings, CPU)

The services one by one

ServiceRole
gatewaynginx. The only reachable door. Routes by path: console, agent API, Keycloak.
consoleThe web interface, a React/Vite SPA. Signs in over OIDC with PKCE.
agentThe backend (Fastify/TypeScript): tools, gates, ingestion, embeddings, lineage, audit.
keycloakLogin and identity. Issues the tokens every other service verifies.
trinoThe SQL engine. Runs every statement under the caller's exchanged token.
nessieVersioned Iceberg catalog — branching and time travel, Git-style.
minioS3-compatible object storage. Buckets: warehouse for table data, audit for the log.
postgresPlatform state and, through pgvector, the embedding index. Plus the Keycloak and Nessie databases.
backupIn Compose: daily backup of all databases and configuration; object storage data needs separate backup.
ollamaThe local embedding model (bge-m3) behind an OpenAI-compatible endpoint. No cloud key.

Delegated identity

The agent holds no data account of its own. When a request arrives, it exchanges the user's token through Keycloak's standard token exchange (RFC 8693) for a token with audience trino, and issues the query with that. Trino's own grants and the row and column policies decide what comes back.

One issuer, in lockstep

Keycloak sits under /auth and pins the public issuer. Every token carries exactly that one — including the token for Trino, while backchannel calls stay internal.

Why the vector index is only an index

PostgreSQL holds embeddings, search text and source-row references; the authoritative tables live in the lakehouse. A search only determines there which rows might match; their content is then re-fetched from Trino under the searcher's identity. That costs a second hop, but it keeps governance in one place instead of forcing a second implementation of it inside the search index.

Deployment shapes

  • Docker Compose — the reference deployment on one machine; Ansible automates installation and updates on Debian/Ubuntu.
  • Kubernetes through infra/helm/flaky-platform — a separate deployment path; the values-datenrechte.yaml overlay enables policy distribution to Trino.

The catalog ships with it

An installation brings its own Iceberg catalog (Nessie on s3://warehouse/). Mounting an existing catalog alongside it is not possible yet.

Applies to: This page describes lavalake 0.201.0. Product and documentation live in separate repositories — when in doubt, what the console shows is authoritative.

Something missing?

If these pages do not answer your question, we will walk through the platform against your own case in half an hour.

Book a demo