Skip to content

Courses & Sessions

API fact source: Django backend generated docs

Why CourseOccurrence Exists

courses owns course records, import rules, seasonal schedules, and concrete class session instances. A course record describes what the course is; CourseOccurrence describes the concrete class session on a specific day and period. Classroom schedules, signage display, reservation conflicts, and check-ins consume the latter so each module does not expand timetables independently.

Code entry:

  • backend/apps/courses/models/
  • backend/apps/courses/views.py
  • backend/apps/courses/services/
  • backend/apps/courses/tasks.py

Schedule Configuration

Seasonal class times are controlled by SeasonConfigService and SystemConfig; business code does not hard-code class period times. Successful import can update semester_start_date, which affects future schedule expansion, so import logic and system config write-back belong in the same review.

Why Import Runs Asynchronously

Course import parses Excel, writes course records, and expands class sessions. That work does not fit well in the request thread. Import tasks write to TaskRecord, and uploaded files need to live somewhere the Celery worker can read.

Current import rules include project-specific filters: UC administrative classes are imported directly; other records are limited to floors 2/3 of Building 5; PE courses have special handling. These filters are business policy, not generic Excel parsing logic.

Where Schedule Changes Propagate

  • Changes to CourseOccurrence status or generation logic affect classrooms, borrowings, checkins, and signage call sites.
  • A new schedule source needs a modeling decision: convert it into CourseOccurrence, or accept the cost of parallel occupancy state.
  • Seasonal schedule changes need related cache invalidation.
  • When changing the import template, also check the import service, frontend upload flow, and async task result shape.