""" 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" VAST_API_KEY = os.getenv("VAST_API_KEY") # --------------------------------------------------------------------------- # Lifespan # --------------------------------------------------------------------------- @asynccontextmanager async def lifespan(app: FastAPI): logger.info("Backend-Lehrer starting up (DB search_path=lehrer,core,public)") 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") 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 # --- 5. Meetings / Jitsi --- from meetings_api import router as meetings_api_router app.include_router(meetings_api_router) # Already has /api/meetings prefix from recording_api import router as recording_api_router app.include_router(recording_api_router) # Already has /api/recordings prefix from jitsi_api import router as jitsi_router app.include_router(jitsi_router) # Already has /api/jitsi 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"]) # --- 14. vast.ai GPU Infrastructure (optional) --- if VAST_API_KEY: from infra.vast_power import router as vast_router app.include_router(vast_router, tags=["GPU Infrastructure"]) # --------------------------------------------------------------------------- # 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)