eduverse-backend / Documentation /COURSES_ASSIGNMENTS_LABS_API_DOCS.md
Marwan Hassan Sobhy
feat(labs): add instructor labs CRUD, grading, and attendance improvements for Flutter Phase 7
fbaa73d
|
Raw
History Blame Contribute Delete
64.4 kB

πŸ“– EduVerse API Documentation β€” Courses / Assignments / Labs

Purpose: Complete Flutter frontend integration guide. Base URL: http://<host>:3001 (default port 3001) Auth: Most endpoints require Authorization: Bearer <JWT> header. Content-Type: application/json unless otherwise noted (file uploads use multipart/form-data).


Table of Contents

  1. Global Information
  2. Enums Reference
  3. Courses Module
  4. Course Sections Module
  5. Course Schedules Module
  6. Assignments Module
  7. Labs Module
  8. Role-Based Access Matrix
  9. Error Handling
  10. Flutter Integration Tips

1. Global Information

1.1 Authentication

All authenticated endpoints require the header:

Authorization: Bearer <access_token>

The token is obtained from POST /api/auth/login.

1.2 Roles

Role Enum Value Display Name Description
student Student Regular student users
instructor Instructor Faculty members
teaching_assistant TA Teaching assistants
admin Admin Administrative staff
it_admin IT Admin Full system access
department_head Department Head Department leadership

1.3 Pagination Response Shape

All paginated endpoints return:

{
  "data": [ /* array of items */ ],
  "meta": {
    "total": 150,       // integer β€” total matching records
    "page": 1,          // integer β€” current page number
    "limit": 20,        // integer β€” items per page
    "totalPages": 8     // integer β€” total number of pages
  }
}

1.4 Validation Rules

The API uses class-validator with:

  • whitelist: true β€” unknown properties are stripped
  • forbidNonWhitelisted: true β€” unknown properties cause 400 error
  • transform: true β€” query strings auto-converted to proper types

2. Enums Reference

2.1 Course Enums

CourseLevel

Value Description
FRESHMAN Freshman-level course
SOPHOMORE Sophomore-level course
JUNIOR Junior-level course
SENIOR Senior-level course
GRADUATE Graduate-level course

CourseStatus

Value Description
ACTIVE Course is currently active
INACTIVE Course is inactive
ARCHIVED Course is archived

SectionStatus

Value Description
OPEN Section accepting enrollments
CLOSED Section manually closed
FULL Section at max capacity
CANCELLED Section cancelled

ScheduleType

Value Description
LECTURE Lecture session
LAB Laboratory session
TUTORIAL Tutorial/recitation session
EXAM Examination session

DayOfWeek

Value
MONDAY
TUESDAY
WEDNESDAY
THURSDAY
FRIDAY
SATURDAY
SUNDAY

2.2 Assignment Enums

SubmissionType

Value Description
file File-based submission
text Text-based submission
link Link/URL submission
multiple Combination of types

AssignmentStatus

Value Description
draft Not visible to students
published Visible and accepting submissions
closed No longer accepting submissions
archived Hidden from all views

Status Transitions: draft β†’ published β†’ closed β†’ archived (one-way only)

SubmissionStatus

Value Description
submitted Student has submitted
graded Submission has been graded
returned Returned to student for review
resubmit Student must resubmit

2.3 Lab Enums

LabStatus

Value Description
draft Not visible to students
published Visible and accepting submissions
closed No longer accepting submissions
archived Hidden from all views

LabSubmissionStatus

Value Description
submitted Student has submitted
graded Submission has been graded
returned Returned to student
resubmit Student must resubmit

LabAttendanceStatus

Value Description
present Student was present
absent Student was absent
excused Excused absence
late Student arrived late

3. Courses Module

Base Path: /api/courses

Authentication: Courses listing/viewing endpoints are public (no auth required). Course creation/update/delete endpoints need authentication and specific roles.


3.1 List All Courses

GET /api/courses

Auth Required: ❌ No (Public) Roles: All (public endpoint)

Query Parameters

Parameter Type Required Default Description
departmentId integer ❌ β€” Filter by department ID
level string ❌ β€” Filter by course level enum (e.g. FRESHMAN, GRADUATE)
status string ❌ β€” Filter by CourseStatus enum (ACTIVE, INACTIVE, ARCHIVED)
search string ❌ β€” Search in course name or code (partial match)
page integer ❌ 1 Page number (1-indexed)
limit integer ❌ 20 Items per page (max 100)

Response 200 OK

{
  "data": [
    {
      "id": 1,                              // number β€” Course ID (bigint)
      "departmentId": 3,                    // number β€” FK to departments
      "name": "Introduction to CS",         // string β€” Course name
      "code": "CS101",                      // string β€” Unique course code
      "description": "Fundamentals of...",  // string | null β€” Description
      "credits": 3,                         // number β€” Credit hours (1-6)
      "level": "FRESHMAN",                  // string β€” CourseLevel enum
      "syllabusUrl": "https://...",         // string | null β€” Syllabus URL
      "instructorId": 5,                    // number | null β€” Assigned instructor
      "taIds": [1, 2],                      // number[] | null β€” Assigned TA IDs
      "status": "ACTIVE",                   // string β€” CourseStatus enum
      "createdAt": "2025-01-15T10:00:00Z",  // string (ISO 8601) β€” Creation timestamp
      "updatedAt": "2025-01-15T10:00:00Z",  // string (ISO 8601) β€” Last update
      "department": {                        // object β€” Joined department info
        "id": 3,
        "name": "Computer Science",
        "code": "CS"
      }
    }
  ],
  "meta": {
    "total": 42,
    "page": 1,
    "limit": 20,
    "totalPages": 3
  }
}

3.2 Get Courses by Department

GET /api/courses/department/:deptId

Auth Required: ❌ No (Public) Roles: All

Path Parameters

Parameter Type Required Description
deptId integer βœ… Department ID

Response 200 OK

Returns an array of course objects (same shape as items in data array above, including department relation).

Error Responses

Status Description
404 Department not found

3.3 Get Course by ID

GET /api/courses/:id

Auth Required: ❌ No (Public) Roles: All

Path Parameters

Parameter Type Required Description
id integer βœ… Course ID

Response 200 OK

{
  "id": 1,
  "departmentId": 3,
  "name": "Introduction to CS",
  "code": "CS101",
  "description": "Fundamentals of programming...",
  "credits": 3,
  "level": "FRESHMAN",
  "syllabusUrl": "https://example.com/syllabus.pdf",
  "instructorId": 5,
  "taIds": [1, 2],
  "status": "ACTIVE",
  "createdAt": "2025-01-15T10:00:00Z",
  "updatedAt": "2025-01-15T10:00:00Z",
  "department": {
    "id": 3,
    "name": "Computer Science",
    "code": "CS"
  },
  "prerequisites": [],         // CoursePrerequisite[] β€” loaded relation
  "sections": [],              // CourseSection[] β€” loaded relation
  "prerequisitesCount": 0,     // number β€” count of prerequisites
  "sectionsCount": 2           // number β€” count of active sections
}

Error Responses

Status Description
404 Course not found

3.4 Create Course

