Files
tft/.planer/einheiten/backend__tft__api__app.py.md
2026-07-24 11:24:24 +02:00

108 lines
5.2 KiB
Markdown

# Einheiten: backend/tft/api/app.py
stand: f41ac76b5789
## backend/tft/api/app.py::ActionRequest
beschreibung: Definiert das Pydantic-Schema für eingehende Aktions-Requests einer TFT-Spielpartie.
input: HTTP-Request-Body mit den Aktions-Feldern action, slot, where, idx, item_idx, board_idx, choice
output: Ein ActionRequest-Modell mit validierten, optional typisierten Aktions-Parametern
entscheidungen:
- Sämtliche Aktions-Parameter außer action sind als optional deklariert
beleg: "slot: int | None = None"
- Die Modell-Klasse verwendet Pydantic-BaseModel zur automatischen Validierung
beleg: "class ActionRequest(BaseModel):"
kanten:
## backend/tft/api/app.py::health
beschreibung: Stellt einen Health-Check-Endpunkt zur Verfügung, der den Betriebszustand des Dienstes meldet.
input: HTTP-GET-Aufruf auf /health
output: Ein JSON-Objekt mit status="ok"
entscheidungen:
- Der Endpunkt ist über den Pfad /health erreichbar
beleg: "@app.get(\"/health\")"
- Der Status wird statisch als "ok" zurückgegeben
beleg: "return {\"status\": \"ok\"}"
kanten:
## backend/tft/api/app.py::_load_game_deps
beschreibung: Lädt die für eine Spielsitzung benötigten statischen Set-Daten und Konfigurationswerte.
input: Keine Argumente; liest den Static-Pointer aus dem Dateisystem
output: Ein Tupel aus geladenem Artifact-Set und Konfigurationswerten
entscheidungen:
- Bei fehlendem Static-Pointer wird ein HTTP-503-Fehler ausgelöst
beleg: "raise HTTPException(503, \"no static data: run `tft.cli fetch-static` first\")"
- Die benötigten Submodule werden lokal erst zur Laufzeit importiert
beleg: "from tft.constants.loader import load_constants"
kanten:
## backend/tft/api/app.py::new_game
beschreibung: Erstellt eine neue TFT-Spiellauf-Instanz und registriert sie im globalen Spiellauf-Register.
input: Optionaler Seed-Wert für die Initialisierung des Zufallsgenerators
output: Ein JSON-Objekt mit der frisch vergebenen game_id und dem serialisierten Spielzustand
entscheidungen:
- Die Spiele werden in einem prozessglobalen Dictionary GAMES gehalten
beleg: "GAMES[game_id] = Game(artifact, cfg, seed=seed)"
- Die game_id ist eine 8-stelligen Hex-Kürzel einer UUID
beleg: "game_id = uuid.uuid4().hex[:8]"
kanten:
## backend/tft/api/app.py::state
beschreibung: Liefert den serialisierten Spielzustand einer bestehenden Spiellauf-Instanz.
input: Eine game_id aus der URL
output: Ein JSON-Objekt mit dem Spielzustand oder ein 404-Fehler
entscheidungen:
- Unbekannte Spiele führen zu einem 404-Fehler statt zu einem leeren Zustand
beleg: "raise HTTPException(404, \"unknown game\")"
- Der Endpunkt ist als GET auf /api/game/{game_id} definiert
beleg: "@app.get(\"/api/game/{game_id}\")"
kanten:
## backend/tft/api/app.py::action
beschreibung: Interpretiert eine Aktions-Anfrage und leitet sie an die passende Game-Methode weiter.
input: Eine game_id sowie ein ActionRequest mit Aktionstyp und Parametern
output: Ein serialisierter Spielzustand nach Ausführung oder ein 4xx-Fehler
entscheidungen:
- Unbekannte Aktionen werden als 400-Fehler abgewiesen
beleg: "raise HTTPException(400, f\"unknown action {req.action}\")"
- Ungültige Aktionen der Domäne werden als 400-Fehler übersetzt
beleg: "except InvalidAction as e:"
- Fehlende Parameter werden als 400-Fehler mit Hinweis auf die Aktion gemeldet
beleg: "raise HTTPException(400, f\"missing parameters for action {req.action}\")"
kanten:
## backend/tft/api/app.py::upgrade_hint
beschreibung: Berechnet, in welche Sternstufe eine Einheit durch einen weiteren Kauf aufsteigen würde.
input: Das Game-Objekt sowie der api_name einer Einheit
output: 0 für kein Upgrade, 2 für einen 2-Sterne- oder 3 für einen 3-Sterne-Aufstieg
entscheidungen:
- Bereits 3-Sterne-Einheiten werden vom Upgrade-Pfad ausgeschlossen
beleg: "if u[\"api_name\"] == api and u[\"stars\"] < 3"
- Höhere Sterne zählen mit Stern-Eskalation als 3^(s-1) Kopien
beleg: "sum(3 ** (u[\"stars\"] - 1) for u in owned)"
kanten:
## backend/tft/api/app.py::unit_view
beschreibung: Projiziert eine interne Einheit-Darstellung in die API-Antwortstruktur.
input: Ein Game-Objekt sowie eine Einheit-Dictionary-Repräsentation
output: Ein JSON-Objekt mit Anzeigename, Kosten, Sternen, Traits, Icon und getragenen Items
entscheidungen:
- Fehlende Anzeigenamen fallen auf den api_name zurück
beleg: "\"name\": info.get(\"name\", u[\"api_name\"])"
- Item-Namen und -Icons werden tolerant gegen fehlende Einträge ausgelesen
beleg: "game.artifact[\"static\"][\"items\"].get(i, {}).get(\"name\", i)"
kanten:
## backend/tft/api/app.py::serialize
beschreibung: Erzeugt das vollständige JSON-Spielbild inklusive Brett, Bank, Shop, Traits und Gegnern.
input: Ein Game-Objekt der laufenden Simulation
output: Ein umfangreiches Dictionary, das alle UI-relevanten Spielzustandsdaten bündelt
entscheidungen:
- Die Trait-Liste wird absteigend nach Tier und Count sortiert
beleg: "key=lambda x: (-x[\"tier\"], -x[\"count\"])"
- Gegner werden absteigend nach HP sortiert dargestellt
beleg: "key=lambda x: -x[\"hp\"]"
- Das Log wird auf die letzten acht Einträge begrenzt
beleg: "\"log\": game.log[-8:]"
- Aktive Trait-Tiers werden aus Brett-Einheiten berechnet
beleg: "tiers = active_trait_tiers(game.board, static[\"traits\"], static[\"units\"])"
kanten: