eduverse-backend / COURSES_ASSIGNMENTS_LABS_BACKEND_API_DOCS.md
amirhamdi's picture
1 fix(google-drive): add self-healing folder management with duplicate prevention
b4c4de1
|
Raw
History Blame Contribute Delete
152 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
  11. Course Materials & Video Lectures Module
  12. Course Structure Module
  13. YouTube Integration Module

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 Dept Head
GET /api/courses (list) βœ… Public βœ… Public βœ… Public βœ… Public βœ… Public βœ… Public
GET /api/courses/:id (details) βœ… Public βœ… Public βœ… Public βœ… Public βœ… Public βœ… Public
GET /api/courses/department/:deptId βœ… Public βœ… 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 βœ… Public
POST /api/courses/:id/prerequisites ❌ ❌ ❌ βœ… βœ… ❌
DELETE /api/courses/:id/prerequisites/:id ❌ ❌ ❌ βœ… βœ… ❌

8.2 Course Sections

Endpoint Student Instructor TA Admin IT Admin Dept Head
GET /api/sections/course/:courseId βœ… Public βœ… Public βœ… Public βœ… Public βœ… Public βœ… Public
GET /api/sections/:id βœ… Public βœ… 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 Dept Head
GET /api/schedules/section/:sectionId βœ… Public βœ… Public βœ… Public βœ… Public βœ… Public βœ… Public
GET /api/schedules/:id βœ… Public βœ… Public βœ… Public βœ… Public βœ… Public βœ… Public
POST /api/schedules/section/:sectionId ❌ βœ… ❌ βœ… βœ… ❌
DELETE /api/schedules/:id ❌ βœ… ❌ βœ… βœ… ❌

8.4 Assignments

Endpoint Student Instructor TA Admin IT Admin Dept Head
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 Dept Head
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 βœ… ❌ ❌ ❌ ❌ ❌

8.6 Enrollments

Endpoint Student Instructor TA Admin IT Admin Dept Head
GET /api/enrollments/my-courses βœ… ❌ ❌ ❌ ❌ ❌
GET /api/enrollments/available βœ… ❌ ❌ ❌ ❌ ❌
POST /api/enrollments/register βœ… ❌ ❌ ❌ ❌ ❌
DELETE /api/enrollments/:id βœ… ❌ ❌ βœ… ❌ ❌
GET /api/enrollments/teaching ❌ βœ… βœ… βœ… ❌ ❌
GET /api/enrollments/periods βœ… βœ… βœ… βœ… βœ… βœ…
GET /api/sections/:sectionId/students ❌ βœ… βœ… βœ… ❌ ❌
GET /api/sections/:sectionId/waitlist ❌ βœ… ❌ βœ… ❌ ❌
POST /api/enrollments/sections/:sectionId/instructors ❌ ❌ ❌ βœ… ❌ ❌
DELETE /api/enrollments/sections/:sectionId/instructors/:id ❌ ❌ ❌ βœ… ❌ ❌
GET /api/enrollments/sections/:sectionId/instructors ❌ βœ… βœ… βœ… ❌ ❌
POST /api/enrollments/sections/:sectionId/tas ❌ ❌ ❌ βœ… ❌ ❌
DELETE /api/enrollments/sections/:sectionId/tas/:id ❌ ❌ ❌ βœ… ❌ ❌
GET /api/enrollments/sections/:sectionId/tas ❌ βœ… βœ… βœ… ❌ ❌

Note: department_head role currently has NO access to courses/assignments/labs features. This role only has access to schedule templates and campus events.


9. Course Enrollment Module

Base Path: /api/enrollments

All endpoints require JWT authentication (@UseGuards(JwtAuthGuard, RolesGuard)). This module handles student enrollment in courses, including registration, dropping, available courses with prerequisites validation, and instructor/TA assignment to sections.

9.0 Enrollment Enums

EnrollmentStatus

Value Description
enrolled Student is actively enrolled in the section
waitlisted Student is on the waitlist (not currently implemented)
dropped Student has dropped/withdrawn from the section
completed Student has completed the course with a grade
failed Student failed the course

DropReason

Value Description
student_request Student voluntarily dropped
administrative Admin-initiated drop
academic Academic reasons (e.g., failed prerequisite)
schedule_conflict Schedule conflict detected

9.0.1 Database Entity

course_enrollments Table

Column DB Type TS Type Nullable Default Description
enrollment_id bigint unsigned number ❌ (PK) Auto Primary key
user_id bigint unsigned number ❌ β€” FK β†’ users (student)
section_id bigint unsigned number ❌ β€” FK β†’ course_sections
program_id bigint unsigned number | null βœ… null FK β†’ programs
enrollment_status enum('enrolled','waitlisted','dropped','completed','failed') EnrollmentStatus ❌ 'enrolled' Enrollment status
grade varchar(5) string | null βœ… null Letter grade (A, A-, B+, etc.)
final_score decimal(5,2) number | null βœ… null Final numeric score
enrollment_date datetime Date ❌ Auto When student enrolled
dropped_at datetime Date | null βœ… null When student dropped
completed_at datetime Date | null βœ… null When course was completed
updated_at timestamp Date ❌ Auto Last update timestamp

Indexes: (user_id, status), (section_id, status), unique constraint on (user_id, section_id)


9.1 Get My Enrolled Courses (Student)

GET /api/enrollments/my-courses

Auth Required: βœ… Yes Roles: student only

Query Parameters

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

Response 200 OK

[
  {
    "id": 1,                                // number β€” Enrollment ID
    "userId": 57,                            // number β€” Student user ID
    "sectionId": 11,                          // number β€” Section ID
    "status": "enrolled",                     // string β€” EnrollmentStatus enum
    "grade": null,                           // string | null β€” Letter grade
    "finalScore": null,                      // number | null β€” Final numeric score
    "enrollmentDate": "2025-09-01T10:00:00Z", // string β€” ISO 8601
    "droppedAt": null,                       // string | null
    "completedAt": null,                     // string | null
    "updatedAt": "2025-09-01T10:00:00Z",     // string β€” ISO 8601
    "canDrop": true,                         // boolean β€” Whether student can still drop
    "dropDeadline": "2025-10-15T23:59:59Z",  // string | null β€” Drop deadline
    "course": {
      "id": 1,
      "name": "Introduction to CS",
      "code": "CS101",
      "description": "...",
      "credits": 3,
      "level": "FRESHMAN"
    },
    "section": {
      "id": 11,
      "sectionNumber": "1",
      "maxCapacity": 30,
      "currentEnrollment": 25,
      "location": "Room A101",
      "status": "OPEN"
    },
    "semester": {
      "id": 1,
      "name": "Fall 2025",
      "startDate": "2025-09-01",
      "endDate": "2025-12-15"
    },
    "instructor": null,                      // object | null β€” Currently disabled
    "prerequisites": [                       // array β€” Prerequisites with completion status
      {
        "id": 1,
        "courseId": 1,
        "prerequisiteCourseId": 2,
        "courseCode": "CS100",
        "courseName": "Programming Basics",
        "isMandatory": true,
        "studentCompleted": true,
        "studentGrade": "A"
      }
    ]
  }
]

9.2 Get Available Courses (Student)

GET /api/enrollments/available

Auth Required: βœ… Yes Roles: student only

Returns courses the student can enroll in, checking:

  • Prerequisites completed with grade B- or higher
  • Section has available seats
  • No schedule conflicts with current enrollments
  • Course is active and not cancelled

Query Parameters

Parameter Type Required Default Description
departmentId integer ❌ β€” Filter by department
semesterId integer ❌ β€” Filter by semester
search string ❌ β€” Search in course name/code
level string ❌ β€” Filter by course level
page integer ❌ 1 Page number
limit integer ❌ 20 Items per page

Response 200 OK

[
  {
    "id": 1,                                // number β€” Course ID
    "name": "Introduction to CS",           // string
    "code": "CS101",                         // string
    "description": "...",                    // string | null
    "credits": 3,                            // number
    "level": "FRESHMAN",                     // string β€” CourseLevel enum
    "departmentId": 3,                       // number
    "departmentName": "Computer Science",    // string
    "sections": [                            // array β€” Available sections
      {
        "id": 11,
        "sectionNumber": "1",
        "maxCapacity": 30,
        "currentEnrollment": 25,
        "availableSeats": 5,
        "location": "Room A101",
        "semesterId": 1,
        "semesterName": "Fall 2025"
      }
    ],
    "prerequisites": [                       // array β€” Required prerequisites
      {
        "id": 1,
        "courseId": 1,
        "prerequisiteCourseId": 2,
        "courseCode": "CS100",
        "courseName": "Programming Basics",
        "isMandatory": true
      }
    ],
    "canEnroll": true,                       // boolean β€” Whether student meets all requirements
    "enrollmentStatus": null                 // string | null β€” Current enrollment status if already enrolled
  }
]

9.3 Enroll in a Course (Student)

POST /api/enrollments/register

Auth Required: βœ… Yes Roles: student only

Request Body

Field Type Required Description
sectionId number βœ… Section ID to enroll in

Example Request

{
  "sectionId": 11
}

Response 201 Created

