Lumen Docs

Data flow

Three major flows: chat (read), upload (write), share (public). Each crosses different services — understanding the hop sequence helps when debugging.

Chat flow (docs mode)

Browser                lumen-web           lumen-api            lumen-embedder          lumen-postgres         LLM provider
  │                        │                    │                       │                        │                      │
  │ type question          │                    │                       │                        │                      │
  │ + Enter                │                    │                       │                        │                      │
  │───────────────────────▶│                    │                       │                        │                      │
  │                        │ POST /chat/projects/:id (SSE)              │                        │                      │
  │                        │───────────────────▶│                       │                        │                      │
  │                        │                    │ POST /embed            │                        │                      │
  │                        │                    │  {text: "query: ..."} │                        │                      │
  │                        │                    │──────────────────────▶│                        │                      │
  │                        │                    │◀──────────────────────│ vector (384-dim)        │                      │
  │                        │                    │                       │                        │                      │
  │                        │                    │ hybrid search (raw SQL with inline vector lit) │                      │
  │                        │                    │────────────────────────────────────────────────▶│                      │
  │                        │                    │◀────────────────────────────────────────────────│ top 50 chunks        │
  │                        │                    │                       │                        │                      │
  │                        │                    │ POST /rerank           │                        │                      │
  │                        │                    │  {query, docs, top_k} │                        │                      │
  │                        │                    │──────────────────────▶│                        │                      │
  │                        │                    │◀──────────────────────│ top 5-8 indices         │                      │
  │                        │                    │                       │                        │                      │
  │                        │                    │ resolveProvider(modelId)                       │                      │
  │                        │                    │────────────────────────────────────────────────▶│                      │
  │                        │                    │◀────────────────────────────────────────────────│ provider config      │
  │                        │                    │                       │                        │                      │
  │                        │                    │ POST /chat/completions (streaming)             │                      │
  │                        │                    │────────────────────────────────────────────────────────────────────▶ │
  │                        │ ← SSE stream       │ ← SSE stream         │                        │                      │
  │                        │                    │                       │                        │                      │
  │ ← rendered tokens      │                    │                       │                        │                      │

Latency budget:

  • Embed: ~50ms
  • Hybrid search: ~100ms
  • Rerank: ~200ms
  • LLM first token: ~500-1000ms
  • Total to first token: ~1s

Code paths:

  • Entry: apps/api/src/routes/chat.ts
  • RAG: apps/api/src/services/rag.ts
  • Provider resolver: apps/api/src/services/llm.ts resolveProvider()
  • Frontend stream: apps/web/lib/api.ts chatStream() — async generator over SSE

Upload flow

Browser                lumen-api           lumen-postgres    Redis          lumen-worker         lumen-embedder
  │                        │                     │              │                  │                      │
  │ select file + submit   │                     │              │                  │                      │
  │───────────────────────▶│                     │              │                  │                      │
  │                        │ save file to        │              │                  │                      │
  │                        │ /data/uploads/...   │              │                  │                      │
  │                        │                     │              │                  │                      │
  │                        │ INSERT document     │              │                  │                      │
  │                        │  status=processing  │              │                  │                      │
  │                        │────────────────────▶│              │                  │                      │
  │                        │                     │              │                  │                      │
  │                        │ bullmq.add(         │              │                  │                      │
  │                        │  "doc-processing",  │              │                  │                      │
  │                        │  {docId})           │              │                  │                      │
  │                        │────────────────────────────────────▶│                  │                      │
  │ 200 {document}         │                     │              │                  │                      │
  │◀───────────────────────│                     │              │                  │                      │
  │                        │                     │              │ pick up job      │                      │
  │                        │                     │              │─────────────────▶│                      │
  │                        │                     │              │                  │ parse (PyMuPDF etc)  │
  │                        │                     │              │                  │                      │
  │                        │                     │              │                  │ chunk into ~400-tok  │
  │                        │                     │              │                  │ segments + 50 tok    │
  │                        │                     │              │                  │ overlap              │
  │                        │                     │              │                  │                      │
  │                        │                     │              │                  │ POST /embed          │
  │                        │                     │              │                  │ [passage: ...]       │
  │                        │                     │              │                  │────────────────────▶│
  │                        │                     │              │                  │◀────────────────────│ vectors
  │                        │                     │              │                  │                      │
  │                        │                     │              │                  │ INSERT chunks        │
  │                        │                     │              │                  │  (embedding, content,│
  │                        │                     │              │                  │   page_number...)    │
  │                        │                     │◀─────────────────────────────────│                      │
  │                        │                     │              │                  │                      │
  │                        │                     │              │                  │ UPDATE document      │
  │                        │                     │              │                  │  status=indexed      │
  │                        │                     │◀─────────────────────────────────│                      │
  │                        │                     │              │                  │                      │
  │ polls status widget    │                     │              │                  │                      │
  │───────────────────────▶│ GET /documents/:id  │              │                  │                      │
  │                        │────────────────────▶│              │                  │                      │
  │ 200 {status:"indexed"} │                     │              │                  │                      │
  │◀───────────────────────│                     │              │                  │                      │

