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
┌──────────── 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
| Service | Role |
|---|---|
| gateway | nginx. The only reachable door. Routes by path: console, agent API, Keycloak. |
| console | The web interface, a React/Vite SPA. Signs in over OIDC with PKCE. |
| agent | The backend (Fastify/TypeScript): tools, gates, ingestion, embeddings, lineage, audit. |
| keycloak | Login and identity. Issues the tokens every other service verifies. |
| trino | The SQL engine. Runs every statement under the caller's exchanged token. |
| nessie | Versioned Iceberg catalog — branching and time travel, Git-style. |
| minio | S3-compatible object storage. Buckets: warehouse for table data, audit for the log. |
| postgres | Platform state and, through pgvector, the embedding index. Plus the Keycloak and Nessie databases. |
| backup | In Compose: daily backup of all databases and configuration; object storage data needs separate backup. |
| ollama | The 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