Returns enrollment response object (same shape as items in 9.1 response).

Business Rules & Validation

  1. Already Enrolled: Cannot enroll if already enrolled in the same section (throws 409)
  2. Prerequisites: All prerequisites must be completed with grade B- or higher
  3. Schedule Conflicts: No time overlap with current enrollments in the same semester
  4. Capacity: If section is full, student is still enrolled (waitlist not implemented)
  5. Retake Logic:
    • If previously failed (grade F): Can retake freely
    • If previously passed with B- or better and wants to improve: Requires admin approval (throws 400 with RetakeRequiresAdminApprovalException)

Error Responses

Status Description
400 Prerequisites not met / Schedule conflict / User or section not found
409 Already enrolled in this section

9.4 Drop/Withdraw from a Course

DELETE /api/enrollments/:id

Auth Required: βœ… Yes Roles: student (own enrollments), admin (any enrollment)

Path Parameters

Parameter Type Required Description
id integer βœ… Enrollment ID

Request Body (Optional)

Field Type Required Description
reason string ❌ Drop reason from DropReason enum

Response 200 OK

Returns the updated enrollment object with status: "dropped" and droppedAt timestamp.

Business Rules

  1. Permission: Students can only drop their own enrollments; admins can drop any
  2. Drop Deadline: Students can only drop before 50% of semester has elapsed (admins can override)
  3. Status Changes: Enrollment status changes from enrolled β†’ dropped
  4. Section Count: Section's currentEnrollment is decremented

Error Responses

Status Description
400 Drop deadline passed / Cannot drop past enrollment
403 Forbidden β€” not your enrollment
404 Enrollment not found

9.5 Get Teaching Courses (Instructor/TA)

GET /api/enrollments/teaching

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

Returns all course sections where the user is assigned as an instructor or TA.

Response 200 OK

[
  {
    "sectionId": 11,
    "courseId": 1,
    "course": {
      "id": 1,
      "name": "Introduction to CS",
      "code": "CS101",
      "description": "...",
      "credits": 3,
      "level": "FRESHMAN"
    },
    "section": {
      "id": 11,
      "sectionNumber": "1",
      "maxCapacity": 30,
      "currentEnrollment": 25,
      "location": "Room A101"
    },
    "semester": {
      "id": 1,
      "name": "Fall 2025",
      "startDate": "2025-09-01",
      "endDate": "2025-12-15"
    }
  }
]

9.6 Get Section Students

GET /api/sections/:sectionId/students

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

Returns all actively enrolled students (status = enrolled) in a section.

Path Parameters

Parameter Type Required Description
sectionId integer βœ… Section ID

Response 200 OK

Returns array of enrollment objects (same shape as 9.1), sorted by enrollmentDate ASC.


9.7 Get Section Waitlist

GET /api/sections/:sectionId/waitlist

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

Currently Not Implemented: Returns empty array. Waitlist functionality requires a separate waitlist table.

Response 200 OK

[]

9.8 Assign Instructor to Section (Admin)

POST /api/enrollments/sections/:sectionId/instructors

Auth Required: βœ… Yes Roles: admin only

Path Parameters

Parameter Type Required Description
sectionId integer βœ… Section ID

Request Body

Field Type Required Default Description
userId number βœ… β€” User ID of instructor (must have instructor role)
role string ❌ primary One of: primary, co_instructor, guest
responsibilities string ❌ β€” Free-text description

Example Request

{
  "userId": 58,
  "role": "primary",
  "responsibilities": "Lead lectures, grade assignments"
}

Response 201 Created

{
  "id": 1,                   // number β€” Instructor assignment ID
  "sectionId": 11,
  "userId": 58,
  "role": "primary",
  "responsibilities": "Lead lectures, grade assignments",
  "assignedAt": "2025-09-01T10:00:00Z",
  "user": {
    "userId": 58,
    "firstName": "Tarek",
    "lastName": "Instructor",
    "email": "tarek@example.com"
  }
}

Error Responses

Status Description
400 Invalid user ID or section ID
404 Section or user not found
409 Instructor already assigned to this section

9.9 Get Section Instructors

GET /api/enrollments/sections/:sectionId/instructors

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

Path Parameters

Parameter Type Required Description
sectionId integer βœ… Section ID

Response 200 OK

Returns array of instructor assignment objects (same shape as 9.8 response).


9.10 Remove Instructor from Section (Admin)

DELETE /api/enrollments/sections/:sectionId/instructors/:assignmentId

Auth Required: βœ… Yes Roles: admin only

Path Parameters

Parameter Type Required Description
sectionId integer βœ… Section ID
assignmentId integer βœ… Instructor assignment ID

Response 204 No Content

Empty body.


9.11 Assign TA to Section (Admin)

POST /api/enrollments/sections/:sectionId/tas

Auth Required: βœ… Yes Roles: admin only

Path Parameters

Parameter Type Required Description
sectionId integer βœ… Section ID

Request Body

Field Type Required Description
userId number βœ… User ID of TA (must have teaching_assistant role)
responsibilities string ❌ Free-text description (e.g., "Grading labs, office hours Mon/Wed")

Example Request

{
  "userId": 60,
  "responsibilities": "Grade lab submissions, hold office hours on Tuesday"
}

Response 201 Created

{
  "id": 2,                   // number β€” TA assignment ID
  "sectionId": 11,
  "userId": 60,
  "responsibilities": "Grade lab submissions, hold office hours on Tuesday",
  "assignedAt": "2025-09-01T10:00:00Z",
  "user": {
    "userId": 60,
    "firstName": "John",
    "lastName": "TA",
    "email": "ta@example.com"
  }
}

Error Responses

Status Description
400 Invalid user ID or section ID
404 Section or user not found
409 TA already assigned to this section

9.12 Get Section TAs

GET /api/enrollments/sections/:sectionId/tas

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

Path Parameters

Parameter Type Required Description
sectionId integer βœ… Section ID

Response 200 OK

Returns array of TA assignment objects (same shape as 9.11 response).


9.13 Remove TA from Section (Admin)

DELETE /api/enrollments/sections/:sectionId/tas/:assignmentId

Auth Required: βœ… Yes Roles: admin only

Path Parameters

Parameter Type Required Description
sectionId integer βœ… Section ID
assignmentId integer βœ… TA assignment ID

Response 204 No Content

Empty body.


9.14 Get Section Instructor Summary

GET /api/enrollments/section/:sectionId/instructor

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

Returns simplified instructor info for a section.

Path Parameters

Parameter Type Required Description
sectionId integer βœ… Section ID

Response 200 OK

{
  "instructorId": 58,
  "instructor": {
    "userId": 58,
    "fullName": "Tarek Instructor",
    "email": "tarek@example.com"
  }
}

9.15 Get Section TA Summaries

GET /api/enrollments/section/:sectionId/tas

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

Returns simplified TA info for a section.

Path Parameters

Parameter Type Required Description
sectionId integer βœ… Section ID

Response 200 OK

[
  {
    "userId": 60,
    "fullName": "Tarek TA",
    "email": "ta@example.com"
  }
]

9.16 Get Enrollment Periods

GET /api/enrollments/periods

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

Returns semesters with registration date ranges.

Response 200 OK

[
  {
    "id": 1,
    "semesterName": "Fall 2025",
    "semesterCode": "FA25",
    "registrationStart": "2025-08-01T00:00:00Z",
    "registrationEnd": "2025-08-25T23:59:59Z",
    "semesterStart": "2025-09-01T00:00:00Z",
    "semesterEnd": "2025-12-15T23:59:59Z",
    "status": "active"
  }
]

10. 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;

11. Course Materials & Video Lectures Module

Base Path: /api/courses/:courseId/materials

All endpoints require JWT authentication (@UseGuards(JwtAuthGuard, RolesGuard)). This module handles uploading, viewing, organizing, and managing all course materials β€” including video lectures uploaded to YouTube and documents stored on Google Drive.

11.0 Enums Reference (Course Materials)

MaterialType

Value Description
lecture Lecture content (notes, handouts)
slide Presentation slides
video Video content (YouTube integration)
reading Reading material
link External link
document Generic document
other Uncategorized material

OrganizationType (for Course Structure)

Value Description
lecture Main lecture content
section Discussion or tutorial section
lab Hands-on lab session
tutorial Tutorial session

11.0.1 Database Entities

course_materials Table

Column DB Type TS Type Nullable Default Description
material_id bigint unsigned number ❌ (PK) Auto Primary key
course_id bigint unsigned number ❌ β€” FK β†’ courses
file_id bigint unsigned number | null βœ… null FK β†’ files (local files)
drive_file_id bigint unsigned number | null βœ… null FK β†’ drive_files (Google Drive)
material_type enum('lecture','slide','video','reading','link','document','other') MaterialType ❌ 'document' Type of material
title varchar(255) string ❌ β€” Material title
description text string | null βœ… null Description
external_url varchar(500) string | null βœ… null External URL (YouTube embed URL, Google Drive link, etc.)
youtube_video_id varchar(50) string | null βœ… null YouTube video ID (for video materials)
order_index int number ❌ 0 Sort order within week
week_number int number | null βœ… null Week number for organizing by course week
view_count int number ❌ 0 Number of times viewed
download_count int number ❌ 0 Number of times downloaded
uploaded_by bigint unsigned number ❌ β€” FK β†’ users (creator)
is_published tinyint boolean ❌ 0 0 = draft (hidden), 1 = published (visible to students)
published_at timestamp Date | null βœ… null When material was first published
created_at timestamp Date ❌ Auto Creation timestamp
updated_at timestamp Date ❌ Auto Last update timestamp

