-
Notifications
You must be signed in to change notification settings - Fork 0
FAC-97 perf: add pagination to curriculum list endpoints #209
Copy link
Copy link
Closed
Labels
Description
title: 'Curriculum list endpoints return unbounded result sets (no pagination)'
severity: Major
category: Performance
labels: [performance, enhancement]
Summary
All three curriculum list endpoints (/departments, /programs, /courses) return the full result set with no pagination, unlike other list endpoints in the codebase that implement page/limit.
Location
- File(s):
src/modules/curriculum/services/curriculum.service.ts(lines 28–67, 69–123, 125–225) - Function/Class:
CurriculumService.ListDepartments,ListPrograms,ListCourses - DTOs:
src/modules/curriculum/dto/requests/*.dto.ts
Problem
The curriculum service returns all matching records with no upper bound. There are no page or limit query parameters in any of the three request DTOs.
// curriculum.service.ts — ListDepartments (same pattern in ListPrograms, ListCourses)
const departments = await this.em.find(Department, filter, {
orderBy: { name: QueryOrder.ASC_NULLS_LAST },
});
// No limit or offset — returns ALL matching rows
return departments.map((d) => DepartmentItemResponseDto.Map(d));Three other modules in the codebase implement pagination on their list endpoints:
admin/dto/requests/list-users-query.dto.ts—page = 1,limit = 20faculty/dto/requests/list-faculty-query.dto.ts—page = 1,limit = 20dimensions/dto/requests/list-dimensions-query.dto.ts—page = 1,limit = 20
Impact
- Memory pressure: A semester with hundreds of departments/programs or thousands of courses would serialize the entire set into memory and transmit it in a single response.
- Response latency: No cap on payload size means unpredictable response times under real data volumes.
- Inconsistency: Consumers already paginate other list endpoints — curriculum endpoints break that contract.
Suggested Fix
Add optional page and limit query params to each request DTO and apply them via MikroORM's limit/offset options, following the established codebase pattern.
// In each request DTO (e.g., ListDepartmentsQueryDto)
@ApiPropertyOptional({ description: 'Page number', default: 1 })
@Type(() => Number)
@IsInt()
@Min(1)
@IsOptional()
page?: number = 1;
@ApiPropertyOptional({ description: 'Items per page', default: 20 })
@Type(() => Number)
@IsInt()
@Min(1)
@Max(100)
@IsOptional()
limit?: number = 20;// In service methods
const departments = await this.em.find(Department, filter, {
orderBy: { name: QueryOrder.ASC_NULLS_LAST },
limit: query.limit,
offset: (query.page - 1) * query.limit,
});Acceptance Criteria
-
ListDepartmentsQueryDto,ListProgramsQueryDto, andListCoursesQueryDtoaccept optionalpageandlimitparameters with sensible defaults - Service methods pass
limitandoffsettoem.find() - Existing tests updated; new tests cover pagination edge cases (first page, last page, out-of-range page)
- Existing tests still pass
Reactions are currently unavailable