Architecture
How the web client, FastAPI service, vector store, graph store, and model runtime fit together.
bash-A keeps the browser, API, data stores, and model runtime separate. The same retrieval and agent code can serve the web UI, local scripts, and API clients.
Component responsibilities
| Component | Responsibility | Code |
|---|---|---|
| Next.js app | Chat, document views, analytics, and API client | src/app/, src/lib/, src/components/ |
| FastAPI service | Ingestion, search, chat, feedback, and analytics routes | src/backend/main.py |
| PostgreSQL + pgvector | Chunk text, embeddings, documents, conversations, messages, feedback, and memories | src/backend/db.py, src/backend/store.py |
| Neo4j | Extracted entities, relationships, and links to source chunk IDs | src/backend/graph_store.py, src/backend/graph_search.py |
| Model runtime | Chat, embeddings, and graph extraction via configured providers | src/backend/llm.py, src/backend/embeddings.py |
Data path
When a document is added
POST /api/ingest extracts PDF text, chunks it, embeds each chunk, and writes text plus vectors to PostgreSQL. A separate graph stage extracts entities and relationships into Neo4j. The vector index is the core searchable source; graph extraction may be incomplete or unavailable.
When a question is asked
POST /api/chat persists the turn, obtains bounded tool steps from the planner, executes them, resolves evidence into source passages, and streams a supported answer or a decline. Citation data is retained with the assistant message.
Trust boundaries
The browser talks to FastAPI across configured CORS origins. CORS is a browser policy, not authentication. The optional DEMO_TOKEN protects selected mutation and administration routes; it does not create user identities or protect every read route.
See Ingestion and indexing, Retrieval, and Agentic chat for each request path.