Files
pragativeer-v2/API_DOCUMENTATION.md

1217 lines
40 KiB
Markdown

# PragatiVeer v2 — Comprehensive API & Architecture Developer Documentation
> **Document Type:** Full Developer Reference & Technical API Specification
> **Target Audience:** Frontend Engineers, Backend Engineers, DevOps, QA Engineers
> **Last Verified:** September 2026
> **Backend Engine:** FastAPI (Python 3.11) + SQLModel (SQLAlchemy) + Celery + Redis
> **Frontend Engine:** Next.js 16 (React 19, TypeScript, TailwindCSS)
> **Database & Storage:** PostgreSQL 15 (PgBouncer connection pooler) + MinIO (S3-compatible)
---
## 1. System Architecture & Container Topology
PragatiVeer v2 operates as an 8-container orchestrated cluster via Docker Compose:
```mermaid
graph TD
Client["Browser / Mobile Client"] -->|Port 3000| Frontend["pragativeer_frontend (Next.js 16)"]
Client -->|Port 8000| Backend["pragativeer_backend (FastAPI)"]
Frontend -->|Internal Rewrites /api/*| Backend
Backend -->|Pooled Queries :5432| PgBouncer["pragativeer_pgbouncer"]
PgBouncer --> DB[("pragativeer_db (PostgreSQL 15)")]
Backend -->|Pub/Sub & Cache :6379| Redis[("pragativeer_cache (Redis 7)")]
Backend -->|Uploads / Files :9000| MinIO[("pragativeer_storage (MinIO S3)")]
Worker["pragativeer_worker (Celery)"] --> Redis
Worker --> DB
Worker --> MinIO
Beat["pragativeer_beat (Celery Beat)"] --> Redis
```
### Port Mapping & Infrastructure Reference
| Container Service | Image / Engine | Internal Port | Host Port | Role |
| :--- | :--- | :---: | :---: | :--- |
| `pragativeer_frontend` | Next.js 16 Standalone | 3000 | `3000` | UI, CBT Interface, Next.js Edge OG Image Generation |
| `pragativeer_backend` | Python 3.11 / Uvicorn | 8000 | `8000` | Core REST API, Auth, CBT Engine, AI Coach |
| `pragativeer_db` | PostgreSQL 15 Alpine | 5432 | `5432` | Relational storage (Users, Tests, Attempts, Mistakes) |
| `pragativeer_pgbouncer` | PgBouncer | 5432 | Internal | High-concurrency connection pooler for PostgreSQL |
| `pragativeer_cache` | Redis 7 Alpine | 6379 | `6379` | Response cache & Celery task message broker |
| `pragativeer_worker` | Celery Worker | — | Internal | Background PDF AI question parsing & exam analytics |
| `pragativeer_beat` | Celery Beat | — | Internal | Scheduled 5:00 AM IST study plan generation |
| `pragativeer_storage` | MinIO S3 | 9000 / 9001 | `9000` / `9001` | PDF test uploads, question diagrams, user avatars |
---
## 2. Authentication, Cookies & Request/Response Headers Overview
### 2.1 Next.js 16 Proxy Middleware Protection (`src/proxy.ts`)
Next.js 16 uses `src/proxy.ts` (modern convention replacing older middleware patterns) to govern edge route protection:
- **Cookie Name:** `auth_token`
- **Dashboard Routes (`/dashboard/:path*`):** Requires cookie `auth_token=<user_id_or_token>`. If absent, redirects to `/login` (HTTP 307 Temporary Redirect).
- **Admin Routes (`/admin/:path*`):** Requires cookie `auth_token=admin`. If mismatched or missing, redirects to `/login` (HTTP 307 Temporary Redirect).
- **Public Routes:** `/`, `/login`, `/signup`, `/about`, `/contact`, `/pricing`, `/cbt-exam/:path*`.
### 2.2 Global Header Standards Across APIs
All PragatiVeer v2 endpoints conform to strict HTTP/1.1 and HTTP/2 header conventions:
#### Common Request Headers
| Header | Description | Required On |
| :--- | :--- | :--- |
| `Accept` | `application/json`, `text/event-stream`, or `image/png` | All API requests |
| `Content-Type` | `application/json` (or `multipart/form-data` for file uploads) | All `POST`, `PUT`, `PATCH` requests |
| `Cookie` | `auth_token=<uuid_or_admin>` | Protected routes (`/dashboard/*`, `/admin/*`) |
| `X-Razorpay-Signature` | HMAC-SHA256 hex digest computed with Razorpay Webhook Secret | `POST /api/billing/webhook/razorpay` |
| `Cache-Control` | `no-cache` | Streaming SSE endpoints |
#### Common Response Headers
| Header | Value / Usage | Endpoints |
| :--- | :--- | :--- |
| `Content-Type` | `application/json` | REST endpoints |
| `Content-Type` | `text/event-stream; charset=utf-8` | AI Tutor Streaming (`/api/ai-coach/chat/stream`) |
| `Content-Type` | `image/png` | Dynamic OG Image Generator (`/api/og/progress`) |
| `Cache-Control` | `no-cache, no-transform` | Real-time AI Coach streaming |
| `Connection` | `keep-alive` | Long-lived streaming connections |
| `X-Accel-Buffering` | `no` | Prevents Nginx/Reverse Proxy chunk buffering |
### 2.3 Tier-Based Gating (`require_tier`)
FastAPI dependency `require_tier(allowed_tiers: List[models.TierEnum])` inspects `user.tier`:
- **`Free`:** Unlocks basic mock tests, question practice, dashboard overview.
- **`Pro`:** Unlocks advanced mock tests, detailed performance metrics, daily practice sheets (DPS).
- **`Al_Coach`:** Unlocks real-time AI Tutor streaming (`/api/ai-coach/chat/stream`), Exam Readiness & College Prediction (`/api/ai-coach/readiness/{user_id}`), and Daily AI Study Plans (`/api/ai-coach/study-plan/today`).
---
## 3. Exhaustive REST API Specification (With Headers, Payloads & Responses)
---
### 3.1 Authentication Subsystem
#### `POST /api/auth/register`
- **Purpose:** Create a new student account with bcrypt password hashing and default profile fields.
- **Access:** Public
- **Request Headers:**
- `Accept: application/json`
- `Content-Type: application/json`
- **Request Body Schema:**
```json
{
"name": "Aryan Sharma",
"email": "aryan@example.com",
"password": "Password123!"
}
```
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**:
```json
{
"success": true,
"message": "User registered successfully"
}
```
- **`400 Bad Request`**:
```json
{
"detail": "Email already registered"
}
```
- **`422 Unprocessable Entity`**: If required fields (`name`, `email`, `password`) are missing or malformed.
---
#### `POST /api/auth/login`
- **Purpose:** Authenticate credentials using bcrypt verification, support seeded credentials & demo bypass, and issue active user token.
- **Access:** Public
- **Request Headers:**
- `Accept: application/json`
- `Content-Type: application/json`
- **Request Body Schema:**
```json
{
"email": "demo@pragativeer.com",
"password": "Pv9#kL2$mQ8!vX4@"
}
```
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK (Student)`**:
```json
{
"success": true,
"role": "user",
"token": "b0e17378-864d-439e-8806-708dc48a891b"
}
```
- **`200 OK (Admin)`**:
```json
{
"success": true,
"role": "admin",
"token": "admin"
}
```
- **`401 Unauthorized`**:
```json
{
"detail": "Invalid email or password"
}
```
- **`422 Unprocessable Entity`**: If email or password is omitted.
---
#### `POST /api/auth/otp-request`
- **Purpose:** Request one-time verification code for phone/email authentication.
- **Access:** Public
- **Request Headers:**
- `Accept: application/json`
- **Request Query Parameters:**
- `phone_or_email` (string, required): e.g. `9876543210` or `demo@pragativeer.com`
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**:
```json
{
"message": "Verification code dispatched successfully",
"debug_otp": "123456"
}
```
- **`422 Unprocessable Entity`**: If `phone_or_email` is missing.
---
#### `POST /api/auth/otp-verify`
- **Purpose:** Verify OTP code and return session token.
- **Access:** Public
- **Request Headers:**
- `Accept: application/json`
- **Request Query Parameters:**
- `phone_or_email` (string, required): Phone number or email
- `code` (string, required): 6-digit verification code
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**:
```json
{
"status": "authenticated",
"token": "mock_jwt_session_token_string"
}
```
- **`400 Bad Request`**: `{"detail": "Invalid or expired OTP code"}`
---
### 3.2 Users, Session Storage & Avatar Uploads
#### Single-Device Session Storage Architecture
PragatiVeer v2 enforces a strict single-device login policy:
1. Upon successful login (`/login`), the browser generates a random UUID: `const sessionToken = crypto.randomUUID()`.
2. The browser writes this token to `localStorage.setItem("active_session_token", sessionToken)`.
3. The browser makes an immediate `POST /api/users/{user_id}/session` request, storing `active_session_token` in the database.
4. On subsequent page loads, `useActiveUser` calls `GET /api/users/{user_id}`. If the database's `active_session_token` does not match the browser's `localStorage` session token, the student has logged in on another device, triggering an automatic logout and redirect.
---
#### `GET /api/users/{user_id}`
- **Purpose:** Retrieve student profile and automatically compute consecutive-day streaks based on `last_active`.
- **Access:** Authenticated User
- **Request Headers:**
- `Accept: application/json`
- `Cookie: auth_token=<user_id>`
- **Request Path Parameters:**
- `user_id` (UUID, required): Student user UUID
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**:
```json
{
"id": "b0e17378-864d-439e-8806-708dc48a891b",
"phone": "9999999999",
"email": "demo@pragativeer.com",
"name": "Rahul Sharma",
"student_class": "12",
"medium": "English",
"target_exam": "JEE_Main",
"school": "Delhi Public School",
"city": "New Delhi",
"state": "Delhi",
"tier": "Al_Coach",
"streak_count": 6,
"longest_streak": 6,
"profile_image_url": "http://localhost:9000/avatars/user_avatar.jpg",
"active_session_token": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"last_active": "2026-09-04T06:00:00.000000",
"created_at": "2026-08-01T10:00:00.000000"
}
```
- **`404 Not Found`**: `{"detail": "User not found"}`
- **`422 Unprocessable Entity`**: If `user_id` is not a valid UUID format.
---
#### `PUT /api/users/{user_id}`
- **Purpose:** Update profile attributes (target exam, school, grade class, state).
- **Access:** Authenticated User
- **Request Headers:**
- `Accept: application/json`
- `Content-Type: application/json`
- `Cookie: auth_token=<user_id>`
- **Request Path Parameters:**
- `user_id` (UUID, required): Student UUID
- **Request Body Schema:**
```json
{
"name": "Rahul Sharma",
"target_exam": "JEE_Advanced",
"student_class": "12",
"school": "DPS RK Puram",
"state": "Delhi"
}
```
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**: Returns updated `models.User` object.
- **`404 Not Found`**: `{"detail": "User not found"}`
- **`422 Unprocessable Entity`**: Malformed JSON or invalid UUID.
---
#### `POST /api/users/{user_id}/session`
- **Purpose:** Update single active session token in database to prevent multi-device concurrent logins.
- **Access:** Authenticated User
- **Request Headers:**
- `Accept: application/json`
- `Content-Type: application/json`
- `Cookie: auth_token=<user_id>`
- **Request Path Parameters:**
- `user_id` (UUID, required): Student UUID
- **Request Body Schema:**
```json
{
"session_token": "4f3b2a1c-9e8d-7c6b-5a4f-3e2d1c0b9a8f"
}
```
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**: Returns `models.User` with updated `active_session_token`.
- **`404 Not Found`**: `{"detail": "User not found"}`
- **`422 Unprocessable Entity`**: Invalid UUID or missing `session_token`.
---
#### `POST /api/users/{user_id}/avatar`
- **Purpose:** Multipart form image upload for student avatar. Uploads image to MinIO S3 bucket `avatars` and updates `user.profile_image_url`.
- **Access:** Authenticated User
- **Request Headers:**
- `Accept: application/json`
- `Content-Type: multipart/form-data; boundary=----WebKitFormBoundary...`
- `Cookie: auth_token=<user_id>`
- **Request Path Parameters:**
- `user_id` (UUID, required): Student UUID
- **Request Form Data:**
- `file`: Image binary (`image/jpeg`, `image/png`, `image/webp`)
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**:
```json
{
"success": true,
"profile_image_url": "http://localhost:9000/avatars/b0e17378_avatar.jpg"
}
```
- **`400 Bad Request`**: If uploaded file is not a supported image format.
- **`404 Not Found`**: `{"detail": "User not found"}`
---
#### `GET /api/users/{user_id}/attempts`
- **Purpose:** List historical exam test attempts for a student, with scores, accuracy, and timestamps.
- **Access:** Authenticated User
- **Request Headers:**
- `Accept: application/json`
- `Cookie: auth_token=<user_id>`
- **Request Path Parameters:**
- `user_id` (UUID, required): Student UUID
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**: Array of `models.Attempt` records:
```json
[
{
"id": "e4f5a6b7-c8d9-0e1f-2a3b-4c5d6e7f8a9b",
"user_id": "b0e17378-864d-439e-8806-708dc48a891b",
"source_type": "Test",
"source_id": "b6faa295-3bf5-4de2-a587-d72b889629c4",
"score": 184,
"max_score": 300,
"accuracy": 74.2,
"time_taken": 9840,
"retake_count": 0,
"created_at": "2026-09-02T14:30:00.000000"
}
]
```
- **`404 Not Found`**: If student does not exist.
---
### 3.3 CBT Testing Engine & Question Bank
#### `GET /api/tests`
- **Purpose:** List active examination tests (Mock Tests, Weekly Tests, PYQs, DPS).
- **Access:** Authenticated User
- **Request Headers:**
- `Accept: application/json`
- `Cookie: auth_token=<user_id>`
- **Request Query Parameters:**
- `exam_pattern` (string, optional): `JEE_Main` | `JEE_Advanced` | `NEET`
- `type` (string, optional): `Mock` | `Weekly` | `PYQ` | `DPS`. If omitted, automatically excludes `DPS` to keep Mock Tests separate.
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**: Array of `models.Test` objects:
```json
[
{
"id": "b6faa295-3bf5-4de2-a587-d72b889629c4",
"title": "JEE Main Full Mock Test #1 (2025)",
"type": "Mock",
"exam_pattern": "JEE_Main",
"sections": {
"Physics Section A": { "questions": ["uuid-1", "uuid-2"], "time_limit": 3600 },
"Chemistry Section A": { "questions": ["uuid-3", "uuid-4"], "time_limit": 3600 }
},
"total_time": 10800,
"difficulty": "Mixed",
"is_active": true
}
]
```
---
#### `GET /api/tests/{test_id}`
- **Purpose:** Retrieve specific test configuration and section mapping.
- **Access:** Authenticated User
- **Request Headers:**
- `Accept: application/json`
- `Cookie: auth_token=<user_id>`
- **Request Path Parameters:**
- `test_id` (UUID, required): Test ID
- **Request Query Parameters:**
- `user_id` (UUID, optional): Optional student UUID to check eligibility
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**: Returns single `models.Test` record.
- **`404 Not Found`**: `{"detail": "Requested examination structure not found."}`
- **`422 Unprocessable Entity`**: Invalid UUID format.
---
#### `GET /api/tests/{test_id}/questions`
- **Purpose:** Fetch all full Question records belonging to a test's sections.
- **Access:** Authenticated User
- **Request Headers:**
- `Accept: application/json`
- `Cookie: auth_token=<user_id>`
- **Request Path Parameters:**
- `test_id` (UUID, required): Test ID
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**: Array of `models.Question` entities:
```json
[
{
"id": "00000000-0000-0000-0000-000000000001",
"subject": "Physics",
"topic": "Kinematics",
"subtopic": "Relative Motion",
"difficulty": "Medium",
"type": "MCQ_Single",
"question_text": "A particle moves along a straight line with constant acceleration...",
"question_text_hi": "एक कण स्थिर त्वरण के साथ एक सीधी रेखा में गति करता है...",
"options": {
"A": "10 m/s",
"B": "20 m/s",
"C": "30 m/s",
"D": "40 m/s"
},
"correct_answer": { "correct": "B" },
"solution_text": "Using kinematic formula v = u + at...",
"language": "Bilingual",
"exam": "JEE_Main",
"is_active": true
}
]
```
- **`404 Not Found`**: If `test_id` is invalid or contains no questions.
---
#### `GET /api/questions/{question_id}`
- **Purpose:** Fetch single question data with complete step-by-step solution text.
- **Access:** Authenticated User
- **Request Headers:**
- `Accept: application/json`
- `Cookie: auth_token=<user_id>`
- **Request Path Parameters:**
- `question_id` (UUID, required)
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**: Single `models.Question` record.
- **`404 Not Found`**: `{"detail": "Requested question not found."}`
---
#### `POST /api/attempts/submit`
- **Purpose:** Core grading engine. Auto-grades student answers, calculates accuracy %, tracks retakes, and automatically records mistakes into `models.Mistake` with SuperMemo-2 spaced repetition intervals.
- **Access:** Authenticated User
- **Request Headers:**
- `Accept: application/json`
- `Content-Type: application/json`
- `Cookie: auth_token=<user_id>`
- **Request Body Schema:**
```json
{
"user_id": "b0e17378-864d-439e-8806-708dc48a891b",
"source_type": "Test",
"source_id": "b6faa295-3bf5-4de2-a587-d72b889629c4",
"time_taken": 3600,
"answers": [
{
"question_id": "00000000-0000-0000-0000-000000000001",
"selected_answer": "B",
"is_subjective": false,
"time_spent": 45
}
]
}
```
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**: Returns graded `models.Attempt` record with total score, accuracy %, and mistake IDs recorded.
- **`404 Not Found`**: If `user_id` or test source does not exist.
- **`422 Unprocessable Entity`**: Malformed payload.
---
### 3.4 AI Coach, Tutor Stream & Spaced Repetition
#### `POST /api/ai-coach/chat/stream`
- **Purpose:** Real-time conversational AI tutor for instant doubt resolution. Streams response tokens using Server-Sent Events (SSE).
- **Access:** Gated to `Al_Coach` tier (`HTTP 403` if Free or Pro)
- **Request Headers:**
- `Accept: text/event-stream`
- `Content-Type: application/json`
- `Cache-Control: no-cache`
- `Cookie: auth_token=<user_id>`
- **Request Body Schema:**
```json
{
"user_id": "b0e17378-864d-439e-8806-708dc48a891b",
"message": "Why does friction act forward on the driven wheel of an accelerating car?"
}
```
- **Response Headers:**
- `Content-Type: text/event-stream; charset=utf-8`
- `Cache-Control: no-cache, no-transform`
- `Connection: keep-alive`
- `X-Accel-Buffering: no`
- **Response Stream Chunks:**
```
data: When
data: a
data: car
data: accelerates,
data: the
data: engine
data: applies
data: torque...
```
- **Status Codes:**
- **`200 OK`**: Server-Sent Events stream initiated.
- **`403 Forbidden`**: `{"detail": "Access denied. Gated to AI_COACH tier."}`
- **`404 Not Found`**: `{"detail": "Student profile not found."}`
- **`422 Unprocessable Entity`**: If `user_id` or `message` is missing.
---
#### `GET /api/ai-coach/study-plan/today`
- **Purpose:** Retrieve today's personalized AI study tasks generated nightly by Celery Beat scheduler based on weak areas and pending mistakes.
- **Access:** Gated to `Al_Coach` tier (`HTTP 403` if Free or Pro)
- **Request Headers:**
- `Accept: application/json`
- `Cookie: auth_token=<user_id>`
- **Request Query Parameters:**
- `user_id` (UUID, required): Student UUID
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**:
```json
{
"id": "7f8e9d0a-1b2c-3d4e-5f6a-7b8c9d0e1f2a",
"user_id": "b0e17378-864d-439e-8806-708dc48a891b",
"date": "2026-09-04",
"tasks": [
{
"type": "Revision",
"description": "Revise Rotational Mechanics",
"duration_minutes": 15,
"status": "Pending"
},
{
"type": "Mistake_Review",
"description": "Daily Mistake Review Session",
"duration_minutes": 10,
"status": "Pending"
},
{
"type": "DPS",
"description": "Attempt Rotational Mechanics Practice Sheet",
"duration_minutes": 20,
"status": "Pending"
}
],
"is_completed": false
}
```
- **`403 Forbidden`**: If user is not on `Al_Coach` tier.
- **`404 Not Found`**: `{"detail": "No study plan generated for today yet."}`
- **`422 Unprocessable Entity`**: If `user_id` query param is omitted.
---
#### `GET /api/ai-coach/readiness/{user_id}`
- **Purpose:** Computes weighted exam readiness score, predicts All India Rank (AIR), and estimates probability of admission to top IITs/AIIMS colleges.
- **Access:** Gated to `Al_Coach` tier
- **Request Headers:**
- `Accept: application/json`
- `Cookie: auth_token=<user_id>`
- **Request Path Parameters:**
- `user_id` (UUID, required): Student UUID
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**:
```json
{
"readiness_score": 78.4,
"predicted_rank": 2840,
"target_exam": "JEE_Main",
"predicted_college": "IIT Delhi (Mechanical / Chemical)",
"probability": 84.5,
"weak_topics": ["Thermodynamics", "Wave Optics"],
"strong_topics": ["Kinematics", "Electrostatics"]
}
```
- **`403 Forbidden`**: If user is not subscribed to `Al_Coach`.
- **`404 Not Found`**: If user does not exist.
---
#### `GET /api/mistakes/today`
- **Purpose:** Retrieve mistake notebook items scheduled for review today based on SuperMemo-2 (SM-2) spaced repetition interval.
- **Access:** Authenticated User
- **Request Headers:**
- `Accept: application/json`
- `Cookie: auth_token=<user_id>`
- **Request Query Parameters:**
- `user_id` (UUID, required): Student UUID
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**: Array of `models.Mistake` items with associated question context:
```json
[
{
"id": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
"user_id": "b0e17378-864d-439e-8806-708dc48a891b",
"question_id": "00000000-0000-0000-0000-000000000001",
"mistake_type": "Calculation_Error",
"review_count": 1,
"interval_days": 3,
"ease_factor": 2.5,
"next_review": "2026-09-04",
"resolved": false
}
]
```
- **`422 Unprocessable Entity`**: If `user_id` parameter is missing.
---
#### `POST /api/mistakes/review`
- **Purpose:** Update spaced repetition schedule after reviewing a mistake item (SM-2 algorithm calculates next review interval based on student recall quality 0-5).
- **Access:** Authenticated User
- **Request Headers:**
- `Accept: application/json`
- `Content-Type: application/json`
- `Cookie: auth_token=<user_id>`
- **Request Body Schema:**
```json
{
"mistake_id": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
"quality": 4
}
```
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**:
```json
{
"success": true,
"next_review": "2026-09-10",
"interval_days": 6,
"ease_factor": 2.6
}
```
- **`404 Not Found`**: `{"detail": "Mistake record not found"}`
---
### 3.5 Subscription, Billing & Gateways
#### `POST /api/billing/create-order`
- **Purpose:** Initiates Razorpay payment order for tier upgrade (`Pro` or `Al_Coach`).
- **Access:** Authenticated User
- **Request Headers:**
- `Accept: application/json`
- `Content-Type: application/json`
- `Cookie: auth_token=<user_id>`
- **Request Body Schema:**
```json
{
"user_id": "b0e17378-864d-439e-8806-708dc48a891b",
"tier": "Al_Coach",
"amount": 299900,
"coupon_code": "DISCOUNT20"
}
```
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**:
```json
{
"order_id": "order_EKf34dhu72ndD2",
"amount": 239920,
"currency": "INR",
"key_id": "rzp_test_YOUR_KEY"
}
```
- **`400 Bad Request`**: `{"detail": "Invalid tier or invalid coupon code."}`
---
#### `POST /api/billing/verify-payment`
- **Purpose:** Verifies Razorpay payment signature HMAC-SHA256, records transaction, and upgrades user's tier.
- **Access:** Authenticated User
- **Request Headers:**
- `Accept: application/json`
- `Content-Type: application/json`
- `Cookie: auth_token=<user_id>`
- **Request Body Schema:**
```json
{
"user_id": "b0e17378-864d-439e-8806-708dc48a891b",
"razorpay_order_id": "order_EKf34dhu72ndD2",
"razorpay_payment_id": "pay_29QQoUBi66xm2f",
"razorpay_signature": "9ef4705b83f6c19ff76543210abcd1234567890abcdef1234567890abcdef",
"tier": "Al_Coach"
}
```
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**:
```json
{
"success": true,
"tier": "Al_Coach",
"message": "Payment verified and tier upgraded successfully."
}
```
- **`400 Bad Request`**: `{"detail": "Payment verification failed. Invalid signature."}`
---
#### `POST /api/billing/webhook/razorpay`
- **Purpose:** Asynchronous payment confirmation webhook from Razorpay for recurring charges or asynchronous UPI captures.
- **Access:** Public (Protected by HMAC Webhook Secret)
- **Request Headers:**
- `Accept: application/json`
- `Content-Type: application/json`
- `X-Razorpay-Signature: <hmac_sha256_hex_digest>`
- **Request Body Schema:** Standard Razorpay Webhook Event payload:
```json
{
"entity": "event",
"event": "payment.captured",
"payload": {
"payment": {
"entity": {
"id": "pay_29QQoUBi66xm2f",
"amount": 239920,
"status": "captured",
"order_id": "order_EKf34dhu72ndD2"
}
}
}
}
```
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**: `{"status": "ok"}`
- **`400 Bad Request`**: `{"detail": "Invalid webhook signature."}`
---
### 3.6 Admin Control Panel Subsystem
All Admin endpoints require superadmin access:
- **Required Cookie:** `Cookie: auth_token=admin`
- **Default Superadmin:** `admin@pragativeer.com` / `admin123`
---
#### `GET /api/admin/settings`
- **Purpose:** Retrieve system-wide runtime configuration (maintenance mode, free trial flags, AI model selection).
- **Access:** Admin
- **Request Headers:**
- `Accept: application/json`
- `Cookie: auth_token=admin`
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**:
```json
{
"maintenance_mode": false,
"allow_free_trials": true,
"ai_model": "gemini-2.5-pro",
"max_daily_questions": 150
}
```
- **`401 Unauthorized`**: If admin cookie is missing or invalid.
---
#### `PUT /api/admin/settings`
- **Purpose:** Update system-wide configuration settings.
- **Access:** Admin
- **Request Headers:**
- `Accept: application/json`
- `Content-Type: application/json`
- `Cookie: auth_token=admin`
- **Request Body Schema:**
```json
{
"maintenance_mode": false,
"allow_free_trials": true,
"ai_model": "gemini-2.5-pro"
}
```
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**: Returns updated settings object.
- **`401 Unauthorized`**: If unauthorized.
---
#### `GET /api/admin/tests`
- **Purpose:** List all tests, PYQs, and DPS (including drafts and inactive tests).
- **Access:** Admin
- **Request Headers:**
- `Accept: application/json`
- `Cookie: auth_token=admin`
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**: Array of all `models.Test` records.
---
#### `POST /api/admin/tests/upload`
- **Purpose:** Upload PDF exam paper to MinIO storage and dispatch background AI parsing task to Celery worker.
- **Access:** Admin
- **Request Headers:**
- `Accept: application/json`
- `Content-Type: multipart/form-data; boundary=----WebKitFormBoundary...`
- `Cookie: auth_token=admin`
- **Request Form Data:**
- `file`: PDF binary (`application/pdf`)
- `exam_pattern`: `JEE_Main` | `JEE_Advanced` | `NEET`
- `title`: Test name string
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**:
```json
{
"task_id": "c56d78ef-12ab-34cd-56ef-7890abcdef12",
"status": "Processing",
"message": "PDF uploaded to MinIO. Celery AI parser dispatched."
}
```
- **`400 Bad Request`**: If file is not a valid PDF.
---
#### `POST /api/admin/tests/create_manual`
- **Purpose:** Manually create a CBT mock test structure and map questions.
- **Access:** Admin
- **Request Headers:**
- `Accept: application/json`
- `Content-Type: application/json`
- `Cookie: auth_token=admin`
- **Request Body Schema:**
```json
{
"title": "All India Grand Mock Test #5",
"type": "Mock",
"exam_pattern": "JEE_Main",
"total_time": 10800,
"difficulty": "Hard",
"sections": {
"Physics": { "questions": [], "time_limit": 3600 }
}
}
```
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**: Created `models.Test` record.
---
#### `PUT /api/admin/tests/{test_id}/toggle`
- **Purpose:** Toggle test `is_active` status (publish/unpublish).
- **Access:** Admin
- **Request Headers:**
- `Accept: application/json`
- `Cookie: auth_token=admin`
- **Request Path Parameters:**
- `test_id` (UUID, required)
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**: `{"id": "...", "is_active": true}`
- **`404 Not Found`**: If test does not exist.
---
#### `DELETE /api/admin/tests/{test_id}`
- **Purpose:** Permanently delete a test and dissociate question mappings.
- **Access:** Admin
- **Request Headers:**
- `Accept: application/json`
- `Cookie: auth_token=admin`
- **Request Path Parameters:**
- `test_id` (UUID, required)
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**: `{"success": true, "message": "Test deleted successfully."}`
- **`404 Not Found`**: If test does not exist.
---
#### `GET /api/admin/coupons`
- **Purpose:** List all promotional discount coupons.
- **Access:** Admin
- **Request Headers:**
- `Accept: application/json`
- `Cookie: auth_token=admin`
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**: Array of `models.Coupon` records.
---
#### `POST /api/admin/coupons`
- **Purpose:** Create a new promotional discount coupon.
- **Access:** Admin
- **Request Headers:**
- `Accept: application/json`
- `Content-Type: application/json`
- `Cookie: auth_token=admin`
- **Request Body Schema:**
```json
{
"code": "FESTIVE25",
"discount_percentage": 25,
"max_uses": 500,
"valid_until": "2026-12-31T23:59:59.000000"
}
```
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**: Returns created `models.Coupon` entity.
---
#### `DELETE /api/admin/coupons/{coupon_id}`
- **Purpose:** Delete promotional coupon.
- **Access:** Admin
- **Request Headers:**
- `Accept: application/json`
- `Cookie: auth_token=admin`
- **Request Path Parameters:**
- `coupon_id` (UUID, required)
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**: `{"success": true, "message": "Coupon deleted"}`
- **`404 Not Found`**: `{"detail": "Coupon not found"}`
---
#### `GET /api/admin/students`
- **Purpose:** List all registered students with attempts and accuracy metrics.
- **Access:** Admin
- **Request Headers:**
- `Accept: application/json`
- `Cookie: auth_token=admin`
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**: Array of student summary objects.
---
#### `GET /api/admin/students/{user_id}`
- **Purpose:** Detailed student profile with weak topics, recent tests, transactions.
- **Access:** Admin
- **Request Headers:**
- `Accept: application/json`
- `Cookie: auth_token=admin`
- **Request Path Parameters:**
- `user_id` (UUID, required)
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**: Detailed student dossier.
- **`404 Not Found`**: Student not found.
---
#### `PATCH /api/admin/students/{user_id}`
- **Purpose:** Modify student tier, streak count, school, city, or exam.
- **Access:** Admin
- **Request Headers:**
- `Accept: application/json`
- `Content-Type: application/json`
- `Cookie: auth_token=admin`
- **Request Path Parameters:**
- `user_id` (UUID, required)
- **Request Body Schema:**
```json
{
"tier": "Al_Coach",
"streak_count": 15
}
```
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**: Returns modified `models.User` record.
- **`404 Not Found`**: Student not found.
---
### 3.7 Parent Subsystem & Viral Growth
#### `POST /api/parent/register`
- **Purpose:** Register parent user profile in `models.Parent`.
- **Access:** Public
- **Request Headers:**
- `Accept: application/json`
- `Content-Type: application/json`
- **Request Body Schema:**
```json
{
"name": "Rajesh Kumar",
"phone": "9876543210",
"email": "parent@example.com",
"password_hash": "hashed_password"
}
```
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**:
```json
{
"id": "c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f",
"name": "Rajesh Kumar",
"phone": "9876543210",
"email": "parent@example.com"
}
```
- **`400 Bad Request`**: If phone or email is already registered.
---
#### `POST /api/parent/link-student`
- **Purpose:** Link a student's profile to a parent account using student's phone or email.
- **Access:** Parent User
- **Request Headers:**
- `Accept: application/json`
- **Request Query Parameters:**
- `parent_id` (UUID, required): Parent UUID
- `student_phone_or_email` (string, required): Student's registered phone or email
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**:
```json
{
"success": true,
"message": "Student linked to parent account successfully."
}
```
- **`404 Not Found`**: `{"detail": "Student or parent account not found."}`
---
#### `GET /api/parent/{parent_id}/dashboard/{student_id}`
- **Purpose:** Generate complete parent report with test summary, syllabus progress, and AI recommendations.
- **Access:** Parent User
- **Request Headers:**
- `Accept: application/json`
- **Request Path Parameters:**
- `parent_id` (UUID, required)
- `student_id` (UUID, required)
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**:
```json
{
"student_name": "Rahul Sharma",
"target_exam": "JEE_Main",
"tests_attempted": 8,
"average_accuracy": 74.2,
"current_streak": 6,
"ai_insight": "Rahul is performing exceptionally well in Kinematics but needs focused revision on Thermodynamics."
}
```
- **`404 Not Found`**: If parent or student record does not exist.
---
#### `GET /api/growth/referral/{user_id}`
- **Purpose:** Generates referral code, viral share URL, referral count, and milestone unlocks.
- **Access:** Authenticated User
- **Request Headers:**
- `Accept: application/json`
- `Cookie: auth_token=<user_id>`
- **Request Path Parameters:**
- `user_id` (UUID, required): Student UUID
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**:
```json
{
"referral_code": "PV-RAHUL-1A2B",
"referral_url": "http://localhost:3000/signup?ref=PV-RAHUL-1A2B",
"total_referred": 3,
"unlocked_rewards": ["1 Free Mock Test", "7 Days AI Coach Trial"]
}
```
- **`404 Not Found`**: If student does not exist.
---
### 3.8 Next.js Route Handlers & Edge Handlers
#### `POST /api/auth/forgot-password`
- **Location:** `src/app/api/auth/forgot-password/route.ts`
- **Runtime:** Node.js App Router
- **Access:** Public
- **Request Headers:**
- `Accept: application/json`
- `Content-Type: application/json`
- **Request Body Schema:**
```json
{
"email": "demo@pragativeer.com"
}
```
- **Response Headers:**
- `Content-Type: application/json`
- **Status Codes & Response Payloads:**
- **`200 OK`**:
```json
{
"success": true,
"message": "Reset instructions sent."
}
```
- **`400 Bad Request`**: `{"detail": "Email address is required."}`
---
#### `GET /api/og/progress`
- **Location:** `src/app/api/og/progress/route.tsx`
- **Runtime:** Edge (`@vercel/og` ImageResponse)
- **Access:** Public
- **Request Headers:**
- `Accept: image/png, image/*`
- **Request Query Parameters:**
- `streak` (integer, optional): Day streak count (e.g. `12`)
- `accuracy` (number, optional): Accuracy percentage (e.g. `78`)
- `name` (string, optional): Student name (e.g. `Rahul`)
- **Response Headers:**
- `Content-Type: image/png`
- `Cache-Control: public, max-age=31536000, immutable`
- **Status Codes & Response Payloads:**
- **`200 OK`**: Dynamic 1200x630 PNG social card image.
---
## 4. Planned APIs (Roadmap / Frontend Mock Status)
The following endpoints are specified in [PRD.md](file:///c:/Users/naman/OneDrive/Desktop/pragativeer-v2/PRD.md) or rendered using client-side mock data in the UI:
| Planned API | Expected Route | Frontend UI File | Backend Provisioning Needed |
| :--- | :--- | :--- | :--- |
| **Leaderboard API** | `GET /api/leaderboard` | [leaderboard/page.tsx](file:///c:/Users/naman/OneDrive/Desktop/pragativeer-v2/src/app/dashboard/leaderboard/page.tsx) | Redis sorted set queries (`ZREVRANGE`) by exam/state |
| **Student Analytics API** | `GET /api/users/{id}/analytics` | [analytics/page.tsx](file:///c:/Users/naman/OneDrive/Desktop/pragativeer-v2/src/app/dashboard/analytics/page.tsx) | Weekly score trajectories and topic heatmap accuracies |
| **Streak Rewards API** | `GET /api/streaks/rewards` | [streaks/page.tsx](file:///c:/Users/naman/OneDrive/Desktop/pragativeer-v2/src/app/dashboard/streaks/page.tsx) | Gamification milestone reward unlocks |
| **Syllabus Progress Tracker** | `GET/PUT /api/syllabus/progress` | [progress/page.tsx](file:///c:/Users/naman/OneDrive/Desktop/pragativeer-v2/src/app/dashboard/progress/page.tsx) | Chapter-by-chapter completion % per subject |
| **Community Doubts Feed** | `GET/POST /api/community/doubts` | [community/page.tsx](file:///c:/Users/naman/OneDrive/Desktop/pragativeer-v2/src/app/dashboard/community/page.tsx) | Discussion forum posts, replies, and upvotes |
| **Study Materials Library** | `GET /api/materials` | [materials/page.tsx](file:///c:/Users/naman/OneDrive/Desktop/pragativeer-v2/src/app/dashboard/materials/page.tsx) | MinIO PDF formula sheet catalog and access controls |
| **Voice AI & Live Battle** | `/ws/battles`, `/api/ai-coach/voice` | Future Scope | WebSockets for multiplayer CBT battles & Whisper voice |
## 5. Seeded Credentials Reference
The platform provides two pre-configured accounts for administration and end-to-end evaluation:
| Role | Email | Password | Tier / Features |
| :--- | :--- | :--- | :--- |
| **Super Admin** | `admin@pragativeer.com` | `admin123` | Full access to `/admin` management console & question bank |
| **AI Coach Student** | `demo@pragativeer.com` | `Pv9#kL2$mQ8!vX4@` | Full AI Coach access (AI Tutor SSE stream, College Predictor, CBT Mock Engine, Spaced Repetition) |