Menu

Menu

Close

Close

CourseHen Project

CourseHen

A system for automatically generating university course timetables using constraint-based optimization. It handles complex scheduling requirements such as professor availability, course prerequisites, cross-department courses, and varied time slot patterns.

Overview

The University Course Scheduler is a system for automatically generating university course timetables using constraint-based optimization. It was developed to handle complex scheduling requirements such as professor availability, course prerequisites, cross-department or cross-program courses, and varied time slot patterns. Instead of manually scheduling classes (which is time-consuming and error-prone), this system uses a solver to produce an optimized schedule that meets all specified constraints and preferences. It can manage scheduling across multiple departments and programs simultaneously, ensuring that resources (professors, rooms, time slots) are utilized effectively without conflicts.

Architecture & Components

The application employs a hybrid architecture combining a Node.js/Express backend with a Python constraint solving engine, plus a React frontend for the user interface. All data is stored in a PostgreSQL relational database. The major components are:

- Frontend: A single-page application built with React and TypeScript (using Material-UI for design). This provides an intuitive UI for administrators to input scheduling parameters (courses, professors, availabilities, etc.) and to review or adjust the generated schedules. There are different interfaces for admin tasks (like managing courses and programs) and for professors to submit their availability. The frontend communicates with the backend via REST API calls and visualizes schedules and any conflicts in user-friendly tables/calendars.- Backend API: A server built with Node.js and Express that exposes RESTful endpoints for all scheduling operations. It uses Sequelize ORM to interact with the PostgreSQL database for reading and writing data. This layer handles business logic such as gathering all necessary data for scheduling, initiating the solver process, and applying any manual adjustments. It also implements authentication (likely via JWT) to secure the admin and professor routes.- Scheduler Engine: A Python module that performs the constraint solving using Google's OR-Tools CP-SAT solver. The heavy optimization logic lives here. The Node backend triggers the Python engine (for example, by spawning a separate process) and passes in all relevant data (courses, time slots, professor constraints, etc.) in a structured format. The Python solver then defines the decision variables for each course (assigning course X to professor Y in time slot Z) and applies a series of hard constraints that must be satisfied. These constraints include:- A professor can only teach one class at a time and must be available during the time slot.- A professor must be qualified (authorized) to teach the course assigned to them.- Time slot constraints: e.g., if a course requires a 2-hour block, it should be placed in a matching 2-hour slot; multi-session courses (like Monday/Wednesday classes) should follow the proper pattern (MW, TTh, etc.).- Core courses or required courses should not clash for the same student cohorts, etc. (ensuring no student has two required courses at the same time).After enforcing all hard constraints (which make a schedule valid or not), the solver optimizes for soft goals or objectives. For instance, it may try to maximize the number of courses scheduled (minimize unassigned classes), balance the distribution of classes throughout the week, avoid overloading any single professor, and keep multi-session classes in consistent time slots. OR-Tools CP-SAT finds an optimal or near-optimal assignment given these criteria.
- Database: PostgreSQL is used to store all the academic data and results. Key tables (entities) include Departments, Programs, Courses, Professors, TimeSlots, Semesters, etc., as well as relationships like which courses are in which program, prerequisite mappings, which professors can teach which course, and professors' available times. When a schedule is generated, the results are saved in tables for Schedules and ScheduledCourses (which link a course offering to a professor and time slot) and any Conflicts identified. The database schema is designed with foreign keys to maintain integrity (e.g., a ScheduledCourse links to valid Course, Professor, TimeSlot records).All these components work in concert: for example, an admin uses the React frontend to request a new schedule for next semester; the request goes to Node/Express, which gathers data from Postgres (via Sequelize), calls the Python solver; the solver returns an optimized schedule or any conflicts; Node saves the result to the database and the frontend displays it for the admin to review.

Data Model

The system's data model captures the academic scheduling domain comprehensively. Some key entities and relationships:

- Department – e.g., Computer Science, Mathematics. Departments contain Programs and Courses.- Program – e.g., B.Sc. in Computer Science or M.Sc. in Data Science. Programs belong to a department and have a set of required/elective courses. Courses can be shared by multiple programs (cross-listed) – this is captured via a CourseProgram association table.- Course – an individual course offering (with a course code, title, duration, etc.). Courses may have prerequisites (self-referential relationship, CoursePrerequisite) and may be designated as core or elective in different programs. A course can be scheduled multiple times if it has multiple class sessions (like a lecture and lab, or multiple sections).- Professor – an instructor who can teach courses. Professors have a home department and certain courses they are qualified to teach (ProfessorCourse mapping). They also have specified availabilities (ProfessorAvailability records) indicating which time slots they are free to teach.- TimeSlot – a scheduling slot in the week (e.g., Monday 9:00–10:00 or Tue/Thu 14:00–15:30). Time slots can have attributes like duration and days of week. The system supports varied slot patterns (single period vs. double blocks, MW vs TTh patterns, etc.).- Schedule – a generated timetable for a specific semester (e.g., "Fall 2025 Schedule"). A Schedule is composed of many ScheduledCourse entries.- ScheduledCourse – an assignment of a Course to a specific Professor in a specific TimeSlot as part of a Schedule. If a course meets multiple times a week, there could be multiple ScheduledCourse entries representing each meeting (the solver ensures they follow the required pattern). Each ScheduledCourse can be checked for conflicts.- Conflict – a record of any issue in a generated schedule (for example, a professor double-booked, or an unschedulable course if no suitable slot was found). Conflicts help administrators quickly identify and address problems in the automatically generated schedule, either by adjusting inputs or manually overriding certain assignments.This data model, with its many-to-many relationships and constraint entities, provides the foundation that the solver algorithm uses to ensure all conditions are met.

