Backend Deep Dive¶
Application structure¶
backend/app/main.py creates the FastAPI app, configures CORS and language middleware, seeds categories during lifespan, and registers auth, admin, chat, grievance, dashboard, file, and tracking routers.
The async stack is FastAPI + Uvicorn + SQLAlchemy/asyncpg. Configuration is loaded with pydantic-settings; database URLs support both local TCP and Cloud SQL socket overrides.
Router inventory¶
| Router | Representative responsibilities |
|---|---|
auth |
Login, JWT creation, current-user resolution |
admin |
User/category/knowledge-base administration |
chat |
Session lifecycle, SSE messages, uploads, STT/TTS, RAG |
grievances |
Case listing, details, status actions, assignment-facing APIs |
dashboard |
Role-specific counts, workload, SLA metrics |
files |
Attachment and ATR storage/download operations |
tracking |
Natural-language status questions |
The chat router demonstrates the request lifecycle particularly well: it authenticates, loads a user-owned session, delegates to handle_chat_turn, and wraps each yielded event as data: ...\n\n for browser SSE consumption.
Provider adapters¶
The backend isolates external systems behind modules such as app.files.storage, app.services.vector_store, app.chat.audio_service, and app.llm. This keeps route handlers focused on HTTP contracts and makes local MinIO/Redis/Postgres development possible while GCP services are the deployment target.
Configuration details¶
Settings cover Postgres credentials and pool sizing, LiteLLM endpoint/model, NVIDIA and Vertex options, Gemini embedding model/dimension, chunk sizing, allowed origins, Firebase/GCS identifiers, and seed-admin credentials. database_url_override is important for Cloud SQL Unix socket connection strings.
The defaults are useful for local boot but unsafe as production values: changeme database/password fields and placeholder API/JWT secrets must be replaced through environment variables or Secret Manager.
Async and consistency¶
FastAPI dependencies provide an AsyncSession; database operations use SQLAlchemy async queries. Redis session writes and PostgreSQL grievance finalization are separate consistency domains. If finalization succeeds in one and fails in the other, recovery behavior must be verified in handle_chat_turn and should be made idempotent around the session completion marker.
API lifecycle¶
Authenticated dependencies resolve the current user before chat, upload, RAG, and case operations. Chat returns text/event-stream; upload parsing and GCS storage are explicit steps. Errors become HTTP exceptions and are logged with structured messages.
Notable choices¶
- Redis holds temporary conversational session state while PostgreSQL owns durable cases.
- Cloud services are behind focused storage, audio, and vector-store modules.
- Startup category seeding reduces first-run setup friction but can make boot depend on database availability.
- Cloud Run migration, seed, and ingestion jobs separate operational work from request handling.
Interview answer¶
“The backend is an async modular monolith: routers expose role-aware APIs, services own workflow logic, SQLAlchemy owns durable records, Redis owns chat sessions, and provider adapters isolate GCS, Gemini, and audio services.”