""" State Engine Models - Datenstrukturen für das Phasen-Management. Definiert: - SchoolYearPhase: Die 9 Phasen des Schuljahres - TeacherContext: Aggregierter Kontext für Antizipation - Event, Milestone, Stats: Unterstützende Modelle """ from dataclasses import dataclass, field from datetime import datetime from enum import Enum from typing import List, Optional, Dict, Any import uuid class SchoolYearPhase(str, Enum): """Die 9 Phasen eines Schuljahres.""" # Phase 1: Schuljahresbeginn (Aug/Sep) ONBOARDING = "onboarding" # Neue Lehrer, Schulsuche, Grundkonfiguration # Phase 2: Schuljahresstart (Sep/Okt) SCHOOL_YEAR_START = "school_year_start" # Klassen anlegen, Stundenplan, erste Einheiten # Phase 3: Unterrichtsaufbau (Okt/Nov) TEACHING_SETUP = "teaching_setup" # Lerneinheiten, Materialien, Elternkommunikation # Phase 4: Leistungsphase 1 (Nov/Dez) PERFORMANCE_1 = "performance_1" # Klausuren, Korrektur, erste Noten # Phase 5: Halbjahresabschluss (Jan/Feb) SEMESTER_END = "semester_end" # Halbjahreszeugnisse, Konferenzen, Elterngespräche # Phase 6: 2. Halbjahr Unterricht (Feb/Apr) TEACHING_2 = "teaching_2" # Wiederholung von Phase 3 # Phase 7: Leistungsphase 2 (Apr/Jun) PERFORMANCE_2 = "performance_2" # Klausuren, Korrektur, finale Noten # Phase 8: Jahresabschluss (Jun/Jul) YEAR_END = "year_end" # Abschlusszeugnisse, Versetzung, Archivierung # Phase 9: Archiviert ARCHIVED = "archived" # Schuljahr abgeschlossen @dataclass class PhaseInfo: """Metadaten zu einer Phase.""" phase: SchoolYearPhase display_name: str description: str typical_months: List[int] # 1-12 expected_duration_weeks: int required_actions: List[str] optional_actions: List[str] # Phasen-Definitionen mit Metadaten PHASE_INFO: Dict[SchoolYearPhase, PhaseInfo] = { SchoolYearPhase.ONBOARDING: PhaseInfo( phase=SchoolYearPhase.ONBOARDING, display_name="Onboarding", description="Willkommen bei BreakPilot! Richte dein Schuljahr ein.", typical_months=[8, 9], expected_duration_weeks=2, required_actions=["school_select", "consent_accept", "profile_complete"], optional_actions=["import_previous_year"], ), SchoolYearPhase.SCHOOL_YEAR_START: PhaseInfo( phase=SchoolYearPhase.SCHOOL_YEAR_START, display_name="Schuljahresstart", description="Lege deine Klassen und den Stundenplan an.", typical_months=[9, 10], expected_duration_weeks=3, required_actions=["create_classes", "add_students", "create_timetable"], optional_actions=["import_students_csv", "invite_parents"], ), SchoolYearPhase.TEACHING_SETUP: PhaseInfo( phase=SchoolYearPhase.TEACHING_SETUP, display_name="Unterrichtsaufbau", description="Erstelle Lerneinheiten und Materialien.", typical_months=[10, 11], expected_duration_weeks=4, required_actions=["create_learning_units"], optional_actions=["generate_worksheets", "prepare_parent_meeting"], ), SchoolYearPhase.PERFORMANCE_1: PhaseInfo( phase=SchoolYearPhase.PERFORMANCE_1, display_name="Leistungsphase 1", description="Erste Klausuren und Bewertungen.", typical_months=[11, 12], expected_duration_weeks=6, required_actions=["schedule_exams", "enter_grades"], optional_actions=["use_correction_module", "generate_feedback"], ), SchoolYearPhase.SEMESTER_END: PhaseInfo( phase=SchoolYearPhase.SEMESTER_END, display_name="Halbjahresabschluss", description="Halbjahreszeugnisse und Konferenzen.", typical_months=[1, 2], expected_duration_weeks=3, required_actions=["complete_grades", "generate_certificates"], optional_actions=["parent_conferences", "archive_semester"], ), SchoolYearPhase.TEACHING_2: PhaseInfo( phase=SchoolYearPhase.TEACHING_2, display_name="2. Halbjahr", description="Weiterführender Unterricht im 2. Halbjahr.", typical_months=[2, 3, 4], expected_duration_weeks=8, required_actions=["update_learning_units"], optional_actions=["generate_worksheets"], ), SchoolYearPhase.PERFORMANCE_2: PhaseInfo( phase=SchoolYearPhase.PERFORMANCE_2, display_name="Leistungsphase 2", description="Finale Klausuren und Bewertungen.", typical_months=[4, 5, 6], expected_duration_weeks=8, required_actions=["schedule_exams", "enter_final_grades"], optional_actions=["use_correction_module"], ), SchoolYearPhase.YEAR_END: PhaseInfo( phase=SchoolYearPhase.YEAR_END, display_name="Jahresabschluss", description="Abschlusszeugnisse und Versetzung.", typical_months=[6, 7], expected_duration_weeks=3, required_actions=["complete_all_grades", "generate_final_certificates"], optional_actions=["archive_year", "export_data"], ), SchoolYearPhase.ARCHIVED: PhaseInfo( phase=SchoolYearPhase.ARCHIVED, display_name="Archiviert", description="Das Schuljahr ist abgeschlossen.", typical_months=[7, 8], expected_duration_weeks=0, required_actions=[], optional_actions=["view_archive"], ), } def get_phase_info(phase: SchoolYearPhase) -> PhaseInfo: """Gibt Metadaten für eine Phase zurück.""" return PHASE_INFO.get(phase, PHASE_INFO[SchoolYearPhase.ONBOARDING]) @dataclass class ClassSummary: """Zusammenfassung einer Klasse.""" class_id: str name: str grade_level: int student_count: int subject: str @dataclass class Event: """Ein anstehendes Ereignis.""" type: str # "exam", "parent_meeting", "deadline" title: str date: datetime in_days: int class_id: Optional[str] = None priority: str = "medium" # "high", "medium", "low" @dataclass class Milestone: """Ein erreichter Meilenstein.""" milestone: str completed_at: datetime @dataclass class TeacherStats: """Statistiken eines Lehrers.""" learning_units_created: int = 0 exams_scheduled: int = 0 exams_graded: int = 0 grades_entered: int = 0 parent_messages_count: int = 0 avg_response_time_hours: float = 0.0 unanswered_messages: int = 0 @dataclass class TeacherContext: """ Aggregierter Kontext für einen Lehrer. Enthält alle relevanten Informationen für die Antizipations-Engine: - Identifikation - Schulkontext - Zeitlicher Kontext - Klassen und Schüler - Termine und Events - Fortschritt - Statistiken """ # Identifikation teacher_id: str school_id: str school_year_id: str # Schulkontext federal_state: str = "niedersachsen" # Bundesland school_type: str = "gymnasium" # Schulform # Zeitlicher Kontext school_year_start: datetime = field(default_factory=datetime.now) current_phase: SchoolYearPhase = SchoolYearPhase.ONBOARDING phase_entered_at: datetime = field(default_factory=datetime.now) weeks_since_start: int = 0 days_in_phase: int = 0 # Klassen und Schüler classes: List[ClassSummary] = field(default_factory=list) total_students: int = 0 # Termine und Events upcoming_events: List[Event] = field(default_factory=list) overdue_actions: List[Dict[str, Any]] = field(default_factory=list) # Fortschritt completed_milestones: List[str] = field(default_factory=list) pending_milestones: List[str] = field(default_factory=list) # Statistiken stats: TeacherStats = field(default_factory=TeacherStats) def has_completed_milestone(self, milestone: str) -> bool: """Prüft ob ein Meilenstein erreicht wurde.""" return milestone in self.completed_milestones def has_learning_units(self) -> bool: """Prüft ob Lerneinheiten erstellt wurden.""" return self.stats.learning_units_created > 0 def is_in_month(self, month: int) -> bool: """Prüft ob aktueller Monat übereinstimmt.""" return datetime.now().month == month def get_next_deadline(self) -> Optional[Event]: """Gibt die nächste Deadline zurück.""" for e in self.upcoming_events: if e.type == "deadline": return e return None def get_next_exam(self) -> Optional[Event]: """Gibt die nächste Klausur zurück.""" for e in self.upcoming_events: if e.type == "exam" and e.in_days > 0: return e return None def to_dict(self) -> Dict[str, Any]: """Konvertiert zu Dictionary.""" return { "teacher_id": self.teacher_id, "school_id": self.school_id, "school_year_id": self.school_year_id, "federal_state": self.federal_state, "school_type": self.school_type, "school_year_start": self.school_year_start.isoformat(), "current_phase": self.current_phase.value, "phase_entered_at": self.phase_entered_at.isoformat(), "weeks_since_start": self.weeks_since_start, "days_in_phase": self.days_in_phase, "classes": [ { "class_id": c.class_id, "name": c.name, "grade_level": c.grade_level, "student_count": c.student_count, "subject": c.subject, } for c in self.classes ], "total_students": self.total_students, "upcoming_events": [ { "type": e.type, "title": e.title, "date": e.date.isoformat(), "in_days": e.in_days, "class_id": e.class_id, "priority": e.priority, } for e in self.upcoming_events ], "completed_milestones": self.completed_milestones, "pending_milestones": self.pending_milestones, "stats": { "learning_units_created": self.stats.learning_units_created, "exams_scheduled": self.stats.exams_scheduled, "exams_graded": self.stats.exams_graded, "grades_entered": self.stats.grades_entered, "parent_messages_count": self.stats.parent_messages_count, "avg_response_time_hours": self.stats.avg_response_time_hours, "unanswered_messages": self.stats.unanswered_messages, }, }