44 KiB
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.
- For typography, fonts, color tokens, button variants, and light/dark mode styling, see DESIGN_SYSTEM.md.
1. System Architecture & Container Topology
PragatiVeer v2 operates as an 8-container orchestrated cluster via Docker Compose:
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 cookieauth_token=<user_id_or_token>. If absent, redirects to/login(HTTP 307 Temporary Redirect). - Admin Routes (
/admin/:path*): Requires cookieauth_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/jsonContent-Type: application/json
- Request Body Schema:
{ "name": "Aryan Sharma", "email": "aryan@example.com", "password": "Password123!" } - Response Headers:
Content-Type: application/json
- Status Codes & Response Payloads:
200 OK:{ "success": true, "message": "User registered successfully" }400 Bad Request:{ "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/jsonContent-Type: application/json
- Request Body Schema:
{ "email": "demo@pragativeer.com", "password": "Pv9#kL2$mQ8!vX4@" } - Response Headers:
Content-Type: application/json
- Status Codes & Response Payloads:
200 OK (Student):{ "success": true, "role": "user", "token": "b0e17378-864d-439e-8806-708dc48a891b" }200 OK (Admin):{ "success": true, "role": "admin", "token": "admin" }401 Unauthorized:{ "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.9876543210ordemo@pragativeer.com
- Response Headers:
Content-Type: application/json
- Status Codes & Response Payloads:
200 OK:{ "message": "Verification code dispatched successfully", "debug_otp": "123456" }422 Unprocessable Entity: Ifphone_or_emailis 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 emailcode(string, required): 6-digit verification code
- Response Headers:
Content-Type: application/json
- Status Codes & Response Payloads:
200 OK:{ "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:
- Upon successful login (
/login), the browser generates a random UUID:const sessionToken = crypto.randomUUID(). - The browser writes this token to
localStorage.setItem("active_session_token", sessionToken). - The browser makes an immediate
POST /api/users/{user_id}/sessionrequest, storingactive_session_tokenin the database. - On subsequent page loads,
useActiveUsercallsGET /api/users/{user_id}. If the database'sactive_session_tokendoes not match the browser'slocalStoragesession 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/jsonCookie: 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:{ "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: Ifuser_idis 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/jsonContent-Type: application/jsonCookie: auth_token=<user_id>
- Request Path Parameters:
user_id(UUID, required): Student UUID
- Request Body Schema:
{ "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 updatedmodels.Userobject.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/jsonContent-Type: application/jsonCookie: auth_token=<user_id>
- Request Path Parameters:
user_id(UUID, required): Student UUID
- Request Body Schema:
{ "session_token": "4f3b2a1c-9e8d-7c6b-5a4f-3e2d1c0b9a8f" } - Response Headers:
Content-Type: application/json
- Status Codes & Response Payloads:
200 OK: Returnsmodels.Userwith updatedactive_session_token.404 Not Found:{"detail": "User not found"}422 Unprocessable Entity: Invalid UUID or missingsession_token.
POST /api/users/{user_id}/avatar
- Purpose: Multipart form image upload for student avatar. Uploads image to MinIO S3 bucket
avatarsand updatesuser.profile_image_url. - Access: Authenticated User
- Request Headers:
Accept: application/jsonContent-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:{ "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/jsonCookie: 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 ofmodels.Attemptrecords:[ { "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/jsonCookie: auth_token=<user_id>
- Request Query Parameters:
exam_pattern(string, optional):JEE_Main|JEE_Advanced|NEETtype(string, optional):Mock|Weekly|PYQ|DPS. If omitted, automatically excludesDPSto keep Mock Tests separate.
- Response Headers:
Content-Type: application/json
- Status Codes & Response Payloads:
200 OK: Array ofmodels.Testobjects:[ { "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/jsonCookie: 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 singlemodels.Testrecord.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/jsonCookie: 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 ofmodels.Questionentities:[ { "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: Iftest_idis 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/jsonCookie: auth_token=<user_id>
- Request Path Parameters:
question_id(UUID, required)
- Response Headers:
Content-Type: application/json
- Status Codes & Response Payloads:
200 OK: Singlemodels.Questionrecord.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.Mistakewith SuperMemo-2 spaced repetition intervals. - Access: Authenticated User
- Request Headers:
Accept: application/jsonContent-Type: application/jsonCookie: auth_token=<user_id>
- Request Body Schema:
{ "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 gradedmodels.Attemptrecord with total score, accuracy %, and mistake IDs recorded.404 Not Found: Ifuser_idor 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_Coachtier (HTTP 403if Free or Pro) - Request Headers:
Accept: text/event-streamContent-Type: application/jsonCache-Control: no-cacheCookie: auth_token=<user_id>
- Request Body Schema:
{ "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-8Cache-Control: no-cache, no-transformConnection: keep-aliveX-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: Ifuser_idormessageis 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_Coachtier (HTTP 403if Free or Pro) - Request Headers:
Accept: application/jsonCookie: 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:{ "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 onAl_Coachtier.404 Not Found:{"detail": "No study plan generated for today yet."}422 Unprocessable Entity: Ifuser_idquery 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_Coachtier - Request Headers:
Accept: application/jsonCookie: 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:{ "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 toAl_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/jsonCookie: 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 ofmodels.Mistakeitems with associated question context:[ { "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: Ifuser_idparameter 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/jsonContent-Type: application/jsonCookie: auth_token=<user_id>
- Request Body Schema:
{ "mistake_id": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d", "quality": 4 } - Response Headers:
Content-Type: application/json
- Status Codes & Response Payloads:
200 OK:{ "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 (
ProorAl_Coach). - Access: Authenticated User
- Request Headers:
Accept: application/jsonContent-Type: application/jsonCookie: auth_token=<user_id>
- Request Body Schema:
{ "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:{ "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/jsonContent-Type: application/jsonCookie: auth_token=<user_id>
- Request Body Schema:
{ "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:{ "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/jsonContent-Type: application/jsonX-Razorpay-Signature: <hmac_sha256_hex_digest>
- Request Body Schema: Standard Razorpay Webhook Event payload:
{ "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/jsonCookie: auth_token=admin
- Response Headers:
Content-Type: application/json
- Status Codes & Response Payloads:
200 OK:{ "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/jsonContent-Type: application/jsonCookie: auth_token=admin
- Request Body Schema:
{ "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/jsonCookie: auth_token=admin
- Response Headers:
Content-Type: application/json
- Status Codes & Response Payloads:
200 OK: Array of allmodels.Testrecords.
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/jsonContent-Type: multipart/form-data; boundary=----WebKitFormBoundary...Cookie: auth_token=admin
- Request Form Data:
file: PDF binary (application/pdf)exam_pattern:JEE_Main|JEE_Advanced|NEETtitle: Test name string
- Response Headers:
Content-Type: application/json
- Status Codes & Response Payloads:
200 OK:{ "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/jsonContent-Type: application/jsonCookie: auth_token=admin
- Request Body Schema:
{ "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: Createdmodels.Testrecord.
PUT /api/admin/tests/{test_id}/toggle
- Purpose: Toggle test
is_activestatus (publish/unpublish). - Access: Admin
- Request Headers:
Accept: application/jsonCookie: 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/jsonCookie: 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/jsonCookie: auth_token=admin
- Response Headers:
Content-Type: application/json
- Status Codes & Response Payloads:
200 OK: Array ofmodels.Couponrecords.
POST /api/admin/coupons
- Purpose: Create a new promotional discount coupon.
- Access: Admin
- Request Headers:
Accept: application/jsonContent-Type: application/jsonCookie: auth_token=admin
- Request Body Schema:
{ "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 createdmodels.Couponentity.
DELETE /api/admin/coupons/{coupon_id}
- Purpose: Delete promotional coupon.
- Access: Admin
- Request Headers:
Accept: application/jsonCookie: 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/jsonCookie: 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/jsonCookie: 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/jsonContent-Type: application/jsonCookie: auth_token=admin
- Request Path Parameters:
user_id(UUID, required)
- Request Body Schema:
{ "tier": "Al_Coach", "streak_count": 15 } - Response Headers:
Content-Type: application/json
- Status Codes & Response Payloads:
200 OK: Returns modifiedmodels.Userrecord.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/jsonContent-Type: application/json
- Request Body Schema:
{ "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:{ "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 UUIDstudent_phone_or_email(string, required): Student's registered phone or email
- Response Headers:
Content-Type: application/json
- Status Codes & Response Payloads:
200 OK:{ "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:{ "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/jsonCookie: 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:{ "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/jsonContent-Type: application/json
- Request Body Schema:
{ "email": "demo@pragativeer.com" } - Response Headers:
Content-Type: application/json
- Status Codes & Response Payloads:
200 OK:{ "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/ogImageResponse) - 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/pngCache-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 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 | Redis sorted set queries (ZREVRANGE) by exam/state |
| Student Analytics API | GET /api/users/{id}/analytics |
analytics/page.tsx | Weekly score trajectories and topic heatmap accuracies |
| Streak Rewards API | GET /api/streaks/rewards |
streaks/page.tsx | Gamification milestone reward unlocks |
| Syllabus Progress Tracker | GET/PUT /api/syllabus/progress |
progress/page.tsx | Chapter-by-chapter completion % per subject |
| Community Doubts Feed | GET/POST /api/community/doubts |
community/page.tsx | Discussion forum posts, replies, and upvotes |
| Study Materials Library | GET /api/materials |
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 | 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/.envis.gitignore-listed — never commit real secrets. Usebackend/.env.exampleas 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.localis.gitignore-listed. OnlyNEXT_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, orSMTP_PASSare not set, the service logs the email to console and returnsTrue(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