package models import ( "time" "github.com/google/uuid" ) // Each constraint table carries the same audit/policy columns: // - is_hard: true = solver must satisfy, false = soft (weighted) // - weight: higher = stronger penalty when violated (used for soft constraints) // - active: allows toggling a rule off without deletion // - note: free-text rationale ("Lehrer X im Rollstuhl") // - created_by_user_id: the Rektor account that owns this rule // ---------- Teacher constraints (6) ---------- // TeacherUnavailableDay: Lehrer kann an Wochentag NIE. type TeacherUnavailableDay struct { ID uuid.UUID `json:"id" db:"id"` CreatedByUserID uuid.UUID `json:"created_by_user_id" db:"created_by_user_id"` TeacherID uuid.UUID `json:"teacher_id" db:"teacher_id"` DayOfWeek int `json:"day_of_week" db:"day_of_week"` IsHard bool `json:"is_hard" db:"is_hard"` Weight int `json:"weight" db:"weight"` Active bool `json:"active" db:"active"` Note string `json:"note,omitempty" db:"note"` CreatedAt time.Time `json:"created_at" db:"created_at"` } // TeacherUnavailableWindow: Lehrer kann an Tag X von HH:MM bis HH:MM nicht. type TeacherUnavailableWindow struct { ID uuid.UUID `json:"id" db:"id"` CreatedByUserID uuid.UUID `json:"created_by_user_id" db:"created_by_user_id"` TeacherID uuid.UUID `json:"teacher_id" db:"teacher_id"` DayOfWeek int `json:"day_of_week" db:"day_of_week"` StartTime string `json:"start_time" db:"start_time"` EndTime string `json:"end_time" db:"end_time"` IsHard bool `json:"is_hard" db:"is_hard"` Weight int `json:"weight" db:"weight"` Active bool `json:"active" db:"active"` Note string `json:"note,omitempty" db:"note"` CreatedAt time.Time `json:"created_at" db:"created_at"` } // TeacherMaxHoursDay: Lehrer darf max. N Stunden pro Tag haben. type TeacherMaxHoursDay struct { ID uuid.UUID `json:"id" db:"id"` CreatedByUserID uuid.UUID `json:"created_by_user_id" db:"created_by_user_id"` TeacherID uuid.UUID `json:"teacher_id" db:"teacher_id"` MaxHours int `json:"max_hours" db:"max_hours"` IsHard bool `json:"is_hard" db:"is_hard"` Weight int `json:"weight" db:"weight"` Active bool `json:"active" db:"active"` Note string `json:"note,omitempty" db:"note"` CreatedAt time.Time `json:"created_at" db:"created_at"` } // TeacherMaxHoursWeek: Teilzeit-Cap. type TeacherMaxHoursWeek struct { ID uuid.UUID `json:"id" db:"id"` CreatedByUserID uuid.UUID `json:"created_by_user_id" db:"created_by_user_id"` TeacherID uuid.UUID `json:"teacher_id" db:"teacher_id"` MaxHours int `json:"max_hours" db:"max_hours"` IsHard bool `json:"is_hard" db:"is_hard"` Weight int `json:"weight" db:"weight"` Active bool `json:"active" db:"active"` Note string `json:"note,omitempty" db:"note"` CreatedAt time.Time `json:"created_at" db:"created_at"` } // TeacherExcludedSubject: Lehrer darf bestimmtes Fach nicht unterrichten. type TeacherExcludedSubject struct { ID uuid.UUID `json:"id" db:"id"` CreatedByUserID uuid.UUID `json:"created_by_user_id" db:"created_by_user_id"` TeacherID uuid.UUID `json:"teacher_id" db:"teacher_id"` SubjectID uuid.UUID `json:"subject_id" db:"subject_id"` IsHard bool `json:"is_hard" db:"is_hard"` Weight int `json:"weight" db:"weight"` Active bool `json:"active" db:"active"` Note string `json:"note,omitempty" db:"note"` CreatedAt time.Time `json:"created_at" db:"created_at"` } // TeacherExcludedRoom: Lehrer kann Raum nicht nutzen (z.B. kein Aufzug). type TeacherExcludedRoom struct { ID uuid.UUID `json:"id" db:"id"` CreatedByUserID uuid.UUID `json:"created_by_user_id" db:"created_by_user_id"` TeacherID uuid.UUID `json:"teacher_id" db:"teacher_id"` RoomID uuid.UUID `json:"room_id" db:"room_id"` IsHard bool `json:"is_hard" db:"is_hard"` Weight int `json:"weight" db:"weight"` Active bool `json:"active" db:"active"` Note string `json:"note,omitempty" db:"note"` CreatedAt time.Time `json:"created_at" db:"created_at"` } // ---------- Subject constraints (5) ---------- // SubjectMinDayGap: Mindestens N Tage Abstand zwischen zwei Lessons desselben Fachs. type SubjectMinDayGap struct { ID uuid.UUID `json:"id" db:"id"` CreatedByUserID uuid.UUID `json:"created_by_user_id" db:"created_by_user_id"` SubjectID uuid.UUID `json:"subject_id" db:"subject_id"` MinGapDays int `json:"min_gap_days" db:"min_gap_days"` IsHard bool `json:"is_hard" db:"is_hard"` Weight int `json:"weight" db:"weight"` Active bool `json:"active" db:"active"` Note string `json:"note,omitempty" db:"note"` CreatedAt time.Time `json:"created_at" db:"created_at"` } // SubjectMaxConsecutive: Max. N aufeinander folgende Stunden des Fachs (keine Tripel-Stunde). type SubjectMaxConsecutive struct { ID uuid.UUID `json:"id" db:"id"` CreatedByUserID uuid.UUID `json:"created_by_user_id" db:"created_by_user_id"` SubjectID uuid.UUID `json:"subject_id" db:"subject_id"` MaxConsecutive int `json:"max_consecutive" db:"max_consecutive"` IsHard bool `json:"is_hard" db:"is_hard"` Weight int `json:"weight" db:"weight"` Active bool `json:"active" db:"active"` Note string `json:"note,omitempty" db:"note"` CreatedAt time.Time `json:"created_at" db:"created_at"` } // SubjectContiguousWhenRepeated: Wenn das Fach mehrfach am gleichen Tag stattfindet, dann nur als Block. type SubjectContiguousWhenRepeated struct { ID uuid.UUID `json:"id" db:"id"` CreatedByUserID uuid.UUID `json:"created_by_user_id" db:"created_by_user_id"` SubjectID uuid.UUID `json:"subject_id" db:"subject_id"` IsHard bool `json:"is_hard" db:"is_hard"` Weight int `json:"weight" db:"weight"` Active bool `json:"active" db:"active"` Note string `json:"note,omitempty" db:"note"` CreatedAt time.Time `json:"created_at" db:"created_at"` } // SubjectPreferredPeriod: Fach lieber in einem bestimmten Period-Bereich (z.B. Hauptfächer morgens). type SubjectPreferredPeriod struct { ID uuid.UUID `json:"id" db:"id"` CreatedByUserID uuid.UUID `json:"created_by_user_id" db:"created_by_user_id"` SubjectID uuid.UUID `json:"subject_id" db:"subject_id"` PeriodFrom int `json:"period_from" db:"period_from"` PeriodTo int `json:"period_to" db:"period_to"` IsHard bool `json:"is_hard" db:"is_hard"` Weight int `json:"weight" db:"weight"` Active bool `json:"active" db:"active"` Note string `json:"note,omitempty" db:"note"` CreatedAt time.Time `json:"created_at" db:"created_at"` } // SubjectDoubleLesson: Fach bevorzugt als Doppelstunde. type SubjectDoubleLesson struct { ID uuid.UUID `json:"id" db:"id"` CreatedByUserID uuid.UUID `json:"created_by_user_id" db:"created_by_user_id"` SubjectID uuid.UUID `json:"subject_id" db:"subject_id"` IsHard bool `json:"is_hard" db:"is_hard"` Weight int `json:"weight" db:"weight"` Active bool `json:"active" db:"active"` Note string `json:"note,omitempty" db:"note"` CreatedAt time.Time `json:"created_at" db:"created_at"` } // ---------- Class constraints (2) ---------- // ClassMaxHoursDay: Klasse darf max. N Stunden pro Tag haben. type ClassMaxHoursDay struct { ID uuid.UUID `json:"id" db:"id"` CreatedByUserID uuid.UUID `json:"created_by_user_id" db:"created_by_user_id"` ClassID uuid.UUID `json:"class_id" db:"class_id"` MaxHours int `json:"max_hours" db:"max_hours"` IsHard bool `json:"is_hard" db:"is_hard"` Weight int `json:"weight" db:"weight"` Active bool `json:"active" db:"active"` Note string `json:"note,omitempty" db:"note"` CreatedAt time.Time `json:"created_at" db:"created_at"` } // ClassNoGaps: Keine Freistunden für die Klasse zwischen Lessons (Soft-Standard). type ClassNoGaps struct { ID uuid.UUID `json:"id" db:"id"` CreatedByUserID uuid.UUID `json:"created_by_user_id" db:"created_by_user_id"` ClassID uuid.UUID `json:"class_id" db:"class_id"` IsHard bool `json:"is_hard" db:"is_hard"` Weight int `json:"weight" db:"weight"` Active bool `json:"active" db:"active"` Note string `json:"note,omitempty" db:"note"` CreatedAt time.Time `json:"created_at" db:"created_at"` } // ---------- Room constraints (2) ---------- // RoomRequiresType: Fach benötigt einen bestimmten Raumtyp (Sport → Sporthalle). type RoomRequiresType struct { ID uuid.UUID `json:"id" db:"id"` CreatedByUserID uuid.UUID `json:"created_by_user_id" db:"created_by_user_id"` SubjectID uuid.UUID `json:"subject_id" db:"subject_id"` RoomType string `json:"room_type" db:"room_type"` IsHard bool `json:"is_hard" db:"is_hard"` Weight int `json:"weight" db:"weight"` Active bool `json:"active" db:"active"` Note string `json:"note,omitempty" db:"note"` CreatedAt time.Time `json:"created_at" db:"created_at"` } // RoomUnavailable: Raum an Tag X, Stunde Y blockiert (Wartung, Renovierung). type RoomUnavailable struct { ID uuid.UUID `json:"id" db:"id"` CreatedByUserID uuid.UUID `json:"created_by_user_id" db:"created_by_user_id"` RoomID uuid.UUID `json:"room_id" db:"room_id"` DayOfWeek int `json:"day_of_week" db:"day_of_week"` PeriodIndex int `json:"period_index" db:"period_index"` IsHard bool `json:"is_hard" db:"is_hard"` Weight int `json:"weight" db:"weight"` Active bool `json:"active" db:"active"` Note string `json:"note,omitempty" db:"note"` CreatedAt time.Time `json:"created_at" db:"created_at"` } // ---------- Request DTOs ---------- // Teacher type CreateTeacherUnavailableDayRequest struct { TeacherID string `json:"teacher_id" binding:"required,uuid"` DayOfWeek int `json:"day_of_week" binding:"required,min=1,max=7"` IsHard bool `json:"is_hard"` Weight int `json:"weight" binding:"min=0,max=100"` Active bool `json:"active"` Note string `json:"note"` } type CreateTeacherUnavailableWindowRequest struct { TeacherID string `json:"teacher_id" binding:"required,uuid"` DayOfWeek int `json:"day_of_week" binding:"required,min=1,max=7"` StartTime string `json:"start_time" binding:"required"` EndTime string `json:"end_time" binding:"required"` IsHard bool `json:"is_hard"` Weight int `json:"weight" binding:"min=0,max=100"` Active bool `json:"active"` Note string `json:"note"` } type CreateTeacherMaxHoursDayRequest struct { TeacherID string `json:"teacher_id" binding:"required,uuid"` MaxHours int `json:"max_hours" binding:"required,min=1,max=12"` IsHard bool `json:"is_hard"` Weight int `json:"weight" binding:"min=0,max=100"` Active bool `json:"active"` Note string `json:"note"` } type CreateTeacherMaxHoursWeekRequest struct { TeacherID string `json:"teacher_id" binding:"required,uuid"` MaxHours int `json:"max_hours" binding:"required,min=1,max=40"` IsHard bool `json:"is_hard"` Weight int `json:"weight" binding:"min=0,max=100"` Active bool `json:"active"` Note string `json:"note"` } type CreateTeacherExcludedSubjectRequest struct { TeacherID string `json:"teacher_id" binding:"required,uuid"` SubjectID string `json:"subject_id" binding:"required,uuid"` IsHard bool `json:"is_hard"` Weight int `json:"weight" binding:"min=0,max=100"` Active bool `json:"active"` Note string `json:"note"` } type CreateTeacherExcludedRoomRequest struct { TeacherID string `json:"teacher_id" binding:"required,uuid"` RoomID string `json:"room_id" binding:"required,uuid"` IsHard bool `json:"is_hard"` Weight int `json:"weight" binding:"min=0,max=100"` Active bool `json:"active"` Note string `json:"note"` } // Subject type CreateSubjectMinDayGapRequest struct { SubjectID string `json:"subject_id" binding:"required,uuid"` MinGapDays int `json:"min_gap_days" binding:"required,min=1,max=4"` IsHard bool `json:"is_hard"` Weight int `json:"weight" binding:"min=0,max=100"` Active bool `json:"active"` Note string `json:"note"` } type CreateSubjectMaxConsecutiveRequest struct { SubjectID string `json:"subject_id" binding:"required,uuid"` MaxConsecutive int `json:"max_consecutive" binding:"required,min=1,max=5"` IsHard bool `json:"is_hard"` Weight int `json:"weight" binding:"min=0,max=100"` Active bool `json:"active"` Note string `json:"note"` } type CreateSubjectContiguousWhenRepeatedRequest struct { SubjectID string `json:"subject_id" binding:"required,uuid"` IsHard bool `json:"is_hard"` Weight int `json:"weight" binding:"min=0,max=100"` Active bool `json:"active"` Note string `json:"note"` } type CreateSubjectPreferredPeriodRequest struct { SubjectID string `json:"subject_id" binding:"required,uuid"` PeriodFrom int `json:"period_from" binding:"required,min=1,max=12"` PeriodTo int `json:"period_to" binding:"required,min=1,max=12"` IsHard bool `json:"is_hard"` Weight int `json:"weight" binding:"min=0,max=100"` Active bool `json:"active"` Note string `json:"note"` } type CreateSubjectDoubleLessonRequest struct { SubjectID string `json:"subject_id" binding:"required,uuid"` IsHard bool `json:"is_hard"` Weight int `json:"weight" binding:"min=0,max=100"` Active bool `json:"active"` Note string `json:"note"` } // Class type CreateClassMaxHoursDayRequest struct { ClassID string `json:"class_id" binding:"required,uuid"` MaxHours int `json:"max_hours" binding:"required,min=1,max=12"` IsHard bool `json:"is_hard"` Weight int `json:"weight" binding:"min=0,max=100"` Active bool `json:"active"` Note string `json:"note"` } type CreateClassNoGapsRequest struct { ClassID string `json:"class_id" binding:"required,uuid"` IsHard bool `json:"is_hard"` Weight int `json:"weight" binding:"min=0,max=100"` Active bool `json:"active"` Note string `json:"note"` } // Room type CreateRoomRequiresTypeRequest struct { SubjectID string `json:"subject_id" binding:"required,uuid"` RoomType string `json:"room_type" binding:"required"` IsHard bool `json:"is_hard"` Weight int `json:"weight" binding:"min=0,max=100"` Active bool `json:"active"` Note string `json:"note"` } type CreateRoomUnavailableRequest struct { RoomID string `json:"room_id" binding:"required,uuid"` DayOfWeek int `json:"day_of_week" binding:"required,min=1,max=7"` PeriodIndex int `json:"period_index" binding:"required,min=1,max=12"` IsHard bool `json:"is_hard"` Weight int `json:"weight" binding:"min=0,max=100"` Active bool `json:"active"` Note string `json:"note"` }