Skip to content

Configuration

Backend configuration happens through environment variables — exported in your shell before docker compose up, set in a compose override file, or placed in app/.env (loaded by the backend container; note that anything in the compose file’s environment: block wins over app/.env). The frontend reads VITE_* variables from frontend/.env.local at build/dev time.

Variable Default Purpose
BACKEND_PORT 8000 Host port the API is published on
CORS_ORIGINS http://localhost:5173,http://127.0.0.1:5173 Comma-separated origins allowed to call the API from a browser
SECRET_KEY secret JWT signing key — change this for anything beyond local evaluation
FRONTEND_URL http://localhost:5173 Where the backend sends users back to after Google OAuth — set it to your dashboard’s real address
MAX_FILE_SIZE 50 MB Per-file ingestion size limit
Variable Purpose
CLERK_PUBLISHABLE_KEY Your Clerk application’s publishable key
CLERK_SECRET_KEY Clerk secret key — required for social sign-in session exchange
CLERK_WEBHOOK_SECRET Signing secret for the /webhooks/clerk endpoint, if you wire Clerk webhooks up
CLERK_AUTHORIZED_PARTIES Origins allowed in Clerk tokens; defaults to CORS_ORIGINS + FRONTEND_URL

Leave these empty and social sign-in is simply off — email/password accounts work without any of them. (The frontend still needs its VITE_CLERK_PUBLISHABLE_KEY either way; see below.)

Variable Default Purpose
TOP_K_PER_COLLECTION 8 How many chunks to retrieve from each collection
SIMILARITY_THRESHOLD 0.7 Minimum similarity for a chunk to be considered
MAX_CONTEXT_LENGTH 12000 Cap on retrieved context, in characters
LLM_NUM_CTX 8192 The model’s context window, in tokens
RAG_TIMEOUT 10 Seconds to wait for retrieval before answering without it

The two capacity numbers use different units, and they’re coupled: MAX_CONTEXT_LENGTH counts characters of retrieved text, LLM_NUM_CTX counts tokens of model context, and the retrieved text must fit inside the model’s window. If it doesn’t, Ollama silently truncates the front of the prompt — retrieval quietly shrinks with no error anywhere. That’s also the tinyllama catch: tinyllama only has a 2048-token window, so if you’re evaluating with it, lower LLM_NUM_CTX to 2048 and MAX_CONTEXT_LENGTH to match (roughly 4 characters per token).

If you serve the dashboard from anywhere other than localhost:5173 — a different port, another machine, or a real domain — add that origin:

compose.override.yml
services:
backend:
environment:
- CORS_ORIGINS=https://insight.example.com,http://localhost:5173

Browser requests from unlisted origins will fail even though curl works.

Variable Purpose
VITE_BACKEND_URL API base the browser should call — http://localhost:8000/api/v1 in dev, or the relative /api/v1 when nginx proxies same-origin
VITE_CLERK_PUBLISHABLE_KEY Required — the dashboard refuses to start without it
VITE_GOOGLE_PICKER_API_KEY Google API key for the Drive file picker
VITE_GOOGLE_PICKER_APP_ID Google Cloud project number, for the same picker
VITE_CHAT_STREAMING Set false to fall back to non-streaming chat (defaults on)
VITE_DEBUG_MODE Set true to expose debug details (e.g. chunk indexes and similarity scores in citations)

Put them in frontend/.env.local (template: frontend/.env.example). Vite bakes them in at build/dev time — rebuild after changing them.

Data-source credentials and Google grants are stored encrypted. The key lives in app/.encrypted.bin, created on first boot by the init-kek compose service. Two rules:

  • Back the file up. Without it, every stored credential is unreadable — the API starts returning “Stored credentials could not be read” and affected sources must be recreated.
  • Don’t skip init-kek. Starting the backend with --no-deps (or otherwise preventing init-kek from running on a fresh checkout) gets you “Encryption is misconfigured” errors instead of a working instance.

Install the NVIDIA Container Toolkit so the Ollama container can use your GPU. Without it the stack still works — inference just runs on CPU.

Google Drive connectivity takes two sets of credentials from one Google Cloud project (create one in the Google Cloud console, with the Drive API and Google Picker API enabled):

  1. A backend OAuth web client. Create OAuth credentials, authorize your instance’s redirect URI (the value of GOOGLE_OAUTH_REDIRECT_URI, e.g. https://insight.example.com/oauth/callback), and place the downloaded JSON at app/secrets/gdrive_secret.json. The consent screen needs three scopes: openid, email, and drive.file — the identity scopes are what lets Settings show which Google account is connected.
  2. Picker keys for the frontend. Set VITE_GOOGLE_PICKER_API_KEY (an API key) and VITE_GOOGLE_PICKER_APP_ID (the project number). Without them the Browse Drive files picker can’t open — and since the drive.file scope only grants files the user has picked, that means no Drive file can be selected at all.

Also set FRONTEND_URL on the backend so the post-consent redirect lands on your dashboard rather than localhost. If nginx sits in front, make sure /oauth/ is proxied to the backend — Google’s callback arrives there, not under /api/.

Docker Compose project names isolate complete environments (separate databases, volumes, and networks) on one machine — useful for teams or for a staging copy:

Terminal window
export BACKEND_PORT=8001 SAMBA_PORT=1446
docker compose -p alice up -d
# elsewhere
export BACKEND_PORT=8002 SAMBA_PORT=1447
docker compose -p bob up -d

Manage each with the same -p flag: docker compose -p alice ps, docker compose -p alice down, etc.

The samba service is a small SMB server for development and testing. Shares live in samba/shares/ on the host — drop files there and they’re visible to pipelines through a data source pointed at it (credentials testuser/testpass). The credentials are baked into the image at build time, so changing them means editing samba/Dockerfile and rebuilding.