POST /api/courses

Auth Required: βœ… Yes Roles: admin, it_admin, instructor

Request Body (application/json)

Field Type Required Constraints Description
departmentId number βœ… Must exist Department to assign course to
name string βœ… β€” Course name
code string βœ… 2-10 uppercase alphanumeric (/^[A-Z0-9]{2,10}$/) Unique course code
description string βœ… β€” Course description
credits integer βœ… 1–6 Credit hours
level string βœ… CourseLevel enum Course level
syllabusUrl string ❌ Valid URL Syllabus URL
instructorId number ❌ Must reference valid user Instructor user ID
taIds number[] ❌ Array of valid user IDs TA user IDs

Example Request

{
  "departmentId": 1,
  "name": "Introduction to Computer Science",
  "code": "CS101",
  "description": "Fundamentals of programming and computational thinking.",
  "credits": 3,
  "level": "FRESHMAN",
  "syllabusUrl": "https://example.com/syllabus/cs101.pdf",
  "instructorId": 5,
  "taIds": [10, 11]
}

Response 201 Created

Returns the created course object (same shape as Get Course by ID, without prerequisitesCount/sectionsCount).

Error Responses

Status Description
400 Invalid input data / validation failure
404 Department not found
409 Course code already exists in department

3.5 Update Course

PATCH /api/courses/:id

Auth Required: βœ… Yes Roles: admin, it_admin, instructor

Path Parameters

Parameter Type Required Description
id integer βœ… Course ID

Request Body (application/json) β€” All fields optional

Field Type Required Constraints Description
name string ❌ β€” Updated course name
description string ❌ β€” Updated description
credits integer ❌ 1–6 Updated credit hours
level string ❌ CourseLevel enum Updated course level
syllabusUrl string ❌ β€” Updated syllabus URL
status string ❌ CourseStatus enum Change course status
instructorId number ❌ β€” Change instructor
taIds number[] ❌ β€” Change TAs

Response 200 OK

Returns the updated course object.

Error Responses

Status Description
400 Invalid input data
404 Course not found

3.6 Delete Course (Soft Delete)

DELETE /api/courses/:id

Auth Required: βœ… Yes Roles: admin, it_admin

Path Parameters

Parameter Type Required Description
id integer βœ… Course ID

Response 204 No Content

Empty body.

Error Responses

Status Description
400 Cannot delete course with active enrollments
404 Course not found

3.7 Get Course Prerequisites

GET /api/courses/:id/prerequisites

Auth Required: ❌ No (Public) Roles: All

Path Parameters

Parameter Type Required Description
id integer βœ… Course ID

Response 200 OK

[
  {
    "id": 1,                          // number β€” Prerequisite record ID
    "courseId": 5,                     // number β€” The course that has this prerequisite
    "prerequisiteCourseId": 2,         // number β€” The required prereq course ID
    "isMandatory": true,               // boolean β€” Whether this prereq is mandatory
    "prerequisiteCourse": {            // object β€” Joined prerequisite course info
      "id": 2,
      "name": "Programming Basics",
      "code": "CS100",
      "level": "FRESHMAN"
    },
    "createdAt": "2025-01-10T08:00:00Z"   // string (ISO 8601)
  }
]

3.8 Add Prerequisite

POST /api/courses/:id/prerequisites

Auth Required: βœ… Yes Roles: admin, it_admin

Path Parameters

Parameter Type Required Description
id integer βœ… Course ID to add prerequisite to

Request Body

Field Type Required Description
prerequisiteCourseId number βœ… ID of the prerequisite course
isMandatory boolean βœ… Whether this prerequisite is mandatory

Example Request

{
  "prerequisiteCourseId": 2,
  "isMandatory": true
}

Response 201 Created

Returns the created prerequisite record.

Error Responses

Status Description
400 Circular dependency detected / Self-prerequisite
404 Course or prerequisite course not found
409 Prerequisite already exists

3.9 Remove Prerequisite

DELETE /api/courses/:id/prerequisites/:prereqId

Auth Required: βœ… Yes Roles: admin, it_admin

Path Parameters

Parameter Type Required Description
id integer βœ… Course ID
prereqId integer βœ… Prerequisite record ID

Response 204 No Content

Empty body.


4. Course Sections Module

Base Path: /api/sections


4.1 Get Sections by Course

GET /api/sections/course/:courseId

Auth Required: ❌ No (Public) Roles: All

Path Parameters

Parameter Type Required Description
courseId integer βœ… Course ID

Query Parameters

Parameter Type Required Default Description
semesterId integer ❌ β€” Filter by semester

Response 200 OK

[
  {
    "id": 11,                              // number β€” Section ID (bigint)
    "courseId": 1,                          // number β€” FK to courses
    "semesterId": 1,                       // number β€” FK to semesters
    "sectionNumber": "1",                  // string β€” Section number
    "maxCapacity": 30,                     // number β€” Maximum students
    "currentEnrollment": 25,               // number β€” Currently enrolled
    "location": "Room A101",               // string | null β€” Room/location
    "status": "OPEN",                      // string β€” SectionStatus enum
    "createdAt": "2025-01-15T10:00:00Z",
    "updatedAt": "2025-01-15T10:00:00Z",
    "course": {
      "id": 1,
      "name": "Introduction to CS",
      "code": "CS101"
    },
    "semester": {
      "id": 1,
      "name": "Fall 2025",
      "startDate": "2025-09-01",
      "endDate": "2025-12-15"
    },
    "schedules": [
      {
        "id": 1,
        "dayOfWeek": "MONDAY",            // DayOfWeek enum
        "startTime": "09:00",             // string (HH:mm)
        "endTime": "10:30",               // string (HH:mm)
        "room": "A101",                   // string | null
        "building": "Main Building",      // string | null
        "scheduleType": "LECTURE"          // ScheduleType enum
      }
    ]
  }
]

4.2 Get Section by ID

GET /api/sections/:id

Auth Required: ❌ No (Public) Roles: All

Path Parameters

Parameter Type Required Description
id integer βœ… Section ID

Response 200 OK

Same shape as a single item from the array above (includes course, semester, schedules relations).


4.3 Create Section

POST /api/sections

Auth Required: βœ… Yes Roles: admin, it_admin, instructor

Request Body

Field Type Required Default Constraints Description
courseId number βœ… β€” Must exist Course to create section for
semesterId number βœ… β€” Must exist Semester ID
sectionNumber integer ❌ Auto-generated >= 1 Section number
maxCapacity integer βœ… β€” >= 1 Maximum student capacity
currentEnrollment integer ❌ 0 >= 0 Current enrollment count
location string ❌ null β€” Room/location

Example Request

{
  "courseId": 1,
  "semesterId": 1,
  "maxCapacity": 30,
  "location": "Room A101"
}

Response 201 Created

Returns the created section object.

Error Responses

Status Description
400 Invalid input data
404 Course or semester not found
409 Section number already exists for this course/semester combo

4.4 Update Section

PATCH /api/sections/:id

Auth Required: βœ… Yes Roles: admin, it_admin, instructor (section owner)

Path Parameters

Parameter Type Required Description
id integer βœ… Section ID