Indexes: course_id, uploaded_by, material_type, week_number

lecture_sections_labs Table (Course Structure)

Column DB Type TS Type Nullable Default Description
organization_id bigint unsigned number ❌ (PK) Auto Primary key
course_id bigint unsigned number ❌ β€” FK β†’ courses
material_id bigint unsigned number | null βœ… null FK β†’ course_materials
organization_type enum('lecture','section','lab','tutorial') OrganizationType | null βœ… null Type of content organization
title varchar(255) string ❌ β€” Structure item title
week_number int number | null βœ… null Week number
order_index int number ❌ 0 Sort order
description text string | null βœ… null Description
created_at timestamp Date ❌ Auto Creation timestamp
updated_at timestamp Date ❌ Auto Last update timestamp

Indexes: course_id, week_number


11.1 List Course Materials

GET /api/courses/:courseId/materials

Auth Required: βœ… Yes Roles: All authenticated users (role-based visibility filtering)

Role-Based Visibility

Role Can See
student Only published materials (is_published = 1)
instructor All materials (including drafts)
teaching_assistant All materials (including drafts)
admin / it_admin All materials (including drafts)

Path Parameters

Parameter Type Required Description
courseId integer βœ… Course ID

Query Parameters

Parameter Type Required Default Description
materialType string ❌ β€” Filter by MaterialType enum (lecture, slide, video, reading, link, document, other)
weekNumber integer ❌ β€” Filter by week number
isPublished boolean ❌ β€” Filter by visibility. Only effective for instructor, ta, admin roles. Ignored for students.
search string ❌ β€” Search in title and description (partial match / LIKE)
sortBy string ❌ orderIndex Sort field: createdAt, title, orderIndex
sortOrder string ❌ ASC Sort order: ASC or DESC
page integer ❌ 1 Page number (1-indexed, min: 1)
limit integer ❌ 10 Items per page (1-100)

Response 200 OK

{
  "data": [
    {
      "materialId": 1,                              // number (bigint) β€” Material ID (PK)
      "courseId": 1,                                 // number β€” FK to courses
      "fileId": null,                               // number | null β€” FK to local files
      "driveFileId": 123,                           // number | null β€” FK to drive_files
      "materialType": "video",                      // string β€” MaterialType enum
      "title": "Lecture 1: Introduction to DS",     // string β€” Material title (max 255)
      "description": "Covers basics of...",         // string | null β€” Description
      "externalUrl": "https://www.youtube.com/embed/abc123",  // string | null β€” YouTube embed URL or Drive view URL
      "youtubeVideoId": "abc123",                   // string | null β€” YouTube video ID
      "orderIndex": 0,                              // number β€” Sort position
      "weekNumber": 1,                              // number | null β€” Week number
      "viewCount": 42,                              // number β€” Times viewed
      "downloadCount": 10,                          // number β€” Times downloaded
      "uploadedBy": 5,                              // number β€” Creator user ID
      "isPublished": true,                          // boolean β€” Visibility state (tinyint 0/1 mapped to boolean)
      "publishedAt": "2025-06-01T10:00:00Z",        // string | null β€” ISO 8601 timestamp
      "createdAt": "2025-06-01T08:00:00Z",           // string β€” ISO 8601
      "updatedAt": "2025-06-01T08:00:00Z",           // string β€” ISO 8601
      "course": {                                    // object β€” Joined course relation
        "id": 1,
        "departmentId": 3,
        "name": "Introduction to CS",
        "code": "CS101"
      },
      "file": null,                                  // object | null β€” Joined local file relation
      "uploader": {                                  // object β€” Joined uploader user relation
        "user_id": 5,
        "first_name": "Dr. Jane",
        "last_name": "Smith",
        "email": "jane@example.com"
      }
    }
  ],
  "meta": {
    "total": 25,         // number β€” Total matching records
    "page": 1,           // number β€” Current page
    "limit": 10,         // number β€” Items per page
    "totalPages": 3      // number β€” Total pages
  }
}

11.2 Get Material by ID

GET /api/courses/:courseId/materials/:id

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

Students can only view materials where isPublished = true. Requesting an unpublished material as a student returns 404 Not Found.

Path Parameters

Parameter Type Required Description
courseId integer βœ… Course ID
id integer βœ… Material ID

Response 200 OK

Returns a single material object (same shape as items in 11.1 data array, including course, file, and uploader relations).

Error Responses

Status Description
401 Unauthorized β€” missing or invalid token
404 Material not found (or unpublished material accessed by student)

11.3 Create Course Material

POST /api/courses/:courseId/materials

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

Authorization: Non-admin users must be assigned to the course (as instructor of a section or TA of a section). Unassigned instructors/TAs receive 403 Forbidden.

Path Parameters

Parameter Type Required Description
courseId integer βœ… Course ID

Request Body (application/json)

Field Type Required Constraints Description
title string βœ… Max 255 chars, non-empty Material title
materialType string βœ… MaterialType enum Type of material
description string ❌ β€” Material description
fileId number ❌ Must reference valid file ID File ID from the Files module
externalUrl string ❌ Max 500 chars External URL (YouTube link, external resource, etc.)
orderIndex number ❌ Min 0 Sort order for display
weekNumber number ❌ Min 1 Week number for content organization
isPublished boolean ❌ β€” Publish immediately (true) or save as draft (false). Default: false

Example Request

{
  "title": "Lecture 1: Introduction to Programming",
  "materialType": "video",
  "description": "Introduction to basic programming concepts.",
  "externalUrl": "https://www.youtube.com/watch?v=example",
  "weekNumber": 1,
  "orderIndex": 0,
  "isPublished": false
}

Response 201 Created

Returns the created material object (same shape as items in 11.1 response without course/file/uploader relations β€” raw entity).

Error Responses

Status Description
400 Invalid input data (validation failure)
403 Forbidden β€” user not assigned to this course

11.4 Bulk Create Materials

POST /api/courses/:courseId/materials/bulk

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

Maximum 50 materials per request. Non-admin users must be assigned to the course.

Path Parameters

Parameter Type Required Description
courseId integer βœ… Course ID

Request Body (application/json)

Field Type Required Constraints Description
materials CreateMaterialDto[] βœ… 1-50 items, validated individually Array of material objects (same shape as 11.3 request body)

Example Request

{
  "materials": [
    {
      "title": "Lecture 1: Introduction",
      "materialType": "lecture",
      "description": "Introduction to the course",
      "weekNumber": 1
    },
    {
      "title": "Lecture 2: Fundamentals",
      "materialType": "lecture",
      "description": "Fundamentals of the subject",
      "weekNumber": 1
    }
  ]
}

Response 201 Created

{
  "message": "Successfully created 2 materials",  // string β€” Success message
  "count": 2,                                      // number β€” Count of created items
  "data": [                                        // CourseMaterial[] β€” Created material objects
    {
      "materialId": 10,
      "courseId": 1,
      "title": "Lecture 1: Introduction",
      "materialType": "lecture",
      "description": "Introduction to the course",
      "weekNumber": 1,
      "orderIndex": 0,
      "isPublished": false,
      "uploadedBy": 5,
      "createdAt": "2025-06-01T08:00:00Z",
      "updatedAt": "2025-06-01T08:00:00Z"
    }
  ]
}

Error Responses

Status Description
400 Invalid input data β€” minimum 1 material required, maximum 50 allowed
403 Forbidden β€” user not assigned to this course

11.5 Upload Video Material (YouTube)

POST /api/courses/:courseId/materials/video

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

This is the primary endpoint for uploading video lectures. The backend uploads the video to YouTube as unlisted, then creates a course_materials record with the YouTube embed URL and video ID.

Path Parameters

Parameter Type Required Description
courseId integer βœ… Course ID

Form Data Fields

Field Type Required Constraints Description
video binary (file) βœ… Formats: mp4, avi, mov, webm, mkv, flv, wmv Video file to upload
title string βœ… Max 255 chars, non-empty Video title
description string ❌ β€” Video description
tags string[] ❌ Array of strings Tags for the YouTube video
weekNumber integer ❌ 1–52 Week to assign the video to
orderIndex integer ❌ Min 0, default: 0 Sort order within the week
isPublished boolean ❌ Default: false Publish immediately or save as draft

Upload Flow (Internal)

  1. Backend validates user is authorized for this course
  2. Video file buffer is uploaded to YouTube (privacy: unlisted)
  3. YouTube returns videoId and URL
  4. A course_materials record is created with:
    • materialType = video
    • externalUrl = https://www.youtube.com/embed/{videoId}
    • youtubeVideoId = the YouTube video ID
    • Other metadata (weekNumber, orderIndex, isPublished)

