""" SQLAlchemy Database Models fuer Schuljahres-Kontext (Phase 8). Erweitert das Companion-Modul um ein 2-Schichten-Modell: - Makro-Ebene: 7 Schuljahres-Phasen (langsam wechselnd) - Mikro-Ebene: Events, Routinen, Arbeitsmodi (tagesaktuell) """ from datetime import datetime, time from sqlalchemy import ( Column, String, Integer, DateTime, JSON, Boolean, Text, Enum as SQLEnum, Time ) import enum import uuid from .database import Base # Exports __all__ = [ "MacroPhaseEnum", "EventTypeEnum", "EventStatusEnum", "RoutineTypeEnum", "RecurrencePatternEnum", "TeacherContextDB", "SchoolyearEventDB", "RecurringRoutineDB", "FEDERAL_STATES", "SCHOOL_TYPES", ] # ==================== Konstanten ==================== FEDERAL_STATES = { "BW": "Baden-Wuerttemberg", "BY": "Bayern", "BE": "Berlin", "BB": "Brandenburg", "HB": "Bremen", "HH": "Hamburg", "HE": "Hessen", "MV": "Mecklenburg-Vorpommern", "NI": "Niedersachsen", "NW": "Nordrhein-Westfalen", "RP": "Rheinland-Pfalz", "SL": "Saarland", "SN": "Sachsen", "ST": "Sachsen-Anhalt", "SH": "Schleswig-Holstein", "TH": "Thueringen", } SCHOOL_TYPES = { "grundschule": "Grundschule", "hauptschule": "Hauptschule", "realschule": "Realschule", "gymnasium": "Gymnasium", "gesamtschule": "Gesamtschule", "foerderschule": "Foerderschule", "berufsschule": "Berufsschule", "gemeinschaftsschule": "Gemeinschaftsschule", } # ==================== Enums ==================== class MacroPhaseEnum(str, enum.Enum): """ 7 Schuljahres-Phasen (Makro-State). Wechselt alle paar Wochen basierend auf Schulkalender und Nutzungsverhalten. """ ONBOARDING = "onboarding" # Ersteinrichtung (Klassen, Stundenplan) SCHULJAHRESSTART = "schuljahresstart" # Erste 2-3 Wochen UNTERRICHTSAUFBAU = "unterrichtsaufbau" # Routinen etablieren LEISTUNGSPHASE_1 = "leistungsphase_1" # Erste Klausuren HALBJAHRESABSCHLUSS = "halbjahresabschluss" # Notenschluss, Zeugnisse LEISTUNGSPHASE_2 = "leistungsphase_2" # Pruefungsvorbereitung JAHRESABSCHLUSS = "jahresabschluss" # Finale Noten, Versetzung class EventTypeEnum(str, enum.Enum): """Event-Typen fuer Schuljahr-Events.""" EXAM = "exam" # Klassenarbeit, Klausur PARENT_EVENING = "parent_evening" # Elternabend TRIP = "trip" # Klassenfahrt, Ausflug PROJECT = "project" # Projektwoche INTERNSHIP = "internship" # Praktikum PRESENTATION = "presentation" # Referate, Praesentationen SPORTS_DAY = "sports_day" # Sporttag, Bundesjugendspiele SCHOOL_FESTIVAL = "school_festival" # Schulfest PARENT_CONSULTATION = "parent_consultation" # Elternsprechtag GRADE_DEADLINE = "grade_deadline" # Notenschluss REPORT_CARDS = "report_cards" # Zeugnisausgabe HOLIDAY_START = "holiday_start" # Ferienbeginn HOLIDAY_END = "holiday_end" # Ferienende OTHER = "other" class EventStatusEnum(str, enum.Enum): """Status eines Events.""" PLANNED = "planned" IN_PROGRESS = "in_progress" DONE = "done" CANCELLED = "cancelled" class RoutineTypeEnum(str, enum.Enum): """Typen wiederkehrender Routinen.""" TEACHER_CONFERENCE = "teacher_conference" # Lehrerkonferenz SUBJECT_CONFERENCE = "subject_conference" # Fachkonferenz OFFICE_HOURS = "office_hours" # Sprechstunde TEAM_MEETING = "team_meeting" # Teamsitzung SUPERVISION = "supervision" # Pausenaufsicht CORRECTION_TIME = "correction_time" # Korrekturzeit PREP_TIME = "prep_time" # Vorbereitungszeit OTHER = "other" class RecurrencePatternEnum(str, enum.Enum): """Wiederholungsmuster fuer Routinen.""" DAILY = "daily" WEEKLY = "weekly" BIWEEKLY = "biweekly" MONTHLY = "monthly" # ==================== Models ==================== class TeacherContextDB(Base): """ Lehrer-Kontext fuer Schuljahres-Begleitung (Phase 8). Speichert den Makro-Kontext eines Lehrers: - Bundesland (fuer Schulkalender/Ferien) - Schulart - Aktuelles Schuljahr - Aktuelle Makro-Phase Ein Lehrer hat genau einen Context-Eintrag. """ __tablename__ = 'teacher_contexts' id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) teacher_id = Column(String(100), unique=True, nullable=False, index=True) # Schul-Kontext federal_state = Column(String(10), default="BY") # BY, NRW, etc. school_type = Column(String(50), default="gymnasium") # gymnasium, realschule, etc. # Schuljahr schoolyear = Column(String(20), default="2024-2025") # z.B. "2024-2025" schoolyear_start = Column(DateTime, nullable=True) # Erster Schultag # Aktueller Stand (Makro-Phase) macro_phase = Column( SQLEnum(MacroPhaseEnum), default=MacroPhaseEnum.ONBOARDING, nullable=False ) current_week = Column(Integer, default=1) # Schulwoche 1-52 # Berechnete Flags (werden beim Abrufen aktualisiert) is_exam_period = Column(Boolean, default=False) is_before_holidays = Column(Boolean, default=False) # Onboarding-Status onboarding_completed = Column(Boolean, default=False) has_classes = Column(Boolean, default=False) has_schedule = Column(Boolean, default=False) # Metadaten created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) def __repr__(self): return f"" class SchoolyearEventDB(Base): """ Schuljahr-Event (Phase 8). Ein einmaliges Event im Schuljahr wie: - Klassenarbeit - Elternabend - Klassenfahrt - Projektwoche Events haben einen Zeitraum und optionale Klassen-/Fach-Zuordnung. """ __tablename__ = 'schoolyear_events' id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) teacher_id = Column(String(100), nullable=False, index=True) # Event-Typ und Titel event_type = Column( SQLEnum(EventTypeEnum), default=EventTypeEnum.OTHER, nullable=False ) title = Column(String(300), nullable=False) description = Column(Text, default="") # Zeitraum start_date = Column(DateTime, nullable=False, index=True) end_date = Column(DateTime, nullable=True) # Null = eintaegiges Event # Optionale Zuordnung class_id = Column(String(100), nullable=True, index=True) subject = Column(String(100), nullable=True) # Status status = Column( SQLEnum(EventStatusEnum), default=EventStatusEnum.PLANNED, nullable=False, index=True ) # Flags fuer Antizipation needs_preparation = Column(Boolean, default=True) # Braucht Vorbereitung? preparation_done = Column(Boolean, default=False) # Vorbereitung erledigt? reminder_days_before = Column(Integer, default=7) # Tage vorher erinnern # Flexible Zusatzdaten (z.B. Rubric-ID fuer Klausur) extra_data = Column(JSON, default=dict) # Renamed from 'metadata' which is reserved in SQLAlchemy created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) def __repr__(self): return f"" class RecurringRoutineDB(Base): """ Wiederkehrende Routine (Phase 8). Eine regelmaessig wiederkehrende Aktivitaet wie: - Lehrerkonferenz (woechentlich/monatlich) - Fachkonferenz - Sprechstunde - Korrekturzeit Routinen wiederholen sich nach einem bestimmten Muster. """ __tablename__ = 'recurring_routines' id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) teacher_id = Column(String(100), nullable=False, index=True) # Routine-Typ und Titel routine_type = Column( SQLEnum(RoutineTypeEnum), default=RoutineTypeEnum.OTHER, nullable=False ) title = Column(String(300), nullable=False) description = Column(Text, default="") # Wiederholung recurrence_pattern = Column( SQLEnum(RecurrencePatternEnum), default=RecurrencePatternEnum.WEEKLY, nullable=False ) day_of_week = Column(Integer, nullable=True) # 0=Mo, 6=So (Null wenn daily/monthly) day_of_month = Column(Integer, nullable=True) # 1-31 fuer monthly time_of_day = Column(Time, nullable=True) # z.B. 14:00 # Dauer in Minuten duration_minutes = Column(Integer, default=60) # Aktiv? is_active = Column(Boolean, default=True) # Startdatum (ab wann gilt die Routine?) valid_from = Column(DateTime, nullable=True) valid_until = Column(DateTime, nullable=True) # Metadaten extra_data = Column(JSON, default=dict) # Renamed from 'metadata' which is reserved in SQLAlchemy created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) def __repr__(self): return f""