ai-interview-mentor / docs /architecture.md
samar m
Add architecture docs and Phase 0 scaffolding design spec
6a8e2e2

AI InterviewMentor β€” Architecture Overview

System Architecture

Browser (React SPA)
    β”‚
    β–Ό
HF Spaces Docker Container (port 7860)
β”œβ”€β”€ FastAPI (Python 3.11)
β”‚   β”œβ”€β”€ /api/auth/*        β†’ Custom JWT auth (jose + bcrypt)
β”‚   β”œβ”€β”€ /api/batches/*     β†’ Batch/class management
β”‚   β”œβ”€β”€ /api/topics/*      β†’ Topic CRUD + unlock control
β”‚   β”œβ”€β”€ /api/upload        β†’ CSV question bank ingestion
β”‚   β”œβ”€β”€ /api/sessions/*    β†’ Session detail + reports
β”‚   β”œβ”€β”€ /api/instructor/*  β†’ Dashboard + student analytics
β”‚   β”œβ”€β”€ /api/student/*     β†’ Student dashboard
β”‚   β”œβ”€β”€ /interview/*       β†’ LangGraph interview engine
β”‚   └── / (catch-all)      β†’ React static files (Vite build)
β”‚
β”œβ”€β”€ LangGraph Engine
β”‚   β”œβ”€β”€ ask_question       β†’ Picks next question from bank
β”‚   β”œβ”€β”€ evaluate_answer    β†’ Scores: strong | shallow | wrong
β”‚   β”œβ”€β”€ counter_question   β†’ Probing follow-up for shallow answers
β”‚   β”œβ”€β”€ summarize          β†’ Compresses conversation every 4 turns
β”‚   └── generate_report    β†’ Final scored feedback JSON
β”‚
└── External Services
    β”œβ”€β”€ NeonDB (PostgreSQL)
    β”‚   β”œβ”€β”€ public schema  β†’ App data (users, batches, topics, questions, sessions)
    β”‚   └── checkpointer   β†’ LangGraph state (auto-managed)
    └── OpenRouter API     β†’ MiniMax 2.7 model

Tech Stack

Layer Technology
Frontend React 18 + Vite + TypeScript + Tailwind CSS v3 (dark theme only)
Backend FastAPI (Python 3.11)
AI Orchestration LangGraph (state machine with checkpointing)
Database NeonDB (PostgreSQL) β€” app data + LangGraph checkpoints
AI Gateway OpenRouter β†’ MiniMax 2.7
Auth Custom JWT (jose + bcrypt) β€” no third-party auth
Deployment Single Docker container on Hugging Face Spaces (port 7860)

Key Design Decisions

  1. Single container deployment β€” React static build served by FastAPI, no split deployment
  2. Same-origin API calls β€” No CORS needed, browser hits FastAPI directly
  3. Two DB schemas β€” public for app data, checkpointer for LangGraph state
  4. Token budget control β€” Summarize every 4 turns, ~700 token ceiling per LLM call
  5. session_id = thread_id β€” Natural scoping between DB sessions and LangGraph state
  6. CSV-to-DB question ingestion β€” No file storage needed (no S3/R2)
  7. Custom JWT only β€” Supabase/Firebase explicitly banned (hackathon rules)

Database Schema

Tables

  • users β€” id, full_name, email, password_hash, role (student|instructor), batch_id
  • refresh_tokens β€” id, user_id, token_hash, expires_at
  • batches β€” id, name, instructor_id, class_code (auto-generated)
  • topics β€” id, batch_id, name, is_unlocked, order_index
  • questions β€” id, topic_id, question_text, difficulty (easy|medium|hard)
  • interview_sessions β€” id, student_id, topic_id, status, score, feedback (JSONB)

Relationships

instructor (user) β†’ creates batches β†’ has topics β†’ has questions
student (user) β†’ joins batch via class_code β†’ takes interview_sessions on topics

Auth Flow

  • Access token: HS256 JWT, 15min expiry, sent in Authorization: Bearer header
  • Refresh token: 7-day expiry, bcrypt-hashed in DB, sent as httpOnly cookie
  • Route protection: get_current_user dependency extracts JWT β†’ require_instructor / require_student role guards

LangGraph Interview Flow

START β†’ ask_question β†’ [wait for student answer] β†’ evaluate_answer
                                                        β”‚
                              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                              β–Ό                          β–Ό              β–Ό
                       counter_question            ask_question    generate_report β†’ END
                              β”‚                    (or summarize
                              β–Ό                     every 4 turns)
                       evaluate_answer
  • 8 turns max or question bank exhausted β†’ generate_report
  • Counter-questions fire once per shallow answer (no double-countering)
  • Summarize node compresses messages every 4 turns to keep token usage flat

Frontend Architecture

  • Routing: React Router with ProtectedRoute wrapper
  • State: Zustand stores β€” authStore (JWT + user), interviewStore (session state)
  • API layer: Single apiFetch wrapper with auto-refresh on 401
  • Pages: Login, Signup, StudentDashboard, Interview, Report, InstructorDashboard, Upload, StudentDetail

Scope Boundary (Not In V1)

Voice input, email notifications, leaderboard, certificates, question bank editor UI, light theme, multi-instructor batches.