feat(13-03): add link service, schemas, router, and wire subscribers into lifespan
- LinkResponse/UnknownClientResponse Pydantic schemas with from_attributes - Link service with get_links, get_device_links, get_site_links, get_unknown_clients - Unknown clients query uses DISTINCT ON for latest registration per MAC - 4 REST endpoints: tenant links, device links, site links, unknown clients - Interface and link discovery subscribers wired into FastAPI lifespan start/stop - Links router registered at /api prefix Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
56
backend/app/schemas/link.py
Normal file
56
backend/app/schemas/link.py
Normal file
@@ -0,0 +1,56 @@
|
||||
"""Pydantic schemas for Link and Unknown Client endpoints."""
|
||||
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
|
||||
|
||||
class LinkResponse(BaseModel):
|
||||
"""Single wireless link between an AP and CPE device."""
|
||||
|
||||
id: uuid.UUID
|
||||
ap_device_id: uuid.UUID
|
||||
cpe_device_id: uuid.UUID
|
||||
ap_hostname: str | None = None
|
||||
cpe_hostname: str | None = None
|
||||
interface: str | None = None
|
||||
client_mac: str
|
||||
signal_strength: int | None = None
|
||||
tx_ccq: int | None = None
|
||||
tx_rate: str | None = None
|
||||
rx_rate: str | None = None
|
||||
state: str
|
||||
missed_polls: int
|
||||
discovered_at: datetime
|
||||
last_seen: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class LinkListResponse(BaseModel):
|
||||
"""List of wireless links with total count."""
|
||||
|
||||
items: list[LinkResponse]
|
||||
total: int
|
||||
|
||||
|
||||
class UnknownClientResponse(BaseModel):
|
||||
"""A wireless client whose MAC does not resolve to any known device interface."""
|
||||
|
||||
mac_address: str
|
||||
interface: str | None = None
|
||||
signal_strength: int | None = None
|
||||
tx_rate: str | None = None
|
||||
rx_rate: str | None = None
|
||||
last_seen: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class UnknownClientListResponse(BaseModel):
|
||||
"""List of unknown clients with total count."""
|
||||
|
||||
items: list[UnknownClientResponse]
|
||||
total: int
|
||||
Reference in New Issue
Block a user