Files
comunidadhll/backend/app/historical_models.py
2026-06-02 16:29:53 +02:00

127 lines
3.2 KiB
Python

"""Historical domain models for persisted CRCON scoreboard data."""
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime
@dataclass(frozen=True, slots=True)
class HistoricalServerDefinition:
"""Stable identity for one historical CRCON source."""
slug: str
display_name: str
scoreboard_base_url: str
server_number: int | None
source_kind: str = "crcon-scoreboard-json"
@dataclass(frozen=True, slots=True)
class HistoricalMapRecord:
"""Normalized map metadata reused across historical matches."""
external_map_id: str | None
map_name: str | None
pretty_name: str | None
game_mode: str | None
image_name: str | None
@dataclass(frozen=True, slots=True)
class HistoricalMatchRecord:
"""Normalized match identity and summary."""
external_match_id: str
server_slug: str
created_at: datetime | None
started_at: datetime | None
ended_at: datetime | None
map_name: str | None
map_pretty_name: str | None
map_external_id: str | None
game_mode: str | None
image_name: str | None
allied_score: int | None
axis_score: int | None
@dataclass(frozen=True, slots=True)
class HistoricalPlayerIdentity:
"""Stable player identity across historical match stats."""
stable_player_key: str
display_name: str
steam_id: str | None
source_player_id: str | None
@dataclass(frozen=True, slots=True)
class HistoricalPlayerMatchStats:
"""Metrics persisted per player and match."""
stable_player_key: str
match_player_ref: str | None
team_side: str | None
level: int | None
kills: int | None
deaths: int | None
teamkills: int | None
time_seconds: int | None
kills_per_minute: float | None
deaths_per_minute: float | None
kill_death_ratio: float | None
combat: int | None
offense: int | None
defense: int | None
support: int | None
@dataclass(frozen=True, slots=True)
class HistoricalIngestionRunSummary:
"""Outcome metadata recorded for one ingestion execution."""
mode: str
started_at: datetime
completed_at: datetime | None
status: str
pages_processed: int
matches_seen: int
matches_inserted: int
matches_updated: int
player_rows_inserted: int
player_rows_updated: int
@dataclass(frozen=True, slots=True)
class HistoricalBackfillProgressSummary:
"""Persisted resume checkpoint and last attempt metadata per server."""
server_slug: str
mode: str
next_page: int
last_completed_page: int | None
discovered_total_matches: int | None
discovered_total_pages: int | None
archive_exhausted: bool
last_run_id: int | None
last_run_status: str | None
last_run_started_at: datetime | None
last_run_completed_at: datetime | None
last_error: str | None
@dataclass(frozen=True, slots=True)
class HistoricalSnapshotRecord:
"""Persisted precomputed historical snapshot ready for lightweight reads."""
server_key: str
snapshot_type: str
metric: str | None
window: str | None
payload_json: str
generated_at: datetime
source_range_start: datetime | None
source_range_end: datetime | None
is_stale: bool