ExamService
Manage exam sessions with layout-aware capacity
Overview
ExamService manages exam sessions with layout-aware capacity calculations, cohort overlap validation, and automatic buffer time allocation for setup and teardown. It integrates with the booking system to create bookings that include exam-specific constraints.
This service is optional. Enable with
features: { exams: true }in module options. Also requiresExamStoragein storage config.
import { ExamService } from '@roomkit/nestjs';Methods
createExamSession
Create a new exam session. Checks that the cohort does not overlap with an existing session, calculates capacity for the specified layout type, loads room buffers, creates a booking with buffer times for setup and teardown, creates the exam session, and emits an ExamSessionCreated domain event.
async createExamSession(dto: CreateExamSessionDto): Promise<ExamSession>| Parameter | Type | Description |
|---|---|---|
dto | CreateExamSessionDto | Exam session creation data |
const session = await examService.createExamSession({
roomId: 'room-exam-hall-1',
cohortId: 'cohort-cs101-2026',
layoutType: 'every-other-seat',
requiredCapacity: 45,
supervisorIds: ['staff-1', 'staff-2'],
startsAt: new Date('2026-06-15T09:00:00'),
endsAt: new Date('2026-06-15T12:00:00'),
metadata: { subject: 'CS101', semester: '2026-S1' },
});Throws ExamCohortOverlapError if the cohort already has an overlapping exam session.
Throws CapacityExceededError if the required capacity exceeds the room's capacity for the specified layout type.
Throws RoomNotFoundError if the room does not exist.
findByFilters
Query exam sessions by cohort, time range, or room.
async findByFilters(filters: {
cohortId?: string;
timeRange?: { start: Date; end: Date };
roomId?: string;
}): Promise<ExamSession[]>| Parameter | Type | Description |
|---|---|---|
filters | object | Filter criteria |
filters.cohortId | string | Filter by cohort ID |
filters.timeRange | { start: Date; end: Date } | Filter by time range |
filters.roomId | string | Filter by room ID |
// Find all exams for a cohort
const byCorhort = await examService.findByFilters({
cohortId: 'cohort-cs101-2026',
});
// Find exams in a room during a time range
const byRoomAndTime = await examService.findByFilters({
roomId: 'room-exam-hall-1',
timeRange: {
start: new Date('2026-06-01'),
end: new Date('2026-06-30'),
},
});calculateCapacity
Calculate the effective capacity of a room for a given exam layout type. The every_other_seat layout uses the room's examCapacity field, while full uses the seatedCapacity field.
async calculateCapacity(roomId: string, layoutType: ExamLayoutType): Promise<number>| Parameter | Type | Description |
|---|---|---|
roomId | string | The room ID |
layoutType | ExamLayoutType | The exam seating layout |
const everyOther = await examService.calculateCapacity('room-exam-hall-1', 'every-other-seat');
// Uses room.examCapacity (e.g., 60)
const full = await examService.calculateCapacity('room-exam-hall-1', 'full');
// Uses room.seatedCapacity (e.g., 120)Throws RoomNotFoundError if the room does not exist.
ExamSession
interface ExamSession {
bookingId: string;
cohortId: string;
layoutType: ExamLayoutType;
requiredCapacity: number;
supervisorIds: string[];
metadata: Record<string, unknown>;
}ExamLayoutType
enum ExamLayoutType {
EVERY_OTHER_SEAT = 'every-other-seat',
FULL = 'full',
}The EVERY_OTHER_SEAT layout uses the room's examCapacity to ensure proper spacing between students. The FULL layout uses the room's seatedCapacity for standard seating arrangements.