# Collaboration Handoff — AI InterviewMentor > **READ THIS FIRST** before touching any code. > Two developers are working on this project simultaneously using Claude Code. > This file tracks what has been done, who owns what, and the exact API contracts each side expects. --- ## Who Owns What | Area | Owner | Status | |------|-------|--------| | Phases 1–4 (scaffolding, auth, instructor batch/topics, CSV upload) | Done | ✅ | | **Phase 5** — LangGraph backend engine | **Other dev** | 🔄 In progress | | Phases 6–9 (student UI, reports, dashboards, analytics) | **This dev** | ✅ Done | | Phase 10 — Docker + deploy | Shared | ⏳ Pending | **Rule**: Do not touch files owned by the other dev without coordinating first. --- ## Phase 5 — What the Backend Must Deliver (Other Dev's Contract) The frontend (Phases 6–7) is already wired to these endpoints. Do not change the request/response shapes. ### `POST /api/interview/start` Request: `{ "topic_id": "" }` Response: `{ "session_id": "", "message": "" }` Behaviour: - Creates a row in `interview_sessions` with `status='active'` - Initialises LangGraph state with thread_id = session_id - Returns the first AI question as `message` ### `POST /api/interview/turn` Request: `{ "session_id": "", "answer": "" }` Response: `{ "message": "", "turn_count": , "status": "ongoing"|"finished" }` Behaviour: - Appends the student answer + AI response to LangGraph state - When interview ends: sets `interview_sessions.status='completed'`, writes `score` and `feedback` JSON - Returns `"finished"` status when done (max 8 turns or question bank exhausted) ### `GET /api/interview/state/{session_id}` Response: ```json { "id": "", "topic_id": "", "status": "ongoing|finished", "turn_count": 3, "messages": [{"role": "ai|student", "content": "..."}] } ``` Behaviour: used to resume a session after tab close/reload. ### `feedback` JSONB shape (written to `interview_sessions.feedback`) The frontend's `Feedback` type expects: ```json { "score": 82, "summary": "Good understanding of concepts...", "concept_score": 80, "depth_score": 85, "mistakes": ["Missed edge case in X", "..."], "tips": ["Strong on Y", "..."] } ``` --- ## Routers Already Registered in `backend/main.py` ``` /api/auth/* — auth.router (signup, login, refresh, logout) /api/batches/* — batches.router (create, get mine, get by id) /api/topics/* — topics.router (create, list, unlock/lock) /api/upload — upload.router (CSV parse + bulk insert) /api/student/* — student.router (topics for student, sessions list) /api/sessions/* — sessions.router (get session detail/report) /api/instructor/* — instructor.router (student list + detail) ``` **Phase 5 must also register:** ```python from backend.routers import interview app.include_router(interview.router, prefix="/api/interview") ``` --- ## Completed Frontend Files (Do Not Overwrite) ### API Layer (`frontend/src/api/`) | File | Functions | |------|-----------| | `auth.ts` | `login`, `signup`, `logout`, `refreshToken` | | `client.ts` | `apiFetch` — returns `Promise`, auto-refreshes on 401 | | `topics.ts` | `getMyBatch`, `createBatch`, `getTopics`, `createTopic`, `setTopicUnlock`, `getStudentTopics`, `getStudentSessions` | | `interview.ts` | `startInterview(topicId)`, `sendTurn(sessionId, answer)`, `getInterviewState(sessionId)` | | `sessions.ts` | `getSession(sessionId)` | | `upload.ts` | `uploadCSV(topicId, file)` | | `student.ts` | `getStudentDashboard()` | | `instructor.ts` | `getInstructorStudents()`, `getStudentDetail(studentId)` | ### Store (`frontend/src/store/`) | File | State | |------|-------| | `authStore.ts` | `accessToken`, `user`, `setAuth`, `clearAuth` — persisted to localStorage | | `interviewStore.ts` | `sessionId`, `messages`, `turnCount`, `status`, `startSession`, `addMessage`, `setTurnCount`, `setStatus`, `reset` | ### Pages (`frontend/src/pages/`) All pages implemented: `Login`, `Signup`, `StudentDashboard`, `Interview`, `Report`, `InstructorDashboard`, `Upload`, `StudentDetail` ### Types (`frontend/src/types/index.ts`) ```ts User, AuthResponse, Message, Feedback, InterviewSession, SessionReport, StudentSession, StudentTopic, InstructorStudent, StudentAttempt ``` --- ## Key Patterns to Follow ### apiFetch usage (always check `.ok`): ```ts const res = await apiFetch('/api/something') if (!res.ok) { const err = await res.json() throw new Error(err.detail ?? 'Request failed') } return res.json() ``` ### Tailwind dark theme conventions: - Page bg: `bg-gray-950` - Card: `bg-gray-900 border border-gray-800 rounded-xl` - Input: `bg-gray-800 border border-gray-700 rounded-lg focus:border-indigo-500` - Primary button: `bg-indigo-600 hover:bg-indigo-500` - Muted text: `text-gray-400`, `text-gray-500` ### Backend router pattern: ```python from fastapi import APIRouter, Depends, HTTPException from backend.auth.deps import require_student # or require_instructor from backend.db import queries router = APIRouter() # user dict has: user_id, role, batch_id, email ``` --- ## DB Schema Reference ``` users — id, full_name, email, password_hash, role, batch_id, created_at batches — id, name, instructor_id, class_code, created_at topics — id, batch_id, name, is_unlocked, order_index, created_at questions — id, topic_id, question_text, difficulty, created_at interview_sessions — id, student_id, topic_id, status('active'|'completed'), score, feedback(JSONB), started_at, completed_at refresh_tokens — id, user_id, token_hash, expires_at ```