# EXAM SCHEDULING SYSTEM - MEMORY BANK **Project:** Exam Planner Desktop Application **Course:** SE302 - Software Engineering **Team:** Team 3, Section 1 **Date Started:** November 26, 2025 **Technology Stack:** Java 17+, JavaFX, SQLite, Maven --- ## TABLE OF CONTENTS 1. [Project Overview](#project-overview) 2. [Team Members & Roles](#team-members--roles) 3. [Requirements Summary](#requirements-summary) 4. [Database Schema](#database-schema) 5. [Architecture & Design Patterns](#architecture--design-patterns) 6. [Algorithm Design](#algorithm-design) 7. [Constraints & Business Rules](#constraints--business-rules) 8. [User Interface Design](#user-interface-design) 9. [API Contracts Between Layers](#api-contracts-between-layers) 10. [Testing Strategy](#testing-strategy) 11. [Development Workflow](#development-workflow) 12. [Key Technical Decisions](#key-technical-decisions) --- ## PROJECT OVERVIEW ### What We're Building A **Windows desktop application** that automatically generates exam schedules for educational institutions by solving a constraint satisfaction problem (CSP). The system assigns exams to classrooms across time slots while respecting hard constraints like student availability and classroom capacity. ### Core Value Proposition - **Automates** a complex, time-consuming manual scheduling process - **Guarantees** all hard constraints are satisfied (no scheduling conflicts) - **Optimizes** according to configurable strategies (minimize days, balance distribution, etc.) - **Provides** multiple views (by classroom, student, course, day) - **Enables** manual adjustments with real-time constraint validation ### Target Users Student Affairs staff at educational institutions who need to: - Schedule exams for 50-500+ students across 10-50+ courses - Manage classroom allocation based on capacity - Ensure no student conflicts (consecutive exams, max 2 per day) - Export schedules for distribution ### Key Success Metrics - **Performance:** Generate schedule for 50 courses/500 students in <10 seconds - **Reliability:** 100% compliance with hard constraints (no violations allowed) - **Usability:** New users can generate first schedule within 30 minutes - **Accuracy:** Zero data corruption, all imports validated --- ## TEAM MEMBERS & ROLES ### Team Roster | Name | Student ID | Role Specialty | Primary Responsibilities | |------|-----------|----------------|------------------------| | Kerem Bozdag | 20200602012 | Database & Data Layer | SQLite schema, DAO pattern, CSV import/export, data validation | | Milena Larissa Ünal | 20230602107 | Algorithm Specialist | CSP backtracking solver, constraint validation, optimization strategies | | Rabia Tülay Gokdag | 20210602029 | UI/FXML Specialist | JavaFX views, FXML layouts, Scene Builder, UI components | | Mehmet Sefa Keskin | 20230602047 | Controller Layer | MVC controllers, event handling, UI-business logic integration | | Feyza Gereme | 20230602028 | Testing & QA | JUnit tests, integration testing, CI/CD setup, test automation | | Emin Arslan | 20230602007 | Documentation & Integration | JavaDoc, user manual, code reviews, feature integration | ### Collaboration Model - **Specialist ownership** with cross-functional support - **Weekly integration meetings** to sync work across layers - **Pull Request reviews** required from at least one other team member - **Pair programming sessions** for complex integration points (UI-Algorithm, Database-Algorithm) --- ## REQUIREMENTS SUMMARY ### Functional Requirements #### FR1: Data Import from CSV - Import 4 types of CSV files: 1. **Student IDs** - List of all students (one per line) 2. **Course Codes** - List of all courses (one per line) 3. **Classroom Capacities** - Format: `ClassroomID;Capacity` (e.g., `Classroom_01;40`) 4. **Attendance Lists** - Student-Course enrollment mapping - **Validation requirements:** - Detect and reject duplicate entries - Validate file format before processing - Show line numbers for errors - **User feedback:** - Progress indicator during import - Summary report (X students imported, Y duplicates rejected) #### FR2: Configuration of Exam Period - User can specify: - **Number of exam days** (e.g., 5 days) - **Number of time slots per day** (e.g., 4 slots) - Total slots = Days × Slots (e.g., 5 × 4 = 20 exam slots) - Validation: Must have enough slots for all courses #### FR3: Optimization Strategy Selection - User chooses one strategy before generation: 1. **Minimize Days Used** - Pack exams into fewest days possible 2. **Balance Distribution** - Spread exams evenly across all days 3. **Minimize Classrooms** - Use fewest classrooms possible 4. **Balance Classrooms Per Day** - Even classroom usage across days - Strategy affects solver's variable/value ordering heuristics #### FR4: Automatic Schedule Generation - **Algorithm:** Backtracking CSP solver with constraint propagation - **Performance targets:** - Small datasets (50 courses, 500 students): <10 seconds - Medium datasets (100 courses, 1000 students): <2 minutes - Large datasets: May take several minutes (show progress) - **User experience:** - Progress indicator with percentage complete - "Cancel" button to abort long-running generations - Success/failure notification with details #### FR5: Multi-View Schedule Display Four distinct view modes: 1. **Classroom View** - Shows: Which exams are in which classrooms - Columns: Classroom ID, Day, Time Slot, Course Code, Student Count 2. **Student View** - Shows: Personal exam schedule for each student - Columns: Student ID, Course Code, Day, Time Slot, Classroom - Filterable by student ID 3. **Course View** - Shows: Exact time and classroom for each course exam - Columns: Course Code, Day, Time Slot, Classroom, Enrolled Count 4. **Day View** - Shows: All exams scheduled for each day/time slot - Grid format: Days (rows) × Time Slots (columns) - Cell contents: Course codes in that slot #### FR6: Export to CSV and Excel - **CSV Export:** Simple comma-separated format for each view - **Excel Export:** - Multi-sheet workbook (one sheet per view) - Formatted headers, borders, column widths - Ready for printing - User can choose export format and destination folder #### FR7: Manual Schedule Adjustments - **Allowed operations:** - Move exam to different time slot - Move exam to different classroom - Swap two exams - **Constraint validation:** - System checks all constraints before applying change - If any constraint would be violated, reject change - Show specific error message explaining which constraint prevents the change - **Limitations:** Cannot change student enrollments or classroom capacities #### FR8: Database Persistence (SQLite) - **Local storage:** All data persisted in local SQLite file - **Saved data:** - Imported student/course/classroom data - Generated schedules with metadata (creation date, optimization strategy) - User configuration settings - **Operations:** - Save current schedule - Load previously saved schedule - Delete old schedules #### FR10: Conflict Detection and Reporting - **When no solution exists:** - Identify which constraints cannot be satisfied - Report specific conflicts: - Student X has 3 exams on Day Y (violates max 2 per day) - Course Z has 50 students but max classroom capacity is 40 - Students A, B, C have consecutive exam conflicts - **Recommendations:** - Extend exam period (add more days/slots) - Add classrooms with higher capacity - Reduce course enrollments - Alternative: Release consecutive exam constraint (not recommended) #### FR12: Schedule History - **View previous schedules** with metadata: - Creation date and time - Optimization strategy used - Number of days/slots configured - Course/student counts - **Operations:** - Load and view any historical schedule - Compare different schedule versions - Export historical schedules ### Non-Functional Requirements #### NFR1: Usability - **Learning curve:** New users can generate first schedule within 30 minutes - **Interface clarity:** Intuitive labels, clear navigation, logical workflow - **Help system:** Built-in user manual with screenshots and examples - **Error messages:** Clear, actionable, non-technical language #### NFR2: Error Messaging Standards - **Format:** "[Context] Problem detected: [Specific issue]. [Suggested fix]" - **Examples:** - ✅ GOOD: "Import failed: Duplicate student ID 'Std_ID_123' found on lines 45 and 67. Remove duplicate entry and try again." - ❌ BAD: "Error: Duplicate key violation in students table" - **Guidelines:** - Always include line numbers for file import errors - Suggest specific corrective actions - Avoid technical jargon (no SQL errors, stack traces to users) #### NFR3: Performance - **Small datasets:** <10 seconds for 50 courses, 500 students - **Responsiveness:** UI remains responsive during generation (background thread) - **Database queries:** Optimized with proper indexes (<100ms for typical queries) #### NFR4: Reliability - **No crashes:** Graceful error handling for all edge cases - **Data integrity:** ACID transactions for all database operations - **Validation:** All user inputs validated before processing - **Backup:** Export capability serves as backup mechanism #### NFR6: Maintainability - **Code organization:** Clear package structure following MVC pattern - **Naming conventions:** Java standard conventions (camelCase, PascalCase) - **Documentation:** JavaDoc for all public methods and classes - **Comments:** Explain "why" for complex algorithms, not obvious "what" - **Extensibility:** Easy to add new optimization strategies, export formats, constraints --- ## DATABASE SCHEMA ### Entity-Relationship Model ``` ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │ Student │ │ Enrollment │ │ Course │ ├─────────────┤ ├──────────────┤ ├──────────────┤ │ student_id │◄───────►│ student_id │◄───────►│ course_code │ │ │ (M:N) │ course_code │ (M:N)│ │ └─────────────┘ └──────────────┘ └──────────────┘ │ │ (1:M) ▼ ┌──────────────┐ ┌─────────────────┐ │ Classroom │◄────────│ ExamAssignment │ ├──────────────┤ (1:M) ├─────────────────┤ │ classroom_id │ │ exam_id │ │ capacity │ │ course_code │ └──────────────┘ │ classroom_id │ │ day │ │ time_slot │ ┌──────────────┐ │ schedule_id │ │ Schedule │◄────────│ │ ├──────────────┤ (1:M) └─────────────────┘ │ schedule_id │ │ created_date │ │ strategy │ │ num_days │ │ slots_per_day│ └──────────────┘ ``` ### Table Definitions (SQLite) #### 1. students ```sql CREATE TABLE students ( student_id TEXT PRIMARY KEY NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` - **Purpose:** Store all student records - **Sample data:** Std_ID_001, Std_ID_002, ..., Std_ID_250 #### 2. courses ```sql CREATE TABLE courses ( course_code TEXT PRIMARY KEY NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` - **Purpose:** Store all course records - **Sample data:** CourseCode_01, CourseCode_02, ..., CourseCode_20 #### 3. classrooms ```sql CREATE TABLE classrooms ( classroom_id TEXT PRIMARY KEY NOT NULL, capacity INTEGER NOT NULL CHECK(capacity > 0), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` - **Purpose:** Store classroom information with seating capacity - **Sample data:** Classroom_01 (capacity: 40), Classroom_02 (capacity: 40), etc. - **Validation:** Capacity must be positive integer #### 4. enrollments ```sql CREATE TABLE enrollments ( enrollment_id INTEGER PRIMARY KEY AUTOINCREMENT, student_id TEXT NOT NULL, course_code TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (student_id) REFERENCES students(student_id) ON DELETE CASCADE, FOREIGN KEY (course_code) REFERENCES courses(course_code) ON DELETE CASCADE, UNIQUE(student_id, course_code) ); CREATE INDEX idx_enrollments_student ON enrollments(student_id); CREATE INDEX idx_enrollments_course ON enrollments(course_code); ``` - **Purpose:** Many-to-many relationship between students and courses - **Uniqueness:** One enrollment record per student-course pair - **Indexes:** Fast lookups for "which courses for student X" and "which students in course Y" #### 5. schedules ```sql CREATE TABLE schedules ( schedule_id INTEGER PRIMARY KEY AUTOINCREMENT, created_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, optimization_strategy TEXT NOT NULL, num_days INTEGER NOT NULL CHECK(num_days > 0), slots_per_day INTEGER NOT NULL CHECK(slots_per_day > 0), status TEXT DEFAULT 'generated' CHECK(status IN ('generated', 'saved', 'archived')) ); ``` - **Purpose:** Store metadata for each generated schedule - **Optimization strategies:** 'minimize_days', 'balance_distribution', 'minimize_classrooms', 'balance_classrooms' - **Status values:** - 'generated' - Just created - 'saved' - User explicitly saved - 'archived' - Old schedule kept for history #### 6. exam_assignments ```sql CREATE TABLE exam_assignments ( exam_id INTEGER PRIMARY KEY AUTOINCREMENT, schedule_id INTEGER NOT NULL, course_code TEXT NOT NULL, classroom_id TEXT NOT NULL, day INTEGER NOT NULL CHECK(day > 0), time_slot INTEGER NOT NULL CHECK(time_slot > 0), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (schedule_id) REFERENCES schedules(schedule_id) ON DELETE CASCADE, FOREIGN KEY (course_code) REFERENCES courses(course_code) ON DELETE CASCADE, FOREIGN KEY (classroom_id) REFERENCES classrooms(classroom_id) ON DELETE CASCADE, UNIQUE(schedule_id, course_code), UNIQUE(schedule_id, classroom_id, day, time_slot) ); CREATE INDEX idx_assignments_schedule ON exam_assignments(schedule_id); CREATE INDEX idx_assignments_course ON exam_assignments(course_code); CREATE INDEX idx_assignments_classroom_time ON exam_assignments(classroom_id, day, time_slot); ``` - **Purpose:** Store exam scheduling assignments (which course in which room at what time) - **Uniqueness constraints:** - Each course appears once per schedule - Each classroom-day-timeslot combination used once per schedule - **Indexes:** Fast lookups for schedule queries, course lookups, and classroom availability checks ### Sample Data Statistics Based on provided sample data: - **Students:** 250 (Std_ID_001 to Std_ID_250) - **Courses:** 20 (CourseCode_01 to CourseCode_20) - **Classrooms:** 10 (Classroom_01 to Classroom_10, each capacity 40) - **Average enrollments per course:** ~40 students - **Total enrollment records:** ~800 (20 courses × ~40 students) ### Database File Location - **Development:** `./data/exam_scheduler.db` - **Production:** User's Documents folder or configurable path - **Backup:** Auto-export to CSV on schedule save --- ## ARCHITECTURE & DESIGN PATTERNS ### Overall Architecture: MVC (Model-View-Controller) ``` ┌─────────────────────────────────────────────────────────────┐ │ VIEW LAYER │ │ (JavaFX FXML + Scene Builder) │ │ │ │ • ImportView.fxml • ScheduleView.fxml │ │ • ConfigurationView.fxml • ClassroomView.fxml │ │ • StudentView.fxml • CourseView.fxml │ │ • DayView.fxml • ExportView.fxml │ └──────────────────┬──────────────────────────────────────────┘ │ User Events (button clicks, etc.) ▼ ┌─────────────────────────────────────────────────────────────┐ │ CONTROLLER LAYER │ │ (JavaFX Controllers) │ │ │ │ • ImportController • ScheduleController │ │ • ConfigurationController • ViewControllers │ │ • ExportController • MainController │ └──────────────────┬──────────────────────────────────────────┘ │ Method calls ▼ ┌─────────────────────────────────────────────────────────────┐ │ BUSINESS LOGIC LAYER │ │ (Service Classes) │ │ │ │ • ScheduleService • ImportService │ │ • CSPSolver • ExportService │ │ • ConstraintValidator • ConfigurationService │ │ • OptimizationStrategy • ConflictDetector │ └──────────────────┬──────────────────────────────────────────┘ │ Data operations ▼ ┌─────────────────────────────────────────────────────────────┐ │ DATA ACCESS LAYER │ │ (DAO Pattern) │ │ │ │ • StudentDAO • ScheduleDAO │ │ • CourseDAO • ExamAssignmentDAO │ │ • ClassroomDAO • EnrollmentDAO │ │ • DatabaseConnection • TransactionManager │ └──────────────────┬──────────────────────────────────────────┘ │ SQL queries ▼ ┌─────────────────────────────────────────────────────────────┐ │ DATA LAYER │ │ (SQLite Database) │ │ │ │ exam_scheduler.db │ └─────────────────────────────────────────────────────────────┘ ``` ### Package Structure ``` src/main/java/ ├── com.se302.examscheduler/ │ ├── model/ # Domain Models (POJOs) │ │ ├── Student.java │ │ ├── Course.java │ │ ├── Classroom.java │ │ ├── Enrollment.java │ │ ├── Schedule.java │ │ ├── ExamAssignment.java │ │ └── ScheduleConfiguration.java │ │ │ ├── dao/ # Data Access Objects │ │ ├── StudentDAO.java │ │ ├── CourseDAO.java │ │ ├── ClassroomDAO.java │ │ ├── EnrollmentDAO.java │ │ ├── ScheduleDAO.java │ │ ├── ExamAssignmentDAO.java │ │ └── DatabaseConnection.java │ │ │ ├── service/ # Business Logic │ │ ├── ScheduleService.java │ │ ├── ImportService.java │ │ ├── ExportService.java │ │ ├── ConfigurationService.java │ │ └── ValidationService.java │ │ │ ├── algorithm/ # CSP Solver │ │ ├── CSPSolver.java │ │ ├── ConstraintValidator.java │ │ ├── ConflictDetector.java │ │ ├── strategy/ │ │ │ ├── OptimizationStrategy.java (interface) │ │ │ ├── MinimizeDaysStrategy.java │ │ │ ├── BalanceDistributionStrategy.java │ │ │ ├── MinimizeClassroomsStrategy.java │ │ │ └── BalanceClassroomsStrategy.java │ │ └── heuristics/ │ │ ├── VariableOrderingHeuristic.java │ │ └── ValueOrderingHeuristic.java │ │ │ ├── controller/ # JavaFX Controllers │ │ ├── MainController.java │ │ ├── ImportController.java │ │ ├── ConfigurationController.java │ │ ├── ScheduleController.java │ │ ├── ClassroomViewController.java │ │ ├── StudentViewController.java │ │ ├── CourseViewController.java │ │ ├── DayViewController.java │ │ └── ExportController.java │ │ │ ├── util/ # Utility Classes │ │ ├── CSVParser.java │ │ ├── ExcelExporter.java │ │ ├── ValidationUtil.java │ │ └── ProgressTracker.java │ │ │ └── Main.java # Application Entry Point │ src/main/resources/ ├── fxml/ # FXML Layout Files │ ├── MainWindow.fxml │ ├── ImportView.fxml │ ├── ConfigurationView.fxml │ ├── ScheduleView.fxml │ ├── ClassroomView.fxml │ ├── StudentView.fxml │ ├── CourseView.fxml │ ├── DayView.fxml │ └── ExportView.fxml │ ├── css/ # Stylesheets │ └── styles.css │ ├── images/ # Icons and images │ └── database/ └── schema.sql # Database initialization script src/test/java/ ├── com.se302.examscheduler/ │ ├── dao/ # DAO Tests │ ├── service/ # Service Tests │ ├── algorithm/ # Algorithm Tests │ └── integration/ # Integration Tests ``` ### Design Patterns Used #### 1. DAO (Data Access Object) Pattern - **Purpose:** Separate data access logic from business logic - **Implementation:** One DAO class per entity (StudentDAO, CourseDAO, etc.) - **Benefits:** Easy to mock for testing, can swap database implementations #### 2. Strategy Pattern (Optimization Strategies) - **Purpose:** Allow different scheduling optimization algorithms to be swapped at runtime - **Implementation:** `OptimizationStrategy` interface with concrete implementations - **Benefits:** Easy to add new strategies without modifying solver code #### 3. Singleton Pattern (Database Connection) - **Purpose:** Ensure only one database connection pool exists - **Implementation:** `DatabaseConnection.getInstance()` - **Benefits:** Resource efficiency, consistent connection management #### 4. Observer Pattern (Progress Tracking) - **Purpose:** UI observes long-running algorithm execution - **Implementation:** `ProgressTracker` with listeners, JavaFX `Task` - **Benefits:** Responsive UI, can show progress and allow cancellation #### 5. Factory Pattern (DAO Creation) - **Purpose:** Centralize DAO instance creation - **Implementation:** `DAOFactory` class - **Benefits:** Easier testing, dependency injection --- ## ALGORITHM DESIGN ### Backtracking CSP Solver Architecture #### Problem Definition (CSP Formulation) **Variables:** - Each **course** is a variable that needs assignment - Example: `CourseCode_01`, `CourseCode_02`, ..., `CourseCode_20` **Domain (Possible Values):** - Each variable can be assigned to a **{Classroom, Day, TimeSlot}** triple - Example domain for a course with 35 students: ``` {(Classroom_01, 1, 1), (Classroom_01, 1, 2), ..., (Classroom_02, 1, 1), (Classroom_02, 1, 2), ..., (Classroom_10, 5, 4)} ``` - Domain is pre-filtered to remove impossible assignments (e.g., classroom too small) **Constraints:** 1. **No consecutive exams for any student** (Hard) 2. **Max 2 exams per student per day** (Hard) 3. **Classroom capacity must not be exceeded** (Hard) 4. **Each course scheduled exactly once** (Implicit in CSP formulation) 5. **No classroom double-booking** (Implicit - each {classroom, day, slot} used once) #### Backtracking Algorithm Pseudocode ``` function BACKTRACK-CSP(assignment, csp): if assignment is complete: return assignment var = SELECT-UNASSIGNED-VARIABLE(csp, assignment) for each value in ORDER-DOMAIN-VALUES(var, assignment, csp): if value is consistent with assignment (satisfies all constraints): add {var = value} to assignment # Constraint propagation (forward checking) inferences = INFER(csp, var, value) if inferences ≠ failure: add inferences to assignment result = BACKTRACK-CSP(assignment, csp) if result ≠ failure: return result remove {var = value} and inferences from assignment return failure ``` #### Heuristic 1: Variable Ordering (SELECT-UNASSIGNED-VARIABLE) **Strategy: Minimum Remaining Values (MRV)** - Select the course with the **fewest valid domain values** remaining - Rationale: Fail fast on difficult assignments, prune search space early - Tie-breaking: Choose course with most students (harder to place) ```java public Course selectUnassignedVariable(Assignment assignment) { Course minCourse = null; int minDomainSize = Integer.MAX_VALUE; for (Course course : unassignedCourses) { int domainSize = calculateValidDomainSize(course, assignment); if (domainSize < minDomainSize) { minDomainSize = domainSize; minCourse = course; } } return minCourse; } ``` #### Heuristic 2: Value Ordering (ORDER-DOMAIN-VALUES) **Strategy: Least Constraining Value** - Select the {classroom, day, slot} that **leaves most flexibility** for remaining courses - Rationale: Maximize future options, avoid dead-ends **Optimization Strategy Influence:** - **Minimize Days:** Prefer earlier days, earlier slots - **Balance Distribution:** Prefer days/slots with fewer assignments - **Minimize Classrooms:** Prefer already-used classrooms - **Balance Classrooms:** Prefer classrooms with fewer assignments ```java public List orderDomainValues(Course course, OptimizationStrategy strategy) { List domain = getValidAssignments(course); // Sort based on optimization strategy domain.sort((a1, a2) -> strategy.compareAssignments(a1, a2)); return domain; } ``` #### Constraint Checking Functions **1. No Consecutive Exams Constraint** ```java public boolean checkNoConsecutiveExams(Course course, int day, int slot, Assignment assignment) { Set enrolledStudents = getEnrolledStudents(course); for (Student student : enrolledStudents) { // Check if student has exam in previous slot if (slot > 1 && hasExamInSlot(student, day, slot - 1, assignment)) { return false; } // Check if student has exam in next slot if (slot < slotsPerDay && hasExamInSlot(student, day, slot + 1, assignment)) { return false; } // Check boundary with previous day if (slot == 1 && day > 1 && hasExamInSlot(student, day - 1, slotsPerDay, assignment)) { return false; } // Check boundary with next day if (slot == slotsPerDay && day < numDays && hasExamInSlot(student, day + 1, 1, assignment)) { return false; } } return true; } ``` **2. Max 2 Exams Per Day Constraint** ```java public boolean checkMaxTwoExamsPerDay(Course course, int day, Assignment assignment) { Set enrolledStudents = getEnrolledStudents(course); for (Student student : enrolledStudents) { int examsOnDay = countExamsForStudentOnDay(student, day, assignment); if (examsOnDay >= 2) { return false; // Would cause student to have 3+ exams on this day } } return true; } ``` **3. Classroom Capacity Constraint** ```java public boolean checkClassroomCapacity(Course course, Classroom classroom) { int enrolledCount = getEnrolledStudentCount(course); return enrolledCount <= classroom.getCapacity(); } ``` #### Forward Checking (Constraint Propagation) After assigning a course, reduce domains of unassigned courses: - Remove {classroom, day, slot} if it's now occupied - Remove consecutive slots for students in this course - Remove same-day slots if students already have 2 exams that day ```java public Map> forwardCheck(Course assigned, Assignment value) { Map> removedValues = new HashMap<>(); Set students = getEnrolledStudents(assigned); for (Course unassigned : unassignedCourses) { Set toRemove = new HashSet<>(); Set unassignedStudents = getEnrolledStudents(unassigned); // If courses share students, check constraints Set overlap = intersection(students, unassignedStudents); if (!overlap.isEmpty()) { for (Assignment a : getDomain(unassigned)) { if (violatesConstraintWith(a, value, overlap)) { toRemove.add(a); } } } if (!toRemove.isEmpty()) { removedValues.put(unassigned, toRemove); getDomain(unassigned).removeAll(toRemove); } } return removedValues; } ``` #### Conflict Detection (When No Solution Exists) If backtracking exhausts all possibilities without finding a solution: ```java public ConflictReport analyzeFailure() { ConflictReport report = new ConflictReport(); // Find students with too many courses for available slots for (Student student : students) { int courseCount = getEnrolledCourseCount(student); int maxPossibleExams = numDays * 2; // Max 2 per day if (courseCount > maxPossibleExams) { report.addConflict(student, "Enrolled in " + courseCount + " courses but only " + maxPossibleExams + " slots available"); } } // Find courses with insufficient classroom capacity for (Course course : courses) { int enrolledCount = getEnrolledStudentCount(course); int maxCapacity = getMaxClassroomCapacity(); if (enrolledCount > maxCapacity) { report.addConflict(course, "Enrolled count " + enrolledCount + " exceeds max classroom capacity " + maxCapacity); } } // Find groups of students with too many overlapping enrollments // (complex graph analysis - detect cliques in conflict graph) return report; } ``` #### Performance Optimizations 1. **Pre-compute enrollment mappings:** - `Map>` - students in each course - `Map>` - courses for each student - Avoids repeated database queries during backtracking 2. **Domain pre-filtering:** - Eliminate classroom assignments where capacity < enrolled count - Reduce domain size before backtracking starts 3. **Early termination checks:** - If any course has empty domain, fail immediately - If student has more courses than max possible slots, fail immediately 4. **Memoization:** - Cache constraint check results for repeated {student, day, slot} combinations 5. **Parallel domain evaluation:** - Use Java streams to evaluate constraint checks in parallel - Useful for large student sets #### Progress Tracking ```java public class CSPSolver { private ProgressTracker progressTracker; private volatile boolean cancelled = false; public Schedule solve(ScheduleConfiguration config) { int totalCourses = courses.size(); int assignedCourses = 0; while (assignedCourses < totalCourses && !cancelled) { // Backtracking logic assignedCourses++; progressTracker.updateProgress(assignedCourses, totalCourses); } if (cancelled) { throw new CancelledException(); } return buildSchedule(assignment); } public void cancel() { this.cancelled = true; } } ``` --- ## CONSTRAINTS & BUSINESS RULES ### Hard Constraints (CANNOT be violated) #### Constraint 1: No Consecutive Exams for Students **Definition:** If a student has an exam in time slot N, they CANNOT have another exam in time slot N+1 (immediately following). **Rationale:** Students need break time between exams to rest, review, and travel between exam locations. **Edge Cases:** - **Day boundaries:** If a student has an exam in the last slot of Day 1, they CAN have an exam in the first slot of Day 2 (not considered consecutive because of overnight break) - **UPDATE:** Actually, slots are numbered sequentially across days, so slot 4 of Day 1 and slot 1 of Day 2 ARE consecutive. Need to check this in implementation. - **First/last slots:** No previous/next slot to check **Validation Logic:** ```java public boolean validateNoConsecutiveExams(Student student, int day, int slot, Assignment assignment) { // Calculate absolute slot number (for sequential numbering across days) int absoluteSlot = (day - 1) * slotsPerDay + slot; // Check previous slot if (absoluteSlot > 1) { int prevDay = (absoluteSlot - 2) / slotsPerDay + 1; int prevSlot = (absoluteSlot - 2) % slotsPerDay + 1; if (hasExam(student, prevDay, prevSlot, assignment)) { return false; } } // Check next slot int totalSlots = numDays * slotsPerDay; if (absoluteSlot < totalSlots) { int nextDay = absoluteSlot / slotsPerDay + 1; int nextSlot = absoluteSlot % slotsPerDay + 1; if (hasExam(student, nextDay, nextSlot, assignment)) { return false; } } return true; } ``` **Error Message Template:** "Cannot assign [Course] to [Day] [Slot]: Student [StudentID] already has an exam in the consecutive slot [Day] [Slot]." --- #### Constraint 2: Maximum 2 Exams Per Student Per Day **Definition:** A student cannot have more than 2 exams on any single day. **Rationale:** More than 2 exams per day is excessively stressful and reduces exam quality/fairness. **Edge Cases:** - Student enrolled in only 1-2 courses total: Always satisfiable - Student enrolled in 10+ courses over 5 days: May be impossible to satisfy both this constraint and consecutive constraint **Validation Logic:** ```java public boolean validateMaxTwoExamsPerDay(Student student, int day, Assignment assignment) { int examsOnDay = 0; for (int slot = 1; slot <= slotsPerDay; slot++) { if (hasExam(student, day, slot, assignment)) { examsOnDay++; } } return examsOnDay < 2; // Currently has 0 or 1, so can add one more } ``` **Error Message Template:** "Cannot assign [Course] to [Day]: Student [StudentID] already has 2 exams on this day." --- #### Constraint 3: Classroom Capacity Must Not Be Exceeded **Definition:** The number of students enrolled in a course (who will take the exam) cannot exceed the seating capacity of the assigned classroom. **Rationale:** Physical limitation - cannot fit more students than seats available. **Edge Cases:** - Course with 0 students enrolled: Can be assigned to any classroom (but shouldn't appear in schedule at all) - Multiple classrooms needed: Current design doesn't support splitting one exam across multiple classrooms (would need extension) **Validation Logic:** ```java public boolean validateClassroomCapacity(Course course, Classroom classroom) { int enrolledCount = getEnrolledStudentCount(course); return enrolledCount <= classroom.getCapacity(); } ``` **Error Message Template:** "Cannot assign [Course] to [Classroom]: Course has [X] students but classroom capacity is only [Y]." --- #### Constraint 4: Each Course Scheduled Exactly Once (Implicit) **Definition:** Every course must appear in the schedule exactly one time (one exam per course). **Rationale:** Business requirement - each course needs one exam during the exam period. **Implementation:** - CSP formulation ensures this (each course is a variable assigned exactly one value) - Database uniqueness constraint: `UNIQUE(schedule_id, course_code)` --- #### Constraint 5: No Classroom Double-Booking (Implicit) **Definition:** A classroom cannot host two exams at the same time (same day + time slot). **Rationale:** Physical limitation - one room can only hold one exam at a time. **Implementation:** - CSP domain ensures each {classroom, day, slot} used at most once - Database uniqueness constraint: `UNIQUE(schedule_id, classroom_id, day, time_slot)` --- ### Soft Constraints (Optimization Objectives) These are preferences, not requirements. They guide the solver's heuristics but can be violated if necessary. #### Soft Constraint 1: Minimize Days Used - **Objective:** Pack exams into as few days as possible - **Heuristic:** Prefer earlier days when ordering domain values - **Use case:** Shorter exam period, reduce facility costs #### Soft Constraint 2: Balance Distribution Across Days - **Objective:** Spread exams evenly across all available days - **Heuristic:** Prefer days with fewer assigned exams - **Use case:** Reduce student stress, balance proctoring workload #### Soft Constraint 3: Minimize Classrooms Used - **Objective:** Use as few different classrooms as possible - **Heuristic:** Prefer already-assigned classrooms - **Use case:** Reduce setup costs, centralize exam locations #### Soft Constraint 4: Balance Classrooms Per Day - **Objective:** Use similar number of classrooms each day - **Heuristic:** Prefer days with fewer classrooms in use - **Use case:** Balance proctoring staff assignments --- ### Business Rules #### Rule 1: Data Import Validation - No duplicate student IDs in imported file - No duplicate course codes in imported file - No duplicate classroom IDs in imported file - Enrollment records must reference existing students and courses - Classroom capacity must be positive integer - CSV files must have correct format (specific delimiters, expected columns) #### Rule 2: Configuration Validation - Number of days must be positive integer (1-30 reasonable range) - Number of slots per day must be positive integer (1-6 reasonable range) - Total available slots (days × slots) must be ≥ number of courses - At least one classroom must exist - At least one student must exist - At least one course must exist #### Rule 3: Schedule Generation Preconditions - All required data imported (students, courses, classrooms, enrollments) - Configuration set (days, slots, optimization strategy) - Database connection available #### Rule 4: Manual Edit Validation - Can only edit existing schedules (cannot edit during generation) - All hard constraints must still be satisfied after edit - Cannot change student enrollments via manual edit (data integrity) - Cannot change classroom capacity via manual edit #### Rule 5: Export Requirements - Schedule must be fully generated (all courses assigned) - User must specify output file path and format (CSV or Excel) - File path must be writable --- ## USER INTERFACE DESIGN ### Main Window Layout ``` ┌────────────────────────────────────────────────────────────────┐ │ Exam Scheduler [_] [□] [X] │ ├────────────────────────────────────────────────────────────────┤ │ File Edit View Help │ ├────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────┐ ┌────────────────────────────────────┐ │ │ │ │ │ │ │ │ │ NAVIGATION │ │ CONTENT AREA │ │ │ │ PANEL │ │ │ │ │ │ │ │ (Dynamic - changes based on │ │ │ │ • Import Data │ │ selected navigation item) │ │ │ │ • Configure │ │ │ │ │ │ • Generate │ │ │ │ │ │ • View Schedule │ │ │ │ │ │ • Export │ │ │ │ │ │ • History │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─────────────────┘ └────────────────────────────────────┘ │ │ │ ├────────────────────────────────────────────────────────────────┤ │ Status: Ready │ └────────────────────────────────────────────────────────────────┘ ``` ### View 1: Import Data View **Purpose:** Import CSV files with validation feedback **Layout:** ``` Import Data ─────────────────────────────────────────────────────── Students File: [/path/to/students.csv ] [Browse...] Courses File: [/path/to/courses.csv ] [Browse...] Classrooms File: [/path/to/classrooms.csv ] [Browse...] Enrollments File: [/path/to/enrollments.csv ] [Browse...] [Import All] [Clear] Import Results: ┌─────────────────────────────────────────────────────┐ │ ✓ Students: 250 imported, 0 duplicates rejected │ │ ✓ Courses: 20 imported, 0 duplicates rejected │ │ ✓ Classrooms: 10 imported, 0 duplicates rejected │ │ ✓ Enrollments: 800 imported, 0 errors │ └─────────────────────────────────────────────────────┘ ``` **Key Components:** - File path text fields (read-only) - Browse buttons (open file dialog) - Import All button (validates and imports all files) - Results text area (shows success/error messages with line numbers) --- ### View 2: Configuration View **Purpose:** Set exam period parameters and optimization strategy **Layout:** ``` Schedule Configuration ─────────────────────────────────────────────────────── Exam Period: Number of Days: [5 ] days Time Slots Per Day: [4 ] slots Total Available Slots: 20 slots Total Courses: 20 courses ✓ Sufficient slots available Optimization Strategy: ○ Minimize Days Used ● Balance Distribution Across Days ○ Minimize Classrooms Needed ○ Balance Classrooms Per Day [Save Configuration] ``` **Key Components:** - Number spinners for days and slots (with validation) - Calculated field for total slots - Radio buttons for optimization strategy selection - Save button (enables Generate view) --- ### View 3: Generate Schedule View **Purpose:** Run scheduling algorithm with progress feedback **Layout:** ``` Generate Schedule ─────────────────────────────────────────────────────── Configuration: Exam Period: 5 days × 4 slots = 20 total slots Strategy: Balance Distribution Across Days Courses: 20 Students: 250 [ ] Generating schedule... 12 / 20 courses assigned (60%) Estimated time remaining: 8 seconds [Cancel] Recent Generations: ┌─────────────────────────────────────────────────────┐ │ 2025-11-26 10:30 - Balance Distribution - Success │ │ 2025-11-26 09:15 - Minimize Days - Success │ └─────────────────────────────────────────────────────┘ ``` **Key Components:** - Configuration summary (read-only) - Progress bar (animated during generation) - Status text (updates in real-time) - Cancel button (aborts generation) - Recent generations list (clickable to load previous schedules) **Success State:** ``` ✓ Schedule Generated Successfully! All 20 courses assigned All constraints satisfied Generation time: 3.2 seconds [View Schedule] [Export] ``` **Failure State:** ``` ✗ Schedule Generation Failed Unable to satisfy all constraints. Conflicts detected: • Student Std_ID_042 enrolled in 15 courses (max 10 possible) • CourseCode_15 has 55 students (max classroom capacity: 40) Recommendations: • Extend exam period to 7 days • Add classroom with capacity ≥55 • Reduce enrollments for affected students [View Conflicts] [Adjust Configuration] ``` --- ### View 4: Schedule Views (4 Sub-Views) #### 4A: Classroom View **Purpose:** Show which exams are in which classrooms **Layout:** ``` Schedule - Classroom View ─────────────────────────────────────────────────────── Filter: [All Classrooms ▼] Day: [All Days ▼] ┌────────────┬─────┬──────┬────────────┬─────────────┐ │ Classroom │ Day │ Slot │ Course │ Students │ ├────────────┼─────┼──────┼────────────┼─────────────┤ │ Room_01 │ 1 │ 1 │ Course_01 │ 40 │ │ Room_01 │ 1 │ 2 │ Course_05 │ 38 │ │ Room_01 │ 2 │ 1 │ Course_12 │ 40 │ │ Room_02 │ 1 │ 1 │ Course_02 │ 35 │ │ ... │ ... │ ... │ ... │ ... │ └────────────┴─────┴──────┴────────────┴─────────────┘ [Export View] [Edit] ``` #### 4B: Student View **Purpose:** Show personal exam schedule for each student **Layout:** ``` Schedule - Student View ─────────────────────────────────────────────────────── Search Student: [Std_ID_042 ] [Search] ┌─────────────┬────────────┬─────┬──────┬────────────┐ │ Student ID │ Course │ Day │ Slot │ Classroom │ ├─────────────┼────────────┼─────┼──────┼────────────┤ │ Std_ID_042 │ Course_01 │ 1 │ 1 │ Room_01 │ │ Std_ID_042 │ Course_07 │ 1 │ 3 │ Room_03 │ │ Std_ID_042 │ Course_12 │ 2 │ 1 │ Room_01 │ │ Std_ID_042 │ Course_18 │ 3 │ 2 │ Room_05 │ └─────────────┴────────────┴─────┴──────┴────────────┘ [Export Student Schedule] ``` #### 4C: Course View **Purpose:** Show exam details for each course **Layout:** ``` Schedule - Course View ─────────────────────────────────────────────────────── Sort by: [Course Code ▼] ┌────────────┬─────┬──────┬────────────┬─────────────┐ │ Course │ Day │ Slot │ Classroom │ Enrolled │ ├────────────┼─────┼──────┼────────────┼─────────────┤ │ Course_01 │ 1 │ 1 │ Room_01 │ 40 │ │ Course_02 │ 1 │ 1 │ Room_02 │ 35 │ │ Course_03 │ 1 │ 2 │ Room_04 │ 38 │ │ Course_04 │ 1 │ 3 │ Room_02 │ 42 │ │ ... │ ... │ ... │ ... │ ... │ └────────────┴─────┴──────┴────────────┴─────────────┘ [Export View] ``` #### 4D: Day View (Grid Layout) **Purpose:** Visual grid showing all exams by day and time slot **Layout:** ``` Schedule - Day View ─────────────────────────────────────────────────────── ┌──────┬──────────────┬──────────────┬──────────────┬──────────────┐ │ │ Slot 1 │ Slot 2 │ Slot 3 │ Slot 4 │ ├──────┼──────────────┼──────────────┼──────────────┼──────────────┤ │ Day 1│ Course_01 │ Course_05 │ Course_07 │ Course_11 │ │ │ (Room_01) │ (Room_01) │ (Room_03) │ (Room_02) │ │ │ 40 students │ 38 students │ 35 students │ 40 students │ │ │ │ │ │ │ │ │ Course_02 │ Course_06 │ Course_08 │ Course_12 │ │ │ (Room_02) │ (Room_04) │ (Room_05) │ (Room_06) │ │ │ 35 students │ 40 students │ 38 students │ 42 students │ ├──────┼──────────────┼──────────────┼──────────────┼──────────────┤ │ Day 2│ ... │ ... │ ... │ ... │ └──────┴──────────────┴──────────────┴──────────────┴──────────────┘ [Export View] ``` --- ### View 5: Export View **Purpose:** Export schedule to CSV or Excel **Layout:** ``` Export Schedule ─────────────────────────────────────────────────────── Export Format: ○ CSV (Comma-Separated Values) ● Excel (.xlsx) Views to Export: ☑ Classroom View ☑ Student View ☑ Course View ☑ Day View (Excel will create separate sheet for each view) Output Location: [C:\Users\Student\Documents\exam_schedule.xlsx] [Browse...] [Export] [Cancel] Export Status: ┌─────────────────────────────────────────────────────┐ │ ✓ Export completed successfully! │ │ File saved to: C:\Users\Student\Documents\... │ │ File size: 24 KB │ └─────────────────────────────────────────────────────┘ ``` --- ### View 6: History View **Purpose:** View and load previously generated schedules **Layout:** ``` Schedule History ─────────────────────────────────────────────────────── ┌─────────────┬──────────────────┬─────────┬──────────┬────────┐ │ Date/Time │ Strategy │ Days │ Courses │ Status │ ├─────────────┼──────────────────┼─────────┼──────────┼────────┤ │ 11/26 10:30 │ Balance Distrib. │ 5×4=20 │ 20 │ Saved │ │ 11/26 09:15 │ Minimize Days │ 5×4=20 │ 20 │ Saved │ │ 11/25 14:22 │ Minimize Rooms │ 6×3=18 │ 18 │ Saved │ │ ... │ ... │ ... │ ... │ ... │ └─────────────┴──────────────────┴─────────┴──────────┴────────┘ [Load Selected] [Delete] [Export] ``` --- ### UI/UX Guidelines #### Color Scheme - **Primary:** Blue (#2196F3) for action buttons, links - **Success:** Green (#4CAF50) for success messages, checkmarks - **Error:** Red (#F44336) for error messages, warnings - **Neutral:** Gray (#9E9E9E) for disabled elements, borders - **Background:** Light gray (#FAFAFA) for content areas #### Typography - **Font:** System default (Segoe UI on Windows) - **Headers:** 18pt bold - **Body text:** 12pt regular - **Labels:** 11pt regular #### Interaction Patterns - **Buttons:** Hover state (darker shade), click state (pressed effect) - **Tables:** Row hover highlight, sortable columns (click header) - **Forms:** Validation on blur (lose focus), red border for invalid fields - **Progress:** Animated progress bar, percentage text, time remaining estimate #### Accessibility - **Keyboard navigation:** Tab order follows logical flow, Enter activates buttons - **Tooltips:** Hover over fields shows help text - **Error messages:** Red border + icon + text description - **Focus indicators:** Visible blue outline on focused elements --- ## API CONTRACTS BETWEEN LAYERS ### Controller → Service Layer Contracts #### ImportService Interface ```java public interface ImportService { /** * Import students from CSV file * @param filePath Absolute path to CSV file * @return ImportResult with success/failure counts and error messages * @throws FileNotFoundException if file doesn't exist * @throws InvalidFormatException if CSV format is incorrect */ ImportResult importStudents(String filePath) throws FileNotFoundException, InvalidFormatException; /** * Import courses from CSV file */ ImportResult importCourses(String filePath) throws FileNotFoundException, InvalidFormatException; /** * Import classrooms from CSV file * Format: ClassroomID;Capacity */ ImportResult importClassrooms(String filePath) throws FileNotFoundException, InvalidFormatException; /** * Import enrollments (student-course mappings) from CSV file */ ImportResult importEnrollments(String filePath) throws FileNotFoundException, InvalidFormatException; /** * Validate all imported data for consistency * @return ValidationResult with list of issues found */ ValidationResult validateImportedData(); } public class ImportResult { private int successCount; private int errorCount; private List errors; private boolean success; public static class ImportError { private int lineNumber; private String message; private String rawLine; } } ``` --- #### ScheduleService Interface ```java public interface ScheduleService { /** * Generate schedule using CSP solver * @param config Schedule configuration (days, slots, strategy) * @param progressTracker Callback for progress updates * @return Generated Schedule object * @throws NoSolutionException if constraints cannot be satisfied * @throws CancelledException if user cancels during generation */ Schedule generateSchedule(ScheduleConfiguration config, ProgressTracker progressTracker) throws NoSolutionException, CancelledException; /** * Validate manual edit against constraints * @param scheduleId ID of schedule to modify * @param courseCode Course to move * @param newDay New day assignment * @param newSlot New time slot assignment * @param newClassroom New classroom assignment * @return ValidationResult indicating if change is valid */ ValidationResult validateEdit( int scheduleId, String courseCode, int newDay, int newSlot, String newClassroom ); /** * Apply manual edit to schedule * @throws ConstraintViolationException if edit violates constraints */ void applyEdit(int scheduleId, ExamAssignment newAssignment) throws ConstraintViolationException; /** * Save current schedule to database * @return Saved schedule ID */ int saveSchedule(Schedule schedule); /** * Load schedule from database */ Schedule loadSchedule(int scheduleId) throws ScheduleNotFoundException; /** * Get all saved schedules (metadata only) */ List getScheduleHistory(); /** * Delete schedule from database */ void deleteSchedule(int scheduleId); } public class ScheduleConfiguration { private int numDays; private int slotsPerDay; private OptimizationStrategy strategy; } public enum OptimizationStrategy { MINIMIZE_DAYS, BALANCE_DISTRIBUTION, MINIMIZE_CLASSROOMS, BALANCE_CLASSROOMS } ``` --- #### ExportService Interface ```java public interface ExportService { /** * Export schedule to CSV files (one file per view) * @param schedule Schedule to export * @param outputDirectory Directory to save CSV files * @param views Which views to export (CLASSROOM, STUDENT, COURSE, DAY) * @return ExportResult with file paths and success status */ ExportResult exportToCSV( Schedule schedule, String outputDirectory, Set views ) throws IOException; /** * Export schedule to Excel workbook (one sheet per view) * @param schedule Schedule to export * @param outputFilePath Path to save .xlsx file * @param views Which views to export * @return ExportResult with file path and success status */ ExportResult exportToExcel( Schedule schedule, String outputFilePath, Set views ) throws IOException; } public enum ViewType { CLASSROOM, STUDENT, COURSE, DAY } public class ExportResult { private boolean success; private List filePaths; private String message; private long fileSizeBytes; } ``` --- ### Service → DAO Layer Contracts #### StudentDAO Interface ```java public interface StudentDAO { /** * Insert single student */ void insert(Student student) throws SQLException; /** * Batch insert multiple students (more efficient) */ void insertBatch(List students) throws SQLException; /** * Get student by ID */ Optional findById(String studentId); /** * Get all students */ List findAll(); /** * Check if student exists */ boolean exists(String studentId); /** * Delete all students (for re-import) */ void deleteAll() throws SQLException; /** * Get students enrolled in specific course */ List findByCourse(String courseCode); } ``` #### CourseDAO Interface ```java public interface CourseDAO { void insert(Course course) throws SQLException; void insertBatch(List courses) throws SQLException; Optional findById(String courseCode); List findAll(); boolean exists(String courseCode); void deleteAll() throws SQLException; /** * Get enrollment count for course */ int getEnrollmentCount(String courseCode); } ``` #### EnrollmentDAO Interface ```java public interface EnrollmentDAO { void insert(Enrollment enrollment) throws SQLException; void insertBatch(List enrollments) throws SQLException; /** * Get all courses for a student */ List getCoursesForStudent(String studentId); /** * Get all students for a course */ List getStudentsForCourse(String courseCode); /** * Check if enrollment exists */ boolean exists(String studentId, String courseCode); /** * Get total enrollment count */ int getTotalEnrollmentCount(); void deleteAll() throws SQLException; } ``` #### ScheduleDAO Interface ```java public interface ScheduleDAO { /** * Insert new schedule (returns generated ID) */ int insert(Schedule schedule) throws SQLException; /** * Update existing schedule */ void update(Schedule schedule) throws SQLException; /** * Get schedule by ID (includes all exam assignments) */ Optional findById(int scheduleId); /** * Get all schedules (metadata only, no assignments) */ List findAllMetadata(); /** * Delete schedule and all associated assignments (cascade) */ void delete(int scheduleId) throws SQLException; } ``` #### ExamAssignmentDAO Interface ```java public interface ExamAssignmentDAO { /** * Insert single assignment */ void insert(ExamAssignment assignment) throws SQLException; /** * Batch insert all assignments for a schedule */ void insertBatch(List assignments) throws SQLException; /** * Get all assignments for a schedule */ List findBySchedule(int scheduleId); /** * Get assignment for specific course in a schedule */ Optional findByCourse(int scheduleId, String courseCode); /** * Update single assignment (for manual edits) */ void update(ExamAssignment assignment) throws SQLException; /** * Delete all assignments for a schedule */ void deleteBySchedule(int scheduleId) throws SQLException; /** * Check if classroom-day-slot is occupied in schedule */ boolean isSlotOccupied(int scheduleId, String classroomId, int day, int slot); } ``` --- ### Service → Algorithm Layer Contracts #### CSPSolver Interface ```java public interface CSPSolver { /** * Solve CSP to generate schedule * @param courses List of courses to schedule * @param classrooms Available classrooms * @param enrollments Student-course enrollment data * @param config Exam period configuration * @param strategy Optimization strategy to use * @param progressTracker Progress callback * @return Map of course → {classroom, day, slot} assignments * @throws NoSolutionException if no valid schedule exists * @throws CancelledException if solve() is cancelled */ Map solve( List courses, List classrooms, List enrollments, ScheduleConfiguration config, OptimizationStrategy strategy, ProgressTracker progressTracker ) throws NoSolutionException, CancelledException; /** * Cancel ongoing solve operation */ void cancel(); } ``` #### ConstraintValidator Interface ```java public interface ConstraintValidator { /** * Check if assignment satisfies all constraints * @param course Course being assigned * @param classroom Classroom to assign to * @param day Day to assign to * @param slot Time slot to assign to * @param currentAssignment Partial assignment so far * @param enrollments Enrollment data * @return true if assignment is valid */ boolean isValid( Course course, Classroom classroom, int day, int slot, Map currentAssignment, List enrollments ); /** * Get detailed constraint violations for an assignment * @return List of violated constraints with explanations */ List getViolations( Course course, Classroom classroom, int day, int slot, Map currentAssignment, List enrollments ); } public class ConstraintViolation { private ConstraintType type; private String message; private List affectedStudents; // For student-related violations } public enum ConstraintType { CONSECUTIVE_EXAMS, MAX_TWO_PER_DAY, CLASSROOM_CAPACITY, CLASSROOM_DOUBLE_BOOKING } ``` #### ConflictDetector Interface ```java public interface ConflictDetector { /** * Analyze why no solution exists * @return Report detailing conflicts and recommendations */ ConflictReport analyzeFailure( List courses, List classrooms, List enrollments, ScheduleConfiguration config ); } public class ConflictReport { private List studentConflicts; private List courseConflicts; private List recommendations; } public class StudentConflict { private Student student; private String description; // "Enrolled in 15 courses, max 10 possible with constraints" private int courseCount; private int maxPossible; } public class CourseConflict { private Course course; private String description; // "55 students enrolled, max classroom capacity 40" private int enrolledCount; private int maxCapacity; } ``` --- ## TESTING STRATEGY ### Unit Testing #### DAO Layer Tests **Framework:** JUnit 5 **Database:** In-memory SQLite (`:memory:`) **Coverage targets:** >90% **Test categories:** 1. **CRUD operations:** Insert, update, delete, select 2. **Batch operations:** Batch insert performance and correctness 3. **Transactions:** Rollback on error, commit on success 4. **Uniqueness constraints:** Duplicate prevention 5. **Foreign key constraints:** Referential integrity 6. **Index usage:** Query performance **Example test:** ```java @Test public void testBatchInsertStudents_ShouldInsertAllStudents() { // Arrange List students = createTestStudents(100); StudentDAO dao = new StudentDAOImpl(testConnection); // Act dao.insertBatch(students); // Assert assertEquals(100, dao.findAll().size()); assertTrue(dao.exists("Std_ID_001")); } @Test public void testInsertDuplicateStudent_ShouldThrowException() { // Arrange StudentDAO dao = new StudentDAOImpl(testConnection); Student student = new Student("Std_ID_001"); dao.insert(student); // Act & Assert assertThrows(SQLException.class, () -> dao.insert(student)); } ``` --- #### Algorithm Layer Tests **Framework:** JUnit 5 **Test data:** Small synthetic datasets with known solutions **Test categories:** 1. **Constraint validation:** Each constraint checked individually 2. **Simple solvable cases:** 3-5 courses with obvious solution 3. **Unsolvable cases:** Known conflicts (student with 15 courses, etc.) 4. **Edge cases:** - Single course - All students in one course - Minimum/maximum capacity classrooms - Consecutive slots at day boundaries 5. **Optimization strategies:** Verify strategy affects solution 6. **Performance:** Small dataset (<10 courses) solves in <1 second **Example tests:** ```java @Test public void testNoConsecutiveExams_StudentWithTwoCourses_ShouldNotBeInConsecutiveSlots() { // Arrange CSPSolver solver = new BacktrackingSolver(); Student student = new Student("S1"); Course course1 = new Course("C1"); Course course2 = new Course("C2"); Enrollment e1 = new Enrollment(student, course1); Enrollment e2 = new Enrollment(student, course2); Classroom classroom = new Classroom("R1", 50); ScheduleConfiguration config = new ScheduleConfiguration(2, 2); // 2 days, 2 slots // Act Map solution = solver.solve( Arrays.asList(course1, course2), Arrays.asList(classroom), Arrays.asList(e1, e2), config, OptimizationStrategy.MINIMIZE_DAYS, null ); // Assert assertNotNull(solution); ExamAssignment a1 = solution.get(course1); ExamAssignment a2 = solution.get(course2); assertFalse(areConsecutive(a1, a2), "Courses should not be in consecutive slots"); } @Test public void testUnsolvableCase_StudentWith15Courses_ShouldThrowNoSolutionException() { // Arrange: Student enrolled in 15 courses, only 5 days × 2 slots = 10 possible CSPSolver solver = new BacktrackingSolver(); Student student = createStudentWithNCourses(15); ScheduleConfiguration config = new ScheduleConfiguration(5, 2); // Only 10 slots // Act & Assert assertThrows(NoSolutionException.class, () -> solver.solve(courses, classrooms, enrollments, config, strategy, null) ); } ``` --- #### Service Layer Tests **Framework:** JUnit 5 + Mockito **Mocking:** Mock DAO and Algorithm layers **Test categories:** 1. **Business logic validation:** Configuration validation, data consistency checks 2. **Transaction handling:** Rollback on failure, commit on success 3. **Error propagation:** Service catches and wraps DAO/algorithm exceptions appropriately 4. **Null handling:** Graceful handling of null inputs **Example test:** ```java @Test public void testGenerateSchedule_WithValidConfig_ShouldReturnSchedule() { // Arrange ScheduleService service = new ScheduleServiceImpl(mockDAO, mockSolver); ScheduleConfiguration config = new ScheduleConfiguration(5, 4, OptimizationStrategy.BALANCE_DISTRIBUTION); when(mockDAO.findAllCourses()).thenReturn(createTestCourses(20)); when(mockDAO.findAllClassrooms()).thenReturn(createTestClassrooms(10)); when(mockDAO.findAllEnrollments()).thenReturn(createTestEnrollments()); when(mockSolver.solve(any(), any(), any(), any(), any(), any())).thenReturn(createValidSolution()); // Act Schedule schedule = service.generateSchedule(config, null); // Assert assertNotNull(schedule); assertEquals(20, schedule.getAssignments().size()); verify(mockDAO, times(1)).saveSchedule(any()); } ``` --- ### Integration Testing #### Database Integration Tests **Setup:** Real SQLite file (not in-memory) **Cleanup:** Delete database file after each test class **Test categories:** 1. **End-to-end import:** CSV → Database → Verify 2. **Schedule generation → save → load:** Full round-trip 3. **Manual edit → validation → save:** Edit workflow 4. **Concurrent access:** Multiple connections (if applicable) **Example test:** ```java @Test public void testFullImportWorkflow_ShouldPersistAllData() { // Arrange ImportService importService = new ImportServiceImpl(realDAO); String studentsFile = "src/test/resources/test_students.csv"; String coursesFile = "src/test/resources/test_courses.csv"; String classroomsFile = "src/test/resources/test_classrooms.csv"; String enrollmentsFile = "src/test/resources/test_enrollments.csv"; // Act ImportResult r1 = importService.importStudents(studentsFile); ImportResult r2 = importService.importCourses(coursesFile); ImportResult r3 = importService.importClassrooms(classroomsFile); ImportResult r4 = importService.importEnrollments(enrollmentsFile); // Assert assertTrue(r1.isSuccess()); assertTrue(r2.isSuccess()); assertTrue(r3.isSuccess()); assertTrue(r4.isSuccess()); // Verify data persisted assertEquals(250, realDAO.findAllStudents().size()); assertEquals(20, realDAO.findAllCourses().size()); assertEquals(10, realDAO.findAllClassrooms().size()); assertEquals(800, realDAO.getTotalEnrollmentCount()); } ``` --- #### UI Integration Tests **Framework:** TestFX (JavaFX testing framework) **Approach:** Simulate user interactions **Test categories:** 1. **Navigation:** Click navigation items, verify view changes 2. **Import workflow:** Select files, click import, verify results 3. **Generation workflow:** Configure, generate, view schedule 4. **Export workflow:** Select format, export, verify file created **Example test:** ```java @Test public void testImportWorkflow_UserSelectsFilesAndImports_ShouldShowSuccessMessage(FxRobot robot) { // Arrange: Start application // Act robot.clickOn("#importNavButton"); robot.clickOn("#browseStudentsButton"); // (File dialog interaction - may need mocking) robot.clickOn("#importAllButton"); // Assert verifyThat("#importResultsText", hasText(containsString("250 imported"))); } ``` --- ### Performance Testing #### Benchmark Tests **Framework:** JMH (Java Microbenchmark Harness) or simple timing **Test categories:** 1. **Small dataset:** 50 courses, 500 students (target: <10 seconds) 2. **Medium dataset:** 100 courses, 1000 students (target: <2 minutes) 3. **Large dataset:** 200 courses, 2000 students (acceptance: <10 minutes) 4. **Database queries:** All common queries <100ms **Example test:** ```java @Test public void testSmallDatasetPerformance_ShouldCompleteUnder10Seconds() { // Arrange CSPSolver solver = new BacktrackingSolver(); List courses = createTestCourses(50); List students = createTestStudents(500); List enrollments = createRandomEnrollments(students, courses, 10); // 10 courses per student avg List classrooms = createTestClassrooms(15); ScheduleConfiguration config = new ScheduleConfiguration(10, 4); // 40 slots // Act long startTime = System.currentTimeMillis(); Map solution = solver.solve(courses, classrooms, enrollments, config, OptimizationStrategy.BALANCE_DISTRIBUTION, null); long endTime = System.currentTimeMillis(); // Assert assertNotNull(solution); long duration = endTime - startTime; assertTrue(duration < 10000, "Solving took " + duration + "ms, expected <10000ms"); } ``` --- ### Test Data Management #### Test Fixtures **Location:** `src/test/resources/` **Files:** - `test_students_10.csv` - 10 students - `test_students_100.csv` - 100 students - `test_students_250.csv` - 250 students (matches sample data) - `test_courses_5.csv` - 5 courses - `test_courses_20.csv` - 20 courses (matches sample data) - `test_classrooms_small.csv` - 3 classrooms, capacity 20 - `test_classrooms_medium.csv` - 10 classrooms, capacity 40 (matches sample data) - `test_enrollments_simple.csv` - Simple enrollment pattern for easy testing - `test_enrollments_complex.csv` - Complex pattern to stress-test solver #### Test Data Builders Use builder pattern for creating test objects: ```java public class TestDataBuilder { public static List createStudents(int count) { List students = new ArrayList<>(); for (int i = 1; i <= count; i++) { students.add(new Student(String.format("Std_ID_%03d", i))); } return students; } public static List createCourses(int count) { List courses = new ArrayList<>(); for (int i = 1; i <= count; i++) { courses.add(new Course(String.format("Course_%02d", i))); } return courses; } // ... similar methods for classrooms, enrollments } ``` --- ### Continuous Integration Testing **Platform:** GitHub Actions **Workflow:** 1. On every push to feature branch: Run unit tests 2. On PR to `develop`: Run unit + integration tests 3. On merge to `develop`: Run full test suite + performance tests 4. On merge to `main`: Run all tests + generate coverage report **Coverage Requirements:** - **Overall:** >70% code coverage - **Critical paths (algorithm, constraints):** >90% coverage - **DAO layer:** >85% coverage **Example GitHub Actions workflow:** ```yaml name: Java CI on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up JDK 17 uses: actions/setup-java@v3 with: java-version: '17' - name: Build with Maven run: mvn clean compile - name: Run tests run: mvn test - name: Generate coverage report run: mvn jacoco:report - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 ``` --- ## DEVELOPMENT WORKFLOW ### Git Branching Strategy **Branch structure:** ``` main └── develop ├── feature/database-schema ├── feature/csv-import ├── feature/csp-solver ├── feature/ui-main-window ├── feature/classroom-view └── bugfix/constraint-validation-issue ``` **Branch naming conventions:** - `feature/short-description` - New features - `bugfix/issue-description` - Bug fixes - `hotfix/critical-issue` - Urgent production fixes (from main) - `refactor/component-name` - Code refactoring - `test/component-name` - Test additions **Workflow:** 1. **Create feature branch** from `develop`: ```bash git checkout develop git pull origin develop git checkout -b feature/csv-import ``` 2. **Work on feature** with regular commits: ```bash git add . git commit -m "Add CSV parser for student data" git push origin feature/csv-import ``` 3. **Create Pull Request** to `develop`: - Title: Brief description (e.g., "Add CSV import functionality") - Description: Detailed changes, testing done, screenshots (for UI) - Assign reviewer (at least one other team member) - Link to any related issues/tasks 4. **Code Review:** - Reviewer checks code quality, test coverage, documentation - Leaves comments for improvements - Approves when satisfied 5. **Merge to develop:** - Use "Squash and Merge" for clean history - Delete feature branch after merge 6. **Release to main:** - When develop is stable and ready for release - Create PR from `develop` to `main` - Requires approval from Documentation & Integration Lead - Tag release with version number (e.g., `v1.0.0`) --- ### Commit Message Guidelines **Format:** ``` ():