""" SQLAlchemy Database Models fuer Classroom Engine (Feature f13). Persistiert Unterrichtsstunden und deren Verlauf in PostgreSQL. """ from datetime import datetime from sqlalchemy import ( Column, String, Integer, Float, DateTime, JSON, Boolean, Text, Enum as SQLEnum, ForeignKey ) from sqlalchemy.orm import relationship import enum import uuid from .database import Base # Import Phase 8 Context Models from .context_models import ( MacroPhaseEnum, EventTypeEnum, EventStatusEnum, RoutineTypeEnum, RecurrencePatternEnum, TeacherContextDB, SchoolyearEventDB, RecurringRoutineDB, FEDERAL_STATES, SCHOOL_TYPES, ) # Exports __all__ = [ "LessonPhaseEnum", "LessonSessionDB", "PhaseHistoryDB", "LessonTemplateDB", "TeacherSettingsDB", "HomeworkStatusEnum", "HomeworkDB", "MaterialTypeEnum", "PhaseMaterialDB", "LessonReflectionDB", "FeedbackTypeEnum", "FeedbackStatusEnum", "FeedbackPriorityEnum", "TeacherFeedbackDB", # Phase 8: Schuljahres-Kontext "MacroPhaseEnum", "EventTypeEnum", "EventStatusEnum", "RoutineTypeEnum", "RecurrencePatternEnum", "TeacherContextDB", "SchoolyearEventDB", "RecurringRoutineDB", "FEDERAL_STATES", "SCHOOL_TYPES", ] class LessonPhaseEnum(str, enum.Enum): """Unterrichtsphasen als DB-Enum.""" NOT_STARTED = "not_started" EINSTIEG = "einstieg" ERARBEITUNG = "erarbeitung" SICHERUNG = "sicherung" TRANSFER = "transfer" REFLEXION = "reflexion" ENDED = "ended" class LessonSessionDB(Base): """ Persistierte Unterrichtsstunde. Speichert alle Session-Daten inklusive Timer-Status und History. """ __tablename__ = 'lesson_sessions' # Primary Key id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) # Beziehungen teacher_id = Column(String(100), nullable=False, index=True) class_id = Column(String(50), nullable=False, index=True) # Session Metadaten subject = Column(String(100), nullable=False) topic = Column(String(500)) # Status current_phase = Column( SQLEnum(LessonPhaseEnum), default=LessonPhaseEnum.NOT_STARTED, nullable=False ) is_paused = Column(Boolean, default=False) # Timestamps created_at = Column(DateTime, default=datetime.utcnow) lesson_started_at = Column(DateTime) lesson_ended_at = Column(DateTime) phase_started_at = Column(DateTime) pause_started_at = Column(DateTime) # Timer-Daten total_paused_seconds = Column(Integer, default=0) phase_durations = Column(JSON, default=dict) # {"einstieg": 8, ...} # History & Notizen phase_history = Column(JSON, default=list) # [{phase, started_at, ended_at, duration}] notes = Column(Text, default="") homework = Column(Text, default="") # Relationship zu PhaseHistory (optional fuer detaillierte Abfragen) history_entries = relationship("PhaseHistoryDB", back_populates="session", cascade="all, delete-orphan") def __repr__(self): return f"" class PhaseHistoryDB(Base): """ Einzelner Phasen-Verlaufseintrag. Ermoeglicht detaillierte Statistiken ueber Phasendauern. """ __tablename__ = 'lesson_phase_history' id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) session_id = Column(String(36), ForeignKey('lesson_sessions.id'), nullable=False, index=True) phase = Column(SQLEnum(LessonPhaseEnum), nullable=False) started_at = Column(DateTime, nullable=False) ended_at = Column(DateTime) duration_seconds = Column(Integer) # Zusaetzliche Metriken was_extended = Column(Boolean, default=False) extension_minutes = Column(Integer, default=0) pause_count = Column(Integer, default=0) total_pause_seconds = Column(Integer, default=0) # Relationship session = relationship("LessonSessionDB", back_populates="history_entries") def __repr__(self): return f"" class LessonTemplateDB(Base): """ Stunden-Vorlage (Feature f37). Ermoeglicht Speicherung von wiederverwendbaren Stundenkonfigurationen. """ __tablename__ = 'lesson_templates' id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) teacher_id = Column(String(100), nullable=False, index=True) # Basis-Infos name = Column(String(200), nullable=False) description = Column(Text, default="") subject = Column(String(100), default="") grade_level = Column(String(50), default="") # Phasenkonfiguration phase_durations = Column(JSON, default=dict) # Vorbelegungen default_topic = Column(String(500), default="") default_notes = Column(Text, default="") # Metadaten is_public = Column(Boolean, default=False) usage_count = Column(Integer, default=0) created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) def __repr__(self): return f"" class TeacherSettingsDB(Base): """ Lehrer-spezifische Einstellungen (Feature f16). Speichert individuelle Praeferenzen wie Phasendauern. """ __tablename__ = 'teacher_settings' id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) teacher_id = Column(String(100), unique=True, nullable=False, index=True) # Individuelle Phasendauern default_phase_durations = Column(JSON, default=dict) # UI Praeferenzen audio_enabled = Column(Boolean, default=True) high_contrast = Column(Boolean, default=False) # Statistik-Einstellungen show_statistics = Column(Boolean, default=True) created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) def __repr__(self): return f"" class HomeworkStatusEnum(str, enum.Enum): """Status-Enum fuer Hausaufgaben.""" ASSIGNED = "assigned" IN_PROGRESS = "in_progress" COMPLETED = "completed" OVERDUE = "overdue" class HomeworkDB(Base): """ Hausaufgaben-Tracking (Feature f20). Ermoeglicht die Verfolgung von Hausaufgaben ueber Sessions hinweg. """ __tablename__ = 'homework_assignments' id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) teacher_id = Column(String(100), nullable=False, index=True) class_id = Column(String(50), nullable=False, index=True) subject = Column(String(100), nullable=False) # Aufgaben-Details title = Column(String(300), nullable=False) description = Column(Text, default="") # Verknuepfung zur Session (optional) session_id = Column(String(36), ForeignKey('lesson_sessions.id'), nullable=True, index=True) # Faelligkeit und Status due_date = Column(DateTime, nullable=True, index=True) status = Column( SQLEnum(HomeworkStatusEnum), default=HomeworkStatusEnum.ASSIGNED, nullable=False ) created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) def __repr__(self): return f"" class MaterialTypeEnum(str, enum.Enum): """Typ-Enum fuer Materialien.""" DOCUMENT = "document" LINK = "link" VIDEO = "video" IMAGE = "image" WORKSHEET = "worksheet" PRESENTATION = "presentation" OTHER = "other" class PhaseMaterialDB(Base): """ Phasen-Materialien (Feature f19). Ermoeglicht das Anhaengen von Dokumenten und Links an Unterrichtsphasen. """ __tablename__ = 'phase_materials' id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) teacher_id = Column(String(100), nullable=False, index=True) # Material-Details title = Column(String(300), nullable=False) material_type = Column( SQLEnum(MaterialTypeEnum), default=MaterialTypeEnum.DOCUMENT, nullable=False ) url = Column(String(2000), nullable=True) # URL oder Dateipfad description = Column(Text, default="") # Phasen-Zuordnung phase = Column(String(50), nullable=True, index=True) # einstieg, erarbeitung, etc. subject = Column(String(100), default="") grade_level = Column(String(50), default="") # Tags als JSON Array tags = Column(JSON, default=list) # Sharing und Nutzung is_public = Column(Boolean, default=False) usage_count = Column(Integer, default=0) # Optionale Session-Verknuepfung session_id = Column(String(36), ForeignKey('lesson_sessions.id'), nullable=True, index=True) created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) def __repr__(self): return f"" class LessonReflectionDB(Base): """ Post-Lesson Reflection (Phase 5: Analytics). Ermoeglicht Lehrern, nach der Stunde Reflexionsnotizen zu speichern. """ __tablename__ = 'lesson_reflections' id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) session_id = Column(String(36), ForeignKey('lesson_sessions.id'), nullable=False, unique=True, index=True) teacher_id = Column(String(100), nullable=False, index=True) # Reflexions-Inhalt notes = Column(Text, default="") # Optionale Selbst-Bewertung (1-5) overall_rating = Column(Integer, nullable=True) # Was hat gut funktioniert? (JSON Array) what_worked = Column(JSON, default=list) # Was wuerde ich anders machen? (JSON Array) improvements = Column(JSON, default=list) # Notizen fuer naechste Stunde notes_for_next_lesson = Column(Text, default="") created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) def __repr__(self): return f"" class FeedbackTypeEnum(str, enum.Enum): """Feedback-Typen fuer Lehrer-Rueckmeldungen.""" BUG = "bug" FEATURE_REQUEST = "feature_request" IMPROVEMENT = "improvement" PRAISE = "praise" QUESTION = "question" class FeedbackStatusEnum(str, enum.Enum): """Status eines Feedbacks.""" NEW = "new" ACKNOWLEDGED = "acknowledged" PLANNED = "planned" IMPLEMENTED = "implemented" DECLINED = "declined" class FeedbackPriorityEnum(str, enum.Enum): """Prioritaet eines Feedbacks.""" CRITICAL = "critical" HIGH = "high" MEDIUM = "medium" LOW = "low" class TeacherFeedbackDB(Base): """ Lehrer-Feedback zum Companion-Modul (Phase 7). Ermoeglicht Lehrern, Bug-Reports, Feature-Requests und Verbesserungen direkt aus dem Lehrer-Frontend zu senden. """ __tablename__ = 'teacher_feedback' id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) # Wer hat das Feedback gegeben? teacher_id = Column(String(100), nullable=False, index=True) teacher_name = Column(String(200), default="") teacher_email = Column(String(200), default="") # Feedback-Inhalt title = Column(String(500), nullable=False) description = Column(Text, nullable=False) # Kategorisierung feedback_type = Column( SQLEnum(FeedbackTypeEnum), default=FeedbackTypeEnum.IMPROVEMENT, nullable=False ) priority = Column( SQLEnum(FeedbackPriorityEnum), default=FeedbackPriorityEnum.MEDIUM, nullable=False ) status = Column( SQLEnum(FeedbackStatusEnum), default=FeedbackStatusEnum.NEW, nullable=False, index=True ) # Optionale Verknuepfung zu Feature related_feature = Column(String(50), nullable=True) # Kontext: Wo war der User als er Feedback gab? context_url = Column(String(500), default="") context_phase = Column(String(50), default="") # z.B. "einstieg" context_session_id = Column(String(36), nullable=True) # Browser/Device Info user_agent = Column(String(500), default="") # Entwickler-Antwort response = Column(Text, default="") responded_at = Column(DateTime, nullable=True) responded_by = Column(String(100), nullable=True) created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) def __repr__(self): return f""