Request Body β€” All fields optional

Field Type Required Constraints Description
maxCapacity integer ❌ >= 1, cannot be less than current enrollment Updated max capacity
currentEnrollment integer ❌ >= 0 Updated enrollment count
location string ❌ β€” Updated location
status string ❌ SectionStatus enum Change section status

Response 200 OK

Returns the updated section object.


4.5 Update Section Enrollment Count

PATCH /api/sections/:id/enrollment

Auth Required: βœ… Yes Roles: admin, it_admin, instructor

Typically called automatically by the enrollment system.

Path Parameters

Parameter Type Required Description
id integer βœ… Section ID

Request Body

Field Type Required Description
currentEnrollment number βœ… New enrollment count

Response 200 OK

Returns the updated section object with recalculated status.


5. Course Schedules Module

Base Path: /api/schedules


5.1 Get Schedules by Section

GET /api/schedules/section/:sectionId

Auth Required: ❌ No (Public) Roles: All

Path Parameters

Parameter Type Required Description
sectionId integer βœ… Section ID

Response 200 OK

[
  {
    "id": 1,                        // number β€” Schedule ID
    "sectionId": 11,                // number β€” FK to sections
    "dayOfWeek": "MONDAY",          // string β€” DayOfWeek enum
    "startTime": "09:00",           // string β€” HH:mm format (24-hour)
    "endTime": "10:30",             // string β€” HH:mm format (24-hour)
    "room": "A101",                 // string | null
    "building": "Main Building",    // string | null
    "scheduleType": "LECTURE",      // string β€” ScheduleType enum
    "createdAt": "2025-01-15T10:00:00Z"
  }
]

5.2 Get Schedule by ID

GET /api/schedules/:id

Auth Required: ❌ No (Public) Roles: All

Path Parameters

Parameter Type Required Description
id integer βœ… Schedule ID

Response 200 OK

Returns single schedule object with section relation included.


5.3 Create Schedule

POST /api/schedules/section/:sectionId

Auth Required: βœ… Yes Roles: admin, it_admin, instructor

Path Parameters

Parameter Type Required Description
sectionId integer βœ… Section to add schedule to

Request Body

Field Type Required Constraints Description
dayOfWeek string βœ… DayOfWeek enum Day of week
startTime string βœ… HH:mm format 24-hour (/^([0-1][0-9]|2[0-3]):[0-5][0-9]$/) Start time
endTime string βœ… HH:mm format (same regex, must be after startTime) End time
room string ❌ β€” Room number/name
building string ❌ β€” Building name
scheduleType string βœ… ScheduleType enum Type of session

Example Request

{
  "dayOfWeek": "MONDAY",
  "startTime": "09:00",
  "endTime": "10:30",
  "room": "A101",
  "building": "Main Building",
  "scheduleType": "LECTURE"
}

Response 201 Created

Returns the created schedule object.

Error Responses

Status Description
400 Invalid time range (end <= start) or schedule conflict detected
404 Section not found

5.4 Delete Schedule

DELETE /api/schedules/:id

Auth Required: βœ… Yes Roles: admin, it_admin, instructor

Response 204 No Content

Empty body.


6. Assignments Module

Base Path: /api/assignments

All endpoints require JWT authentication (@UseGuards(JwtAuthGuard, RolesGuard)).


6.1 List Assignments

GET /api/assignments

Auth Required: βœ… Yes Roles: All authenticated users

Query Parameters

Parameter Type Required Default Description
courseId integer ❌ β€” Filter by course ID
sectionId integer ❌ β€” Filter by section ID
status string ❌ β€” Filter by AssignmentStatus enum (draft, published, closed, archived)
dueBefore string ❌ β€” Filter assignments due before this date (ISO 8601)
dueAfter string ❌ β€” Filter assignments due after this date (ISO 8601)
search string ❌ β€” Search in assignment title (partial match)
page integer ❌ 1 Page number
limit integer ❌ 10 Items per page
sortBy string ❌ createdAt Sort field: dueDate, createdAt, title
sortOrder string ❌ DESC Sort order: ASC or DESC

Response 200 OK

{
  "data": [
    {
      "id": 3,                                    // number β€” Assignment ID (bigint)
      "courseId": 1,                               // number β€” FK to courses
      "title": "Homework 1 - Binary Search",       // string β€” Assignment title
      "description": "Implement binary search...",  // string | null
      "instructions": "Submit as .zip file...",     // string | null
      "maxScore": 100.00,                           // number (decimal) β€” Maximum possible score
      "weight": 15.00,                              // number (decimal) β€” Weight % in final grade
      "dueDate": "2025-06-15T23:59:59Z",           // string | null β€” Due date (ISO 8601)
      "availableFrom": "2025-06-01T00:00:00Z",     // string | null β€” Available from date
      "lateSubmissionAllowed": 0,                   // number (0 or 1) β€” 0=false, 1=true
      "latePenaltyPercent": 10.00,                  // number (decimal) β€” Late penalty %
      "submissionType": "file",                     // string β€” SubmissionType enum
      "maxFileSizeMb": 10,                          // number β€” Max file size in MB
      "allowedFileTypes": "[\"pdf\",\"zip\"]",      // string | null β€” JSON string of allowed types
      "status": "published",                        // string β€” AssignmentStatus enum
      "createdBy": 5,                               // number β€” Creator user ID
      "createdAt": "2025-06-01T08:00:00Z",          // string (ISO 8601)
      "updatedAt": "2025-06-01T08:00:00Z",          // string (ISO 8601)
      "course": {                                    // object β€” Joined course info
        "id": 1,
        "departmentId": 3,
        "name": "Introduction to CS",
        "code": "CS101",
        "description": "...",
        "credits": 3,
        "level": "FRESHMAN",
        "status": "ACTIVE"
      }
    }
  ],
  "meta": {
    "total": 12,
    "page": 1,
    "limit": 10,
    "totalPages": 2
  }
}

6.2 Get Assignment Details

GET /api/assignments/:id

Auth Required: βœ… Yes Roles: All authenticated users

Path Parameters

Parameter Type Required Description
id integer βœ… Assignment ID

Response 200 OK

{
  "id": 3,
  "courseId": 1,
  "title": "Homework 1 - Binary Search",
  "description": "Implement binary search...",
  "instructions": "Submit as .zip file...",
  "maxScore": 100.00,
  "weight": 15.00,
  "dueDate": "2025-06-15T23:59:59Z",
  "availableFrom": "2025-06-01T00:00:00Z",
  "lateSubmissionAllowed": 0,
  "latePenaltyPercent": 10.00,
  "submissionType": "file",
  "maxFileSizeMb": 10,
  "allowedFileTypes": "[\"pdf\",\"zip\"]",
  "status": "published",
  "createdBy": 5,
  "createdAt": "2025-06-01T08:00:00Z",
  "updatedAt": "2025-06-01T08:00:00Z",
  "course": { /* full course object */ },
  "submissions": [
    {
      "id": 1,                             // number β€” Submission ID
      "assignmentId": 3,                   // number
      "userId": 57,                        // number β€” Student user ID
      "submissionText": "My essay...",     // string | null
      "submissionLink": "https://...",     // string | null
      "fileId": 12,                        // number | null β€” FK to files
      "submissionStatus": "submitted",     // string β€” SubmissionStatus enum
      "isLate": 0,                         // number (0 or 1)
      "attemptNumber": 1,                  // number β€” Attempt count
      "submittedAt": "2025-06-10T14:30:00Z",
      "score": null,                       // number | null β€” Graded score
      "feedback": null,                    // string | null β€” Grader feedback
      "gradedBy": null,                    // number | null β€” Grader user ID
      "gradedAt": null,                    // string | null β€” Grading timestamp
      "user": {
        "user_id": 57,
        "first_name": "John",
        "last_name": "Doe",
        "email": "john@example.com"
      }
    }
  ]
}

