Skip to content

Architecture

VOL is served from a single Cloudflare Pages deployment while the heavy lifting (retrieval, LLM, GPU) runs on a private server reached through Workers VPC and a Cloudflare Tunnel. No inbound port is opened on the server.

Browser
│ https://<host>/ → web (Astro, static)
│ https://<host>/app/ → app (React + Vite, static)
│ https://<host>/docs/ → docs (Astro Starlight, static)
│ https://<host>/api/v1/* → Pages Function
▼
Cloudflare Pages ──► Worker "vol-gateway" (Workers VPC binding)
│
▼ Cloudflare Tunnel (cloudflared, outbound only)
┌───────────────── private server (Docker) ─────────────────┐
│ vol-api :8010 (FastAPI, /v1/*) │
│ ├─► ragflow-server :80/api/v1 (RAG, chat assistants) │
│ ├─► ragflow-es-01 :9200 (Elasticsearch) │
│ ├─► graph artifacts (positions.bin, links.bin, …) │
│ └─► SQLite (API keys, hashed) │
│ ragflow-mysql · ragflow-redis · ragflow-minio │
│ ollama (bge-m3 embeddings, GPU) · tei-reranker (GPU) │
└────────────────────────────────────────────────────────────┘
Supabase (auth: users, Google OAuth, magic links, SSO) ◄── app; vol-api verifies JWTs via JWKS
Component Role
Cloudflare Pages Hosts the three static sites and the /api/v1/* Pages Function.
vol-gateway Worker Forwards API calls into the private network through Workers VPC.
cloudflared Outbound tunnel from the server to Cloudflare.
vol-api FastAPI service implementing the v1 contract; auth, SSE streaming, graph artifacts.
RAGFlow Datasets, hybrid retrieval, RAPTOR, chat assistants per case.
Elasticsearch RAGFlow’s index; also queried directly for search.
Ollama + TEI bge-m3 embeddings and reranking on the GPU.
Supabase User accounts and sessions.
  1. The app calls POST /api/v1/chat with the user’s Supabase token (or an integration sends an API key).
  2. The Pages Function hands the request to vol-gateway, which reaches vol-api through the tunnel.
  3. vol-api authenticates, maps the case to its RAGFlow assistant and opens a streaming completion.
  4. Tokens are re-emitted as SSE delta events; retrieved chunks are mapped to nodeIndex values and sent as a citations event with the RAPTOR clusters; done closes the stream.

In development the app’s Vite server proxies /api/v1/* to http://localhost:8010/v1/*, so the same code runs locally and in production. See Self-hosting with bin/vol.