Response 201 Created

{
  "materialId": 1,                                           // number β€” Created material ID
  "courseId": 1,                                             // number β€” Course ID
  "title": "Lecture 1: Introduction",                        // string β€” Video title
  "materialType": "video",                                   // string β€” Always "video"
  "description": "This covers the basics...",                // string | null
  "externalUrl": "https://www.youtube.com/embed/dQw4w9WgXcQ", // string β€” YouTube embed URL
  "youtubeVideoId": "dQw4w9WgXcQ",                          // string β€” YouTube video ID
  "weekNumber": 1,                                           // number | null
  "orderIndex": 0,                                           // number
  "isPublished": false,                                      // boolean
  "publishedAt": null,                                       // string | null
  "uploadedBy": 5,                                           // number
  "viewCount": 0,                                            // number
  "downloadCount": 0,                                        // number
  "createdAt": "2025-06-01T08:00:00Z",                       // string β€” ISO 8601
  "updatedAt": "2025-06-01T08:00:00Z",                       // string β€” ISO 8601
  "youtubeUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", // string β€” Full YouTube watch URL (appended by service)
  "embedUrl": "https://www.youtube.com/embed/dQw4w9WgXcQ"    // string β€” Embed URL for iframe (appended by service)
}

Error Responses

Status Description
400 No video file provided / YouTube upload failed / Invalid input data
403 Forbidden β€” user not assigned to this course
413 Video file too large (YouTube account limits apply)

11.6 Upload Document Material (Google Drive)

POST /api/courses/:courseId/materials/document

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

Uploads a document to Google Drive in the appropriate course folder hierarchy and creates a material record.

Path Parameters

Parameter Type Required Description
courseId integer βœ… Course ID

Form Data Fields

Field Type Required Constraints Description
document binary (file) βœ… Formats: pdf, ppt, pptx, doc, docx, xls, xlsx, txt, md, zip Document file to upload
title string βœ… Max 255 chars, non-empty Document title
description string ❌ β€” Document description
materialType string ❌ MaterialType enum, default: document Document type: lecture, slide, reading, document, link
weekNumber integer ❌ 1–52 Week to assign the document to
orderIndex integer ❌ Min 0, default: 0 Sort order within the week
isPublished boolean ❌ Default: false Publish immediately or save as draft

Folder Placement Rules

materialType value Google Drive folder target
lecture Course/Lectures/
slide Course/Lectures/ (slides grouped with lectures)
reading Course/General/
document Course/General/
link Course/General/
other Course/General/

File Naming Convention

Files are renamed following the pattern:

{WeekNN_}{SafeTitle}_v1.{ext}
  • Example: Week01_Introduction_to_Data_Structures_v1.pdf

Response 201 Created

{
  "materialId": 2,                                                          // number β€” Created material ID
  "courseId": 1,                                                            // number
  "title": "Week 1 Lecture Notes",                                          // string
  "materialType": "lecture",                                                // string β€” MaterialType enum
  "description": "Comprehensive lecture notes covering the basics.",         // string | null
  "externalUrl": "https://drive.google.com/file/d/abc123/view",             // string β€” Google Drive view URL
  "driveFileId": 123,                                                       // number β€” FK to drive_files table
  "weekNumber": 1,                                                          // number | null
  "orderIndex": 0,                                                          // number
  "isPublished": false,                                                     // boolean
  "publishedAt": null,                                                      // string | null
  "uploadedBy": 5,                                                          // number
  "createdAt": "2025-06-01T08:00:00Z",                                      // string β€” ISO 8601
  "updatedAt": "2025-06-01T08:00:00Z",                                      // string β€” ISO 8601
  "driveId": "abc123",                                                      // string β€” Google Drive file ID (appended)
  "driveViewUrl": "https://drive.google.com/file/d/abc123/view",            // string β€” View URL (appended)
  "driveDownloadUrl": "https://drive.google.com/uc?id=abc123&export=download", // string β€” Download URL (appended)
  "fileName": "Week01_Week_1_Lecture_Notes_v1.pdf"                          // string β€” Generated file name (appended)
}

Error Responses

Status Description
400 No document file / Google Drive upload failed / Invalid input data
403 Forbidden β€” user not assigned to this course

11.7 Update Material

PUT /api/courses/:courseId/materials/:id

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

Ownership: Non-admin users can only update materials they uploaded (uploadedBy must match the requesting user). Admins can update any material.

Path Parameters

Parameter Type Required Description
courseId integer βœ… Course ID
id integer βœ… Material ID

Request Body (application/json) β€” All fields optional (uses PartialType of CreateMaterialDto)

Field Type Required Constraints Description
title string ❌ Max 255 chars Updated title
materialType string ❌ MaterialType enum Updated type
description string ❌ β€” Updated description
fileId number ❌ Must exist Updated file reference
externalUrl string ❌ Max 500 chars Updated external URL
orderIndex number ❌ Min 0 Updated sort order
weekNumber number ❌ Min 1 Updated week number
isPublished boolean ❌ β€” Updated visibility. If changing from false β†’ true, publishedAt is set automatically.

Response 200 OK

Returns the updated material object (with course, file, uploader relations).

Error Responses

Status Description
403 Forbidden β€” you can only update materials you uploaded (non-admin)
404 Material not found

11.8 Delete Material

DELETE /api/courses/:courseId/materials/:id

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

Ownership: Non-admin users can only delete materials they uploaded. Admins can delete any material.

Path Parameters

Parameter Type Required Description
courseId integer βœ… Course ID
id integer βœ… Material ID

Response 200 OK

{
  "message": "Material deleted successfully"   // string
}

Error Responses

Status Description
403 Forbidden β€” you can only delete materials you uploaded (non-admin)
404 Material not found

11.9 Toggle Material Visibility

PATCH /api/courses/:courseId/materials/:id/visibility

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

Controls whether a material is visible to students. Non-admin users can only toggle visibility of materials they uploaded.

Path Parameters

Parameter Type Required Description
courseId integer βœ… Course ID
id integer βœ… Material ID

Request Body (application/json)

Field Type Required Constraints Description
isPublished boolean βœ… β€” true = visible to students, false = draft (hidden)

Example Request

{
  "isPublished": true
}

Response 200 OK

Returns the updated material object (full entity with course, file, uploader relations). publishedAt is set to current timestamp on first publish, preserved on subsequent toggles.

Error Responses

Status Description
403 Forbidden β€” you can only change visibility of materials you uploaded (non-admin)
404 Material not found

11.10 Download Material

GET /api/courses/:courseId/materials/:id/download

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

Students can only download published materials. Increments downloadCount on each successful call.

Path Parameters

Parameter Type Required Description
courseId integer βœ… Course ID
id integer βœ… Material ID

Response 200 OK

{
  "material": {                          // object β€” Full material entity
    "materialId": 1,
    "title": "Lecture Notes Week 1",
    "materialType": "lecture",
    "fileId": 12,
    "externalUrl": null,
    "viewCount": 42,
    "downloadCount": 11
    // ... full material object fields
  },
  "file": {                              // object β€” Associated file entity
    "fileId": 12,
    "fileName": "lecture_notes_w1.pdf",
    "filePath": "/uploads/materials/lecture_notes_w1.pdf",
    "fileSize": 2048576,
    "mimeType": "application/pdf"
    // ... full file object fields
  },
  "downloadUrl": "/uploads/materials/lecture_notes_w1.pdf"   // string β€” Direct download path
}

Error Responses

Status Description
400 Material does not have a downloadable file (fileId is null)
404 Material or associated file not found

11.11 Track Material View

POST /api/courses/:courseId/materials/:id/view

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

Records that a user viewed a material. Increments viewCount counter. Used for analytics and engagement tracking.

Path Parameters

Parameter Type Required Description
courseId integer βœ… Course ID
id integer βœ… Material ID

Request Body

None (empty body)

Response 200 OK

{
  "message": "View tracked successfully",   // string
  "materialId": 1,                          // number β€” Material ID
  "viewCount": 43                           // number β€” New total view count
}

Error Responses

Status Description
404 Material not found

11.12 Get Embed URL (Video Materials)

GET /api/courses/:courseId/materials/:id/embed

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

For video materials only. Returns the YouTube embed URL and ready-to-use iframe HTML.

Path Parameters

Parameter Type Required Description
courseId integer βœ… Course ID
id integer βœ… Material ID

Response 200 OK (YouTube video)

{
  "videoId": "dQw4w9WgXcQ",                                    // string β€” YouTube video ID
  "embedUrl": "https://www.youtube.com/embed/dQw4w9WgXcQ",     // string β€” Embed URL for iframe
  "iframeHtml": "<iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/dQw4w9WgXcQ\" frameborder=\"0\" allowfullscreen></iframe>"  // string β€” Ready-to-use iframe HTML
}

Response 200 OK (Non-YouTube external URL)

{
  "externalUrl": "https://example.com/video.mp4"   // string β€” Raw external URL
}

Error Responses

Status Description
400 Material is not a video (materialType !== 'video') or has no external URL
404 Material not found

12. Course Structure Module

Base Path: /api/courses/:courseId/structure

