[split-required] Split 500-850 LOC files (batch 2)

backend-lehrer (10 files):
- game/database.py (785 → 5), correction_api.py (683 → 4)
- classroom_engine/antizipation.py (676 → 5)
- llm_gateway schools/edu_search already done in prior batch

klausur-service (12 files):
- orientation_crop_api.py (694 → 5), pdf_export.py (677 → 4)
- zeugnis_crawler.py (676 → 5), grid_editor_api.py (671 → 5)
- eh_templates.py (658 → 5), mail/api.py (651 → 5)
- qdrant_service.py (638 → 5), training_api.py (625 → 4)

website (6 pages):
- middleware (696 → 8), mail (733 → 6), consent (628 → 8)
- compliance/risks (622 → 5), export (502 → 5), brandbook (629 → 7)

studio-v2 (3 components):
- B2BMigrationWizard (848 → 3), CleanupPanel (765 → 2)
- dashboard-experimental (739 → 2)

admin-lehrer (4 files):
- uebersetzungen (769 → 4), manager (670 → 2)
- ChunkBrowserQA (675 → 6), dsfa/page (674 → 5)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-04-25 08:24:01 +02:00
parent 34da9f4cda
commit b4613e26f3
118 changed files with 15258 additions and 14680 deletions

View File

@@ -0,0 +1,143 @@
# ==============================================
# Breakpilot Drive - Game Database Models
# ==============================================
# Data models, enums, and achievement definitions.
import os
import logging
from datetime import datetime
from typing import Optional, Dict, Any
from dataclasses import dataclass
from enum import IntEnum
logger = logging.getLogger(__name__)
# Database URL from environment
GAME_DB_URL = os.getenv(
"DATABASE_URL",
"postgresql://breakpilot:breakpilot123@localhost:5432/breakpilot"
)
class LearningLevel(IntEnum):
"""Learning level enum mapping to grade ranges."""
BEGINNER = 1 # Klasse 2-3
ELEMENTARY = 2 # Klasse 3-4
INTERMEDIATE = 3 # Klasse 4-5
ADVANCED = 4 # Klasse 5-6
EXPERT = 5 # Klasse 6+
@dataclass
class StudentLearningState:
"""Student learning state data model."""
id: Optional[str] = None
student_id: str = ""
overall_level: int = 3
math_level: float = 3.0
german_level: float = 3.0
english_level: float = 3.0
total_play_time_minutes: int = 0
total_sessions: int = 0
questions_answered: int = 0
questions_correct: int = 0
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
def to_dict(self) -> Dict[str, Any]:
"""Convert to dictionary."""
return {
"id": self.id,
"student_id": self.student_id,
"overall_level": self.overall_level,
"math_level": self.math_level,
"german_level": self.german_level,
"english_level": self.english_level,
"total_play_time_minutes": self.total_play_time_minutes,
"total_sessions": self.total_sessions,
"questions_answered": self.questions_answered,
"questions_correct": self.questions_correct,
"created_at": self.created_at.isoformat() if self.created_at else None,
"updated_at": self.updated_at.isoformat() if self.updated_at else None,
}
@property
def accuracy(self) -> float:
"""Calculate overall accuracy percentage."""
if self.questions_answered == 0:
return 0.0
return self.questions_correct / self.questions_answered
@dataclass
class GameSessionRecord:
"""Game session record for database storage."""
id: Optional[str] = None
student_id: str = ""
game_mode: str = "video"
duration_seconds: int = 0
distance_traveled: float = 0.0
score: int = 0
questions_answered: int = 0
questions_correct: int = 0
difficulty_level: int = 3
started_at: Optional[datetime] = None
ended_at: Optional[datetime] = None
metadata: Optional[Dict[str, Any]] = None
@dataclass
class GameQuizAnswer:
"""Individual quiz answer record."""
id: Optional[str] = None
session_id: Optional[str] = None
question_id: str = ""
subject: str = ""
difficulty: int = 3
is_correct: bool = False
answer_time_ms: int = 0
created_at: Optional[datetime] = None
@dataclass
class Achievement:
"""Achievement definition and unlock status."""
id: str
name: str
description: str
icon: str = "star"
category: str = "general" # general, streak, accuracy, time, score
threshold: int = 1
unlocked: bool = False
unlocked_at: Optional[datetime] = None
progress: int = 0
# Achievement definitions (static, not in DB)
ACHIEVEMENTS = [
# Erste Schritte
Achievement(id="first_game", name="Erste Fahrt", description="Spiele dein erstes Spiel", icon="rocket", category="general", threshold=1),
Achievement(id="five_games", name="Regelmaessiger Fahrer", description="Spiele 5 Spiele", icon="car", category="general", threshold=5),
Achievement(id="twenty_games", name="Erfahrener Pilot", description="Spiele 20 Spiele", icon="trophy", category="general", threshold=20),
# Serien
Achievement(id="streak_3", name="Guter Start", description="3 richtige Antworten hintereinander", icon="fire", category="streak", threshold=3),
Achievement(id="streak_5", name="Auf Feuer", description="5 richtige Antworten hintereinander", icon="fire", category="streak", threshold=5),
Achievement(id="streak_10", name="Unaufhaltsam", description="10 richtige Antworten hintereinander", icon="fire", category="streak", threshold=10),
# Genauigkeit
Achievement(id="perfect_game", name="Perfektes Spiel", description="100% richtig in einem Spiel (min. 5 Fragen)", icon="star", category="accuracy", threshold=100),
Achievement(id="accuracy_80", name="Scharfschuetze", description="80% Gesamtgenauigkeit (min. 50 Fragen)", icon="target", category="accuracy", threshold=80),
# Zeit
Achievement(id="play_30min", name="Ausdauer", description="30 Minuten Gesamtspielzeit", icon="clock", category="time", threshold=30),
Achievement(id="play_60min", name="Marathon", description="60 Minuten Gesamtspielzeit", icon="clock", category="time", threshold=60),
# Score
Achievement(id="score_5000", name="Punktejaeger", description="5.000 Punkte in einem Spiel", icon="gem", category="score", threshold=5000),
Achievement(id="score_10000", name="Highscore Hero", description="10.000 Punkte in einem Spiel", icon="crown", category="score", threshold=10000),
# Level
Achievement(id="level_up", name="Aufsteiger", description="Erreiche Level 2", icon="arrow-up", category="level", threshold=2),
Achievement(id="master", name="Meister", description="Erreiche Level 5", icon="medal", category="level", threshold=5),
]