66.7%
System architecture
Evidence moves forward.Trust is checked twice.
RAG System separates storage, retrieval, authorization, generation, and evaluation into inspectable stages. The model never chooses what a user is allowed to see; application code and PostgreSQL do.
Production evidence
Measured on the deployed pipeline
A frozen 15-case benchmark keeps the live system accountable while workspace evaluation runs provide newer, tenant-specific evidence.
17.3%
Retrieval precision
74.6%
Citation precision
93.3%
Citation recall
80%
Answer correctness
3.30s
Average latency
Verified Aurora baseline · top-5 hybrid retrieval · Mistral 7B · 49.6 seconds total runtime.
System map
Two pipelines, one authorization boundary
Ingestion prepares evidence. Query-time retrieval selects it. The final permission checkpoint sits between ranking and model context.
INGESTION
User + session
│
▼
[membership: admin/editor] ──► validate ──► hash + dedupe
│
▼
overlapping chunks
│
▼
nomic-embed-text (768 dimensions)
│
▼
PostgreSQL ── full text + pgvector
QUERY
Question + session workspace
│
├────────► keyword rank ────────┐
│ ├──► RRF (k=60) ──► candidates
└────────► vector distance ─────┘ │
▼
[PERMISSION CHECKPOINT]
membership + document workspace
│
▼
authorized chunks only ──► Vercel API
│
Tailscale HTTPS gateway
│
▼
Ollama + Mistral 7B
│
▼
cited answer ──► citation validation
│
▼
response + stored traceProduction stack
Open-source inference, managed delivery
The browser stays on one Vercel origin. Application routes enforce sessions and workspace scope, Neon stores searchable evidence, and a private gateway reaches Ollama without exposing it directly.
Application
Next.js App Router
Server-rendered routes, authenticated API handlers, and responsive React interfaces deployed on Vercel.
Database
Neon PostgreSQL
Workspace-scoped relational data, PostgreSQL full-text search, migration tracking, and durable retrieval traces.
Vector index
pgvector
768-dimensional nomic embeddings and indexed distance search run beside document metadata and permissions.
Inference runtime
Ollama
Open-source embedding and generation models run outside Vercel and remain reachable through an authenticated gateway.
Generation
Mistral 7B
Grounded answer generation receives authorized chunks only and emits source labels for deterministic validation.
Private network
Tailscale gateway
A shared-secret HTTPS bridge connects serverless API routes to Ollama without publishing the local Ollama port.
Pipeline 01
Document ingestion
The write path validates authorization and content before it spends inference time or creates searchable state.
- 01
Authorize
Require live admin or editor membership in the target workspace.
- 02
Validate
Accept non-empty text or Markdown up to 50 MiB locally; cap synchronous Vercel uploads at 100 KB (roughly 50 chunks).
- 03
Hash
A SHA-256 content digest prevents duplicates inside one workspace.
- 04
Chunk
Use ~500-token windows, natural boundaries, and 100-character overlap.
- 05
Embed and store
Persist text, offsets, and optional 768-dimensional vectors.
Recoverable provenance
Each chunk stores its zero-based index and exact start/end character offsets, so the original source slice can be reconstructed.
Bounded concurrency
Embedding work runs in batches with configurable concurrency capped at eight, protecting a local Ollama process from an unbounded fan-out.
Visible partial failure
Failed embeddings are logged and stored as null. A document becomes error only when every chunk embedding fails; status and error details remain inspectable.
Pipeline 02
Hybrid retrieval
Lexical and semantic signals run concurrently, stay workspace-scoped in SQL, and meet through rank fusion rather than incomparable raw scores.
Keyword signal
PostgreSQL full-text search
A stored English tsvector and GIN index serve plainto_tsquery matches. ts_rank normalization 32 bounds each lexical relevance score to 0–1.
Deadline: 5 seconds
Semantic signal
pgvector L2 distance
nomic-embed-text embeds the question, then the HNSW vector index orders completed workspace chunks by embedding distance.
Combined embedding + SQL deadline: 30 seconds
// One-based rank, with k = 60
score(chunk) =
1 / (60 + keywordRank)
+ 1 / (60 + vectorRank)Each list contributes by position. A chunk present in both rankings receives both terms; duplicates are collapsed, ties are deterministic, and the highest fused scores become candidates.
Security boundary
Permission filtering happens before context
Workspace filters inside retrieval reduce exposure, but the orchestration layer does not trust that first check alone.
What the checkpoint proves
- The requesting user is still a member of the session workspace.
- Every candidate chunk belongs to a document in that same workspace.
- Only authorized chunk IDs survive into prompt construction.
- Filtered IDs and counts are logged without sending their text to the model.
The implemented boundary is workspace membership. Fine-grained per-document sharing rules would require an additional grants table and predicate.
const candidates = await hybridSearch(query, workspaceId, topK);
// Security checkpoint: candidate text cannot enter the prompt before this.
const authorized = await filterByPermissions(
candidates,
workspaceId,
userId,
);
return authorized.slice(0, topK);The comment is enforced by data flow: generateAnswer receives only the array returned after filterByPermissions.
Pipeline 03
Grounded generation and citation validation
Mistral receives the question and authorized chunks as untrusted source material, with exact source labels it is allowed to copy.
Build context
Format each chunk as [source: chunk_id] followed by its text.
Constrain
Require document-only claims and an explicit refusal when evidence is missing.
Generate
Call local Mistral without streaming under a 60-second timeout.
Validate
Keep source occurrences only when the ID was in authorized context.
const pattern = /\[source:\s*([^\]\s]+)\s*\]/gi;
for (const match of answer.matchAll(pattern)) {
const chunk = authorizedChunksById.get(match[1]);
if (chunk) citations.push({ chunk_id: chunk.chunk_id, position: match.index });
else console.warn("Fabricated citation filtered", { chunk_id: match[1] });
}Validation is deterministic. Unknown IDs are logged and discarded, while every valid occurrence retains its answer position for inline rendering.
Failure contract
“I cannot answer this question based on the provided documents.”
That response is an intended safety result when retrieval returns no authorized evidence—not a generation failure.
Closed feedback loop
Evaluation and observability
Search traces make production behavior inspectable; the benchmark turns that same path into repeatable quality signals.
Recall
Expected chunks retrieved ÷ expected chunks
Precision
Expected chunks retrieved ÷ retrieved chunks
Citation quality
Cited expected evidence in both directions
Answer correctness
Deterministic expected key-phrase coverage
No-answer accuracy
Correct refusal when no evidence is expected
What is persisted
Each run stores status, case count, aggregate summary, timestamps, and errors. Case results retain retrieved/cited chunk IDs, answer, metrics, latency, and categorized failure reason.
What the score does not claim
Answer correctness is a transparent token-coverage heuristic, not a semantic LLM judge. It is reproducible and free, but human review remains the authority for nuanced paraphrases.
Defense in depth
Trust boundaries at a glance
No single model response, route parameter, or retrieval score decides authorization or provenance.
Session
Input
Opaque cookie token
Control
HMAC-hashed server record, expiry, live workspace membership
Output
User and workspace identity
Database
Input
Validated IDs and text
Control
Parameterized SQL, foreign keys, workspace predicates
Output
Scoped documents and chunks
Retrieval
Input
Ranked candidates
Control
Independent membership + document ownership join
Output
Authorized chunk array
Model
Input
Authorized chunks only
Control
Grounding prompt, source allowlist, timeout
Output
Untrusted answer text
Response
Input
Untrusted source labels
Control
Exact chunk-ID validation and fabricated-citation logging
Output
Answer with validated citations
Inspect the evidence
Architecture is only useful when it can be measured.
Run the seeded cases, inspect individual failures, and compare retrieval, citation, answer, refusal, and latency metrics.