My App
RoomKitBackend

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 requires ExamStorage in 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>
ParameterTypeDescription
dtoCreateExamSessionDtoExam 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[]>
ParameterTypeDescription
filtersobjectFilter criteria
filters.cohortIdstringFilter by cohort ID
filters.timeRange{ start: Date; end: Date }Filter by time range
filters.roomIdstringFilter 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>
ParameterTypeDescription
roomIdstringThe room ID
layoutTypeExamLayoutTypeThe 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.

On this page