diff --git a/backend/app/schemas/device_type.py b/backend/app/schemas/device_type.py new file mode 100644 index 00000000..8d2b70a2 --- /dev/null +++ b/backend/app/schemas/device_type.py @@ -0,0 +1,38 @@ +"""Pydantic schemas for device types.""" +from datetime import datetime +from typing import Optional +from uuid import UUID + +from pydantic import BaseModel, Field + + +class DeviceTypeCreate(BaseModel): + slug: str = Field(min_length=1, max_length=50, pattern=r"^[a-z0-9\-]+$") + label: str = Field(min_length=1, max_length=100) + category: str = Field( + min_length=1, max_length=50, + pattern=r"^(network|compute|storage|cloud|endpoint|infrastructure|security)$", + ) + sort_order: int = Field(default=0, ge=0) + + +class DeviceTypeUpdate(BaseModel): + label: str | None = Field(default=None, min_length=1, max_length=100) + category: str | None = Field( + default=None, min_length=1, max_length=50, + pattern=r"^(network|compute|storage|cloud|endpoint|infrastructure|security)$", + ) + sort_order: int | None = Field(default=None, ge=0) + + +class DeviceTypeResponse(BaseModel): + id: UUID + slug: str + label: str + category: str + is_system: bool + team_id: UUID | None = None + sort_order: int + created_at: datetime + + model_config = {"from_attributes": True} diff --git a/backend/app/schemas/network_diagram.py b/backend/app/schemas/network_diagram.py new file mode 100644 index 00000000..2b25356a --- /dev/null +++ b/backend/app/schemas/network_diagram.py @@ -0,0 +1,130 @@ +"""Pydantic schemas for network diagrams.""" +from datetime import datetime +from typing import Optional +from uuid import UUID + +from pydantic import BaseModel, Field + + +class DeviceProperties(BaseModel): + hostname: str | None = None + ip: str | None = None + subnet: str | None = None + vendor: str | None = None + model: str | None = None + role: str | None = None + vlan: str | None = None + notes: str | None = None + status: str = Field(default="unknown", pattern=r"^(unknown|online|offline|degraded)$") + + +class DiagramNode(BaseModel): + id: str + type: str + label: str + position: dict + properties: DeviceProperties = Field(default_factory=DeviceProperties) + + +class DiagramEdge(BaseModel): + id: str + source: str + target: str + label: str | None = None + connectionType: str = "ethernet" + speed: str | None = None + notes: str | None = None + + +class NetworkDiagramCreate(BaseModel): + name: str = Field(min_length=1, max_length=255) + client_name: str | None = None + asset_name: str | None = None + description: str | None = None + nodes: list[DiagramNode] = Field(default_factory=list) + edges: list[DiagramEdge] = Field(default_factory=list) + + +class NetworkDiagramUpdate(BaseModel): + name: str | None = Field(default=None, min_length=1, max_length=255) + client_name: str | None = None + asset_name: str | None = None + description: str | None = None + nodes: list[DiagramNode] | None = None + edges: list[DiagramEdge] | None = None + + +class NetworkDiagramResponse(BaseModel): + id: UUID + team_id: UUID + name: str + client_name: str | None = None + asset_name: str | None = None + description: str | None = None + nodes: list[DiagramNode] = Field(default_factory=list) + edges: list[DiagramEdge] = Field(default_factory=list) + thumbnail_url: str | None = None + is_archived: bool = False + created_by: UUID | None = None + created_at: datetime + updated_at: datetime + + model_config = {"from_attributes": True} + + +class NetworkDiagramListItem(BaseModel): + id: UUID + name: str + client_name: str | None = None + description: str | None = None + node_count: int = 0 + created_by: UUID | None = None + created_at: datetime + updated_at: datetime + + model_config = {"from_attributes": True} + + +class ExistingBounds(BaseModel): + minX: float + maxX: float + minY: float + maxY: float + + +class AIGenerateRequest(BaseModel): + description: str = Field(min_length=1, max_length=5000) + client_name: str | None = None + mode: str = Field(default="replace", pattern=r"^(replace|merge)$") + existingBounds: ExistingBounds | None = None + + +class AIGenerateResponse(BaseModel): + nodes: list[DiagramNode] + edges: list[DiagramEdge] + suggestedName: str | None = None + notes: str | None = None + + +class DiagramImportRequest(BaseModel): + schemaVersion: int = Field(ge=1, le=1) + name: str = Field(min_length=1, max_length=255) + client_name: str | None = None + description: str | None = None + nodes: list[DiagramNode] = Field(default_factory=list) + edges: list[DiagramEdge] = Field(default_factory=list) + + +class DiagramImportResponse(BaseModel): + diagram: NetworkDiagramResponse + warnings: list[str] = Field(default_factory=list) + + +class DiagramExportResponse(BaseModel): + schemaVersion: int = 1 + name: str + client_name: str | None = None + description: str | None = None + nodes: list[DiagramNode] + edges: list[DiagramEdge] + exportedAt: str