ElectionGuide is a full-stack civic AI platform for Indian elections. It provides Gemini-powered AI chat, voter readiness scoring, guided voting journeys, an interactive EVM/VVPAT simulator, civic quizzes, scenario-based guides, an India electoral map, and verified official resources — all grounded in ECI data and designed for first-time voters, returning voters, NRIs, senior citizens, and persons with disabilities.
The backend is a FastAPI service with Google Gemini streaming, SQLAlchemy async models, three-tier rate limiting, and a full security middleware layer. The frontend is a Next.js 16 app with Framer Motion animations, WCAG 2.1 AA accessibility, and a dark-first India-themed design system. The app is packaged as a single Docker image for Cloud Run. In production, nginx fronts both the Next.js standalone server and the FastAPI API server on one public port.
Chosen vertical: civic information assistant.
ElectionGuide is designed for Indian voters, first-time citizens, candidates, and election volunteers who need reliable, neutral, and source-grounded election guidance. The assistant makes decisions based on user context: selected response language, conversation history, the type of election question, and whether current facts require tool verification before answering.
| Category | Implementation signals |
|---|---|
| Code Quality | Modular FastAPI services, auth and platform packages, typed schemas, split React chat/platform/auth components, reusable hooks/utilities |
| Security | Secret Manager, bounded inputs, rate limiting, browser hardening headers, safe external links, no committed secrets |
| Efficiency | Streaming WebSocket responses, bounded fetch/PDF extraction, model fallback, deterministic platform tools, Cloud Run scale-to-zero |
| Testing | 172 backend tests across auth, platform, security (audit + enhanced + edge cases), integration, config, tools, and Google services; 12 frontend tests for markdown, accessibility, auth, route breadth, and platform client |
| Accessibility | ARIA labels, keyboard focus, disabled states, responsive sidebar, documented manual checks |
| Google Services | Gemini, Google Identity Services, Cloud Run, Cloud Build, Artifact Registry, Secret Manager, Cloud Logging, Cloud Storage, optional Custom Search and Firestore audit |
| Problem Alignment | Non-partisan Indian election assistant with voter readiness, journey, booth guide, quiz, scenarios, and verified chat |
- Landing-first civic platform surface with a dedicated
/assistantchat workspace. - AI chat experience focused on Indian elections, voting processes, eligibility, schedules, and civic information.
- Civic platform APIs for readiness scoring, voting journeys, booth guidance, quizzes, scenario simulation, and engagement insights.
- Auth pages for login/signup with Google OAuth provider discovery and env-driven credentials. Falls back to a local dev session when OAuth credentials are not configured.
- Gemini response streaming with reasoning, tool-call events, source annotations, and fallback model handling.
- Session persistence with SQLite via SQLAlchemy async models.
- Multilingual response support and UI copy translation for Indian languages.
- Google Custom Search grounding with fallback search, page fetching, PDF text extraction, and Election Commission schedule lookup tools.
- Single-container production runtime with Next.js, FastAPI, and nginx.
- Cloud Run deployment through Cloud Build, Artifact Registry, Secret Manager, Cloud Logging, and a Cloud Storage mounted data volume.
| Area | Technology |
|---|---|
| Frontend | Next.js 16, React 19, TypeScript, Tailwind CSS |
| Backend | FastAPI, Uvicorn, Pydantic, SQLAlchemy async |
| AI | Google Gemini / Vertex AI via google-genai |
| Storage | SQLite locally or mounted at /data in Docker/Cloud Run |
| Runtime | Docker, nginx reverse proxy |
| Cloud | Google Cloud Build, Artifact Registry, Cloud Run, Secret Manager, Cloud Logging, Cloud Storage, Google Identity Services, optional Firestore audit |
.
|-- backend/
| |-- auth/ # Google OAuth provider metadata, session issue/lookup/logout
| |-- civic_platform/ # Readiness, journey, quiz, scenario, booth, analytics APIs
| |-- services/ # Gemini streaming service and protocol helpers
| |-- main.py # FastAPI app, streaming chat API, session routes
| |-- config.py # Environment-based settings
| |-- database.py # SQLAlchemy models and async session setup
| |-- genai_client.py # Gemini / Vertex AI client factory
| |-- google_services.py # Google service registry, health, logging, secret/audit helpers
| |-- prompts.py # ElectionGuide system prompt
| |-- tools.py # Search, URL/PDF fetch, election schedule tools
| |-- tests/ # Backend pytest coverage for auth, platform, config, tools, Google services
| `-- requirements.txt # Python dependencies
|-- frontend/
| |-- src/app/ # Landing, assistant, platform, auth, and info routes
| |-- src/components/ # Chat, auth, platform, thinking, citation, and UI components
| |-- src/lib/ # API/auth/platform clients, config, i18n helpers
| |-- tests/ # Frontend Node tests for markdown, routes, auth, accessibility
| `-- package.json # Frontend scripts and dependencies
|-- docs/ # Google service, testing, and submission notes
|-- scripts/ # Quality gate and repository size checks
|-- Dockerfile # Multi-stage production image
|-- docker-compose.yml # Local single-container deployment
|-- docker-entrypoint.sh # Starts FastAPI, Next.js, and nginx
|-- nginx.conf # Routes /api to FastAPI and / to Next.js
|-- cloudbuild.yaml # Cloud Build + Cloud Run deployment
`-- .env.example # Required environment variables
Create backend/.env for local development:
cp .env.example backend/.envThen set the values needed for your environment.
| Variable | Required | Default | Description |
|---|---|---|---|
GOOGLE_API_KEY |
Yes, unless using ADC | none | Gemini or Vertex Express API key. Used as the primary auth path when set. |
USE_VERTEX_AI |
No | false |
Set to true to use Vertex AI Application Default Credentials instead of GOOGLE_API_KEY. |
GCP_PROJECT_ID |
Required for Vertex AI / Cloud Run | none | Google Cloud project ID. |
GCP_LOCATION |
No | us-central1 |
Vertex AI and Cloud Run region. |
GOOGLE_SEARCH_API_KEY |
No | none | Enables Google Custom Search JSON API grounding. |
GOOGLE_SEARCH_ENGINE_ID |
No | none | Programmable Search Engine ID for Google Custom Search. |
ENABLE_CLOUD_LOGGING |
No | false |
Enables Google Cloud Logging setup in Cloud Run. |
ENABLE_FIRESTORE_AUDIT |
No | false |
Enables optional non-sensitive Firestore audit events. |
FIRESTORE_AUDIT_COLLECTION |
No | electionguide_audit |
Firestore collection used for audit events. |
GOOGLE_OAUTH_CLIENT_ID |
No | none | Google Identity Services OAuth client ID for sign-in. |
GOOGLE_OAUTH_CLIENT_SECRET |
No | none | Google OAuth secret. Keep this in Secret Manager for production. |
GOOGLE_OAUTH_REDIRECT_URI |
No | /api/auth/google/callback |
OAuth callback URL for Google sign-in. |
AUTH_SESSION_TTL_HOURS |
No | 24 |
Lifetime for issued auth sessions. |
DATABASE_URL |
No | sqlite+aiosqlite:///./election_guide.db |
Async SQLAlchemy database URL. Docker uses /data/election_guide.db. |
GEMINI_MODEL |
No | gemini-3-flash-preview |
Primary Gemini model. |
GEMINI_FALLBACK_MODEL |
No | gemini-2.5-flash |
Fallback model for retryable model errors. |
NEXT_PUBLIC_BACKEND_URL |
No | same origin in browser | Frontend API base URL. Leave empty for the Docker/nginx deployment. |
PORT |
No | 8080 |
Public container port used by nginx. |
Do not commit real secrets. In Cloud Run, GOOGLE_API_KEY is read from Secret Manager.
Run the backend and frontend as separate processes while developing.
cd backend
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
uvicorn main:app --reload --host 0.0.0.0 --port 8001Backend health check:
curl http://localhost:8001/api/healthIn a separate shell:
cd frontend
npm install
NEXT_PUBLIC_BACKEND_URL=http://localhost:8001 npm run devOpen http://localhost:3000.
Build and run the production container locally:
docker compose up --buildThe app will be available at http://localhost:8080.
Docker Compose mounts ./data to /data, so the SQLite database persists between container restarts.
| Method | Path | Description |
|---|---|---|
GET |
/api/health |
Health, configured model candidates, Gemini transport, and grounding tool status. |
POST |
/api/i18n/translate-ui |
Translate frontend UI copy for a supported language. |
GET |
/api/platform/features |
Machine-readable civic platform feature catalog. |
POST |
/api/platform/readiness |
Score voter readiness and return missing next actions. |
POST |
/api/platform/journey |
Generate persona-aware voting journey steps. |
POST |
/api/platform/booth-guide |
Return polling booth preparation and accessibility guidance. |
GET |
/api/platform/quiz |
Return civic literacy quiz questions. |
POST |
/api/platform/quiz/submit |
Grade quiz answers with explanations. |
POST |
/api/platform/scenario |
Simulate common election problem paths. |
POST |
/api/platform/analytics/insights |
Return non-sensitive civic engagement insights. |
GET |
/api/auth/providers |
Return Google Identity Services provider metadata and required env vars. |
GET |
/api/auth/google/start |
Return a Google OAuth authorization URL when credentials are configured. |
GET |
/api/auth/google/callback |
OAuth callback placeholder for production token exchange wiring. |
POST |
/api/auth/google/dev |
Create a local dev session when OAuth credentials are not configured. |
GET |
/api/auth/session |
Resolve a bearer token to the current auth session. |
POST |
/api/auth/logout |
Revoke an auth session token. |
POST |
/api/chat/sessions |
Create a new chat session. |
GET |
/api/chat/sessions |
List sessions by most recently updated. |
GET |
/api/chat/sessions/{session_id} |
Read a session and its messages. |
DELETE |
/api/chat/sessions/{session_id} |
Delete a session. |
POST |
/api/chat/sessions/{session_id}/stream |
Stream an assistant response using the Vercel AI SDK data stream protocol. |
WS |
/api/chat/sessions/{session_id}/ws |
WebSocket streaming alternative for chat responses. |
Example request flow:
SESSION_ID=$(curl -fsS -X POST http://localhost:8001/api/chat/sessions | jq -r .id)
curl -N \
-H 'Content-Type: application/json' \
-X POST "http://localhost:8001/api/chat/sessions/${SESSION_ID}/stream" \
-d '{"message":"How do I check my voter registration status?","language":"English"}'Backend:
cd backend
pip install -r requirements-dev.txt
pytest --cov=. --cov-report=term-missingFrontend:
cd frontend
npm run lint
npm test
npm run buildFull local quality gate:
./scripts/run_quality_checks.shSubmission size check:
./scripts/check_repo_size.shSee docs/TESTING.md, docs/GOOGLE_SERVICES.md, docs/PLATFORM_FEATURES.md, docs/AUTHENTICATION.md, docs/ACCESSIBILITY.md, SECURITY.md, and docs/SUBMISSION_CHECKLIST.md.
This repo includes a Cloud Build config that:
- Builds the Docker image.
- Pushes it to Artifact Registry.
- Creates a Cloud Storage bucket for the SQLite data volume if needed.
- Deploys Cloud Run service
election-guide. - Mounts the bucket at
/data. - Injects
GOOGLE_API_KEYfrom Secret Manager.
Required Google Cloud resources:
- Artifact Registry repository:
election-guideinus-central1. - Secret Manager secret:
GOOGLE_API_KEY. - Optional Secret Manager secret:
GOOGLE_SEARCH_API_KEYif using Google Custom Search. - Enabled APIs: Cloud Build, Cloud Run, Artifact Registry, Secret Manager, Cloud Logging, Cloud Storage, Vertex AI / Gemini, and optionally Firestore + Custom Search.
- Cloud Build service account permissions to push images, deploy Cloud Run, read the secret, and manage/use the storage bucket.
Deploy:
gcloud builds submit --config cloudbuild.yaml --project=<PROJECT_ID> .After deployment:
gcloud run services describe election-guide \
--region=us-central1 \
--project=<PROJECT_ID> \
--format='value(status.url,status.latestReadyRevisionName)'The most recent deployment from this workspace targeted project new-bro-493718 and produced:
https://election-guide-vqa72x3qma-uc.a.run.app
The production image starts three processes:
- FastAPI on
127.0.0.1:8001. - Next.js standalone server on
127.0.0.1:3000. - nginx on
${PORT:-8080}.
nginx routes:
/api/*to FastAPI with buffering disabled for streaming./and all frontend routes to Next.js.
# Frontend quality check
cd frontend && npm run lint
# Frontend production build
cd frontend && npm run build
# Backend health check
curl http://localhost:8001/api/health
# Container health check
curl http://localhost:8080/api/health
# Cloud Run logs
gcloud run services logs read election-guide --region=us-central1 --project=<PROJECT_ID>backend/.envis the local environment file read by the backend settings loader.NEXT_PUBLIC_BACKEND_URLshould be empty for the single-container Docker/Cloud Run setup because nginx serves frontend and API from the same origin.- The assistant grounds answers with built-in search, URL fetching, PDF extraction, and election schedule lookup tools.
- The chat stream uses the Vercel AI SDK data stream protocol and includes text deltas, reasoning deltas, tool call events, source annotations, and finish messages.