Configuration
Every backend setting is an environment variable with a sensible default. The
backend loads them from backend/app/.env (which overrides the defaults defined in
app/config.py). The frontend reads NEXT_PUBLIC_* values from
frontend/.env.local.
Change values in both places if you also override them in config.py. The
.env file wins at runtime, but the config.py default is the fallback.
#Backend — required
| Variable | Description |
|---|
SUPABASE_URL | Your Supabase project URL. |
SUPABASE_SECRET_KEY | Supabase service role key. The backend uses it server-side to enforce its own access logic (Row Level Security is intentionally bypassed). Keep it secret. |
SUPABASE_JWKS_URL | JWKS endpoint used to validate access tokens (…/auth/v1/.well-known/jwks.json). |
OPENAI_API_KEY | OpenAI key for embeddings, generation, vision, and the eval judge. |
PINECONE_API_KEY | Pinecone API key. |
PINECONE_INDEX | Name of the Pinecone index (must be 1024-dim, cosine). |
#Backend — networking
| Variable | Default | Description |
|---|
ALLOWED_ORIGINS | http://localhost:3000 | Comma-separated allowed CORS origins. Set to your frontend origin(s) in production. |
REDIS_URL | redis://localhost:6379 | Redis connection for the Arq worker. Required for ingestion and async eval scoring. |
#Backend — retrieval & chunking
| Variable | Default | Description |
|---|
EMBEDDING_MODEL | text-embedding-3-small | Embedding model. Must match the index dimension. |
EMBEDDING_DIMENSIONS | 1024 | Embedding dimensionality. Must equal the Pinecone index dimension. |
CHUNK_SIZE | 1800 | Target characters per text chunk (recursive splitter). |
CHUNK_OVERLAP | 250 | Character overlap between adjacent chunks. |
TABLE_MAX_CHARS | 3000 | Max size a structured unit (table/slide/row batch) may reach before it is split into prose. Kept above CHUNK_SIZE so tables/slides stay whole. |
TOP_K | 5 | Number of chunks retrieved and fed to the model. |
NEIGHBOR_WINDOW | 1 | Adjacent chunks stitched around each retrieved chunk (per side). 0 disables. |
#Backend — reranking (opt-in)
| Variable | Default | Description |
|---|
RERANK_ENABLED | false | Set true to enable Cohere cross-encoder reranking on similarity/threshold queries. |
RERANK_MODEL | rerank-english-v3.0 | Cohere rerank model. |
RERANK_FETCH_MULTIPLIER | 4 | Over-fetch factor before reranking (top_k × this). |
COHERE_API_KEY | — | Required when RERANK_ENABLED=true. |
#Backend — vision / multimodal
| Variable | Default | Description |
|---|
VISION_MODEL | gpt-4o | Model used for image description and scanned-PDF OCR. |
MIN_IMAGE_BYTES | 5000 | Embedded PDF images smaller than this are skipped (icons, bullets, rules) to avoid noise. |
#Frontend
| Variable | Description |
|---|
NEXT_PUBLIC_API_URL | Backend origin the browser calls (e.g. http://localhost:8000 or your Railway URL). |
NEXT_PUBLIC_SUPABASE_URL | Supabase project URL (client-side). |
NEXT_PUBLIC_SUPABASE_ANON_KEY | Supabase anon key (safe for the browser; not the service role key). |
The API client normalizes NEXT_PUBLIC_API_URL — if it lacks a scheme it
assumes https://. Set the full origin to be safe.
#External resources you must provision
| Resource | Requirement |
|---|
| Pinecone index | Serverless, dimension 1024, metric cosine. Name → PINECONE_INDEX. |
Supabase Storage: documents | Private bucket. Holds original uploads; served via 1-hour signed URLs. |
Supabase Storage: images | Public bucket. Holds extracted PDF figures; their public URLs go into vector metadata for inline source rendering. |
| Supabase Auth | Email/password enabled. |
| Supabase tables | collections, collection_members, collection_shares, collection_documents, document_chunks, chat_sessions, chat_messages, ingest_jobs, rag_evals, query_logs, ingest_logs. |
| Redis | Reachable at REDIS_URL; backs the Arq worker. |
#Cost-relevant knobs
Most spend is OpenAI usage. The levers:
TOP_K and CHUNK_SIZE drive prompt size → generation cost per query.
- Vision (multimodal PDFs / scanned OCR) is the priciest ingestion path;
MIN_IMAGE_BYTES filters trivial images. Prefer native PDFs.
- Eval scoring uses the cheaper
gpt-4o-mini (two short calls per query).
- Reranking adds a small Cohere cost per query when enabled — usually worth it
for precision.
See Operations & scaling for the runtime/process view.