Spaces:
Sleeping
Sleeping
copilot-swe-agent[bot]
feat: admin API to assign/remove Instructor and TA for course sections
4e9ee49 Assigning Instructor / TA to a Course Section (Sprint 4)
Overview
This document describes the analysis and implementation plan for the admin API that allows assigning or removing an Instructor or Teaching Assistant (TA) for a specific course section.
Problem Statement
Before this feature, there was no REST API for an admin to directly assign an instructor or TA to a course section.
The database tables (course_instructors, course_tas) and entities already existed but had no corresponding service methods or controller endpoints.
Analysis
Existing Infrastructure
| Component | Location | Status before Sprint 4 |
|---|---|---|
course_instructors table |
DB | β Exists |
course_tas table |
DB | β Exists |
CourseInstructor entity |
src/modules/enrollments/entities/course-instructor.entity.ts |
β Exists |
CourseTA entity |
src/modules/enrollments/entities/course-ta.entity.ts |
β Exists |
EnrollmentsService repositories |
enrollments.service.ts lines 58β60 |
β Injected, unused |
Service methods (assignInstructor, assignTA, β¦) |
enrollments.service.ts |
β Missing |
| Controller endpoints | enrollments.controller.ts |
β Missing |
Entity Schemas
course_instructors
| Column | Type | Notes |
|---|---|---|
assignment_id |
bigint PK | Auto-increment |
section_id |
bigint FK | References course_sections |
user_id |
bigint FK | References users |
role |
enum | primary, co_instructor, guest |
assigned_at |
timestamp | Auto-set on insert |
Unique constraint: (section_id, user_id) β one assignment per user per section.
course_tas
| Column | Type | Notes |
|---|---|---|
assignment_id |
bigint PK | Auto-increment |
user_id |
bigint FK | References users |
section_id |
bigint FK | References course_sections |
responsibilities |
text | Optional TA duties description |
assigned_at |
timestamp | Auto-set on insert |
Unique constraint: (section_id, user_id) β one TA assignment per user per section.
Implementation
New Files
| File | Purpose |
|---|---|
src/modules/enrollments/dto/assign-instructor.dto.ts |
AssignInstructorDto, InstructorAssignmentResponseDto |
src/modules/enrollments/dto/assign-ta.dto.ts |
AssignTADto, TAAssignmentResponseDto |
Modified Files
| File | Changes |
|---|---|
src/modules/enrollments/dto/index.ts |
Exported new DTOs |
src/modules/enrollments/exceptions/index.ts |
Added 6 new exception classes |
src/modules/enrollments/services/enrollments.service.ts |
Added 6 new public methods |
src/modules/enrollments/controllers/enrollments.controller.ts |
Added 6 new endpoints |
API Endpoints
All endpoints are under the base path /api/enrollments and require JWT Bearer authentication.
Instructor Assignment
Assign Instructor to Section
POST /api/enrollments/sections/:sectionId/instructors
- Auth: Bearer JWT
- Roles:
admin - Request Body:
{ "userId": 5, "role": "primary" }userId(required) β ID of the user to assignrole(optional, default:primary) βprimary|co_instructor|guest
- Success:
201 CreatedβInstructorAssignmentResponseDto - Errors:
404section/user not found,409already assigned
Remove Instructor from Section
DELETE /api/enrollments/sections/:sectionId/instructors/:assignmentId
- Auth: Bearer JWT
- Roles:
admin - Success:
204 No Content - Errors:
404section/assignment not found
List Section Instructors
GET /api/enrollments/sections/:sectionId/instructors
- Auth: Bearer JWT
- Roles:
admin,instructor - Success:
200 OKβInstructorAssignmentResponseDto[] - Errors:
404section not found
TA Assignment
Assign TA to Section
POST /api/enrollments/sections/:sectionId/tas
- Auth: Bearer JWT
- Roles:
admin - Request Body:
{ "userId": 7, "responsibilities": "Grading assignments, office hours Mon/Wed" }userId(required) β ID of the user to assignresponsibilities(optional) β free-text description of TA duties
- Success:
201 CreatedβTAAssignmentResponseDto - Errors:
404section/user not found,409already assigned
Remove TA from Section
DELETE /api/enrollments/sections/:sectionId/tas/:assignmentId
- Auth: Bearer JWT
- Roles:
admin - Success:
204 No Content - Errors:
404section/assignment not found
List Section TAs
GET /api/enrollments/sections/:sectionId/tas
- Auth: Bearer JWT
- Roles:
admin,instructor - Success:
200 OKβTAAssignmentResponseDto[] - Errors:
404section not found
Response Shapes
InstructorAssignmentResponseDto
{
"id": 1,
"sectionId": 10,
"userId": 5,
"role": "primary",
"assignedAt": "2026-03-11T20:00:00.000Z",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com"
}
TAAssignmentResponseDto
{
"id": 2,
"sectionId": 10,
"userId": 7,
"responsibilities": "Grading assignments, office hours Mon/Wed",
"assignedAt": "2026-03-11T20:00:00.000Z",
"firstName": "Jane",
"lastName": "Smith",
"email": "jane.smith@example.com"
}
New Exception Classes
| Class | HTTP Status | Message |
|---|---|---|
SectionNotFoundException |
404 | Section with id {id} not found |
UserNotFoundException |
404 | User with id {id} not found |
InstructorAlreadyAssignedException |
409 | This user is already assigned as an instructor for this section |
InstructorAssignmentNotFoundException |
404 | Instructor assignment not found |
TAAlreadyAssignedException |
409 | This user is already assigned as a Teaching Assistant for this section |
TAAssignmentNotFoundException |
404 | Teaching Assistant assignment not found |
Access Control Summary
| Endpoint | Admin | Instructor | TA | Student |
|---|---|---|---|---|
| POST sections/:id/instructors | β | β | β | β |
| DELETE sections/:id/instructors/:aid | β | β | β | β |
| GET sections/:id/instructors | β | β | β | β |
| POST sections/:id/tas | β | β | β | β |
| DELETE sections/:id/tas/:aid | β | β | β | β |
| GET sections/:id/tas | β | β | β | β |
Notes
- No database migrations are required β the tables already exist.
- The
TypeORM synchronize: falsesetting means the schema is managed manually. No changes needed. - The existing
buildEnrollmentResponse()method inenrollments.service.tshas the instructor-loading query commented out (// temporarily disabled). Once sections consistently have instructors assigned via this API, that code can be re-enabled.