1301 lines
44 KiB
Markdown
1301 lines
44 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)
|
|
> **Companion Documents:**
|
|
> - For page-by-page UI file locations, buttons, modals, and client API mapping, see [PAGEWISE_API_DOCUMENTATION.md](file:///c:/Users/naman/OneDrive/Desktop/pragativeer-v2/PAGEWISE_API_DOCUMENTATION.md).
|
|
> - For typography, fonts, color tokens, button variants, and light/dark mode styling, see [DESIGN_SYSTEM.md](file:///c:/Users/naman/OneDrive/Desktop/pragativeer-v2/DESIGN_SYSTEM.md).
|
|
|
|
---
|
|
|
|
## 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) |
|
|
|
|
> **Note:** No other accounts are seeded. Any login attempt with a non-registered email returns `401 Unauthorized`.
|
|
|
|
---
|
|
|
|
## 6. Environment Variables & Infrastructure Configuration
|
|
|
|
### 6.1 Backend Environment Variables (`backend/.env`)
|
|
|
|
| Variable | Example Value | Purpose |
|
|
| :--- | :--- | :--- |
|
|
| `OPENAI_API_KEY` | `6a1b502...` | LLM API key for AI Coach (deferred to Phase 2) |
|
|
| `LLM_BASE_URL` | `https://ollama.com/v1` | LLM inference endpoint |
|
|
| `LLM_MODEL_NAME` | `gemma4:31b-cloud` | Model identifier |
|
|
| `RAZORPAY_KEY_ID` | `rzp_test_XXXXXX` | Razorpay public key (test mode) |
|
|
| `RAZORPAY_KEY_SECRET` | `your_secret` | Razorpay private key (server-side only) |
|
|
| `RAZORPAY_WEBHOOK_SECRET` | `your_webhook_secret` | Razorpay webhook signature verification |
|
|
| `SMTP_HOST` | `smtp.gmail.com` | Transactional email SMTP server |
|
|
| `SMTP_PORT` | `587` | SMTP TLS port |
|
|
| `SMTP_USER` | `no-reply@pragativeer.com` | SMTP login username |
|
|
| `SMTP_PASS` | `app_password_here` | Gmail App Password or SMTP password |
|
|
| `SMTP_FROM_NAME` | `PragatiVeer` | Display name in sent emails |
|
|
| `SMTP_FROM_EMAIL` | `no-reply@pragativeer.com` | Reply-to address |
|
|
| `FRONTEND_URL` | `https://pragativeer.com` | Production frontend domain (CORS & email links) |
|
|
| `API_URL` | `https://api.pragativeer.com` | Production API domain |
|
|
| `MINIO_ENDPOINT` | `minio:9000` | MinIO internal endpoint |
|
|
| `MINIO_ACCESS_KEY` | `minio_admin` | MinIO access key |
|
|
| `MINIO_SECRET_KEY` | `minio_secure_password` | MinIO secret key |
|
|
| `MINIO_BUCKET` | `pragativeer-uploads` | Default uploads bucket |
|
|
| `MINIO_AVATARS_BUCKET` | `avatars` | Avatar image bucket |
|
|
|
|
> ⚠️ `backend/.env` is `.gitignore`-listed — **never commit real secrets**. Use `backend/.env.example` as a safe-to-commit template.
|
|
|
|
### 6.2 Frontend Environment Variables (`.env.local`)
|
|
|
|
| Variable | Example Value | Purpose |
|
|
| :--- | :--- | :--- |
|
|
| `NEXT_PUBLIC_RAZORPAY_KEY_ID` | `rzp_test_XXXXXX` | Razorpay public key (exposed to browser) |
|
|
| `NEXT_PUBLIC_API_URL` | `http://localhost:8000` | Backend API base URL |
|
|
| `NEXT_PUBLIC_PAYMENT_GATEWAY` | `razorpay` | Payment provider identifier |
|
|
|
|
> ⚠️ `.env.local` is `.gitignore`-listed. Only `NEXT_PUBLIC_*` variables are safe to expose to the browser.
|
|
|
|
### 6.3 CORS Configuration
|
|
|
|
The backend accepts requests from these origins (configured in `backend/main.py`):
|
|
|
|
| Origin | Environment |
|
|
| :--- | :--- |
|
|
| `http://localhost:3000` | Local development |
|
|
| `http://127.0.0.1:3000` | Local development |
|
|
| `https://pragativeer.com` | Production |
|
|
| `https://www.pragativeer.com` | Production (www redirect) |
|
|
| `https://api.pragativeer.com` | Production API-to-API |
|
|
|
|
### 6.4 Email Service (`backend/email_service.py`)
|
|
|
|
Transactional emails are dispatched via `email_service.py` using `smtplib`:
|
|
|
|
| Trigger | Template Function | Email Subject |
|
|
| :--- | :--- | :--- |
|
|
| New user registration | `send_welcome_email(to, name)` | "🎉 Welcome to PragatiVeer — Your JEE/NEET Journey Starts Now!" |
|
|
| Login/verification OTP | `send_otp_email(to, otp, purpose)` | "PragatiVeer: Your Verification OTP" |
|
|
| Password reset | `send_password_reset_email(to, reset_link)` | "PragatiVeer: Reset Your Password" |
|
|
|
|
> **Fallback behavior:** If `SMTP_HOST`, `SMTP_USER`, or `SMTP_PASS` are not set, the service logs the email to console and returns `True` (no-op mode). This prevents boot failures in staging environments.
|
|
|
|
### 6.5 SMS / Phone OTP (Pending)
|
|
|
|
SMS delivery is ready for integration. Variables are defined but commented out in `.env` pending DLT sender ID registration:
|
|
|
|
```
|
|
SMS_PROVIDER=fast2sms
|
|
SMS_API_KEY=your_api_key
|
|
SMS_DLT_SENDER_ID=PVREDU
|
|
SMS_DLT_TEMPLATE_ID=your_template_id
|
|
```
|
|
|
|
Once DLT registration completes, implement `sms_service.py` following the same pattern as `email_service.py`.
|
|
|
|
---
|
|
|
|
*Document last updated: September 2026*
|