"""History domain models. Internal domain-focused models used by history_service. These represent the business domain layer and are independent of HTTP response shapes. Response models are defined in `app.models.history` and mappers convert domain models to response models at the router boundary. """ from __future__ import annotations from dataclasses import dataclass @dataclass(frozen=True) class DomainHistoryBanItem: """A single row in the history ban-list table (domain model).""" ip: str jail: str banned_at: str ban_count: int failures: int = 0 matches: list[str] | None = None country_code: str | None = None country_name: str | None = None asn: str | None = None org: str | None = None @dataclass(frozen=True) class DomainHistoryList: """Paginated history ban-list (domain model).""" items: list[DomainHistoryBanItem] total: int page: int page_size: int @dataclass(frozen=True) class DomainIpTimelineEvent: """A single ban event in a per-IP timeline (domain model).""" jail: str banned_at: str ban_count: int failures: int = 0 matches: list[str] | None = None @dataclass(frozen=True) class DomainIpDetail: """Full historical record for a single IP address (domain model).""" ip: str total_bans: int total_failures: int last_ban_at: str | None = None country_code: str | None = None country_name: str | None = None asn: str | None = None org: str | None = None timeline: list[DomainIpTimelineEvent] | None = None