Skip to main content

Grading Module

Location: backend/src/grading/

The grading module manages two core entities:

  1. Assessments - exam or coursework items within a term and subject (e.g., "Mid-term Exam", "Take Home Project")
  2. Grades - individual student scores for each assessment

This module uses Supabase Row-Level Security (RLS) to enforce that teachers can only create/modify assessments and grades for subjects they're assigned to.

Files​

FilePurpose
grading.module.tsModule definition
assessment.controller.tsAssessment API endpoints
assessment.service.tsAssessment business logic
grade.controller.tsGrade API endpoints
grade.service.tsGrade business logic
dto/create-assessment.dto.tsAssessment creation validation
dto/update-assessment.dto.tsAssessment update validation
dto/create-grade.dto.tsSingle grade creation
dto/update-grade.dto.tsGrade update
dto/bulk-grade.dto.tsBulk grade creation/update
dto/exclude.dto.tsGrade/assessment exclusion toggle

Assessment Data Model​

FieldTypeDescription
idUUIDPrimary key
term_idUUIDThe term this assessment belongs to
subject_idUUIDThe subject being assessed
titlestringAssessment name (e.g., "Mid-term Exam")
assessment_typeenumexam or coursework
assessment_datedate?Optional date of the assessment
max_scorenumberMaximum possible score (default: 100)
weightnumber?Weight within its type category
is_excludedbooleanIf true, excluded from calculations
exclusion_reasonstring?Why the assessment was excluded
sort_ordernumber?Display ordering

Grade Data Model​

FieldTypeDescription
idUUIDPrimary key
assessment_idUUIDThe assessment this grade belongs to
student_idUUIDThe student being graded
scorenumberThe student's score
letter_gradestring?Auto-calculated letter grade
remarksstring?Optional teacher remarks
is_excludedbooleanIf true, excluded from calculations
exclusion_reasonstring?Why the grade was excluded
created_byUUIDTeacher who created the grade
updated_byUUIDTeacher who last updated the grade

Row-Level Security (RLS)​

Unlike other modules that use the service role client, the grading module uses createUserClient(token, 'grading') for write operations. This means:

  • Teachers can only create/modify assessments for subjects they're assigned to teach
  • RLS policies on the grading schema enforce this at the database level
  • If a teacher tries to grade a subject they don't teach, a 403 Forbidden error is returned

Read operations that need to join student data use the service role client to bypass RLS.

Exclusion System​

Both assessments and individual grades can be excluded from calculations:

  • Excluded Assessment: The entire assessment is skipped when computing term grades. Useful if an assessment is cancelled.
  • Excluded Grade: An individual student's grade is skipped. Useful if a student was absent or excused.

The ExcludeDto is shared between assessment and grade exclusion.

Assessment Endpoints​

All endpoints require AuthGuard.

GET /api/assessments?termId=<id>&subjectId=<id>​

Returns all assessments for a term and subject, ordered by sort_order.


GET /api/assessments/:id​

Returns a single assessment.


POST /api/assessments​

Creates a new assessment. RLS enforced - only the assigned teacher can create.

Body:

{
"termId": "uuid",
"subjectId": "uuid",
"title": "Mid-term Exam",
"assessmentType": "exam",
"maxScore": 100,
"weight": 1,
"sortOrder": 1
}

PATCH /api/assessments/:id​

Updates an assessment. RLS enforced.


PATCH /api/assessments/:id/exclude​

Toggles the exclusion status of an assessment.

Body:

{
"isExcluded": true,
"exclusionReason": "Assessment cancelled due to weather"
}

DELETE /api/assessments/:id​

Deletes an assessment and all its grades. RLS enforced.

Grade Endpoints​

All endpoints require AuthGuard.

GET /api/grades?assessmentId=<id>​

Returns all grades for an assessment, enriched with student names, sorted by last name.


GET /api/grades/by-term?termId=<id>&subjectId=<id>​

Returns all assessments for a term + subject, with nested grades and student data. This powers the grading sheet view.

Response structure:

[
{
"id": "assessment-uuid",
"title": "Mid-term Exam",
"max_score": 100,
"assessment_type": "exam",
"grades": [
{
"id": "grade-uuid",
"student_id": "uuid",
"score": 85,
"remarks": "Good work",
"is_excluded": false,
"student": {
"id": "uuid",
"first_name": "Jane",
"last_name": "Doe"
}
}
]
}
]

POST /api/grades​

Creates a single grade. RLS enforced.

Body:

{
"assessmentId": "uuid",
"studentId": "uuid",
"score": 85,
"remarks": "Good work"
}

Error: 409 Conflict if a grade already exists for this student + assessment.


POST /api/grades/bulk​

Creates or updates multiple grades at once. Uses upsert on (assessment_id, student_id), so existing grades are updated in place.

Body:

{
"assessmentId": "uuid",
"grades": [
{ "studentId": "uuid1", "score": 85, "remarks": "Good" },
{ "studentId": "uuid2", "score": 72 }
]
}

PATCH /api/grades/:id​

Updates a grade's score or remarks. RLS enforced.


PATCH /api/grades/:id/exclude​

Toggles the exclusion status of a grade.

Body:

{
"isExcluded": true,
"exclusionReason": "Student was absent"
}