Files
Se302/MEMORY_BANK.md

2742 lines
97 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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<T>`
- **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<Assignment> orderDomainValues(Course course, OptimizationStrategy strategy) {
List<Assignment> 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<Student> 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<Student> 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<Course, Set<Assignment>> forwardCheck(Course assigned, Assignment value) {
Map<Course, Set<Assignment>> removedValues = new HashMap<>();
Set<Student> students = getEnrolledStudents(assigned);
for (Course unassigned : unassignedCourses) {
Set<Assignment> toRemove = new HashSet<>();
Set<Student> unassignedStudents = getEnrolledStudents(unassigned);
// If courses share students, check constraints
Set<Student> 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<Course, Set<Student>>` - students in each course
- `Map<Student, Set<Course>>` - 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<ImportError> 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<ScheduleMetadata> 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<ViewType> 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<ViewType> views
) throws IOException;
}
public enum ViewType {
CLASSROOM,
STUDENT,
COURSE,
DAY
}
public class ExportResult {
private boolean success;
private List<String> 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<Student> students) throws SQLException;
/**
* Get student by ID
*/
Optional<Student> findById(String studentId);
/**
* Get all students
*/
List<Student> 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<Student> findByCourse(String courseCode);
}
```
#### CourseDAO Interface
```java
public interface CourseDAO {
void insert(Course course) throws SQLException;
void insertBatch(List<Course> courses) throws SQLException;
Optional<Course> findById(String courseCode);
List<Course> 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<Enrollment> enrollments) throws SQLException;
/**
* Get all courses for a student
*/
List<Course> getCoursesForStudent(String studentId);
/**
* Get all students for a course
*/
List<Student> 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<Schedule> findById(int scheduleId);
/**
* Get all schedules (metadata only, no assignments)
*/
List<ScheduleMetadata> 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<ExamAssignment> assignments) throws SQLException;
/**
* Get all assignments for a schedule
*/
List<ExamAssignment> findBySchedule(int scheduleId);
/**
* Get assignment for specific course in a schedule
*/
Optional<ExamAssignment> 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<Course, ExamAssignment> solve(
List<Course> courses,
List<Classroom> classrooms,
List<Enrollment> 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<Course, ExamAssignment> currentAssignment,
List<Enrollment> enrollments
);
/**
* Get detailed constraint violations for an assignment
* @return List of violated constraints with explanations
*/
List<ConstraintViolation> getViolations(
Course course,
Classroom classroom,
int day,
int slot,
Map<Course, ExamAssignment> currentAssignment,
List<Enrollment> enrollments
);
}
public class ConstraintViolation {
private ConstraintType type;
private String message;
private List<String> 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<Course> courses,
List<Classroom> classrooms,
List<Enrollment> enrollments,
ScheduleConfiguration config
);
}
public class ConflictReport {
private List<StudentConflict> studentConflicts;
private List<CourseConflict> courseConflicts;
private List<String> 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<Student> 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<Course, ExamAssignment> 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<Course> courses = createTestCourses(50);
List<Student> students = createTestStudents(500);
List<Enrollment> enrollments = createRandomEnrollments(students, courses, 10); // 10 courses per student avg
List<Classroom> classrooms = createTestClassrooms(15);
ScheduleConfiguration config = new ScheduleConfiguration(10, 4); // 40 slots
// Act
long startTime = System.currentTimeMillis();
Map<Course, ExamAssignment> 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<Student> createStudents(int count) {
List<Student> 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<Course> createCourses(int count) {
List<Course> 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:**
```
<type>(<scope>): <subject>
<body>
<footer>
```
**Types:**
- `feat`: New feature
- `fix`: Bug fix
- `refactor`: Code refactoring (no functional change)
- `test`: Adding or updating tests
- `docs`: Documentation changes
- `style`: Code style changes (formatting, no logic change)
- `chore`: Build process, dependency updates
**Examples:**
```
feat(import): Add CSV import for student data
Implemented CSVParser utility class to read student IDs from CSV file.
Includes validation for duplicates and empty lines.
Closes #15
```
```
fix(csp-solver): Correct consecutive exam constraint checking
Previous implementation didn't handle day boundaries correctly.
Now checks if last slot of day N and first slot of day N+1 are consecutive.
Fixes #42
```
---
### Pull Request Template
Create `.github/PULL_REQUEST_TEMPLATE.md`:
```markdown
## Description
<!-- Brief description of changes -->
## Type of Change
- [ ] New feature
- [ ] Bug fix
- [ ] Refactoring
- [ ] Documentation
- [ ] Testing
## Changes Made
<!-- List of specific changes -->
-
-
-
## Testing Done
<!-- How did you test these changes? -->
-
-
## Screenshots (if applicable)
<!-- For UI changes -->
## Checklist
- [ ] Code follows Java naming conventions
- [ ] Added JavaDoc for public methods
- [ ] Added unit tests (or not applicable)
- [ ] All tests pass locally
- [ ] No new compiler warnings
- [ ] Updated documentation (if needed)
## Related Issues
<!-- Link to issues: Closes #123, Fixes #456 -->
```
---
### Code Review Checklist
**For reviewers:**
#### Code Quality
- [ ] Follows Java naming conventions (camelCase for variables, PascalCase for classes)
- [ ] No magic numbers (use named constants)
- [ ] Meaningful variable/method names
- [ ] Appropriate use of access modifiers (private, public, protected)
- [ ] No code duplication
#### Functionality
- [ ] Code does what PR description says
- [ ] Edge cases handled
- [ ] Error handling appropriate (try-catch where needed)
- [ ] No obvious bugs
#### Architecture
- [ ] Follows MVC pattern (code in correct layer)
- [ ] No tight coupling (DAO doesn't call UI, etc.)
- [ ] Uses appropriate design patterns
#### Testing
- [ ] Unit tests added for new methods
- [ ] Tests cover edge cases
- [ ] All existing tests still pass
#### Documentation
- [ ] JavaDoc added for public methods
- [ ] Complex algorithms have explanatory comments
- [ ] README updated if needed
#### Performance
- [ ] No obvious performance issues (e.g., nested loops with O(n²) that could be O(n))
- [ ] Database queries are efficient (use indexes)
---
### Weekly Development Cycle
**Monday:**
- **Team standup** (15 min): What did you do last week? What will you do this week? Any blockers?
- **Integration review**: Discuss PRs that need merging, resolve conflicts
**Wednesday:**
- **Mid-week check-in** (30 min): Progress update, pair programming sessions scheduled
**Friday:**
- **End-of-week review** (30 min): Demo completed features, retrospective (what went well, what to improve)
- **Planning for next week**: Assign new tasks based on roadmap
---
### Development Environment Setup
**Required tools:**
1. **Java JDK 17+** (download from Oracle or adopt OpenJDK)
2. **Maven or Gradle** (build tool)
3. **IDE:** IntelliJ IDEA (recommended) or Eclipse
4. **Git** (version control)
5. **Scene Builder** (for FXML visual editing)
6. **SQLite Browser** (for database inspection)
**Setup steps:**
```bash
# Clone repository
git clone https://github.com/your-team/exam-scheduler.git
cd exam-scheduler
# Checkout develop branch
git checkout develop
# Build project
mvn clean install
# Run tests
mvn test
# Run application
mvn javafx:run
```
**IDE configuration:**
- Install Checkstyle plugin (for code style enforcement)
- Configure Java 17 as project SDK
- Enable "Optimize imports on the fly"
- Set code formatter to Java standard style
---
## KEY TECHNICAL DECISIONS
### Decision Log
#### Decision 1: Why Backtracking CSP Solver?
**Context:** Need to choose scheduling algorithm approach.
**Options considered:**
1. Greedy heuristic (fast but may not find solution)
2. Genetic algorithm (good for optimization but probabilistic)
3. Integer Linear Programming (optimal but complex to implement)
4. Backtracking CSP solver (systematic, guaranteed to find solution if one exists)
**Decision:** Backtracking CSP solver with constraint propagation
**Rationale:**
- **Correctness:** Guarantees finding solution or proving none exists
- **Constraint handling:** Natural fit for hard constraints
- **Extensibility:** Easy to add new constraints or optimization strategies
- **Performance:** With good heuristics (MRV, least constraining value), performs well on small-medium datasets
- **Understandable:** Algorithm is well-documented and teachable
**Trade-offs:**
- May be slower than greedy for very large datasets (acceptable given requirements)
- Not guaranteed to find *optimal* solution (finds *valid* solution, optimizes via heuristics)
---
#### Decision 2: Why SQLite?
**Context:** Need to choose database for local persistence.
**Options considered:**
1. Flat files (CSV/JSON)
2. Embedded H2 database
3. SQLite
4. MySQL/PostgreSQL (external server)
**Decision:** SQLite
**Rationale:**
- **Zero configuration:** No server setup, no connection strings, just a file
- **Cross-platform:** Works on Windows, Mac, Linux
- **Lightweight:** Small footprint, fast for small-medium datasets
- **ACID transactions:** Full database features (transactions, foreign keys, indexes)
- **No dependencies:** No external process needed
- **Easy backup:** Just copy the .db file
**Trade-offs:**
- Not suitable for concurrent multi-user access (but this is single-user desktop app)
- Limited scalability compared to server databases (but dataset sizes are small)
---
#### Decision 3: Why JavaFX with FXML + MVC?
**Context:** Need to choose UI framework and architecture.
**Options considered:**
1. Swing (older Java UI framework)
2. JavaFX with pure Java code
3. JavaFX with FXML + MVC
4. JavaFX with FXML + MVVM
**Decision:** JavaFX with FXML + MVC
**Rationale:**
- **Modern:** JavaFX is the modern Java UI framework (Swing is legacy)
- **Separation of concerns:** FXML separates UI layout from logic
- **Visual design:** Scene Builder provides WYSIWYG editor for FXML
- **MVC familiarity:** Team likely familiar with MVC pattern from coursework
- **Testability:** Can test controllers independently of views
**Trade-offs:**
- MVVM might be more testable, but MVC is simpler for team to learn
- Pure Java code (no FXML) might be more flexible, but FXML provides better separation
---
#### Decision 4: Why Maven (or Gradle)?
**Context:** Need to choose build tool.
**Options considered:**
1. Manual compilation (javac)
2. Ant
3. Maven
4. Gradle
**Decision:** Maven (or Gradle, team can choose)
**Rationale:**
- **Dependency management:** Automatically downloads libraries (SQLite JDBC, JUnit, etc.)
- **Standardized structure:** Convention over configuration
- **Build lifecycle:** Compile, test, package (JAR), run all automated
- **CI/CD integration:** Easy to integrate with GitHub Actions
- **Plugin ecosystem:** JavaFX plugin, testing plugins, coverage plugins
**Trade-offs:**
- Adds complexity compared to manual compilation
- Gradle is more flexible but has steeper learning curve
---
#### Decision 5: Why Feature Branching (Not Trunk-Based Development)?
**Context:** Need to choose Git workflow for team of 6.
**Options considered:**
1. Everyone commits to main (chaos)
2. Trunk-based development (frequent merges to main)
3. Git Flow (complex with release branches)
4. Feature branching with develop branch
**Decision:** Feature branching with `main` and `develop` branches
**Rationale:**
- **Isolation:** Each feature developed independently without breaking others
- **Code review:** PRs enable peer review before merging
- **Stable main:** Main branch always has working code
- **Learning:** Teaches industry-standard Git workflow
- **Flexibility:** Can work on multiple features in parallel
**Trade-offs:**
- More complex than trunk-based development
- Risk of long-lived branches and merge conflicts (mitigated by frequent integration)
---
#### Decision 6: Test Coverage Target: 70%
**Context:** Need to set realistic test coverage goal.
**Options considered:**
1. No specific target (risky)
2. 50% coverage (too low for quality)
3. 70% coverage (balanced)
4. 90%+ coverage (too time-consuming)
**Decision:** 70% overall coverage, 90% for critical paths (algorithm, constraints)
**Rationale:**
- **Balanced:** Provides confidence without excessive test maintenance
- **Focus on critical:** Algorithm correctness is most important
- **Achievable:** Team of 6 can reach this in 10-week timeline
- **Industry standard:** 70% is common target for projects
**Trade-offs:**
- Not 100% coverage (but diminishing returns after 70%)
- Some UI code may be hard to test (acceptable)
---
#### Decision 7: Progress Tracking via JavaFX Task
**Context:** Need to show progress during long-running schedule generation.
**Options considered:**
1. No progress indication (bad UX)
2. Custom threading with callbacks
3. JavaFX Task<T> with progress updates
4. Background service with polling
**Decision:** JavaFX Task<T> with ProgressTracker callback
**Rationale:**
- **Built-in:** JavaFX Task provides progress, cancellation, error handling
- **Thread-safe:** Updates UI from background thread safely
- **Cancellable:** User can cancel long-running operations
- **Standard pattern:** Well-documented JavaFX approach
**Implementation:**
```java
public class ScheduleGenerationTask extends Task<Schedule> {
@Override
protected Schedule call() throws Exception {
updateMessage("Initializing solver...");
updateProgress(0, 100);
// Solver updates progress via callback
Schedule schedule = solver.solve(..., (current, total) -> {
updateProgress(current, total);
updateMessage("Assigned " + current + " / " + total + " courses");
});
return schedule;
}
}
```
---
#### Decision 8: CSV Format for Import (Not JSON/XML)
**Context:** Sample data provided in CSV format.
**Options considered:**
1. CSV (simple text format)
2. JSON (structured data)
3. XML (verbose but structured)
4. Excel (.xlsx) directly
**Decision:** CSV for import, both CSV and Excel for export
**Rationale:**
- **Simplicity:** CSV is easiest to create/edit for users (Excel, Google Sheets, text editor)
- **Sample data:** Already provided in CSV format
- **Lightweight:** No XML/JSON parsing libraries needed
- **Universal:** All spreadsheet programs support CSV
**Trade-offs:**
- Less structured than JSON/XML (but data is simple enough)
- Encoding issues possible (mitigated by using UTF-8)
---
## GLOSSARY
**Terms used throughout project:**
- **CSP (Constraint Satisfaction Problem):** A problem where variables must be assigned values subject to constraints
- **Backtracking:** Algorithm that tries assignments and "backs up" when constraints are violated
- **Domain:** Set of possible values a variable can take
- **Hard Constraint:** Constraint that CANNOT be violated (vs soft constraint = preference)
- **Forward Checking:** Constraint propagation technique that reduces domains after each assignment
- **Heuristic:** Rule of thumb to guide search (e.g., MRV, least constraining value)
- **MRV (Minimum Remaining Values):** Choose variable with fewest valid domain values
- **DAO (Data Access Object):** Design pattern separating data access from business logic
- **POJO (Plain Old Java Object):** Simple Java class with no special requirements
- **FXML:** JavaFX XML-based language for describing UI layouts
- **MVC (Model-View-Controller):** Architecture pattern separating data, UI, and logic
- **JDBC (Java Database Connectivity):** Java API for database operations
- **ORM (Object-Relational Mapping):** Mapping between objects and database tables
- **ACID (Atomicity, Consistency, Isolation, Durability):** Database transaction properties
- **PR (Pull Request):** Request to merge code changes into a branch
- **CI/CD (Continuous Integration/Continuous Deployment):** Automated testing and deployment
- **Enrollment:** Student-course relationship (which students are in which courses)
- **Assignment (in CSP context):** Mapping of variable to value (course → {classroom, day, slot})
- **Slot:** Time period for an exam (e.g., Slot 1 = 9:00-11:00 AM)
- **Optimization Strategy:** Preference for how to schedule (minimize days, balance load, etc.)
---
## VERSION HISTORY
| Version | Date | Author | Changes |
|---------|------|--------|---------|
| 1.0 | 2025-11-26 | Claude Code | Initial memory bank creation |
---
## CONTACT & RESOURCES
**Team Communication:**
- Primary channel: [Specify - WhatsApp group, Discord, Slack, etc.]
- Code repository: [GitHub URL once created]
- Documentation: This memory bank + inline JavaDoc
**External Resources:**
- JavaFX Documentation: https://openjfx.io/javadoc/17/
- SQLite Documentation: https://www.sqlite.org/docs.html
- JUnit 5 User Guide: https://junit.org/junit5/docs/current/user-guide/
- Constraint Satisfaction (AI textbook): Russell & Norvig, Chapter 6
**Course Materials:**
- SE302 course website: [URL from instructor]
- Professor contact: [Email]
- Office hours: [Schedule]
---
## NOTES & ASSUMPTIONS
**Assumptions made:**
1. Exams are single-session (no multi-part exams spanning multiple slots)
2. All students in a course take exam at same time (no separate sections)
3. One exam per course (no midterm + final during same exam period)
4. Classrooms are generic (no special equipment requirements)
5. All exams have same duration (fit in one time slot)
6. Students are physically able to take 2 exams per day (no disability accommodations modeled)
7. Desktop application for single user (Student Affairs staff person), not multi-user
8. Windows OS is primary target (but Java ensures cross-platform compatibility)
9. Exam period is contiguous (no gaps, e.g., no exams on weekends if those days aren't configured)
10. Consecutive = immediately following slot number (whether same day or across day boundary)
**Open questions:**
- [To be filled in during development as questions arise]
---
**END OF MEMORY BANK**
---
This memory bank should be treated as a living document. Update it as:
- Decisions are made
- Requirements are clarified
- Implementation details are finalized
- Issues are discovered and resolved
All team members should review this document at start of project and reference it throughout development.