Files
ss-tools/backend/src/api/routes/maintenance/_schemas.py
2026-05-26 09:30:41 +03:00

158 lines
5.6 KiB
Python

# #region MaintenanceSchemasModule [C:2] [TYPE Module] [SEMANTICS pydantic, schema, maintenance, request, response]
# @BRIEF Pydantic models for Maintenance Banner API: request/response schemas per data-model.md.
# @LAYER API
# @RELATION DEPENDS_ON -> [EXT:Library:pydantic]
# @INVARIANT All response schemas use the standard envelope shape: { status, data, error, meta }
from datetime import datetime
from pydantic import BaseModel, Field
# ── Request Schemas ──────────────────────────────────────────
# #region MaintenanceStartRequest [C:1] [TYPE Class]
# @BRIEF POST /api/maintenance/start request body with environment scoping.
class MaintenanceStartRequest(BaseModel):
tables: list[str] = Field(..., min_length=1, max_length=100)
start_time: datetime
end_time: datetime | None = None
message: str | None = Field(None, max_length=500)
environment_id: str = Field(..., description="Target environment for the maintenance operation")
# #endregion MaintenanceStartRequest
# #region MaintenanceSettingsUpdate [C:1] [TYPE Class]
# @BRIEF PUT /api/maintenance/settings request body — all fields optional for partial update.
class MaintenanceSettingsUpdate(BaseModel):
target_environment_id: str | None = None
display_timezone: str | None = None
banner_template: str | None = None
dashboard_scope: str | None = None
excluded_dashboard_ids: list[int] | None = None
forced_dashboard_ids: list[int] | None = None
# #endregion MaintenanceSettingsUpdate
# ── Response Schemas ─────────────────────────────────────────
# #region MaintenanceStartResponse [C:1] [TYPE Class]
# @BRIEF Response for /api/maintenance/start — always 202 with task_id.
class MaintenanceStartResponse(BaseModel):
task_id: str
maintenance_id: str
status: str # "pending"
# #endregion MaintenanceStartResponse
# #region MaintenanceDashboardResult [C:1] [TYPE Class]
# @BRIEF Describes a single dashboard affected by a maintenance operation.
class MaintenanceDashboardResult(BaseModel):
id: int
title: str
chart_id: int | None = None
# #endregion MaintenanceDashboardResult
# #region MaintenanceFailedDashboard [C:1] [TYPE Class]
# @BRIEF Describes a dashboard that failed during banner apply/removal.
class MaintenanceFailedDashboard(BaseModel):
id: int
title: str
error: str
# #endregion MaintenanceFailedDashboard
# #region MaintenanceTaskResult [C:1] [TYPE Class]
# @BRIEF Result payload for a completed maintenance start task.
class MaintenanceTaskResult(BaseModel):
maintenance_id: str
status: str # "active" | "partial" | "completed" | "no_match"
affected_dashboards: int = 0
dashboards: list[MaintenanceDashboardResult] = []
failed_dashboards: list[MaintenanceFailedDashboard] = []
unmatched_tables: list[str] = []
# #endregion MaintenanceTaskResult
# #region MaintenanceEndResponse [C:1] [TYPE Class]
# @BRIEF Response for /api/maintenance/{id}/end and /api/maintenance/end-all — always 202 with task_id.
class MaintenanceEndResponse(BaseModel):
task_id: str
status: str # "pending"
# #endregion MaintenanceEndResponse
# #region MaintenanceEndTaskResult [C:1] [TYPE Class]
# @BRIEF Result payload for a completed end maintenance task.
class MaintenanceEndTaskResult(BaseModel):
maintenance_id: str
removed_from: int = 0
failed_removals: list[MaintenanceFailedDashboard] = []
# #endregion MaintenanceEndTaskResult
# #region MaintenanceEndAllTaskResult [C:1] [TYPE Class]
# @BRIEF Result payload for a completed end-all maintenance task.
class MaintenanceEndAllTaskResult(BaseModel):
closed_events: int = 0
removed_from: int = 0
failed_removals: list[MaintenanceFailedDashboard] = []
# #endregion MaintenanceEndAllTaskResult
# #region MaintenanceSettingsResponse [C:1] [TYPE Class]
# @BRIEF Response for GET /api/maintenance/settings.
class MaintenanceSettingsResponse(BaseModel):
target_environment_id: str
display_timezone: str
banner_template: str
dashboard_scope: str
excluded_dashboard_ids: list[int]
forced_dashboard_ids: list[int]
updated_at: str | None = None
# #endregion MaintenanceSettingsResponse
# #region MaintenanceEventItem [C:1] [TYPE Class]
# @BRIEF Single maintenance event summary for GET /api/maintenance/events.
class MaintenanceEventItem(BaseModel):
id: str
tables: list[str]
start_time: str
end_time: str | None = None
message: str | None = None
status: str
affected_count: int
created_at: str
# #endregion MaintenanceEventItem
# #region MaintenanceEventListResponse [C:1] [TYPE Class]
# @BRIEF Response for GET /api/maintenance/events.
class MaintenanceEventListResponse(BaseModel):
active: list[MaintenanceEventItem]
completed: list[MaintenanceEventItem]
# #endregion MaintenanceEventListResponse
# #region MaintenanceDashboardBannerState [C:1] [TYPE Class]
# @BRIEF Per-dashboard banner state for GET /api/maintenance/dashboard-banners.
class MaintenanceDashboardBannerState(BaseModel):
dashboard_id: int
active: bool
events: list[str]
start_time: str | None = None
end_time: str | None = None
# #endregion MaintenanceDashboardBannerState
# #region MaintenanceAlreadyActiveResponse [C:1] [TYPE Class]
# @BRIEF Response for duplicate /start call — idempotency hit.
class MaintenanceAlreadyActiveResponse(BaseModel):
maintenance_id: str
status: str = "already_active"
# #endregion MaintenanceAlreadyActiveResponse
# #endregion MaintenanceSchemasModule