# Constraint-Referenz Jeder Constraint-Eintrag im UI legt eine Row in der korrespondierenden `tt_constraint_*` Tabelle an. Der Solver liest sie als Problem-Facts und joined sie gegen die Lessons. ## Gemeinsame Felder | Feld | Typ | Bedeutung | |------|-----|-----------| | `is_hard` | bool | true = Solver muss einhalten (HardScore -1 pro Verstoss). false = Soft-Penalty (SoftScore -weight pro Verstoss) | | `weight` | int 0-100 | Multiplikator fuer Soft-Penalties; bei Hard ignoriert | | `active` | bool | inaktive Rows werden vom Solver ignoriert | | `note` | TEXT | Freier Begruendungstext fuer den Rektor | ## Constraint-Typen ### Universal (immer aktiv, nicht abschaltbar) | Constraint | Bedeutung | |------------|-----------| | `class_conflict` | Eine Klasse hat nur eine Lesson pro Timeslot | | `teacher_conflict` | Ein Lehrer haelt nur eine Lesson pro Timeslot | | `room_conflict` | Ein Raum hostet nur eine Lesson pro Timeslot | ### DB-Driven (vom Rektor konfigurierbar) Jeder Typ existiert als `_hard` und `_soft` Constraint im Provider: | Typ | Tabelle | Beispiel | |-----|---------|----------| | Lehrer Tag nicht verfuegbar | `tt_constraint_teacher_unavailable_day` | „Anna nie Montags" | | Lehrer Zeitfenster nicht verfuegbar | `tt_constraint_teacher_unavailable_window` | „Bob Dienstag 13–17 Uhr nicht" | | Lehrer Max h/Tag | `tt_constraint_teacher_max_hours_day` | Anti-Burnout | | Lehrer Max h/Woche | `tt_constraint_teacher_max_hours_week` | Teilzeit-Cap | | Lehrer Fach ausgeschlossen | `tt_constraint_teacher_excluded_subject` | Qualifikationsluecke | | Lehrer Raum ausgeschlossen | `tt_constraint_teacher_excluded_room` | Rollstuhl, kein Fahrstuhl | | Fach Mindest-Tagesabstand | `tt_constraint_subject_min_day_gap` | Mathe nicht 2 Tage hintereinander | | Fach Max Stunden am Stueck | `tt_constraint_subject_max_consecutive` | Keine Dreifachstunde | | Fach Mehrfach=zusammen | `tt_constraint_subject_contiguous_when_repeated` | Wenn 2× am Tag, dann benachbart | | Fach Bevorzugte Stunden | `tt_constraint_subject_preferred_period` | Hauptfaecher morgens | | Fach Doppelstunde bevorzugt | `tt_constraint_subject_double_lesson` | Sport als 90-min-Block | | Klasse Max h/Tag | `tt_constraint_class_max_hours_day` | Jugendgerecht | | Klasse Keine Freistunden | `tt_constraint_class_no_gaps` | Soft, minimiert Loecher | | Raumtyp erforderlich | `tt_constraint_room_requires_type` | Sport → Sporthalle | | Raum nicht verfuegbar | `tt_constraint_room_unavailable` | Wartung, Renovierung | ## Hard vs. Soft — Faustregel - **Hard** wenn die Schule den Plan rechtlich oder physisch nicht ausfuehren kann (Lehrervertrag, Behinderung, Raum existiert nicht). - **Soft** wenn es nur eine Praeferenz ist („Mathe lieber morgens", „keine Freistunden"). Score-Bewertung im UI: - `hard_score = 0` → Plan ist gueltig - `hard_score < 0` → mindestens eine harte Regel ist verletzt (Solver meldet das als `infeasible`) - `soft_score` → wird in den UI angezeigt; je naeher an 0, desto besser ## Erweitern um einen 16. Constraint-Typ 1. Neue Tabelle in `school-service/internal/database/timetable_constraints_migrations.go` 2. Model + DTO in `models/timetable_constraints.go` 3. Service + Handler im gleichen Paket-Pattern wie die existierenden 15 4. Route in `cmd/server/main.go` 5. Rule-Dataclass in `timetable-solver-service/app/rules.py` 6. ProblemFactCollection in `domain.py` 7. ConstraintProvider-Funktion in `constraints.py` (Hard + Soft Variante) 8. Frontend: Editor-Komponente in `_components/regeln/`, dann in `RegelnHub.tsx` registrieren