fix: Restore all files lost during destructive rebase
A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.
This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).
Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
291
backend/classroom_engine/context_models.py
Normal file
291
backend/classroom_engine/context_models.py
Normal file
@@ -0,0 +1,291 @@
|
||||
"""
|
||||
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"<TeacherContext {self.teacher_id} ({self.macro_phase.value})>"
|
||||
|
||||
|
||||
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"<SchoolyearEvent {self.title} ({self.event_type.value})>"
|
||||
|
||||
|
||||
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"<RecurringRoutine {self.title} ({self.recurrence_pattern.value})>"
|
||||
Reference in New Issue
Block a user