131 lines
3.1 KiB
Python
131 lines
3.1 KiB
Python
"""Typed contracts for the Repairs domain."""
|
|
|
|
from datetime import datetime
|
|
from typing import Any, Literal
|
|
from uuid import UUID
|
|
|
|
from pydantic import AwareDatetime, BaseModel, ConfigDict, Field
|
|
|
|
|
|
RepairReason = Literal[
|
|
"HARDWARE_FAILURE",
|
|
"LOW_HASHRATE",
|
|
"CONTROL_BOARD",
|
|
"HASHBOARD",
|
|
"PSU",
|
|
"FAN",
|
|
"OVERHEATING",
|
|
"NETWORKING",
|
|
"PREVENTIVE_MAINTENANCE",
|
|
"INSPECTION",
|
|
"OTHER",
|
|
]
|
|
RepairStatus = Literal[
|
|
"OPEN",
|
|
"IN_PROGRESS",
|
|
"WAITING_FOR_PARTS",
|
|
"READY_FOR_TEST",
|
|
"COMPLETED",
|
|
"CANCELLED",
|
|
]
|
|
RepairEventType = Literal[
|
|
"REPAIR_STARTED",
|
|
"INITIAL_NOTE",
|
|
"REPAIR_COMPLETED",
|
|
]
|
|
RepairEligibleLifecycle = Literal["active", "spare"]
|
|
RepairPostLifecycle = Literal["active", "spare"]
|
|
RepairMinerLifecycle = Literal["active", "spare", "retired", "in_repair"]
|
|
|
|
|
|
class BeginRepairRequest(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
miner_id: UUID
|
|
reason: RepairReason
|
|
notes: str | None = Field(default=None, max_length=4000)
|
|
|
|
|
|
class RepairCompleteRequest(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
target_lifecycle: RepairPostLifecycle
|
|
completion_summary: str | None = Field(default=None, max_length=4000)
|
|
|
|
|
|
class RepairStartedPayload(BaseModel):
|
|
reason: RepairReason
|
|
from_lifecycle: RepairEligibleLifecycle
|
|
to_lifecycle: Literal["in_repair"] = "in_repair"
|
|
|
|
|
|
class InitialRepairNotePayload(BaseModel):
|
|
note: str = Field(min_length=1, max_length=4000)
|
|
|
|
|
|
class RepairCompletedPayload(BaseModel):
|
|
previous_miner_lifecycle: Literal["in_repair"] = "in_repair"
|
|
resulting_miner_lifecycle: RepairPostLifecycle
|
|
pre_repair_lifecycle: RepairEligibleLifecycle | None = None
|
|
completion_summary: str | None = Field(default=None, max_length=4000)
|
|
|
|
|
|
class BeginRepairResult(BaseModel):
|
|
repair_id: UUID
|
|
miner_id: UUID
|
|
status: Literal["OPEN"]
|
|
reason: RepairReason
|
|
opened_at: datetime
|
|
opened_by: UUID
|
|
|
|
|
|
class BeginRepairResponse(BaseModel):
|
|
data: BeginRepairResult
|
|
meta: dict[str, object] = Field(default_factory=dict)
|
|
error: None = None
|
|
|
|
|
|
class RepairActor(BaseModel):
|
|
user_id: UUID
|
|
display_name: str
|
|
|
|
|
|
class RepairDetail(BaseModel):
|
|
repair_id: UUID
|
|
miner_id: UUID
|
|
miner_asset_id: str | None = None
|
|
status: RepairStatus
|
|
reason: RepairReason
|
|
opened_at: AwareDatetime
|
|
opened_by: RepairActor
|
|
closed_at: AwareDatetime | None = None
|
|
closed_by: RepairActor | None = None
|
|
miner_lifecycle: RepairMinerLifecycle
|
|
latest_event_sequence: int | None = Field(default=None, ge=1)
|
|
|
|
|
|
class RepairTimelineEvent(BaseModel):
|
|
event_id: UUID
|
|
sequence: int = Field(ge=1)
|
|
event_type: RepairEventType
|
|
actor: RepairActor
|
|
occurred_at: AwareDatetime
|
|
payload: dict[str, Any]
|
|
|
|
|
|
class RepairTimeline(BaseModel):
|
|
repair_id: UUID
|
|
events: list[RepairTimelineEvent] = Field(default_factory=list)
|
|
|
|
|
|
class RepairDetailResponse(BaseModel):
|
|
data: RepairDetail
|
|
meta: dict[str, object] = Field(default_factory=dict)
|
|
error: None = None
|
|
|
|
|
|
class RepairTimelineResponse(BaseModel):
|
|
data: RepairTimeline
|
|
meta: dict[str, object] = Field(default_factory=dict)
|
|
error: None = None
|