Some checks failed
Tests / Go Tests (push) Has been cancelled
Tests / Python Tests (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / Go Lint (push) Has been cancelled
Tests / Python Lint (push) Has been cancelled
Tests / Security Scan (push) Has been cancelled
Tests / All Checks Passed (push) Has been cancelled
Security Scanning / Secret Scanning (push) Has been cancelled
Security Scanning / Dependency Vulnerability Scan (push) Has been cancelled
Security Scanning / Go Security Scan (push) Has been cancelled
Security Scanning / Python Security Scan (push) Has been cancelled
Security Scanning / Node.js Security Scan (push) Has been cancelled
Security Scanning / Docker Image Security (push) Has been cancelled
Security Scanning / Security Summary (push) Has been cancelled
CI/CD Pipeline / Go Tests (push) Has been cancelled
CI/CD Pipeline / Python Tests (push) Has been cancelled
CI/CD Pipeline / Website Tests (push) Has been cancelled
CI/CD Pipeline / Linting (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Docker Build & Push (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / CI Summary (push) Has been cancelled
ci/woodpecker/manual/build-ci-image Pipeline was successful
ci/woodpecker/manual/main Pipeline failed
All services: admin-v2, studio-v2, website, ai-compliance-sdk, consent-service, klausur-service, voice-service, and infrastructure. Large PDFs and compiled binaries excluded via .gitignore.
292 lines
9.0 KiB
Python
292 lines
9.0 KiB
Python
"""
|
|
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})>"
|