Error Responses

Status Description
404 Assignment not found

6.3 Create Assignment

POST /api/assignments

Auth Required: βœ… Yes Roles: instructor, admin

Request Body

Field Type Required Default Constraints Description
courseId number βœ… β€” Must exist Course ID
title string βœ… β€” 3-200 chars Assignment title
description string ❌ null β€” Description
instructions string ❌ null β€” Detailed instructions
submissionType string ❌ file SubmissionType enum How students submit
maxScore number ❌ 100 0-1000 Maximum score
weight number ❌ 0 0-100 Weight percentage in final grade
dueDate string ❌ null ISO 8601 datetime Due date
availableFrom string ❌ null ISO 8601 datetime Available from date
lateSubmissionAllowed boolean ❌ false β€” Allow late submissions
latePenaltyPercent number ❌ 0 0-100 Late penalty %
maxFileSizeMb number ❌ 10 β€” Max file size in MB
allowedFileTypes string ❌ null JSON string array Allowed file extensions
status string ❌ draft AssignmentStatus enum Initial status

Example Request

{
  "courseId": 1,
  "title": "Homework 1 - Binary Search",
  "description": "Implement a binary search tree with insert, delete, and search operations.",
  "instructions": "Submit your code as a single .zip file. Include a README with compilation instructions.",
  "submissionType": "file",
  "maxScore": 100,
  "weight": 15,
  "dueDate": "2025-06-15T23:59:59Z",
  "availableFrom": "2025-06-01T00:00:00Z",
  "lateSubmissionAllowed": true,
  "latePenaltyPercent": 10,
  "maxFileSizeMb": 10,
  "allowedFileTypes": "[\"pdf\",\"docx\",\"zip\"]",
  "status": "draft"
}

Response 201 Created

Returns the created assignment with joined course relation.


6.4 Update Assignment

PATCH /api/assignments/:id

Auth Required: βœ… Yes Roles: instructor, admin

Path Parameters

Parameter Type Required Description
id integer βœ… Assignment ID

Request Body

All fields from CreateAssignmentDto are optional (uses PartialType).

Response 200 OK

Returns the updated assignment object.


6.5 Delete Assignment (Soft Delete)

DELETE /api/assignments/:id

Auth Required: βœ… Yes Roles: instructor, admin

Path Parameters

Parameter Type Required Description
id integer βœ… Assignment ID

Response 200 OK

Empty body (assignment removed).


6.6 Change Assignment Status

PATCH /api/assignments/:id/status

Auth Required: βœ… Yes Roles: instructor, admin

Path Parameters

Parameter Type Required Description
id integer βœ… Assignment ID

Request Body

Field Type Required Constraints Description
status string βœ… Must follow: draft -> published -> closed -> archived New status

WARNING β€” Transition rules: Only the next status in the chain is allowed. You cannot skip statuses. E.g., you cannot go from draft directly to closed.

Example Request

{
  "status": "published"
}

Response 200 OK

Returns the updated assignment object.

Error Responses

Status Description
400 Invalid status transition
404 Assignment not found

6.7 Submit Assignment (Student)

POST /api/assignments/:id/submit

Auth Required: βœ… Yes Roles: student only

Path Parameters

Parameter Type Required Description
id integer βœ… Assignment ID

Request Body

Field Type Required Description
submissionText string ❌ Text content for text submissions
fileId number ❌ File ID from the files module (for file submissions)
submissionLink string ❌ External URL (e.g., GitHub repo link)

At least one of submissionText, fileId, or submissionLink should be provided.

Example Request

{
  "submissionText": "This is my essay submission about data structures...",
  "submissionLink": "https://github.com/student/project"
}

Response 201 Created (via POST)

{
  "id": 15,                               // number β€” Submission ID
  "assignmentId": 3,                      // number
  "userId": 57,                           // number β€” From JWT
  "submissionText": "This is my essay...",
  "submissionLink": "https://github.com/student/project",
  "fileId": null,
  "submissionStatus": "submitted",
  "isLate": 0,                            // number β€” 0=on-time, 1=late
  "attemptNumber": 1,                     // number β€” Auto-incremented
  "submittedAt": "2025-06-10T14:30:00Z",
  "score": null,
  "feedback": null,
  "gradedBy": null,
  "gradedAt": null
}

Error Responses

Status Description
400 Student not enrolled in course / Late submission not allowed / Assignment not available yet
404 Assignment not found

Business Rules

  • Assignment must be in published status
  • If availableFrom is set, current time must be after it
  • If dueDate is set and past, lateSubmissionAllowed must be true (otherwise 400)
  • Auto-marks isLate = 1 if submitted after dueDate
  • Auto-increments attemptNumber
  • Student must be enrolled in the assignment's course

6.8 Get My Submission (Student)

GET /api/assignments/:id/submissions/my

Auth Required: βœ… Yes Roles: student only

Path Parameters

Parameter Type Required Description
id integer βœ… Assignment ID

Response 200 OK

Returns the student's latest submission (highest attemptNumber):

{
  "id": 15,
  "assignmentId": 3,
  "userId": 57,
  "submissionText": "My submission...",
  "submissionLink": null,
  "fileId": 12,
  "submissionStatus": "graded",
  "isLate": 0,
  "attemptNumber": 2,
  "submittedAt": "2025-06-10T14:30:00Z",
  "score": 85.00,
  "feedback": "Well done! Consider improving error handling.",
  "gradedBy": 5,
  "gradedAt": "2025-06-12T10:00:00Z"
}

Error Responses

Status Description
404 No submission found for this student/assignment

6.9 List All Submissions (Instructor/TA/Admin)

GET /api/assignments/:id/submissions

Auth Required: βœ… Yes Roles: instructor, teaching_assistant, admin

Path Parameters

Parameter Type Required Description
id integer βœ… Assignment ID

Response 200 OK

[
  {
    "id": 15,
    "assignmentId": 3,
    "userId": 57,
    "submissionText": "My submission...",
    "submissionLink": null,
    "fileId": 12,
    "submissionStatus": "submitted",
    "isLate": 0,
    "attemptNumber": 1,
    "submittedAt": "2025-06-10T14:30:00Z",
    "score": null,
    "feedback": null,
    "gradedBy": null,
    "gradedAt": null,
    "user": {
      "user_id": 57,
      "first_name": "John",
      "last_name": "Doe",
      "email": "john@example.com"
    }
  }
]

