127 lines
3.2 KiB
Python
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
|