How param20h/pdf-assistant-rag works
1. This repo is a full-stack “document AI analyst” with a clear split between a FastAPI backend and a Next.js frontend. The backend owns authentication, document lifecycle, ingestion, retrieval, chat generation, and admin/health APIs; the frontend owns user interaction, document management, chat streaming UI, and PDF/graph viewing.
2. The backend is the system boundary for almost all business logic. backend/app/main.py wires the FastAPI app, middleware, routers, and lifespan hooks. The route layer is organized by domain: auth, documents, chat, workspaces, profile, admin, graph, health, and GitHub integration.
3. Persistent application state is stored in a relational database via SQLAlchemy models. PostgreSQL is the primary deployment target, with SQLite supported for local/dev. The database holds users, documents, sessions, roles, workspace membership, and ingestion/chat metadata; migrations in the repo show schema evolution for roles, processing columns, extracted URLs, and indexes.
4. Document ingestion is asynchronous and decoupled from request handling. Upload endpoints enqueue Celery jobs through Redis, and the ingestion service then extracts text, chunks content, generates embeddings, builds search indexes, and persists document status. This makes the upload path fast while heavy processing happens in the background.
5. The RAG pipeline is the core architecture. backend/app/rag/ contains extraction, chunking, embeddings, vector storage, BM25 keyword indexing, hybrid retrieval, reranking, prompt assembly, summarization, OCR/vision helpers, URL extraction, and GraphRAG graph building. The retrieval path is explicitly multi-stage: vector search + BM25, merged with reciprocal rank fusion, then reranked before generation.
6. Vector and lexical search are separate storage/compute paths. ChromaDB stores embeddings, while BM25 indexes are maintained per document. Embeddings are generated locally with sentence-transformers and cached with Redis/LRU, so the system minimizes repeated compute and keeps semantic search local before anything is sent to an external LLM.
7. Answer generation is delegated to HuggingFace Inference API. The backend assembles retrieved context and calls the configured model for generation, then streams tokens back to the client over SSE. The frontend chat panel is built around this streaming contract, so response rendering is incremental rather than request/response only.
8. Per-user isolation is an architectural boundary, not just an authorization check. The system scopes documents, vectors, chats, and graph artifacts by user/workspace identity, and the auth layer uses JWT plus bcrypt. Rate limiting, CORS, password validation, and file validation are additional guardrails around the public API.
9. There is a second knowledge layer beyond plain RAG: graph extraction and graph retrieval. graph_builder.py and graph_retriever.py indicate entity/relationship extraction for document-specific knowledge graphs, and the README references GraphRAG evaluation. This means the system supports both chunk-based retrieval and graph-oriented context.
10. The frontend is a stateful client application built on Next.js App Router with TypeScript, Tailwind, and Zustand stores. It contains dedicated surfaces for login/register, dashboard, drive/document management, chat, settings, sharing, admin, and legal pages. Key UI components include a PDF viewer, knowledge graph view, source cards, and document sidebars.
11. The repo includes several integration surfaces beyond the main app. bots/discord/bot.py adds Discord connectivity, while backend/app/routes/github.py suggests GitHub-related workflows. These are adjacent services, but the main architecture still centers on the FastAPI core and shared backend state.
12. Observability and operational safety are first-class concerns. The backend exposes deep health checks for database, Redis, Celery, and ChromaDB, and also includes metrics and tracing modules. The repo ships Grafana dashboard assets, indicating the deployment expects runtime monitoring rather than just basic uptime checks.
13. Deployment is container-oriented. A multi-stage backend Dockerfile, a separate frontend Dockerfile, and docker-compose.yml support CPU, GPU, and debug profiles. This is important architecturally because the app is designed to run as a composed stack with database, Redis, worker, API, and frontend services.
14. Quality gates are spread across unit, integration, and browser testing. The backend has extensive pytest coverage for retrieval, ingestion, auth, chat, vector storage, OCR, and GraphRAG. The frontend adds Vitest and Playwright E2E/snapshot tests, so the repo’s architecture is validated at both API and UI boundaries.
Main entry points: routes Routes · database.py Database · health.py Health · document_ingestion.py Ingestion
Components 26
Backend
FastAPI core for auth, documents, chat, RAG, persistence, and background processing
- App entry · Wires middleware, routers, and lifespan hooks
backend/app/main.py - Routes · Domain route surface for auth, documents, chat, workspaces, admin, graph, health, and GitHub
backend/app/routes - Auth · Login, registration, verification, and security boundaries
backend/app/routes/auth.py - Documents · Upload, validation, metadata, sharing, and document status
backend/app/routes/documents.py - Chat · Conversation endpoints and SSE token streaming
backend/app/routes/chat.py - Workspaces · Workspace membership and per-user document isolation
backend/app/routes/workspaces.py - Graph API · Graph retrieval and graph artifact access
backend/app/routes/graph.py - Health · Deep checks for database, Redis, Celery, and vector store
backend/app/routes/health.py - Admin · Administrative actions and exports
backend/app/routes/admin.py - Ingestion · Background document extraction, chunking, indexing, and persistence
backend/app/services/document_ingestion.py - Retrieval · Vector search, BM25, fusion, and reranking
backend/app/rag/retriever.py - Generation · Prompt assembly and HuggingFace inference calls
backend/app/rag/prompts.py - Graph RAG · Entity/relationship extraction and graph retrieval
backend/app/rag/graph_builder.py - Database · Users, documents, sessions, roles, workspaces, and ingestion metadata
backend/app/database.py - Vector store · Embedding-backed semantic index
backend/app/rag/vectorstore.py - Cache · Embedding and runtime caching plus job coordination
backend/app/cache.py - Queue · Asynchronous job execution for ingestion and maintenance
backend/app/celery_app.py
Frontend
Next.js client for login, document management, chat, and graph viewing
- Next app · Client entrypoints, page shells, and shared UI composition
frontend/src/app - Chat UI · Streaming chat panel, session sidebar, and source cards
frontend/src/components/chat - Docs UI · Drive, PDF viewer, sidebar, compare, and document actions
frontend/src/components/document - Graph view · Document graph visualization surface
frontend/src/components/graph/KnowledgeGraph.tsx - State · Auth, chat, settings, and workspace client state
frontend/src/store - API client · Frontend service layer for backend requests and auth/session handling
frontend/src/lib/api.ts
Ops & Integrations
Deployment, monitoring, and adjacent integrations
- Discord bot · Adjacent chat integration service
bots/discord/bot.py - Observability · Metrics, tracing, and monitoring surfaces
backend/app/observability.py - Deploy stack · Docker Compose, backend/frontend images, and runtime profiles
docker-compose.yml
Connections 35
- Next app → API client: uses · Pages and components call the client API layer
- API client → App entry: requests · Frontend talks to the FastAPI backend
- Chat UI → State: reads/writes · Chat interaction is stateful on the client
- Docs UI → State: reads/writes · Document workspace state is kept in stores
- Graph view → API client: loads · Graph view fetches graph artifacts and metadata
- App entry → Routes: mounts · Main app wires the route surface
- Routes → Auth: exposes · Authentication endpoints
- Routes → Documents: exposes · Document lifecycle endpoints
- Routes → Chat: exposes · Chat and streaming endpoints
- Routes → Workspaces: exposes · Workspace membership and scoping endpoints
- Routes → Graph API: exposes · Graph retrieval endpoints
- Routes → Health: exposes · Operational health endpoints
- Routes → Admin: exposes · Admin and export endpoints
- Documents → Queue: enqueues · Uploads push heavy processing into background jobs
- Queue → Ingestion: runs · Celery executes ingestion work
- Ingestion → Database: persists · Stores document state and metadata
- Ingestion → Vector store: indexes · Builds embeddings for semantic retrieval
- Ingestion → Cache: caches · Caches repeated embedding and compute results
- Chat → Retrieval: retrieves · Chat requests trigger multi-stage retrieval
- Retrieval → Vector store: searches · Semantic search over embeddings
- Retrieval → Database: filters · Uses document and permission metadata
- Retrieval → Generation: supplies context · Retrieved passages are assembled for generation
- Generation → Chat: streams · Generated tokens stream back to chat endpoints
- Graph API → Graph RAG: queries · Graph endpoints use extracted entity relations
- Graph RAG → Database: persists · Stores graph artifacts and ownership metadata
- Auth → Database: authenticates · Users and credentials live in the relational store
- Workspaces → Database: scopes · Workspace membership controls data isolation
- Health → Database: checks · Database readiness and liveness
- Health → Cache: checks · Redis/cache readiness and liveness
- Health → Queue: checks · Worker/queue readiness and liveness
- Health → Vector store: checks · Vector store readiness and liveness
- Observability → App entry: observes · Runtime metrics and tracing wrap the API
- Deploy stack → App entry: runs · Backend is deployed as a containerized service
- Deploy stack → Next app: runs · Frontend is deployed as a separate containerized service
- Discord bot → Routes: integrates · Adjacent integration surface connected to backend APIs