Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 59s
CI / test-go-edu-search (push) Successful in 45s
CI / test-python-klausur (push) Failing after 3m7s
CI / test-python-agent-core (push) Successful in 24s
CI / test-nodejs-website (push) Successful in 31s
Strategic pivot: Studio-v2 becomes a language learning platform. Compliance guardrail added to CLAUDE.md — no scan/OCR of third-party content in customer frontend. Upload of OWN materials remains allowed. Phase 1.1 — vocabulary_db.py: PostgreSQL model for 160k+ words with english, german, IPA, syllables, examples, images, audio, difficulty, tags, translations (multilingual). Trigram search index. Phase 1.2 — vocabulary_api.py: Search, browse, filters, bulk import, learning unit creation from word selection. Creates QA items with enhanced fields (IPA, syllables, image, audio) for flashcards. Phase 1.3 — /vocabulary page: Search bar with POS/difficulty filters, word cards with audio buttons, unit builder sidebar. Teacher selects words → creates learning unit → redirects to flashcards. Sidebar: Added "Woerterbuch" (/vocabulary) and "Lernmodule" (/learn). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
216 lines
8.3 KiB
Python
216 lines
8.3 KiB
Python
"""
|
|
BreakPilot Backend-Lehrer
|
|
|
|
Lehrer-spezifische APIs extrahiert aus dem Monorepo.
|
|
Laeuft auf Port 8001 mit DB search_path=lehrer,core,public.
|
|
"""
|
|
|
|
import os
|
|
import logging
|
|
from contextlib import asynccontextmanager
|
|
|
|
from fastapi import FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Logging
|
|
# ---------------------------------------------------------------------------
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
|
|
)
|
|
logger = logging.getLogger("backend-lehrer")
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Database configuration (search_path = lehrer, core, public)
|
|
# ---------------------------------------------------------------------------
|
|
DATABASE_URL = os.getenv(
|
|
"DATABASE_URL",
|
|
"postgresql+asyncpg://breakpilot:breakpilot@postgres:5432/breakpilot",
|
|
)
|
|
# Append search_path options if not already present
|
|
if "options=" not in DATABASE_URL:
|
|
sep = "&" if "?" in DATABASE_URL else "?"
|
|
DATABASE_URL += f"{sep}options=-csearch_path%3Dlehrer,core,public"
|
|
|
|
os.environ["DATABASE_URL"] = DATABASE_URL
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Feature flags (optional services)
|
|
# ---------------------------------------------------------------------------
|
|
LLM_GATEWAY_ENABLED = os.getenv("LLM_GATEWAY_ENABLED", "false").lower() == "true"
|
|
ALERTS_AGENT_ENABLED = os.getenv("ALERTS_AGENT_ENABLED", "false").lower() == "true"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Lifespan
|
|
# ---------------------------------------------------------------------------
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI):
|
|
logger.info("Backend-Lehrer starting up (DB search_path=lehrer,core,public)")
|
|
# Initialize vocabulary tables
|
|
try:
|
|
from vocabulary_db import init_vocabulary_tables
|
|
await init_vocabulary_tables()
|
|
except Exception as e:
|
|
logger.warning(f"Vocabulary tables init failed (non-critical): {e}")
|
|
yield
|
|
logger.info("Backend-Lehrer shutting down")
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# FastAPI app
|
|
# ---------------------------------------------------------------------------
|
|
app = FastAPI(
|
|
title="BreakPilot Backend-Lehrer",
|
|
description="Lehrer-spezifische APIs fuer Classroom, State-Engine, Worksheets, Meetings, AI u.a.",
|
|
version="1.0.0",
|
|
lifespan=lifespan,
|
|
)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# CORS
|
|
# ---------------------------------------------------------------------------
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=["*"], # In Produktion spezifische Origins angeben
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Health endpoint
|
|
# ---------------------------------------------------------------------------
|
|
@app.get("/health", tags=["System"])
|
|
async def health():
|
|
return {"status": "ok", "service": "backend-lehrer", "port": 8001}
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Import and register Lehrer-specific routers
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# --- 1. Classroom Management ---
|
|
from classroom_api import router as classroom_router
|
|
app.include_router(classroom_router, prefix="/api/classroom")
|
|
|
|
# --- 2. State Engine (Begleiter-Modus mit Phasen und Antizipation) ---
|
|
from state_engine_api import router as state_engine_router
|
|
app.include_router(state_engine_router, prefix="/api")
|
|
|
|
# --- 3. Worksheets & Corrections ---
|
|
from worksheets_api import router as worksheets_router
|
|
app.include_router(worksheets_router, prefix="/api")
|
|
|
|
from correction_api import router as correction_router
|
|
app.include_router(correction_router, prefix="/api")
|
|
|
|
# --- 4. Learning Units ---
|
|
from learning_units_api import router as learning_units_router
|
|
app.include_router(learning_units_router, prefix="/api")
|
|
|
|
# --- 4b. Learning Progress ---
|
|
from progress_api import router as progress_router
|
|
app.include_router(progress_router, prefix="/api")
|
|
|
|
# --- 4c. Vocabulary Catalog ---
|
|
from vocabulary_api import router as vocabulary_router
|
|
app.include_router(vocabulary_router, prefix="/api")
|
|
|
|
from unit_api import router as unit_router
|
|
app.include_router(unit_router) # Already has /api/units prefix
|
|
|
|
from unit_analytics_api import router as unit_analytics_router
|
|
app.include_router(unit_analytics_router) # Already has /api/analytics prefix
|
|
|
|
|
|
from recording_api import router as recording_api_router
|
|
app.include_router(recording_api_router) # Already has /api/recordings prefix
|
|
|
|
|
|
# --- 6. Messenger ---
|
|
from messenger_api import router as messenger_router
|
|
app.include_router(messenger_router) # Already has /api/messenger prefix
|
|
|
|
# --- 7. Klausur & School Proxies ---
|
|
from klausur_service_proxy import router as klausur_service_router
|
|
app.include_router(klausur_service_router, prefix="/api")
|
|
|
|
from school_api import router as school_api_router
|
|
app.include_router(school_api_router, prefix="/api")
|
|
|
|
# --- 8. Teacher Dashboard & Abitur Docs ---
|
|
from abitur_docs_api import router as abitur_docs_router
|
|
app.include_router(abitur_docs_router, prefix="/api")
|
|
|
|
from teacher_dashboard_api import router as teacher_dashboard_router
|
|
app.include_router(teacher_dashboard_router) # Already has /api/teacher prefix
|
|
|
|
# --- 9. Certificates & Letters ---
|
|
from certificates_api import router as certificates_router
|
|
app.include_router(certificates_router, prefix="/api")
|
|
|
|
from letters_api import router as letters_router
|
|
app.include_router(letters_router, prefix="/api")
|
|
|
|
# --- 10. Game System ---
|
|
from game_api import router as game_router
|
|
app.include_router(game_router) # Already has /api/game prefix
|
|
|
|
# --- 11. AI Processor (OCR + Content generation) ---
|
|
# ai_processor.py and ai_processing/ are library modules, no router to mount.
|
|
# They are used by worksheets_api, correction_api etc. internally.
|
|
|
|
# --- 12. LLM Gateway (optional) ---
|
|
if LLM_GATEWAY_ENABLED:
|
|
from llm_gateway.routes import chat_router, playbooks_router, health_router, tools_router
|
|
app.include_router(health_router, prefix="/llm", tags=["LLM Gateway"])
|
|
app.include_router(chat_router, prefix="/llm/v1", tags=["LLM Gateway"])
|
|
app.include_router(playbooks_router, prefix="/llm", tags=["LLM Gateway"])
|
|
app.include_router(tools_router, prefix="/llm/tools", tags=["LLM Tools"])
|
|
|
|
# EduSearch Seeds (immer aktiv wenn LLM Gateway da)
|
|
from llm_gateway.routes.edu_search_seeds import router as edu_search_seeds_router
|
|
app.include_router(edu_search_seeds_router, prefix="/v1", tags=["EduSearch"])
|
|
|
|
# Communication API (Lehrer-Eltern-Kommunikation mit GFK-Prinzipien)
|
|
from llm_gateway.routes.communication import router as communication_router
|
|
app.include_router(communication_router, prefix="/v1", tags=["Communication"])
|
|
|
|
# Legal Crawler API
|
|
from llm_gateway.routes.legal_crawler import router as legal_crawler_router
|
|
app.include_router(legal_crawler_router, prefix="/v1", tags=["Legal Crawler"])
|
|
|
|
# --- 13. Alerts Agent (optional) ---
|
|
if ALERTS_AGENT_ENABLED:
|
|
from alerts_agent.api import router as alerts_router
|
|
app.include_router(alerts_router, prefix="/api", tags=["Alerts Agent"])
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Middleware (from shared middleware/ package)
|
|
# ---------------------------------------------------------------------------
|
|
try:
|
|
from middleware.request_id import RequestIDMiddleware
|
|
app.add_middleware(RequestIDMiddleware)
|
|
logger.info("RequestIDMiddleware loaded")
|
|
except ImportError:
|
|
logger.warning("RequestIDMiddleware not available")
|
|
|
|
try:
|
|
from middleware.security_headers import SecurityHeadersMiddleware
|
|
app.add_middleware(SecurityHeadersMiddleware)
|
|
logger.info("SecurityHeadersMiddleware loaded")
|
|
except ImportError:
|
|
logger.warning("SecurityHeadersMiddleware not available")
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Run with uvicorn (for local dev)
|
|
# ---------------------------------------------------------------------------
|
|
if __name__ == "__main__":
|
|
import uvicorn
|
|
uvicorn.run("main:app", host="0.0.0.0", port=8001, reload=True)
|