How razin-ccc/chatbot works
1. Overall shape
This is a two-tier full-stack chatbot: a Next.js frontend talks to a FastAPI backend. The backend is not a simple request/response API; it centralizes the product logic in a LangGraph state machine that routes each message to chat, document RAG, weather, or bug-report handling.
2. Frontend boundary
The frontend lives under frontend/Chatbot and uses the Next.js App Router. Its main user surfaces are:
- public marketing pages
- /login and /register
- /chat for the main assistant experience
- /admin for ticket review
The UI is mostly a thin client over backend APIs, with dedicated hooks and API wrappers for auth, chat, conversations, documents, and admin flows.
3. Primary backend boundary
The backend lives under backend/app and is organized around FastAPI route modules:
- auth/ for JWT, refresh cookies, scopes, and RBAC
- api/routes/ for chat, conversations, documents, admin, and health
- services/ for the actual business logic
- services/graph/ for the LangGraph orchestration layer
This separation makes the HTTP layer relatively thin while the orchestration and integrations sit in services.
4. Core chat flow
All assistant interactions go through a single POST /chat endpoint. The frontend does not choose the mode; it sends the message, conversation ID, and auth token, and the backend decides the path. Responses are streamed back with Server-Sent Events, which the frontend parses incrementally so the assistant can render token-by-token output.
5. LangGraph orchestration
The center of the system is services/graph/runner.py and the nodes under services/graph/nodes/. The graph first classifies the message, then routes to one of four paths:
- general chat
- document RAG
- weather
- bug report
The classifier uses simple pattern matching first, then Gemini-based structured classification when needed. This is the main architectural boundary between “user intent” and the concrete capability that handles it.
6. Document RAG subsystem
Documents are scoped to a conversation. Uploads go through the documents API, are parsed and chunked, embedded with a local ONNX BGE-small model, and stored in a vector store. Retrieval uses query embedding, vector search, and reranking before the writer node streams a grounded answer. The design keeps document Q&A isolated to the active conversation and its documents rather than searching globally.
7. Storage model
The persistent state is split by purpose:
- PostgreSQL stores durable records: users, sessions, conversations, messages, documents, and pending Jira tickets
- Redis stores hot conversation state, summaries, and rate-limit keys
- Vector store / Pinecone stores document embeddings for RAG
This dual-memory pattern means the assistant can keep recent context quickly while still rehydrating from durable history when needed.
8. Authentication and authorization
Auth is JWT-based with a short-lived access token and an httpOnly refresh cookie. The auth/ package also implements permissions/scopes, with role-based access control for admin-only actions like ticket:manage. The frontend has separate login/register flows, and protected UI areas depend on the authenticated user and their permissions.
9. Bug report to Jira workflow
Bug reports are handled as a human-reviewed pipeline, not an automatic ticket dump. The graph extracts a title and description, inserts a pending_jira_tickets row, and returns a confirmation in chat. The admin dashboard then approves or rejects the item:
- approval creates a Jira issue and sends email
- rejection sends a rejection email
This workflow is intentionally gated by admin permissions and backed by database state for traceability.
10. External integrations
The backend integrates with several external systems that materially shape the architecture:
- Google Gemini for chat, classification, summarization, and ticket extraction
- Open-Meteo for weather lookup
- Cohere Rerank for RAG quality improvement
- Jira Cloud for approved bug tickets
- SMTP for notifications
These integrations are isolated behind service modules so the API routes and graph nodes do not directly embed external protocol logic.
11. Data access and persistence lifecycle
Chat turns are streamed, then persisted after completion. The runner loads conversation state, streams graph events to the client, and finally writes message history and updated summaries back to storage. Document indexing is asynchronous, which means a conversation may temporarily have uploaded PDFs that are not yet eligible for RAG routing until indexing finishes.
12. Deployment and runtime
The backend is containerized with a multi-stage Docker build, and the repo includes docker-compose.yml for running the stack together. The backend uses Python tooling (uv, Alembic migrations, SQLAlchemy async), while the frontend is a separate Node/Next.js runtime. The local ONNX model files are checked into the backend tree because embeddings run on CPU locally rather than via a hosted embedding API.
13. What to draw in an architecture diagram
The key boxes are: frontend pages/components, FastAPI route layer, auth subsystem, LangGraph orchestrator, RAG/document pipeline, Redis, PostgreSQL, vector store, and external services (Gemini, Jira, SMTP, Open-Meteo, Cohere). The most important arrows are:
- frontend SSE chat traffic to POST /chat
- POST /chat to LangGraph runner
- graph nodes to Redis/PostgreSQL/vector store and external APIs
- admin actions from /admin to PostgreSQL, Jira, and email
Main entry points: routes API Routes · runner.py Graph Runner · nodes Graph Nodes · rag.py RAG Pipeline
Components 19
Frontend
Next.js app and client-side feature modules
- App Router · Public pages plus chat, login, register, and admin routes
frontend/Chatbot/app - Chat UI · Streaming chat shell, conversation list, documents panel, and message rendering
frontend/Chatbot/components/chat - Client Hooks · Auth, chat, conversation, and document hooks that wrap backend APIs
frontend/Chatbot/hooks - API Client · Typed API wrappers for auth, chat, conversations, documents, and admin
frontend/Chatbot/lib/api - SSE Parser · Parses streamed assistant responses into incremental UI updates
frontend/Chatbot/lib/stream/sseParser.ts
Backend
FastAPI app, orchestration, and services
- FastAPI App · Application entrypoint, middleware, and route registration
backend/app/main.py - API Routes · Chat, conversations, documents, admin, and health endpoints
backend/app/api/routes - Auth Stack · JWT access tokens, refresh cookies, scopes, and role checks
backend/app/auth - Graph Runner · LangGraph state machine that classifies intent and coordinates response paths
backend/app/services/graph/runner.py - Intent Classifier · Pattern-first then Gemini-backed classification into chat, RAG, weather, or bug report
backend/app/services/graph/classifier.py - Graph Nodes · Chat, RAG, weather, and bug-report nodes executed by the graph
backend/app/services/graph/nodes - RAG Pipeline · Upload, parse, chunk, embed, retrieve, rerank, and answer from conversation-scoped documents
backend/app/services/rag.py - Conversation Memory · Loads, summarizes, and persists conversation state across turns
backend/app/services/memory.py - Data Services · User, conversation, message, document, and ticket data access
backend/app/services
Storage
Persistent and hot state stores
- PostgreSQL · Users, sessions, conversations, messages, documents, and pending Jira tickets
- Redis · Conversation summaries, active state, and rate-limit keys
- Vector Store · Document embeddings used for retrieval augmented generation
External
Third-party APIs and local ML assets
- AI Services · Gemini, Cohere rerank, and local ONNX embeddings model
backend/app/models/onnx/baai-bge-small/model.onnx - Ops Services · Jira Cloud, SMTP notifications, and Open-Meteo weather lookup
Connections 20
- App Router → API Client: calls APIs · Pages and routes delegate data operations to typed client wrappers
- Chat UI → SSE Parser: parses SSE · Streaming chat UI incrementally renders assistant output
- Chat UI → Client Hooks: uses hooks · Chat screens coordinate state through custom hooks
- Client Hooks → API Client: requests data · Hooks invoke backend endpoints through API wrappers
- API Client → API Routes: HTTP/SSE · Client talks to chat, auth, conversation, document, and admin endpoints
- FastAPI App → API Routes: mounts · FastAPI application registers the route modules
- API Routes → Auth Stack: protects · Protected endpoints validate tokens, cookies, and scopes
- API Routes → Graph Runner: POST /chat · Chat endpoint hands messages to the orchestration runner
- API Routes → Data Services: admin/docs · Conversation, document, and ticket flows persist through service layer
- Graph Runner → Intent Classifier: routes intent · Runner classifies each turn before selecting a capability path
- Intent Classifier → Graph Nodes: selects node · Classification chooses chat, RAG, weather, or bug-report execution
- Graph Nodes → RAG Pipeline: grounded answers · RAG node delegates document retrieval and answer synthesis
- Graph Runner → Conversation Memory: loads state · Runner rehydrates and updates conversation context
- Conversation Memory → Redis: hot context · Summaries and active conversation state live in Redis
- Data Services → PostgreSQL: stores records · Durable app data is written to PostgreSQL
- RAG Pipeline → Vector Store: retrieves embeddings · Document chunks are searched in the vector store
- RAG Pipeline → AI Services: embed/re-rank · Uses ONNX embeddings and Cohere reranking for retrieval quality
- Graph Runner → AI Services: LLM calls · Gemini powers chat generation, classification fallback, summarization, and ticket extraction
- Graph Nodes → Ops Services: integrates · Weather lookup, Jira creation, and email notifications are handled externally
- Data Services → Auth Stack: users/roles · Auth subsystem depends on user and permission records