Examinations & Results
Last updated August 2, 2026
Classgrid has two exam engines that work together:
- Exam Scheduling System — Supabase-backed exam creation, timetable management, and AI-powered PDF timetable extraction (
exam.routes.js) - Marks & Results System — MongoDB-backed Excel upload, marks entry, grading, ranking, analytics, multi-subject result processing, and report cards (
marks.routes.js)
Part 1: Exam Scheduling (exam.routes.js)
Create an Exam
API: POST /api/exams/
Roles: org_admin
Storage: Supabase exams table
Body:
Fields stored: org_id, exam_name, type, date_from, date_to, exam_fee, fee_enabled, created_by, status (default: upcoming)
List Exams
API: GET /api/exams/
Roles: Any authenticated user
Returns all exams for the organization, ordered by created_at descending.
Get Exam + Timetable
API: GET /api/exams/:id
Roles: Any authenticated user
Returns exam details + all timetable entries from exam_timetable_entries table, ordered by exam_date ascending.
Delete Exam
API: DELETE /api/exams/:id
Roles: org_admin
AI-Powered Timetable Extraction from PDF
API: POST /api/exams/:id/parse-timetable
Roles: org_admin
Upload: PDF file (max 10MB, multer memory storage)
Workflow:
- Extracts raw text from uploaded PDF using
pdf-parse(capped at 8000 characters) - Sends text to Classgrid AI (model:
classgrid-v3) with a structured prompt - AI returns a JSON array of timetable entries with:
subject,exam_date(YYYY-MM-DD),day_of_week,start_time(HH:MM 24h),end_time,room - Entries are validated (must have
subject+exam_date) - Returns parsed entries for admin review before saving
Save Timetable Entries
API: POST /api/exams/:id/timetable
Roles: org_admin
- Deletes existing entries for this exam (full replace)
- Inserts new rows into
exam_timetable_entriestable - Auto-updates the exam's
date_fromanddate_tofrom the entry dates
Edit/Delete Timetable Rows
- Edit:
PUT /api/exams/:id/timetable/:entryId— updatessubject,exam_date,day_of_week,start_time,end_time,room - Delete:
DELETE /api/exams/:id/timetable/:entryId
Exam Fee Management
- Set Fee:
POST /api/exams/:id/fees/set— updatesexam_feeandfee_enabledon the exam - View Fee Status:
GET /api/exams/:id/fees— returns allexam_feesrecords withpaid/unpaidsummary
Part 2: Marks & Results System (marks.routes.js)
Plan Required: PRO plan (enforced via requirePlan("PRO") middleware)
Step 1: Upload Excel File
API: POST /api/marks/upload/:classroomId
Roles: Classroom owner (faculty)
Upload: .xlsx, .xls, or .csv file (max 5MB)
Body (multipart):
file— the Excel filetitle— exam title (required)examType—unit_test|semester|midterm|othertotalMarks— must be a positive numberpassingMarks— optional (default: 0)prnColumn,marksColumn,nameColumn— optional overrides for column detection
Workflow:
- Parses Excel using
parseExcelFile()service - Auto-detects columns via
autoDetectColumns()— looks for headers matching PRN/Roll No patterns and Marks patterns - Matches Excel rows to enrolled students using
mapStudentsToExcel()— cross-references PRN/roll numbers againstClassroomMembershiprecords - Creates an
ExamRecordinprocessingstatus withmappingStats - Returns preview: matched students, unmatched rows, duplicates, and detected column mappings
Step 2: Confirm & Save Marks
API: POST /api/marks/confirm/:examId
Roles: Exam creator (faculty)
Body:
Workflow:
- Creates
StudentMarkdocuments for each matched student with:marksObtained,totalMarks,percentage(calculated)grade— calculated viacalculateGrade()serviceisPassed— true if marks ≥ passingMarks (or percentage ≥ 45% if no passing marks set)
- Assigns ranks via
assignRanks()— sorted by marks obtained descending - Calculates class analytics via
calculateAnalytics():classAverage,highest,lowest,passPercentagegradeDistribution— count per grade
- Updates
ExamRecord.statustoactiveand stores analytics - Sends push notifications to students: "Results for '[title]' are now available (Grade: X)"
View Exams for a Classroom
API: GET /api/marks/classroom/:classroomId
Roles: Classroom teacher or enrolled student
Returns list of exams with title, type, total marks, class average, and highest score.
View All Exams (Teacher/Admin)
API: GET /api/marks/classroom/all
Roles: faculty, org_admin, super_admin
Faculty sees only their exams; admins see all exams for the organization.
Full Exam Detail + All Marks
API: GET /api/marks/exam/:examId
Roles: Exam creator
Returns exam record + all student marks (populated with name, email, PRN), sorted by rank.
Exam Analytics
API: GET /api/marks/exam/:examId/analytics
Roles: Exam creator
Returns classAverage, highest, lowest, passPercentage, gradeDistribution.
Student's Own Marks
API: GET /api/marks/student/me
Roles: Authenticated student
Returns marks grouped by classroom:
Edit Individual Mark (with Audit Trail)
API: PUT /api/marks/exam/:examId/mark/:markId
Roles: Exam creator
- Pushes old state to
mark.history[]array (full audit trail) - Recalculates percentage, grade (using
OrgResultPolicyfrom Supabase), and pass status - Increments
mark.version - Creates a
ResultAuditLogentry:{ action: "mark_overridden", details: "..." } - Recalculates ranks for all students in the exam
- Recalculates class analytics
Delete Exam
API: DELETE /api/marks/exam/:examId
Roles: Exam creator
Deletes all StudentMark documents first (orphan prevention), then deletes the ExamRecord.
Download Excel Template
API: GET /api/marks/download-template
Roles: Any authenticated PRO user
Returns a .xlsx file with sample columns: PRN, Student Name, Marks Obtained.
Result Calculation Policy
Get Policy
API: GET /api/marks/policy
Roles: PRO plan users
Returns the organization's OrgResultPolicy from Supabase with:
calculationMethod—percentage|grade|cgpapassPercentage— default 40gradeRules— array of{ minPct, maxPct, grade, gradePoint }
Save Policy
API: PUT /api/marks/policy
Roles: org_admin, super_admin
Upserts the policy for the organization.
Subject Management
- List subjects:
GET /api/marks/subjects— returns allOrgSubjectdocuments for the org - Create subject:
POST /api/marks/subjects— creates withsubjectName,maxMarks, optionalclassroomId