Spaces:
Sleeping
Sleeping
| # 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": "<uuid>" }` | |
| Response: `{ "session_id": "<uuid>", "message": "<first AI question>" }` | |
| 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": "<uuid>", "answer": "<student text>" }` | |
| Response: `{ "message": "<AI response or next question>", "turn_count": <int>, "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": "<uuid>", | |
| "topic_id": "<uuid>", | |
| "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<Response>`, 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 | |
| ``` | |