Reference

API Reference

All business logic in AEGIS is implemented as Next.js Server Actions inside src/lib/actions.ts. These functions execute exclusively on the server, keeping all MongoDB logic and credentials out of the client bundle. Parameters are validated with Zod schemas before any database operation.

Why Server Actions? In a proctoring environment, exposing API route structures to the client would allow a tech-savvy student to reconstruct requests to bypass validation. Server Actions compile to opaque POST endpoints, making the interface impossible to reverse-engineer from the browser.

Authentication

AUTH authenticate(prevState, formData)

Validates admin credentials against the admins collection. On success, sets two HttpOnly cookies: auth=true and admin_user (containing username and role as JSON). Also writes an Admin Logged In audit log entry. Redirects to /dashboard on success.

ParameterTypeDescription
prevStateanyPrevious form state (Next.js useFormState pattern)
formDataFormDataMust contain username and password fields

Returns: {"{"}message: string{"}"} on failure | Redirects on success

AUTH logout()

Reads the current admin_user cookie, writes an Admin Logged Out audit log entry, then deletes both auth and admin_user cookies. Redirects to /login.

Workstation (PC) Management

PC registerPc(prevState, formData)

Creates a PC registration request. Validates that pcName is at least 3 characters. Generates a unique 12-character random identifier (pc-id-xxxxxxxxxxxx) using a custom alphanumeric RNG and inserts a pending document into the pc_requests collection.

Design Note: This action does NOT require authentication. It is intentionally exposed to allow any machine on the network to self-register. An Admin must then manually approve/reject the request from the dashboard.

Returns: {"{"}message: string, status: 'success'|'error', identifier?: string{"}"}

PC getPcStatus(identifier: string)

The heartbeat check for client PCs. Performs a MongoDB aggregation pipeline with two $lookup stages: first joining the assigned student, then joining the student's assigned exam. Updates lastSeen timestamp on every call. Returns the full nested PC context (PC → Student → Exam) for client-side routing decisions.

Returns: {"{"}status: string | null, pcDetails: PC & {"{"}student: Student, exam: Exam{"}"} | null{"}"}

PC updatePcLiveStatus(identifier, status)

Atomically updates a PC's liveStatus field. Called by the exam page's heartbeat interval every 15 seconds and on lifecycle events (exam start, exam submit). Status values: 'Online' | 'Ready' | 'Waiting' | 'Attempting' | 'Finished'.

Student Management

STUDENT bulkUploadStudents(csvData: string)

Processes a raw CSV string with a custom state-machine parser that handles RFC 4180 quoted fields containing commas. Expected columns: Name, Roll Number, Class/Batch, [Exam ID or Title].

Performs multi-layer validation: (1) field presence check, (2) in-memory duplicate roll number scan within the upload batch, (3) DB lookup for pre-existing roll numbers, (4) exam ID/title resolution with case-insensitive matching. Only inserts if all rows pass.

Returns: {"{"}success: boolean, successCount: number, errorCount: number, results: RowResult[]{"}"}

STUDENT deleteStudent(studentId: string)

Performs a cascading delete. Before removing the student document, it calls pcsCollection.updateMany to null out assignedStudentId, assignedStudentName, and assignedStudentRollNumber on all PCs that referenced this student. This prevents dangling references that would break the admin dashboard's aggregation queries.

Question Bank

AI/QUESTION bulkUploadQuestions(csvData: string)

Accepts a 10-column CSV. Parses and validates each row independently, collecting results without failing the entire batch on a single error. Expected schema:

Question Text | Option 1 | Option 2 | Option 3 | Option 4 | Correct Options | Category | Tags | Weight | Negative Marking
  • Correct Options: 0-based comma-separated indices (e.g., 0,2 for multi-correct)
  • Category: Case-sensitive — must be exactly Easy, Medium, or Hard
  • Tags: Semicolon-delimited (e.g., Math;Algebra)
  • Negative Marking: true/false or 1/0

Examination Engine

EXAM · CRITICAL getExamDetails(examId, studentId, pcIdentifier?)

The primary security gate. Executes the following validation chain in order — any failure returns an error without revealing why:

  1. Verify pcIdentifier exists in the pcs collection and status === 'Approved'
  2. Verify the PC's assignedStudentId matches the provided studentId
  3. Verify the student's assignedExamId matches the provided examId
  4. Verify the exam's status === 'In Progress'
  5. Check the exam_results collection — if a result exists for this student+exam, return alreadyTaken: true

Returns: {"{"}exam: Exam, questions: Question[], alreadyTaken: boolean, error?: string{"}"}

EXAM · CRITICAL submitExam(examId, studentId, answers, pcIdentifier?)

Re-validates the full security chain from getExamDetails. Then applies answer sanitization: filters the submitted answers array to include only entries whose questionId belongs to the exam's own questionIds list. This neutralizes injection attacks where a student submits answers for questions outside their exam.

Calculates the score by iterating validated answers against the question's correctOptions and weight fields. Inserts the result into exam_results, then sets only the submitting PC's liveStatus to Finished to prevent side-effects on other machines sharing the exam.

Returns: {"{"}success: boolean, error?: string{"}"}

Audit & Results

getAdminLogs()

Returns all entries from admin_logs sorted by timestamp descending. Every admin action (login, CRUD operations, exam control) writes to this collection via the internal logAdminAction(action, details) helper, which reads the admin_user cookie to attribute the identity.