All endpoints require JWT authentication (@UseGuards(JwtAuthGuard, RolesGuard)). This module provides the organizational layer for course content β€” mapping materials into weeks, lectures, sections, and labs.


12.1 Get Course Structure

GET /api/courses/:courseId/structure

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

Path Parameters

Parameter Type Required Description
courseId integer βœ… Course ID

Response 200 OK

{
  "data": [                                   // LectureSectionLab[] β€” Flat list of all structure items
    {
      "organizationId": 1,                   // number β€” Structure item ID (PK)
      "courseId": 1,                          // number β€” FK to courses
      "materialId": 5,                        // number | null β€” FK to course_materials
      "organizationType": "lecture",          // string | null β€” OrganizationType enum
      "title": "Week 1: Introduction",        // string β€” Item title
      "weekNumber": 1,                        // number | null β€” Week number
      "orderIndex": 0,                        // number β€” Sort position
      "description": "Overview of course",    // string | null
      "createdAt": "2025-06-01T08:00:00Z",    // string β€” ISO 8601
      "updatedAt": "2025-06-01T08:00:00Z",    // string β€” ISO 8601
      "material": {                           // object | null β€” Joined material relation
        "materialId": 5,
        "title": "Lecture 1 Slides",
        "materialType": "slide",
        "externalUrl": "https://drive.google.com/...",
        "youtubeVideoId": null,
        "weekNumber": 1,
        "viewCount": 20,
        "isPublished": true
      }
    }
  ],
  "byWeek": {                                // Record<number, LectureSectionLab[]> β€” Grouped by week
    "0": [ /* items without a week */ ],
    "1": [ /* week 1 items */ ],
    "2": [ /* week 2 items */ ]
  }
}

Sorting: Items sorted by weekNumber ASC, then orderIndex ASC.


12.2 Get Structure Item by ID

GET /api/courses/:courseId/structure/:id

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

Path Parameters

Parameter Type Required Description
courseId integer βœ… Course ID
id integer βœ… Structure item ID

Response 200 OK

Returns a single structure item with course and material relations joined.

{
  "organizationId": 1,
  "courseId": 1,
  "materialId": 5,
  "organizationType": "lecture",
  "title": "Week 1: Introduction",
  "weekNumber": 1,
  "orderIndex": 0,
  "description": "Overview of the course",
  "createdAt": "2025-06-01T08:00:00Z",
  "updatedAt": "2025-06-01T08:00:00Z",
  "course": {
    "id": 1,
    "name": "Introduction to CS",
    "code": "CS101"
  },
  "material": {
    "materialId": 5,
    "title": "Lecture 1 Slides",
    "materialType": "slide"
  }
}

Error Responses

Status Description
404 Structure item not found

12.3 Create Structure Item

POST /api/courses/:courseId/structure

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

Note: TAs cannot create structure items. Non-admin instructors must be assigned to the course.

Path Parameters

Parameter Type Required Description
courseId integer βœ… Course ID

Request Body (application/json)

Field Type Required Constraints Description
title string βœ… Max 255 chars, non-empty Structure item title
organizationType string βœ… OrganizationType enum (lecture, section, lab, tutorial) Type of content
description string ❌ β€” Description of this content section
weekNumber number ❌ Min 1 Week number for this content
orderIndex number ❌ Min 0. Auto-calculated if omitted (max existing + 1 within the week). Sort order
materialId number ❌ Must reference valid material ID Link to an existing material

Example Request

{
  "title": "Week 1: Introduction to Data Structures",
  "organizationType": "lecture",
  "description": "Introduction to the course and basic concepts",
  "weekNumber": 1,
  "materialId": 5
}

Response 201 Created

Returns the created structure item entity.

Error Responses

Status Description
400 Invalid input data
403 Forbidden β€” only instructors/admins; must be assigned to course

12.4 Update Structure Item

PUT /api/courses/:courseId/structure/:id

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

All fields from CreateStructureDto are optional (PartialType). TAs cannot update structure. Non-admin instructors must be assigned to the course.

Path Parameters

Parameter Type Required Description
courseId integer βœ… Course ID
id integer βœ… Structure item ID

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

Field Type Required Constraints Description
title string ❌ Max 255 chars Updated title
organizationType string ❌ OrganizationType enum Updated type
description string ❌ β€” Updated description
weekNumber number ❌ Min 1 Updated week number
orderIndex number ❌ Min 0 Updated sort order
materialId number ❌ Valid material ID Updated material link

Response 200 OK

Returns the updated structure item entity.

Error Responses

Status Description
403 Forbidden β€” only instructors/admins; must be assigned
404 Structure item not found

12.5 Delete Structure Item

DELETE /api/courses/:courseId/structure/:id

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

Important: Deleting a structure item does NOT delete associated materials. The material remains in the course_materials table.

Path Parameters

Parameter Type Required Description
courseId integer βœ… Course ID
id integer βœ… Structure item ID

Response 200 OK

{
  "message": "Structure item deleted successfully"   // string
}

Error Responses

Status Description
403 Forbidden β€” only instructors/admins; must be assigned
404 Structure item not found

12.6 Reorder Structure Items

PATCH /api/courses/:courseId/structure/reorder

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

Reorders multiple structure items in a single request. All IDs must belong to the specified course.

Path Parameters

Parameter Type Required Description
courseId integer βœ… Course ID

Request Body (application/json)

Field Type Required Constraints Description
orderIds number[] βœ… Non-empty array of existing structure item IDs Array of item IDs in the desired new order

Example Request

{
  "orderIds": [3, 1, 2, 4]
}

This would set:

  • ID 3 β†’ orderIndex: 0
  • ID 1 β†’ orderIndex: 1
  • ID 2 β†’ orderIndex: 2
  • ID 4 β†’ orderIndex: 3

Response 200 OK

{
  "message": "Structure reordered successfully"   // string
}

Error Responses

Status Description
400 Invalid input data (empty array, non-number values)
403 Forbidden β€” only instructors/admins; must be assigned
404 Some structure items not found or do not belong to this course

13. YouTube Integration Module

Base Path: /youtube

This module provides standalone YouTube API integration for OAuth authentication, video upload, search, and video details retrieval. ⚠️ These endpoints are primarily used internally by the Course Materials module (section 11.5) but are also exposed directly for advanced use cases.


13.1 Get YouTube Auth URL

GET /youtube/auth

Auth Required: ❌ No (Public endpoint) Roles: None

Returns the Google OAuth2 authorization URL. The user must visit this URL to grant YouTube upload permission.

Response 200 OK

{
  "authUrl": "https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube.upload&response_type=code&client_id=xxx&redirect_uri=xxx&prompt=consent"
  // string β€” Full OAuth2 URL to redirect the user to
}

13.2 Handle YouTube OAuth Callback

GET /youtube/callback

Auth Required: ❌ No (Called by Google redirect) Roles: None

Exchanges the authorization code (received from Google after user consent) for access/refresh tokens.

Query Parameters

Parameter Type Required Description
code string βœ… Authorization code from Google OAuth redirect

Response 200 OK

{
  "message": "Authentication successful",          // string
  "refreshToken": "ya29.a0AfB_byC..."              // string β€” Refresh token for future API calls
}

Error Responses

Status Description
400 Invalid or expired authorization code

13.3 Upload Video to YouTube (Standalone)

POST /youtube/upload

Auth Required: βœ… Requires YouTube OAuth configured (refresh token in environment) Roles: Any user with YouTube credentials Content-Type: multipart/form-data

Note: For uploading course lecture videos, prefer the dedicated endpoint POST /api/courses/:courseId/materials/video (section 11.5) which also creates the material record.

Form Data Fields

Field Type Required Constraints Description
video binary (file) βœ… MP4, AVI, MOV, WMV, FLV, WebM Video file
title string βœ… β€” Video title
description string βœ… β€” Video description
tags string ❌ Comma-separated string Tags (e.g. "education,course,lecture")

Note: tags here is a comma-separated string, not an array (unlike the Course Materials video endpoint).

Response 201 Created

{
  "success": true,                                              // boolean
  "videoId": "dQw4w9WgXcQ",                                    // string β€” YouTube video ID
  "videoUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",   // string β€” Full watch URL
  "data": {                                                     // object β€” Full YouTube API response data
    "kind": "youtube#video",
    "etag": "...",
    "id": "dQw4w9WgXcQ",
    "snippet": {
      "title": "My Course Lecture",
      "description": "Lecture about...",
      "tags": ["education", "course", "lecture"],
      "categoryId": "22"
    },
    "status": {
      "privacyStatus": "unlisted"
    }
  }
}

Error Responses

Status Description
400 No video file or invalid format
401 YouTube authentication required (no valid refresh token)
413 Video file too large

13.4 Search YouTube Videos

GET /youtube/search

Auth Required: ❌ No (Uses service account OAuth2) Roles: None

Query Parameters

Parameter Type Required Default Description
query string βœ… β€” Search terms
maxResults integer ❌ 10 Max number of results (capped at 50)

Response 200 OK