Returns submissions sorted by submittedAt DESC.


6.10 Grade a Submission

PATCH /api/assignments/:id/submissions/:subId/grade

Auth Required: βœ… Yes Roles: instructor, teaching_assistant

Path Parameters

Parameter Type Required Description
id integer βœ… Assignment ID
subId integer βœ… Submission ID

Request Body

Field Type Required Constraints Description
score number βœ… >= 0 Numeric score
feedback string ❌ β€” Feedback comments

Example Request

{
  "score": 85,
  "feedback": "Well done! Consider improving the conclusion."
}

Response 200 OK

{
  "submissionId": 15,        // number β€” Graded submission ID
  "score": 85,               // number β€” Score assigned
  "maxScore": 100,           // number β€” Assignment max score
  "feedback": "Well done!",  // string | undefined
  "gradeId": 42              // number β€” Created grade record ID in central gradebook
}

Side effect: Also creates a grade record in the central grades table with gradeType = 'assignment', isPublished = true.


6.11 Upload Assignment Instruction (Google Drive)

POST /api/assignments/:id/instructions/upload

Auth Required: βœ… Yes Roles: instructor, teaching_assistant, admin Content-Type: multipart/form-data

Path Parameters

Parameter Type Required Description
id integer βœ… Assignment ID

Form Data Fields

Field Type Required Constraints Description
file binary βœ… PDF, DOCX, etc. The instruction file
title string ❌ Max 255 chars Instruction title
orderIndex integer ❌ >= 0, default 0 Sort order

Response 201 Created

{
  "assignmentId": 3,
  "driveFile": {
    "driveFileId": 123,           // number β€” Internal drive file record ID
    "driveId": "1abc...",          // string β€” Google Drive file ID
    "fileName": "HW1_Instructions_v1.pdf",
    "webViewLink": "https://drive.google.com/file/d/1abc.../view",
    "webContentLink": "https://drive.google.com/uc?id=1abc..."
  }
}

6.12 Upload Assignment Submission (Google Drive β€” Student)

POST /api/assignments/:id/submissions/upload

Auth Required: βœ… Yes Roles: student only Content-Type: multipart/form-data

Path Parameters

Parameter Type Required Description
id integer βœ… Assignment ID

Form Data Fields

Field Type Required Description
file binary βœ… Submission file
submissionText string ❌ Notes/comments
submissionLink string ❌ External link (e.g., GitHub)

Response 201 Created

{
  "submission": {
    "id": 16,
    "assignmentId": 3,
    "userId": 57,
    "submissionText": "Completed all tasks.",
    "submissionLink": "https://github.com/student/project",
    "fileId": null,
    "submissionStatus": "submitted",
    "isLate": 0,
    "attemptNumber": 1,
    "submittedAt": "2025-06-10T14:30:00Z",
    "score": null,
    "feedback": null,
    "gradedBy": null,
    "gradedAt": null
  },
  "driveFile": {
    "driveFileId": 124,
    "driveId": "1def...",
    "fileName": "Assignment_3_Submission_20250610.zip",
    "webViewLink": "https://drive.google.com/file/d/1def.../view",
    "webContentLink": "https://drive.google.com/uc?id=1def..."
  },
  "isLate": false                // boolean β€” Whether submission was late
}

Business Rules

Same as regular submit (section 6.7): must be published, enrolled, respects late submission rules.


7. Labs Module

Base Path: /api/labs

All endpoints require JWT authentication (@UseGuards(JwtAuthGuard, RolesGuard)).


7.1 List Labs

GET /api/labs

Auth Required: βœ… Yes Roles: All authenticated users

Query Parameters

Parameter Type Required Default Description
courseId integer ❌ β€” Filter by course ID
status string ❌ β€” Filter by LabStatus enum (draft, published, closed, archived)
page integer ❌ 1 Page number (>= 1)
limit integer ❌ 20 Items per page (1-100)

Response 200 OK

{
  "data": [
    {
      "id": 1,                              // number β€” Lab ID (bigint)
      "courseId": 1,                         // number β€” FK to courses
      "title": "Binary Search Lab",          // string β€” Lab title
      "description": "Implement binary...",  // string | null
      "labNumber": 1,                        // number | null β€” Lab sequence number
      "dueDate": "2026-04-15T23:59:59Z",    // string | null β€” Due date (ISO 8601)
      "availableFrom": "2026-04-01T00:00:00Z", // string | null
      "maxScore": 100.00,                    // number (decimal) β€” Max score
      "weight": 10.00,                       // number (decimal) β€” Weight in final grade
      "status": "published",                 // string β€” LabStatus enum
      "createdBy": 5,                        // number β€” Creator user ID
      "createdAt": "2026-04-01T08:00:00Z",
      "updatedAt": "2026-04-01T08:00:00Z",
      "course": {
        "id": 1,
        "departmentId": 3,
        "name": "Introduction to CS",
        "code": "CS101"
      }
    }
  ],
  "meta": {
    "total": 8,
    "page": 1,
    "limit": 20,
    "totalPages": 1
  }
}

7.2 Get Lab by ID

GET /api/labs/:id

Auth Required: βœ… Yes Roles: All authenticated users

Path Parameters

Parameter Type Required Description
id integer βœ… Lab ID

Response 200 OK

{
  "id": 1,
  "courseId": 1,
  "title": "Binary Search Lab",
  "description": "Implement binary search in Python",
  "labNumber": 1,
  "dueDate": "2026-04-15T23:59:59Z",
  "availableFrom": "2026-04-01T00:00:00Z",
  "maxScore": 100.00,
  "weight": 10.00,
  "status": "published",
  "createdBy": 5,
  "createdAt": "2026-04-01T08:00:00Z",
  "updatedAt": "2026-04-01T08:00:00Z",
  "course": { /* course object */ },
  "instructions": [
    {
      "id": 1,                          // number β€” Instruction ID
      "labId": 1,                       // number
      "fileId": null,                   // number | null β€” FK to files
      "instructionText": "Step 1: Create a new Python file",  // string | null
      "orderIndex": 1,                  // number β€” Sort order
      "createdAt": "2026-04-01T08:00:00Z"
    }
  ]
}

7.3 Create Lab

POST /api/labs

Auth Required: βœ… Yes Roles: instructor, teaching_assistant, admin, it_admin

Request Body

Field Type Required Default Constraints Description
courseId integer βœ… β€” Must exist Course ID
title string βœ… β€” β€” Lab title
description string ❌ null β€” Lab description
labNumber integer ❌ null β€” Lab sequence number
dueDate string ❌ null ISO 8601 Due date
availableFrom string ❌ null ISO 8601 Available from date
maxScore number ❌ 100 β€” Maximum score
weight number ❌ 0 β€” Weight in final grade
status string ❌ draft LabStatus enum Initial status

Example Request

{
  "courseId": 1,
  "title": "Binary Search Lab",
  "description": "Implement binary search in Python",
  "labNumber": 1,
  "dueDate": "2026-04-15T23:59:59Z",
  "availableFrom": "2026-04-01T00:00:00Z",
  "maxScore": 100,
  "weight": 10,
  "status": "draft"
}