A ~10-page PDF takes ~5-15 seconds from upload to indexed.

Code paths:

  • Upload handler: apps/api/src/routes/documents.ts
  • Worker entry: apps/worker/main.py
  • Chunking: apps/worker/chunker.py

Share flow (public)

Member                 lumen-api           Postgres          Admin                Guest
  │                         │                  │                │                   │
  │ POST /share-requests    │                  │                │                   │
  │────────────────────────▶│                  │                │                   │
  │                         │ INSERT request   │                │                   │
  │                         │  status=pending  │                │                   │
  │                         │─────────────────▶│                │                   │
  │ 201                     │                  │                │                   │
  │◀────────────────────────│                  │                │                   │
  │                         │                  │                │                   │
  │                         │                  │                │                   │
  │                         │                  │                │ sees 1 pending    │
  │                         │                  │                │ in sidebar badge  │
  │                         │                  │                │                   │
  │                         │                  │                │ approve           │
  │                         │◀────────────────────────────────────────             │
  │                         │                  │                │                   │
  │                         │ INSERT share_token               │                   │
  │                         │  (token = random 32 bytes)       │                   │
  │                         │─────────────────▶│                │                   │
  │                         │ UPDATE request   │                │                   │
  │                         │  status=approved │                │                   │
  │                         │─────────────────▶│                │                   │
  │                         │                  │                │                   │
  │ (notification that      │                  │                │                   │
  │  request was approved,  │                  │                │                   │
  │  link copied or emailed)│                  │                │                   │
  │◀────────────────────────│                  │                │                   │
  │                         │                  │                │                   │
  │                         │                  │                │                   │
  │ shares link to guest ────────────────────────────────────────────────────────▶│
  │                         │                  │                │                   │
  │                         │                  │                │ GET /share/<token>│
  │                         │◀────────────────────────────────────────────────────│
  │                         │ SELECT token,    │                │                   │
  │                         │  conversation,   │                │                   │
  │                         │  messages...     │                │                   │
  │                         │─────────────────▶│                │                   │
  │                         │ 200 {snapshot}   │                │                   │
  │                         │────────────────────────────────────────────────────▶│
  │                         │                  │                │                   │
  │                         │                  │                │ guest can ask     │
  │                         │                  │                │ follow-ups with   │
  │                         │                  │                │ project context   │

Guest chat uses the same RAG flow as a member, but:

  • No auth required (token in URL is the credential)
  • Cannot access other conversations in the project
  • Cannot see or edit project settings
  • Can be revoked anytime by deleting the share token

Code paths:

  • Public page: apps/web/app/share/[token]/page.tsx (no dashboard layout)
  • Endpoints: apps/api/src/routes/public-share.ts