{
  "success": true,                                              // boolean
  "items": [                                                    // array β€” Search results
    {
      "videoId": "dQw4w9WgXcQ",                                // string β€” YouTube video ID
      "title": "Example Video Title",                           // string β€” Video title
      "description": "Video description...",                    // string β€” Truncated description
      "thumbnail": "https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg",  // string β€” HQ thumbnail URL
      "channelTitle": "Channel Name",                           // string β€” Channel name
      "publishedAt": "2023-01-15T10:30:00Z",                    // string β€” ISO 8601 publish date
      "videoUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", // string β€” Watch URL
      "embedUrl": "https://www.youtube.com/embed/dQw4w9WgXcQ"   // string β€” Embed URL
    }
  ],
  "totalResults": 1000000,                                      // number β€” Total matching results
  "resultsPerPage": 10                                          // number β€” Results returned
}

Error Responses

Status Description
400 Invalid query parameters (missing query)

13.5 Get Video Details by ID

GET /youtube/videos/:videoId

Auth Required: ❌ No (Uses service account OAuth2) Roles: None

Path Parameters

Parameter Type Required Description
videoId string βœ… YouTube video ID (e.g. dQw4w9WgXcQ)

Response 200 OK (Found)

{
  "success": true,                                              // boolean
  "video": {                                                    // object β€” Complete video info
    "videoId": "dQw4w9WgXcQ",                                  // string β€” YouTube ID
    "title": "Example Video",                                   // string β€” Title
    "description": "Full video description...",                 // string β€” Full description
    "thumbnail": "https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg",  // string β€” Thumbnail
    "channelId": "UC1234567890",                                // string β€” Channel ID
    "channelTitle": "Channel Name",                             // string β€” Channel name
    "publishedAt": "2023-01-15T10:30:00Z",                      // string β€” Publish date
    "duration": "PT4M33S",                                      // string β€” ISO 8601 duration
    "viewCount": "1000000",                                     // string β€” View count
    "likeCount": "50000",                                       // string β€” Like count
    "commentCount": "2000",                                     // string β€” Comment count
    "privacyStatus": "public",                                  // string β€” "public" | "private" | "unlisted"
    "videoUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",  // string β€” Watch URL
    "embedUrl": "https://www.youtube.com/embed/dQw4w9WgXcQ"     // string β€” Embed URL
  }
}

Response 200 OK (Not Found)

{
  "success": false,                       // boolean
  "message": "Video not found"            // string
}

Note: Returns 200 with success: false when video doesn't exist β€” not a 404.


13.6 Get Channel Videos

GET /youtube/channel/:channelId/videos

Auth Required: ❌ No (Uses service account OAuth2) Roles: None

Path Parameters

Parameter Type Required Description
channelId string βœ… YouTube channel ID (e.g. UC1234567890)

Query Parameters

Parameter Type Required Default Description
maxResults integer ❌ 10 Max number of results (capped at 50)

Response 200 OK

{
  "success": true,                                              // boolean
  "items": [                                                    // array β€” Channel videos (newest first)
    {
      "videoId": "dQw4w9WgXcQ",                                // string β€” Video ID
      "title": "Latest Video",                                  // string β€” Title
      "description": "Video description...",                    // string
      "thumbnail": "https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg",  // string
      "publishedAt": "2023-01-15T10:30:00Z",                    // string β€” ISO 8601
      "videoUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", // string
      "embedUrl": "https://www.youtube.com/embed/dQw4w9WgXcQ"   // string
    }
  ],
  "totalResults": 150,                                          // number β€” Total channel videos
  "resultsPerPage": 10                                          // number β€” Results returned
}

Error Responses

Status Description
404 Channel not found

14. Course Materials Role-Based Access Matrix

Endpoint Student Instructor (assigned) TA (assigned) Admin / IT Admin
GET .../materials βœ… (published only) βœ… (all) βœ… (all) βœ… (all)
GET .../materials/:id βœ… (published only) βœ… βœ… βœ…
POST .../materials ❌ βœ… βœ… βœ…
POST .../materials/bulk ❌ βœ… βœ… βœ…
POST .../materials/video ❌ βœ… βœ… βœ…
POST .../materials/document ❌ βœ… βœ… βœ…
PUT .../materials/:id ❌ βœ… (own only) βœ… (own only) βœ… (any)
DELETE .../materials/:id ❌ βœ… (own only) βœ… (own only) βœ… (any)
PATCH .../materials/:id/visibility ❌ βœ… (own only) βœ… (own only) βœ… (any)
GET .../materials/:id/download βœ… (published only) βœ… βœ… βœ…
POST .../materials/:id/view βœ… βœ… βœ… βœ…
GET .../materials/:id/embed βœ… βœ… βœ… βœ…
GET .../structure βœ… βœ… βœ… βœ…
GET .../structure/:id βœ… βœ… βœ… βœ…
POST .../structure ❌ βœ… ❌ βœ…
PUT .../structure/:id ❌ βœ… ❌ βœ…
DELETE .../structure/:id ❌ βœ… ❌ βœ…
PATCH .../structure/reorder ❌ βœ… ❌ βœ…

15. Video Lecture Viewing β€” End-to-End Flow

15.1 Instructor Uploads a Video Lecture

sequenceDiagram
    participant I as Instructor
    participant API as Backend API
    participant YT as YouTube API
    participant DB as Database

    I->>API: POST /api/courses/1/materials/video (multipart: video + metadata)
    API->>API: Validate user is assigned to course
    API->>YT: Upload video buffer (unlisted)
    YT-->>API: Return { videoId, videoUrl }
    API->>DB: INSERT INTO course_materials (materialType='video', youtubeVideoId, externalUrl=embed URL)
    DB-->>API: Return saved material entity
    API-->>I: 201 { materialId, youtubeVideoId, embedUrl, youtubeUrl }

15.2 Student Views a Video Lecture

sequenceDiagram
    participant S as Student
    participant API as Backend API
    participant DB as Database

    S->>API: GET /api/courses/1/materials?materialType=video
    API->>DB: SELECT WHERE course_id=1 AND material_type='video' AND is_published=1
    DB-->>API: Return published video materials
    API-->>S: 200 { data: [...], meta: { total, page, limit, totalPages } }
    Note over S: Student selects a video
    S->>API: POST /api/courses/1/materials/5/view
    API->>DB: UPDATE viewCount = viewCount + 1
    API-->>S: 200 { message, materialId, viewCount }
    S->>API: GET /api/courses/1/materials/5/embed
    API-->>S: 200 { videoId, embedUrl, iframeHtml }
    Note over S: Flutter renders YouTube video using embedUrl in WebView/iframe

15.3 Flutter Integration Example (Video Player)

// Fetch video material
final response = await dio.get(
  '$baseUrl/api/courses/$courseId/materials/$materialId/embed',
  options: Options(headers: {'Authorization': 'Bearer $token'}),
);

final embedUrl = response.data['embedUrl'] as String;
final videoId = response.data['videoId'] as String;

// Option 1: Use WebView for embedded YouTube
WebViewWidget(controller: WebViewController()
  ..loadRequest(Uri.parse(embedUrl)));

// Option 2: Use youtube_player_flutter package
YoutubePlayer(
  controller: YoutubePlayerController(
    initialVideoId: videoId,
    flags: YoutubePlayerFlags(autoPlay: false),
  ),
);

16. Course Details Handling β€” What Each Role Sees

16.1 Course Visibility & Access Per Role

Student View

  • Course Catalog: Can browse all courses (public endpoints, no auth required)
  • Course Details (GET /api/courses/:id):
    • Full course information (name, code, description, credits, level)
    • Prerequisites list
    • Available sections count
    • Cannot see: Other students' information, unpublished materials
  • Course Materials:
    • Only published materials (isPublished = true)
    • Can view videos, download documents, track views
    • Cannot see: Draft materials, other students' submissions
  • Assignments:
    • Only published assignments
    • Can submit if enrolled in the course section
    • Can view own submissions and grades
    • Cannot see: Other students' submissions
  • Labs:
    • Only published labs
    • Can submit if enrolled (currently no enrollment check for labs β€” missing validation)
    • Can view own submissions and grades
    • Can view lab instructions
  • Sections & Schedules: Can view all sections and schedules (public)

Instructor View

  • Teaching Courses (GET /api/enrollments/teaching):
    • All sections where instructor is assigned
    • Course details, section info, semester dates
  • Course Details:
    • Same as student view PLUS:
    • Can create/update/delete courses (if authorized)
    • Can manage sections and schedules
  • Course Materials:
    • All materials (including drafts) for courses they teach
    • Can upload videos to YouTube, documents to Google Drive
    • Can organize materials by weeks using course structure
    • Can update/delete own materials only (admins can manage any)
  • Assignments:
    • Can create/update/publish/close assignments
    • Can view all submissions for assignments in their courses
    • Can grade submissions (creates central grade record)
    • Can upload instruction files to Google Drive
  • Labs:
    • Can create/update/publish/close labs
    • Can add instructions with file attachments
    • Can view all submissions and grade them
    • Can mark student attendance
    • Can upload TA materials (answer keys, rubrics)
    • Can delete labs