Response 201 Created

Returns the created lab object.


7.4 Update Lab

PUT /api/labs/:id

Auth Required: βœ… Yes Roles: instructor, teaching_assistant, admin, it_admin

Note: This endpoint uses PUT (full replacement), but since UpdateLabDto extends PartialType(CreateLabDto), all fields are optional.

Path Parameters

Parameter Type Required Description
id integer βœ… Lab ID

Request Body

All fields from CreateLabDto are optional (uses PartialType).

Response 200 OK

Returns the updated lab object.


7.5 Delete Lab

DELETE /api/labs/:id

Auth Required: βœ… Yes Roles: instructor, admin, it_admin

Note: TAs cannot delete labs.

Path Parameters

Parameter Type Required Description
id integer βœ… Lab ID

Response 204 No Content

Empty body.


7.6 Change Lab Status

PATCH /api/labs/:id/status

Auth Required: βœ… Yes Roles: instructor, teaching_assistant, admin, it_admin

Path Parameters

Parameter Type Required Description
id integer βœ… Lab ID

Request Body

Field Type Required Description
status string βœ… One of: draft, published, closed, archived

Note: Unlike assignments, lab status changes do not enforce strict one-way transitions. Any valid status value can be set.

Response 200 OK

Returns the updated lab object (full Lab entity with relations).


7.7 Get Lab Instructions

GET /api/labs/:id/instructions

Auth Required: βœ… Yes Roles: All authenticated users

Path Parameters

Parameter Type Required Description
id integer βœ… Lab ID

Response 200 OK

[
  {
    "id": 1,                        // number β€” Instruction ID
    "labId": 1,                     // number β€” FK to labs
    "fileId": null,                 // number | null β€” FK to files table
    "instructionText": "Step 1...", // string | null β€” Markdown text
    "orderIndex": 1,                // number β€” Sort order (ascending)
    "createdAt": "2026-04-01T08:00:00Z"
  },
  {
    "id": 2,
    "labId": 1,
    "fileId": 5,
    "instructionText": "See attached PDF",
    "orderIndex": 2,
    "createdAt": "2026-04-01T08:05:00Z"
  }
]

7.8 Add Instruction to Lab

POST /api/labs/:id/instructions

Auth Required: βœ… Yes Roles: instructor, teaching_assistant, admin, it_admin

Path Parameters

Parameter Type Required Description
id integer βœ… Lab ID

Request Body

Field Type Required Default Description
instructionText string ❌ null Instruction content (supports markdown)
fileId integer ❌ null FK to files table for attachment
orderIndex integer ❌ 0 Sort order

Example Request

{
  "instructionText": "Step 1: Create a new Python file called `binary_search.py`",
  "orderIndex": 1
}

Response 201 Created

Returns the created instruction object.


7.9 Submit Lab Work (Student)

POST /api/labs/:id/submit

Auth Required: βœ… Yes Roles: student only

Path Parameters

Parameter Type Required Description
id integer βœ… Lab ID

Request Body

Field Type Required Description
submissionText string ❌ Text/code submission content
fileId integer ❌ File ID from files module

Example Request

{
  "submissionText": "def binary_search(arr, target):\n    ...",
  "fileId": 10
}

Response 201 Created

{
  "id": 5,                           // number β€” Submission ID
  "labId": 1,                        // number
  "userId": 57,                      // number β€” From JWT
  "submissionText": "def binary...",  // string | null
  "fileId": 10,                      // number | null
  "submittedAt": "2026-04-10T14:30:00Z",
  "isLate": false,                   // boolean β€” Auto-detected
  "status": "submitted",             // string β€” LabSubmissionStatus
  "score": null,                     // number | null
  "feedback": null,                  // string | null
  "gradedBy": null,                  // number | null
  "gradedAt": null                   // string | null
}

Business Rules

  • Auto-detects late submission based on lab.dueDate
  • Sets isLate = true if current time > dueDate

7.10 List Lab Submissions (Instructor/TA/Admin)

GET /api/labs/:id/submissions

Auth Required: βœ… Yes Roles: instructor, teaching_assistant, admin, it_admin

Path Parameters

Parameter Type Required Description
id integer βœ… Lab ID

Response 200 OK

[
  {
    "id": 5,
    "labId": 1,
    "userId": 57,
    "submissionText": "My solution...",
    "fileId": 10,
    "submittedAt": "2026-04-10T14:30:00Z",
    "isLate": false,
    "status": "submitted",
    "score": null,
    "feedback": null,
    "gradedBy": null,
    "gradedAt": null,
    "user": {
      "user_id": 57,
      "first_name": "John",
      "last_name": "Doe",
      "email": "john@example.com"
    },
    "file": {
      "file_id": 10,
      "file_name": "solution.py",
      "file_path": "/uploads/...",
      "mime_type": "text/x-python"
    }
  }
]

Sorted by submittedAt DESC.


7.11 Get My Lab Submission (Student)

GET /api/labs/:id/submissions/my

Auth Required: βœ… Yes Roles: student only

Path Parameters

Parameter Type Required Description
id integer βœ… Lab ID

Response 200 OK

Returns an array of the student's submissions for this lab (may have multiple), sorted by submittedAt DESC. Includes user and file relations.

[
  {
    "id": 5,
    "labId": 1,
    "userId": 57,
    "submissionText": "...",
    "fileId": 10,
    "submittedAt": "2026-04-10T14:30:00Z",
    "isLate": false,
    "status": "graded",
    "score": 90.00,
    "feedback": "Great work!",
    "gradedBy": 5,
    "gradedAt": "2026-04-12T10:00:00Z",
    "user": { /* student info */ },
    "file": { /* file info or null */ }
  }
]

Note: Unlike assignments (which returns the latest single submission), labs returns all submissions as an array.


7.12 Grade Lab Submission

PATCH /api/labs/:id/submissions/:subId/grade

Auth Required: βœ… Yes Roles: instructor, teaching_assistant, admin, it_admin

Path Parameters

Parameter Type Required Description
id integer βœ… Lab ID
subId integer βœ… Submission ID

Request Body

Field Type Required Constraints Description
status string βœ… One of: submitted, graded, returned, resubmit Submission status
score number ❌ >= 0 Score to assign
feedback string ❌ β€” Feedback for student

Example Request

{
  "status": "graded",
  "score": 85,
  "feedback": "Good work! Consider optimizing your code for better performance."
}

Response 200 OK

Returns the updated submission object with user, file, and grader relations:

{
  "id": 5,
  "labId": 1,
  "userId": 57,
  "submissionText": "...",
  "fileId": 10,
  "submittedAt": "2026-04-10T14:30:00Z",
  "isLate": false,
  "status": "graded",
  "score": 85.00,
  "feedback": "Good work!...",
  "gradedBy": 5,
  "gradedAt": "2026-04-12T10:00:00Z",
  "user": { /* student info */ },
  "file": { /* file info or null */ },
  "grader": {
    "user_id": 5,
    "first_name": "Prof. Smith",
    "last_name": "Smith",
    "email": "smith@example.com"
  }
}

