Spaces:
Sleeping
π EduVerse API Documentation β Courses / Assignments / Labs
Purpose: Complete Flutter frontend integration guide. Base URL:
http://<host>:3001(default port3001) Auth: Most endpoints requireAuthorization: Bearer <JWT>header. Content-Type:application/jsonunless otherwise noted (file uploads usemultipart/form-data).
Table of Contents
- Global Information
- Enums Reference
- Courses Module
- Course Sections Module
- Course Schedules Module
- Assignments Module
- Labs Module
- Role-Based Access Matrix
- Error Handling
- Flutter Integration Tips
- Course Materials & Video Lectures Module
- Course Structure Module
- 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 strippedforbidNonWhitelisted: trueβ unknown properties cause 400 errortransform: 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
draftdirectly toclosed.
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, orsubmissionLinkshould 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
publishedstatus - If
availableFromis set, current time must be after it - If
dueDateis set and past,lateSubmissionAllowedmust betrue(otherwise 400) - Auto-marks
isLate = 1if submitted afterdueDate - 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
submittedAtDESC.
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
gradestable withgradeType = '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 = trueif 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
submittedAtDESC.
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'andscoreis provided, automatically creates a grade record in the centralgradestable withgradeType = '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
checkInTimeis automatically set when status ispresentorlate
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
createdAtASC.
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
isLatebased onlab.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_headrole 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
- Already Enrolled: Cannot enroll if already enrolled in the same section (throws
409) - Prerequisites: All prerequisites must be completed with grade B- or higher
- Schedule Conflicts: No time overlap with current enrollments in the same semester
- Capacity: If section is full, student is still enrolled (waitlist not implemented)
- 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
400withRetakeRequiresAdminApprovalException)
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
- Permission: Students can only drop their own enrollments; admins can drop any
- Drop Deadline: Students can only drop before 50% of semester has elapsed (admins can override)
- Status Changes: Enrollment status changes from
enrolledβdropped - Section Count: Section's
currentEnrollmentis 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 returns404 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_materialsrecord 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)
- Backend validates user is authorized for this course
- Video file buffer is uploaded to YouTube (privacy:
unlisted) - YouTube returns
videoIdand URL - A
course_materialsrecord is created with:materialType=videoexternalUrl=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 (
uploadedBymust 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
downloadCounton 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
viewCountcounter. 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, thenorderIndex 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
CreateStructureDtoare 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_materialstable.
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:
tagshere 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
200withsuccess: falsewhen video doesn't exist β not a404.
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
- Only published materials (
- 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)
- Schedule templates (
- 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:
instructorIdandtaIdsare stored in thecoursestable but actual section-level instructor/TA assignments are managed separately incourse_instructorsandcourse_tastables 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:
- Assignment must be in
publishedstatus - If
availableFromis set, current time must be after it - If past
dueDate:- If
lateSubmissionAllowed = false: ThrowsSubmissionDeadlinePassedException - If
lateSubmissionAllowed = true: SetsisLate = 1
- If
- Student must be enrolled in the course's section with status
enrolled - UPSERT Logic:
- If latest submission is
graded: Creates new attempt (incrementattemptNumber) - If latest submission is not graded: Updates existing submission
- If latest submission is
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 < CapacityFULL: Enrollment >= CapacityCLOSED: Manually set by instructor/adminCANCELLED: 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:
- Overview: Description, syllabus, instructor/TA info
- Materials: Published videos, documents (organized by weeks)
- Video player (YouTube embed)
- Document viewer/download
- View tracking (analytics for instructor)
- 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
- 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
- Grades: All graded work with scores, feedback, overall grade
- 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:
Overview:
- Course details (edit if assigned)
- Section info (capacity, location)
- Instructor/TA assignments (view only, admin manages)
- Enrolled students list (with contact info)
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)
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
- Table of all students with:
- Grade Submission:
- Side-by-side view:
- Left: Student submission (file viewer, text, link)
- Right: Grade input (score, feedback, status)
- Side-by-side view:
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
Grades:
- Gradebook view with all graded work
- Assignment grades, lab grades
- Calculate overall grades
- Export grades
Schedule:
- Section schedules (days, times, rooms)
- Create/edit schedules with conflict detection
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:
Course Catalog Management:
- Create/edit/delete courses
- Manage prerequisites (with circular dependency detection)
- Assign departments, instructors, TAs at course level
Section Management:
- Create/edit/delete sections
- Set capacity, location, status
- Override enrollment counts
Instructor/TA Assignment:
- Assign instructors to sections (primary, co_instructor, guest)
- Assign TAs to sections
- View all assignments across sections
Enrollment Management:
- View all student enrollments
- Manually enroll/drop students
- Override drop deadlines
- Approve retake requests
System Administration:
- Manage departments, semesters, programs
- User management (create, assign roles)
- System settings, integrations
19.5 IT Admin UI
All Admin capabilities PLUS:
System Monitoring:
- Server health, performance metrics
- Error tracking, alerts
- SSL certificate status
Database Management:
- Backup/restore
- Database migrations
- Query performance
Security:
- Audit logs
- IP blocking/unblocking
- Security settings
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
- Lab Submission Enrollment Check: Labs should validate student enrollment like assignments do
- Department Head Course Access: Endpoints for department heads to view/manage department courses
- Waitlist Management: Full waitlist table and enrollment logic
- Course Copy/Duplicate: Clone a course with all materials, assignments, labs
- Bulk Enrollment: Admin enroll multiple students at once
- Grade Export: Export grades to CSV/Excel
- Assignment/Lab Cloning: Duplicate for reuse in future semesters
- Discussion Forums: Per-course discussion boards
- Announcements: Course-wide announcements
- Notifications: Push/email notifications for deadlines, grades
20.2 Recommended Improvements
- Add enrollment check to lab submission endpoints for consistency
- Implement department_head role permissions for course oversight
- Add soft delete to labs (currently hard delete)
- Add attempt tracking to lab submissions (like assignments)
- Implement waitlist with auto-enrollment when seats open
- Add grade curves and grading policies
- Add plagiarism detection integration
- Implement real-time notifications (WebSockets)
- Add course templates for quick setup
- 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