copilot-swe-agent[bot]
feat: admin API to assign/remove Instructor and TA for course sections
4e9ee49
|
Raw
History Blame Contribute Delete
7.04 kB
# 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**:
```json
{
"userId": 5,
"role": "primary"
}
```
- `userId` *(required)* – ID of the user to assign
- `role` *(optional, default: `primary`)* – `primary` | `co_instructor` | `guest`
- **Success**: `201 Created` β†’ `InstructorAssignmentResponseDto`
- **Errors**: `404` section/user not found, `409` already assigned
#### Remove Instructor from Section
```
DELETE /api/enrollments/sections/:sectionId/instructors/:assignmentId
```
- **Auth**: Bearer JWT
- **Roles**: `admin`
- **Success**: `204 No Content`
- **Errors**: `404` section/assignment not found
#### List Section Instructors
```
GET /api/enrollments/sections/:sectionId/instructors
```
- **Auth**: Bearer JWT
- **Roles**: `admin`, `instructor`
- **Success**: `200 OK` β†’ `InstructorAssignmentResponseDto[]`
- **Errors**: `404` section not found
---
### TA Assignment
#### Assign TA to Section
```
POST /api/enrollments/sections/:sectionId/tas
```
- **Auth**: Bearer JWT
- **Roles**: `admin`
- **Request Body**:
```json
{
"userId": 7,
"responsibilities": "Grading assignments, office hours Mon/Wed"
}
```
- `userId` *(required)* – ID of the user to assign
- `responsibilities` *(optional)* – free-text description of TA duties
- **Success**: `201 Created` β†’ `TAAssignmentResponseDto`
- **Errors**: `404` section/user not found, `409` already assigned
#### Remove TA from Section
```
DELETE /api/enrollments/sections/:sectionId/tas/:assignmentId
```
- **Auth**: Bearer JWT
- **Roles**: `admin`
- **Success**: `204 No Content`
- **Errors**: `404` section/assignment not found
#### List Section TAs
```
GET /api/enrollments/sections/:sectionId/tas
```
- **Auth**: Bearer JWT
- **Roles**: `admin`, `instructor`
- **Success**: `200 OK` β†’ `TAAssignmentResponseDto[]`
- **Errors**: `404` section not found
---
## Response Shapes
### `InstructorAssignmentResponseDto`
```json
{
"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`
```json
{
"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: false` setting means the schema is managed manually. No changes needed.
- The existing `buildEnrollmentResponse()` method in `enrollments.service.ts` has the instructor-loading query commented out (`// temporarily disabled`). Once sections consistently have instructors assigned via this API, that code can be re-enabled.