Side effect: When status = 'graded' and score is provided, automatically creates a grade record in the central grades table with gradeType = 'lab', isPublished = true.


7.13 Mark Lab Attendance

POST /api/labs/:id/attendance

Auth Required: βœ… Yes Roles: instructor, teaching_assistant, admin, it_admin

Path Parameters

Parameter Type Required Description
id integer βœ… Lab ID

Request Body

Field Type Required Description
userId integer βœ… Student user ID to mark
attendanceStatus string βœ… One of: present, absent, excused, late
notes string ❌ Additional notes

Example Request

{
  "userId": 57,
  "attendanceStatus": "present",
  "notes": "Arrived on time"
}

Response 201 Created

{
  "id": 10,                          // number β€” Attendance record ID
  "labId": 1,                        // number
  "userId": 57,                      // number
  "attendanceStatus": "present",     // string β€” LabAttendanceStatus
  "checkInTime": "2026-04-10T09:00:00Z",  // string | null β€” Auto-set for present/late
  "notes": "Arrived on time",        // string | null
  "markedBy": 5,                     // number β€” User who marked (from JWT)
  "createdAt": "2026-04-10T09:00:00Z"
}

Business Rules

  • If a record already exists for this student+lab, it updates the existing record
  • checkInTime is automatically set when status is present or late

7.14 Get Lab Attendance

GET /api/labs/:id/attendance

Auth Required: βœ… Yes Roles: instructor, teaching_assistant, admin, it_admin

Path Parameters

Parameter Type Required Description
id integer βœ… Lab ID

Response 200 OK

[
  {
    "id": 10,
    "labId": 1,
    "userId": 57,
    "attendanceStatus": "present",
    "checkInTime": "2026-04-10T09:00:00Z",
    "notes": "Arrived on time",
    "markedBy": 5,
    "createdAt": "2026-04-10T09:00:00Z"
  }
]

Sorted by createdAt ASC.


7.15 Upload Lab Instruction (Google Drive)

POST /api/labs/:id/instructions/upload

Auth Required: βœ… Yes Roles: instructor, teaching_assistant, admin, it_admin Content-Type: multipart/form-data

Path Parameters

Parameter Type Required Description
id integer βœ… Lab ID

Form Data Fields

Field Type Required Constraints Description
file binary βœ… PDF, DOCX, etc. Instruction file
title string ❌ Max 255 chars Instruction title
orderIndex integer ❌ >= 0, default 0 Sort order

Response 201 Created

{
  "instruction": {
    "id": 3,
    "labId": 1,
    "instructionText": "Lab 1 - Getting Started Guide",
    "orderIndex": 1,
    "createdAt": "2026-04-01T08:00:00Z"
  },
  "driveFile": {
    "driveId": "1abc...",
    "fileName": "Lab_1_-_Getting_Started_Guide_v1.pdf",
    "webViewLink": "https://drive.google.com/file/d/1abc.../view",
    "webContentLink": "https://drive.google.com/uc?id=1abc..."
  }
}

7.16 Upload TA Material (Google Drive)

POST /api/labs/:id/ta-materials/upload

Auth Required: βœ… Yes Roles: instructor, teaching_assistant, admin, it_admin Content-Type: multipart/form-data

Path Parameters

Parameter Type Required Description
id integer βœ… Lab ID

Form Data Fields

Field Type Required Constraints Description
file binary βœ… β€” TA material file
title string ❌ Max 255 chars Material title
materialType string ❌ One of: answer_key, grading_rubric, solution, notes Type of TA material

Response 201 Created

{
  "driveFile": {
    "driveFileId": 125,
    "driveId": "1ghi...",
    "fileName": "solution_Lab_1_Answer_Key.pdf",
    "webViewLink": "https://drive.google.com/file/d/1ghi.../view",
    "webContentLink": "https://drive.google.com/uc?id=1ghi..."
  }
}

7.17 Upload Lab Submission (Google Drive β€” Student)

POST /api/labs/:id/submissions/upload

Auth Required: βœ… Yes Roles: student only Content-Type: multipart/form-data

Path Parameters

Parameter Type Required Description
id integer βœ… Lab ID

Form Data Fields

Field Type Required Description
file binary βœ… Submission file
submissionText string ❌ Notes/comments

Response 201 Created

{
  "submission": {
    "id": 6,
    "labId": 1,
    "userId": 57,
    "submissionText": "My implementation uses iterative approach",
    "submittedAt": "2026-04-10T14:30:00Z",
    "isLate": false,
    "status": "submitted",
    "score": null,
    "feedback": null,
    "gradedBy": null,
    "gradedAt": null
  },
  "driveFile": {
    "driveFileId": 126,
    "driveId": "1jkl...",
    "fileName": "Lab1_Submission_20260410.py",
    "webViewLink": "https://drive.google.com/file/d/1jkl.../view",
    "webContentLink": "https://drive.google.com/uc?id=1jkl..."
  },
  "isLate": false
}

Business Rules

  • If a submission already exists for this student+lab, the existing record is updated (not duplicated)
  • Auto-detects isLate based on lab.dueDate

8. Role-Based Access Matrix

8.1 Courses

Endpoint Student Instructor TA Admin IT Admin
GET /api/courses (list) βœ… Public βœ… Public βœ… Public βœ… Public βœ… Public
GET /api/courses/:id (details) βœ… Public βœ… Public βœ… Public βœ… Public βœ… Public
GET /api/courses/department/:deptId βœ… Public βœ… Public βœ… Public βœ… Public βœ… Public
POST /api/courses (create) ❌ βœ… ❌ βœ… βœ…
PATCH /api/courses/:id (update) ❌ βœ… ❌ βœ… βœ…
DELETE /api/courses/:id (delete) ❌ ❌ ❌ βœ… βœ…
GET /api/courses/:id/prerequisites βœ… Public βœ… Public βœ… Public βœ… Public βœ… Public
POST /api/courses/:id/prerequisites ❌ ❌ ❌ βœ… βœ…
DELETE /api/courses/:id/prerequisites/:id ❌ ❌ ❌ βœ… βœ…

8.2 Course Sections

Endpoint Student Instructor TA Admin IT Admin
GET /api/sections/course/:courseId βœ… Public βœ… Public βœ… Public βœ… Public βœ… Public
GET /api/sections/:id βœ… Public βœ… Public βœ… Public βœ… Public βœ… Public
POST /api/sections (create) ❌ βœ… ❌ βœ… βœ…
PATCH /api/sections/:id (update) ❌ βœ… ❌ βœ… βœ…
PATCH /api/sections/:id/enrollment ❌ βœ… ❌ βœ… βœ…

8.3 Course Schedules

Endpoint Student Instructor TA Admin IT Admin
GET /api/schedules/section/:sectionId βœ… Public βœ… Public βœ… Public βœ… Public βœ… Public
GET /api/schedules/:id βœ… Public βœ… Public βœ… Public βœ… Public βœ… Public
POST /api/schedules/section/:sectionId ❌ βœ… ❌ βœ… βœ…
DELETE /api/schedules/:id ❌ βœ… ❌ βœ… βœ…

8.4 Assignments

