feat: Projektfundament mit Datenmodell, Migrationen und Seed
- 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
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
"""Sammelrouter für alle /api-Endpunkte."""
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
from app.api.routes import system
|
||||
|
||||
api_router = APIRouter(prefix="/api")
|
||||
api_router.include_router(system.router)
|
||||
@@ -0,0 +1,54 @@
|
||||
"""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,
|
||||
)
|
||||
Reference in New Issue
Block a user