From

manual

scheduling

to

automated

optimization

Key Features and Constraints

Some of the advanced features and constraints supported by the University Scheduler include:

1. Multi-Program Course Association

Courses can belong to multiple programs or departments, each potentially with different attributes (e.g., a course can be core in one program and elective in another). The scheduler accounts for cross-program courses so that if a course is required in two programs, the schedule avoids conflicts for students taking both. It also handles specifying the number of class instances needed if two programs both require the course (shared courses).

2. Advanced Scheduling Constraints

The system handles a variety of complex rules:

- Professor Availability & Qualification: A professor is only assigned to classes they can teach and at times they are available.- Course Prerequisites and Cohorts: Ensures that courses which should not be taken simultaneously (like a course and its prerequisite, or two core courses of the same cohort) are not scheduled at conflicting times.- Time Slot Compatibility: Matches courses to appropriate length time slots (e.g., a 3-credit course might need two 1.5-hour slots per week on Tue/Thu). It enforces patterns for multi-session courses (e.g., a class that meets M/W/F or Tu/Th, etc., must follow those patterns).- Balanced Schedules: Attempts to distribute classes so that, for example, a program's core courses are spread out over the week and not all clumped on one day (improving student experience).

3. Conflict Detection & Resolution

After generating a schedule, the system automatically identifies any conflicts. For instance, if two courses ended up assigned to the same professor at the same time (which shouldn't happen if constraints are correct, but could if input data had issues) or if a certain course couldn't be scheduled at all due to constraints (unschedulable course). These are logged as Conflict records with explanations. The admin interface highlights conflicts and allows manual resolution: an administrator can override certain assignments or adjust parameters and re-run the solver for just the conflicted parts. This feature ensures that the final schedule presented is feasible and any unresolved issues are clearly flagged.

4. Flexible Time Management

The scheduler supports variable course durations and multiple scheduling patterns. For example, it can schedule courses that meet once per week for 3 hours, or twice a week for 1.5 hours each, etc., depending on how the TimeSlots are configured. It also can accommodate single, double, or triple period classes, and ensures that if a class occupies multiple consecutive slots (like a double-period lab), those slots are available and assigned together. This flexibility is crucial for modeling real university timetables where not all classes have the same format.

Scheduling Algorithm and Integration

At the heart of the system is the constraint solver powered by Google OR-Tools CP-SAT. The Node.js backend gathers all required data and then launches the Python solver process, passing the data via inter-process communication (serialization to JSON). The Python engine formulates the scheduling problem as a Constraint Satisfaction Problem:

- It creates binary decision variables for each possible assignment (e.g., X_{course,prof,timeslot} = 1 if a specific course is assigned to a specific professor at a specific time).- It then adds hard constraints to the model: for each course, exactly one professor-time assignment must be chosen (unless the course is unschedulable); each professor can have at most one assignment per time slot; if a course is multi-session, those sessions must align to the pattern (e.g., if assigned to Monday 9am, also assign to Wednesday 9am for a MW pattern), and so on. All the rules described earlier (availability, prerequisites, etc.) translate into mathematical constraints in this model.- After that, it defines an objective function to maximize schedule quality – e.g., maximize total number of courses scheduled and minimize any gaps or violations of preferences (like uneven distribution).OR-Tools then searches for an optimal solution that satisfies all constraints and optimizes the objective. Once found, the Python solver outputs the results (a set of assignments for all courses) along with any unsatisfiable requirements (conflicts) as a JSON structure.

The integration between Node and Python is carefully designed: the Node backend uses a child process to run the Python script, feeding it input via stdin and reading results from stdout. This decoupling means the solver could even be swapped out or updated independently of the Node API. When the Python solver finishes, the Node process receives the JSON output, then:

1. Saves the schedule results into the database (populating the Schedule and ScheduledCourse tables, and any Conflict table entries). It uses transactions to ensure that partial schedules aren't saved if something failed mid-process, maintaining data integrity.
2. Returns the results to the frontend (the admin UI) via the API response. The user can then review the proposed schedule and any conflict alerts.

All communications are secured via JWT auth on the API, so only authorized users can trigger scheduling or view results. The design also ensures that if the Python solver or Node service crashes, it won't bring down the entire system – they are separate components with defined interaction points.

Deployment and Requirements

To run the University Scheduler, one needs both Node.js (for the backend and frontend build) and Python (for the solver). The project specifies using Node v14+ and Python 3.10 (with OR-Tools library installed). PostgreSQL 14 is used as the database. During deployment, environment variables are used to configure database connection details, JWT secrets, and the paths to the Python interpreter if needed.

In a development setup, one would install Node dependencies (for the frontend and backend), Python dependencies (OR-Tools), set up the Postgres database with initial schema (there might be scripts or Sequelize migrations for this), and then start the backend server and frontend dev server. The backend's ability to spawn the Python process assumes the Python environment is accessible on the same host and has the required solver libraries.

The architecture is designed with separation of concerns, so it would be feasible to containerize each piece (frontend, backend, solver, database) for production. The system's modular design and robust constraint-solving approach make it a powerful tool for university administrators to generate and manage course schedules efficiently.

Optimizing

schedules,

maximizing

efficiency

profile

Let's work together!

Software Engineer | Programmer | Analyst | Cutting-edge tech advocate | Passionate about using technology to make the world a better place.