Endpoint Student Instructor TA Admin IT Admin
GET /api/assignments (list) βœ… βœ… βœ… βœ… βœ…
GET /api/assignments/:id (details) βœ… βœ… βœ… βœ… βœ…
POST /api/assignments (create) ❌ βœ… ❌ βœ… ❌
PATCH /api/assignments/:id (update) ❌ βœ… ❌ βœ… ❌
DELETE /api/assignments/:id (delete) ❌ βœ… ❌ βœ… ❌
PATCH /api/assignments/:id/status ❌ βœ… ❌ βœ… ❌
POST /api/assignments/:id/submit βœ… ❌ ❌ ❌ ❌
GET /api/assignments/:id/submissions/my βœ… ❌ ❌ ❌ ❌
GET /api/assignments/:id/submissions ❌ βœ… βœ… βœ… ❌
PATCH /:id/submissions/:subId/grade ❌ βœ… βœ… ❌ ❌
POST /:id/instructions/upload ❌ βœ… βœ… βœ… ❌
POST /:id/submissions/upload βœ… ❌ ❌ ❌ ❌

8.5 Labs

Endpoint Student Instructor TA Admin IT Admin
GET /api/labs (list) βœ… βœ… βœ… βœ… βœ…
GET /api/labs/:id (details) βœ… βœ… βœ… βœ… βœ…
POST /api/labs (create) ❌ βœ… βœ… βœ… βœ…
PUT /api/labs/:id (update) ❌ βœ… βœ… βœ… βœ…
DELETE /api/labs/:id (delete) ❌ βœ… ❌ βœ… βœ…
PATCH /api/labs/:id/status ❌ βœ… βœ… βœ… βœ…
GET /api/labs/:id/instructions βœ… βœ… βœ… βœ… βœ…
POST /api/labs/:id/instructions ❌ βœ… βœ… βœ… βœ…
POST /api/labs/:id/submit βœ… ❌ ❌ ❌ ❌
GET /api/labs/:id/submissions ❌ βœ… βœ… βœ… βœ…
GET /api/labs/:id/submissions/my βœ… ❌ ❌ ❌ ❌
PATCH /:id/submissions/:subId/grade ❌ βœ… βœ… βœ… βœ…
POST /api/labs/:id/attendance ❌ βœ… βœ… βœ… βœ…
GET /api/labs/:id/attendance ❌ βœ… βœ… βœ… βœ…
POST /:id/instructions/upload ❌ βœ… βœ… βœ… βœ…
POST /:id/ta-materials/upload ❌ βœ… βœ… βœ… βœ…
POST /:id/submissions/upload βœ… ❌ ❌ ❌ ❌

9. Error Handling

9.1 Standard Error Response Shape

{
  "statusCode": 404,
  "message": "Assignment not found",
  "error": "Not Found"
}

Or for validation errors (400):

{
  "statusCode": 400,
  "message": [
    "courseId must be a number",
    "title must be longer than or equal to 3 characters"
  ],
  "error": "Bad Request"
}

9.2 Common Error Codes

Status When
400 Validation failure, invalid state transition, business rule violation
401 Missing or invalid JWT token
403 Insufficient role permissions
404 Resource not found
409 Duplicate resource (e.g., course code)

9.3 Business Rule Errors (400)

Module Error Description
Courses Course code exists CourseCodeAlreadyExistsException β€” code+department must be unique
Courses Circular prerequisite CircularPrerequisiteDetectedException β€” detected via DFS
Courses Delete with sections CannotDeleteCourseWithActiveSectionsException
Assignments Not published AssignmentNotPublishedException β€” must be published to submit
Assignments Not available yet AssignmentNotAvailableYetException β€” before availableFrom
Assignments Deadline passed SubmissionDeadlinePassedException β€” past dueDate and late not allowed
Assignments Not enrolled Student not enrolled in the course
Assignments Invalid transition Status transition not allowed (e.g., draft to closed)
Sections Section full SectionFullException β€” enrollment exceeds capacity
Sections Capacity reduction Cannot reduce capacity below current enrollment
Schedules Invalid time InvalidTimeRangeException β€” end time <= start time
Schedules Conflict ScheduleConflictException β€” room/time overlap

10. Flutter Integration Tips

10.1 HTTP Client Setup

// Base configuration
const baseUrl = 'http://your-server:3001';

// Auth header
final headers = {
  'Content-Type': 'application/json',
  'Authorization': 'Bearer $accessToken',
};

10.2 Parsing lateSubmissionAllowed

The backend stores this as a MySQL TINYINT(1) β€” it comes back as 0 or 1 (number), not true/false:

final isLateAllowed = (assignment['lateSubmissionAllowed'] as num) == 1;

10.3 Parsing allowedFileTypes

This field is a JSON string (not an array). Parse it:

final List<String> fileTypes = assignment['allowedFileTypes'] != null
    ? List<String>.from(jsonDecode(assignment['allowedFileTypes']))
    : [];

10.4 Decimal Fields

maxScore, weight, latePenaltyPercent, score come back as decimal numbers (may be strings from some DB drivers). Always parse:

final maxScore = double.tryParse(assignment['maxScore'].toString()) ?? 100.0;

10.5 File Uploads (multipart/form-data)

Use dio or http.MultipartRequest:

// Using Dio
final formData = FormData.fromMap({
  'file': await MultipartFile.fromFile(filePath, filename: fileName),
  'title': 'My submission',
  'submissionText': 'Notes here',
});

final response = await dio.post(
  '$baseUrl/api/assignments/3/submissions/upload',
  data: formData,
  options: Options(headers: {'Authorization': 'Bearer $token'}),
);

10.6 Pagination Helper

class PaginatedResponse<T> {
  final List<T> data;
  final int total;
  final int page;
  final int limit;
  final int totalPages;

  bool get hasNextPage => page < totalPages;
  bool get hasPreviousPage => page > 1;
}

10.7 Enum Mapping

enum AssignmentStatus { draft, published, closed, archived }

extension AssignmentStatusExt on AssignmentStatus {
  String get value => name; // 'draft', 'published', etc.

  static AssignmentStatus fromString(String s) =>
    AssignmentStatus.values.firstWhere((e) => e.name == s);
}

10.8 Date Handling

All dates are ISO 8601 strings. Parse with:

final dueDate = DateTime.parse(assignment['dueDate']); // UTC
final localDueDate = dueDate.toLocal(); // Convert to local timezone

10.9 Role-Based UI

// Show/hide actions based on role
final userRoles = currentUser.roles; // List<String>
final canCreateAssignment = userRoles.any(
  (r) => ['instructor', 'admin'].contains(r),
);
final canSubmit = userRoles.contains('student');
final canGrade = userRoles.any(
  (r) => ['instructor', 'teaching_assistant'].contains(r),
);

10.10 Handling isLate Differences

Module isLate Type Values
Assignments number (tinyint) 0 = on-time, 1 = late
Labs boolean true / false
// Assignments
final isLate = (submission['isLate'] as num) == 1;

// Labs
final isLate = submission['isLate'] as bool;

Last Updated: April 2026 Backend Framework: NestJS (TypeScript) Database: MySQL with TypeORM File Storage: Google Drive API