- Repo-Struktur für Backend, Frontend, Dokumentation und Gitea-Workflows - FastAPI-Skeleton mit pydantic-settings und RFC-7807-artigem Fehlerformat - Vollständiges Datenmodell (15 Tabellen) als SQLAlchemy-2.0-Modelle - Alembic gegen die Async-Engine inklusive Erstmigration - Idempotenter Seed für den deutschen Kategoriebaum und Standardregeln - Endpunkte /api/health und /api/version - pytest-Infrastruktur mit transaktionsisolierten Fixtures Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014e7t8UpmoVNMtWivY5LiSH
55 lines
1.7 KiB
Python
55 lines
1.7 KiB
Python
"""Systemendpunkte: Health-Check und Versionsinformation (ohne Authentifizierung)."""
|
|
|
|
from datetime import datetime
|
|
from zoneinfo import ZoneInfo
|
|
|
|
from fastapi import APIRouter, Depends
|
|
from pydantic import BaseModel, Field
|
|
from sqlalchemy import text
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.core.config import settings
|
|
from app.db.session import get_session
|
|
|
|
router = APIRouter(tags=["system"])
|
|
|
|
|
|
class HealthResponse(BaseModel):
|
|
status: str = Field(description="'ok' wenn Anwendung und Datenbank erreichbar sind.")
|
|
database: str = Field(description="'ok' oder 'unavailable'.")
|
|
time: datetime = Field(description="Aktuelle Serverzeit in Europe/Berlin.")
|
|
|
|
|
|
class VersionResponse(BaseModel):
|
|
name: str
|
|
version: str
|
|
environment: str
|
|
timezone: str
|
|
currency: str
|
|
|
|
|
|
@router.get("/health", response_model=HealthResponse, summary="Health-Check")
|
|
async def health(session: AsyncSession = Depends(get_session)) -> HealthResponse:
|
|
"""Prüft die Datenbankverbindung. Wird vom Docker-Healthcheck verwendet."""
|
|
database = "ok"
|
|
try:
|
|
await session.execute(text("SELECT 1"))
|
|
except Exception:
|
|
database = "unavailable"
|
|
return HealthResponse(
|
|
status="ok" if database == "ok" else "degraded",
|
|
database=database,
|
|
time=datetime.now(ZoneInfo(settings.timezone)),
|
|
)
|
|
|
|
|
|
@router.get("/version", response_model=VersionResponse, summary="Versionsinformation")
|
|
async def version() -> VersionResponse:
|
|
return VersionResponse(
|
|
name=settings.app_name,
|
|
version=settings.app_version,
|
|
environment=settings.environment,
|
|
timezone=settings.timezone,
|
|
currency=settings.default_currency,
|
|
)
|