Teaching Assistant (TA) View

  • Teaching Courses: Same as instructor (sections where assigned as TA)
  • Course Materials:
    • All materials (including drafts) for courses they're assigned to
    • Can upload/create materials
    • Can update/delete own materials only
    • Cannot create/update course structure (weeks, lectures organization)
  • Assignments:
    • Can create/update/delete assignments (same as instructor)
    • Can view all submissions and grade them
    • Can upload instruction files
  • Labs:
    • Can create/update labs
    • Can add instructions and upload files
    • Can view all submissions and grade them
    • Can mark attendance
    • Can upload TA materials
    • Cannot delete labs (only instructors/admins)
  • Sections & Students:
    • Can view enrolled students in their sections
    • Can view instructor/TA assignments

Admin / IT Admin View

  • Full Access to all courses, sections, schedules, materials, assignments, labs
  • Can manage any material (not just own)
  • Can manage course structure
  • Can assign instructors/TAs to sections
  • Can manage student enrollments
  • Can delete any resource
  • IT Admin additionally has system-level access (backup, monitoring, security)

Department Head View

  • Currently NO specific access to courses/assignments/labs features
  • Only has access to:
    • Schedule templates (/api/schedule-templates)
    • Campus events (/api/campus-events)
  • Enhancement Needed: Would need additional endpoints to view department courses overview, instructor assignments, etc.

16.2 Course Details Response Fields

When calling GET /api/courses/:id, the response includes:

{
  "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,                   // ⭐ Primary instructor ID (may be null)
  "taIds": [1, 2],                     // ⭐ Array of TA user IDs (may be null)
  "status": "ACTIVE",
  "createdAt": "2025-01-15T10:00:00Z",
  "updatedAt": "2025-01-15T10:00:00Z",
  "department": {
    "id": 3,
    "name": "Computer Science",
    "code": "CS"
  },
  "prerequisites": [],                 // Array of prerequisite objects
  "sections": [],                      // Array of section objects
  "prerequisitesCount": 0,             // ⭐ Convenience field
  "sectionsCount": 2                   // ⭐ Convenience field
}

Note: instructorId and taIds are stored in the courses table but actual section-level instructor/TA assignments are managed separately in course_instructors and course_tas tables via the enrollments module.


17. Business Logic Details

17.1 Assignment Submission β€” Enrollment Check

Critical: Assignment submission (POST /api/assignments/:id/submit and POST /api/assignments/:id/submissions/upload) requires the student to be enrolled in the assignment's course.

// Enrollment validation in assignments.service.ts
const enrollment = await this.enrollmentRepo
  .createQueryBuilder('enrollment')
  .innerJoin('course_sections', 'section', 'section.section_id = enrollment.section_id')
  .where('enrollment.user_id = :userId', { userId })
  .andWhere('section.course_id = :courseId', { courseId: assignment.courseId })
  .andWhere('enrollment.enrollment_status = :status', { status: 'enrolled' })
  .getOne();

if (!enrollment) {
  throw new BadRequestException('Student is not enrolled in this course');
}

Business Rules:

  1. Assignment must be in published status
  2. If availableFrom is set, current time must be after it
  3. If past dueDate:
    • If lateSubmissionAllowed = false: Throws SubmissionDeadlinePassedException
    • If lateSubmissionAllowed = true: Sets isLate = 1
  4. Student must be enrolled in the course's section with status enrolled
  5. UPSERT Logic:
    • If latest submission is graded: Creates new attempt (increment attemptNumber)
    • If latest submission is not graded: Updates existing submission

17.2 Lab Submission β€” Missing Enrollment Check

Important: Lab submission (POST /api/labs/:id/submit and POST /api/labs/:id/submissions/upload) currently does NOT check if the student is enrolled in the course.

// labs.service.ts β€” submit() method
// ⚠️ NO enrollment validation found
async submit(labId: number, userId: number, dto: SubmitLabDto): Promise<LabSubmission> {
  const lab = await this.findById(labId);
  
  let isLate = false;
  if (lab.dueDate && new Date() > new Date(lab.dueDate)) {
    isLate = true;
  }
  
  // UPSERT logic...
}

Recommendation: Add enrollment check similar to assignments for consistency.

17.3 Assignment vs Lab Submission Differences

Feature Assignments Labs
Late Detection isLate: number (0 or 1) isLate: boolean (true/false)
Attempt Tracking attemptNumber auto-incremented No attempt tracking
UPSERT Behavior Updates if not graded, new attempt if graded Updates existing or creates new
Enrollment Check βœ… Required ❌ Missing (should be added)
Get My Submission Returns single latest submission Returns array of all submissions
Submission Types file, text, link, multiple text, file only
Grade Integration Creates central grade record Creates central grade record (only if status=graded)

17.4 Grade Integration

Both assignments and labs automatically create records in the central grades table when graded:

Assignment Grading (PATCH /api/assignments/:id/submissions/:subId/grade):

await this.gradesService.createGrade({
  userId: submission.userId,
  courseId: assignment.courseId,
  gradeType: GradeType.ASSIGNMENT,
  assignmentId: assignmentId,
  score: dto.score,
  maxScore: Number(assignment.maxScore),
  feedback: dto.feedback,
  isPublished: true,  // Immediately visible
}, graderId);

Lab Grading (PATCH /api/labs/:id/submissions/:subId/grade):

// Only creates grade if status is 'graded' and score provided
if (dto.score !== undefined && dto.status === 'graded') {
  await this.gradesService.createGrade({
    userId: submission.userId,
    courseId: lab.courseId,
    gradeType: GradeType.LAB,
    labId: labId,
    score: dto.score,
    maxScore: Number(lab.maxScore),
    feedback: dto.feedback,
    isPublished: true,
  }, graderId);
}

17.5 Google Drive File Organization

Assignment Instructions:

  • Folder: EduVerse/Courses/{CourseCode}/Assignments/Assignment_{ID}/Instructions/
  • File naming: {Title}_v1.{ext}

Assignment Submissions:

  • Folder: EduVerse/Courses/{CourseCode}/Assignments/Assignment_{ID}/Submissions/User_{UserID}/
  • File naming: Assignment_{ID}_Submission_{YYYYMMDD}.{ext}

Lab Instructions:

  • Folder: EduVerse/Courses/{CourseCode}/Labs/Lab_{LabNumber}/Instructions/
  • File naming: {Title}_v1.{ext}

Lab TA Materials:

  • Folder: EduVerse/Courses/{CourseCode}/Labs/Lab_{LabNumber}/TA_Materials/
  • File naming: {Type}_{Title}.{ext} (e.g., solution_Lab_1_Answer_Key.pdf)

Lab Submissions:

  • Folder: EduVerse/Courses/{CourseCode}/Labs/Lab_{LabNumber}/Submissions/User_{UserID}/
  • File naming: Lab{LabNumber}_Submission_{YYYYMMDD}.{ext}

17.6 Course Section Status Auto-Calculation

Section status is automatically calculated based on enrollment:

private calculateSectionStatus(maxCapacity: number, currentEnrollment: number): SectionStatus {
  if (currentEnrollment >= maxCapacity) {
    return SectionStatus.FULL;
  }
  return SectionStatus.OPEN;
}
  • OPEN: Enrollment < Capacity
  • FULL: Enrollment >= Capacity
  • CLOSED: Manually set by instructor/admin
  • CANCELLED: Manually set by instructor/admin

18. End-to-End Flow Diagrams

18.1 Student Course Enrollment Flow

sequenceDiagram
    participant S as Student
    participant API as Backend API
    participant DB as Database

    S->>API: GET /api/enrollments/available
    API->>DB: Query active courses with sections
    DB-->>API: Return courses
    API->>API: Check prerequisites, capacity, conflicts
    API-->>S: 200 { courses with canEnroll flag }
    
    Note over S: Student selects a section
    
    S->>API: POST /api/enrollments/register { sectionId }
    API->>DB: Check prerequisites (grade B- or higher)
    API->>DB: Check schedule conflicts
    API->>DB: Check existing enrollment
    API->>DB: INSERT course_enrollments
    API->>DB: UPDATE sections SET currentEnrollment + 1
    API-->>S: 201 { enrollment details }

18.2 Assignment Submission Flow (with Enrollment Check)

sequenceDiagram
    participant S as Student
    participant API as Backend API
    participant DB as Database
    participant GD as Google Drive

    S->>API: GET /api/assignments/:id
    API->>DB: Get assignment with course info
    API-->>S: 200 { assignment details }
    
    Note over S: Student prepares submission
    
    S->>API: POST /api/assignments/:id/submissions/upload (multipart)
    API->>DB: Check assignment status = published
    API->>DB: Check availableFrom <= now
    API->>DB: Check dueDate (late detection)
    API->>DB: CHECK enrollment in course section ⭐
    alt Not enrolled
        API-->>S: 400 "Student is not enrolled in this course"
    else Enrolled
        API->>GD: Upload file to student folder
        GD-->>API: Return driveFileId, URLs
        API->>DB: UPSERT submission (check if graded)
        API-->>S: 201 { submission + driveFile }
    end

18.3 Lab Submission Flow (without Enrollment Check)

sequenceDiagram
    participant S as Student
    participant API as Backend API
    participant DB as Database
    participant GD as Google Drive

    S->>API: GET /api/labs/:id
    API->>DB: Get lab with instructions
    API-->>S: 200 { lab + instructions }
    
    Note over S: Student prepares submission
    
    S->>API: POST /api/labs/:id/submissions/upload (multipart)
    API->>DB: Check lab exists
    API->>DB: Check dueDate (late detection)
    API->>DB: ⚠️ NO enrollment check
    API->>GD: Upload file to student folder
    GD-->>API: Return driveFileId, URLs
    API->>DB: UPSERT submission
    API-->>S: 201 { submission + driveFile }

18.4 Grading Flow (Central Gradebook Integration)

sequenceDiagram
    participant I as Instructor/TA
    participant API as Backend API
    participant DB as Database
    participant GB as Grades Module

    I->>API: PATCH /api/assignments/:id/submissions/:subId/grade
    API->>DB: Get submission + assignment
    API->>DB: UPDATE submission (status=graded, score, feedback)
    API->>GB: createGrade({ assignment, score, maxScore })
    GB->>DB: INSERT grades (gradeType='assignment', isPublished=true)
    GB-->>API: Return gradeId
    API-->>I: 200 { submissionId, score, maxScore, gradeId }

19. UI Shape for 5 Roles

This section describes the expected UI structure for each role based on the backend API capabilities.

19.1 Student UI

Dashboard / Home

  • My Courses: Grid/list of enrolled courses with:
    • Course name, code, instructor
    • Current grade (if available)
    • Quick links to materials, assignments, labs
  • Upcoming Deadlines: Assignments and labs due soon
  • Recent Grades: Latest graded submissions

Course Catalog (Public)

  • Browse all courses by department, level, search
  • View course details:
    • Description, credits, prerequisites
    • Available sections with schedules
    • Enroll button (if canEnroll = true)

Course Details Page (Per Course)

  • Tabs:
    1. Overview: Description, syllabus, instructor/TA info
    2. Materials: Published videos, documents (organized by weeks)
      • Video player (YouTube embed)
      • Document viewer/download
      • View tracking (analytics for instructor)
    3. Assignments: Published assignments list
      • Title, due date, status
      • Submit button β†’ Modal with:
        • Text editor
        • File upload
        • Link input
        • Late warning if past due
      • View submission history with grades/feedback
    4. Labs: Published labs list
      • Title, due date, lab number
      • View instructions (with file attachments)
      • Submit button β†’ Modal with:
        • Text/code editor
        • File upload
      • View submission history with grades/feedback
    5. Grades: All graded work with scores, feedback, overall grade
    6. Schedule: Section schedule (days, times, rooms)

Enrollment Management

  • My Enrollments: List of current/past courses
  • Available Courses: Browse and register (with prerequisites check)
  • Drop Course: Button with deadline warning

19.2 Instructor UI

Dashboard / Home

  • Teaching Courses: Grid of assigned sections with:
    • Course name, section number
    • Enrollment count
    • Quick stats: pending submissions, upcoming deadlines
  • Recent Activity: New submissions, recent grading

Course Management (Per Assigned Section)

  • Tabs:
    1. Overview:

      • Course details (edit if assigned)
      • Section info (capacity, location)
      • Instructor/TA assignments (view only, admin manages)
      • Enrolled students list (with contact info)
    2. Materials:

      • All materials (including drafts)
      • Upload buttons:
        • πŸ“Ή Upload Video β†’ YouTube upload modal (title, description, tags, week)
        • πŸ“„ Upload Document β†’ Google Drive upload (title, type, week)
      • Organize by weeks (course structure):
        • Create/edit weeks, lectures, sections, labs
        • Drag-and-drop reorder
      • Toggle visibility (publish/draft)
      • View analytics (view count, download count)
    3. Assignments:

      • List all assignments (draft/published/closed/archived)
      • Create Assignment modal:
        • Title, description, instructions
        • Submission type (file/text/link/multiple)
        • Due date, available from date
        • Late submission settings
        • Max score, weight
        • Allowed file types, max size
      • View Submissions:
        • Table of all students with:
          • Name, submission time, late flag
          • Status (submitted/graded/returned)
          • Attempt number
          • Grade input (score, feedback)
        • Bulk actions: download all, grade selected
      • Grade Submission:
        • Side-by-side view:
          • Left: Student submission (file viewer, text, link)
          • Right: Grade input (score, feedback, status)
    4. Labs:

      • List all labs (draft/published/closed/archived)
      • Create Lab modal:
        • Title, description, lab number
        • Due date, available from
        • Max score, weight
      • Manage Instructions:
        • Add steps (markdown text, file attachments)
        • Reorder instructions
        • Upload instruction files to Drive
      • View Submissions: Same as assignments
      • Grade Submissions: Same as assignments
      • Attendance:
        • Student list with attendance status
        • Mark present/absent/excused/late
        • Export attendance
    5. Grades:

      • Gradebook view with all graded work
      • Assignment grades, lab grades
      • Calculate overall grades
      • Export grades
    6. Schedule:

      • Section schedules (days, times, rooms)
      • Create/edit schedules with conflict detection
    7. Analytics (if available):

      • Student engagement (material views, downloads)
      • Grade distribution
      • Submission patterns

19.3 Teaching Assistant (TA) UI

Similar to Instructor UI with these differences:

Restrictions:

  • ❌ Cannot delete labs
  • ❌ Cannot manage course structure (weeks, lectures organization)
  • ❌ Cannot assign/remove instructors or TAs
  • βœ… Can create/edit/delete assignments
  • βœ… Can create/edit labs (but not delete)
  • βœ… Can grade all submissions
  • βœ… Can upload instructions and TA materials
  • βœ… Can mark lab attendance
  • βœ… Can view all materials (including drafts)

Additional TA-Specific Features:

  • TA Materials Tab (in Labs):
    • Upload answer keys, grading rubrics, solutions
    • Visible only to instructors and TAs (not students)
  • Responsibilities View:
    • Shows assigned duties (e.g., "Grading labs, office hours Mon/Wed")

19.4 Admin UI

Full System Access

  • All instructor/TA capabilities without restrictions
  • Can manage any material (not just own)
  • Can manage course structure
  • Can delete any resource

Admin-Specific Features:

  1. Course Catalog Management:

    • Create/edit/delete courses
    • Manage prerequisites (with circular dependency detection)
    • Assign departments, instructors, TAs at course level
  2. Section Management:

    • Create/edit/delete sections
    • Set capacity, location, status
    • Override enrollment counts
  3. Instructor/TA Assignment:

    • Assign instructors to sections (primary, co_instructor, guest)
    • Assign TAs to sections
    • View all assignments across sections
  4. Enrollment Management:

    • View all student enrollments
    • Manually enroll/drop students
    • Override drop deadlines
    • Approve retake requests
  5. System Administration:

    • Manage departments, semesters, programs
    • User management (create, assign roles)
    • System settings, integrations

19.5 IT Admin UI

All Admin capabilities PLUS:

  1. System Monitoring:

    • Server health, performance metrics
    • Error tracking, alerts
    • SSL certificate status
  2. Database Management:

    • Backup/restore
    • Database migrations
    • Query performance
  3. Security:

    • Audit logs
    • IP blocking/unblocking
    • Security settings
  4. Integrations:

    • Google Drive configuration
    • YouTube API setup
    • Email service configuration

19.6 Department Head UI

Current State: Minimal access to courses/assignments/labs

Currently Available:

  • Schedule templates (create/manage templates)
  • Campus events (create/manage events)

Recommended Enhancements (not yet implemented):

  • Department courses overview
  • Instructor assignments per course
  • Enrollment statistics
  • Department-level analytics

20. Missing Endpoints & Future Enhancements

20.1 Currently Missing Endpoints

  1. Lab Submission Enrollment Check: Labs should validate student enrollment like assignments do
  2. Department Head Course Access: Endpoints for department heads to view/manage department courses
  3. Waitlist Management: Full waitlist table and enrollment logic
  4. Course Copy/Duplicate: Clone a course with all materials, assignments, labs
  5. Bulk Enrollment: Admin enroll multiple students at once
  6. Grade Export: Export grades to CSV/Excel
  7. Assignment/Lab Cloning: Duplicate for reuse in future semesters
  8. Discussion Forums: Per-course discussion boards
  9. Announcements: Course-wide announcements
  10. Notifications: Push/email notifications for deadlines, grades

20.2 Recommended Improvements

  1. Add enrollment check to lab submission endpoints for consistency
  2. Implement department_head role permissions for course oversight
  3. Add soft delete to labs (currently hard delete)
  4. Add attempt tracking to lab submissions (like assignments)
  5. Implement waitlist with auto-enrollment when seats open
  6. Add grade curves and grading policies
  7. Add plagiarism detection integration
  8. Implement real-time notifications (WebSockets)
  9. Add course templates for quick setup
  10. Add analytics dashboard for instructors (engagement, grade distribution)

Last Updated: April 2026 Backend Framework: NestJS (TypeScript) Database: MySQL with TypeORM File Storage: Google Drive API Video Storage: YouTube API (unlisted uploads) Authentication: JWT with role-based access control