refactor: update module docstrings for clarity and consistency

This commit is contained in:
Abhimanyu Saharan
2026-02-09 15:49:50 +05:30
parent 78bb08d4a3
commit 7ca1899d9f
99 changed files with 2345 additions and 855 deletions

View File

@@ -1,3 +1,5 @@
"""Public schema exports shared across API route modules."""
from app.schemas.activity_events import ActivityEventRead
from app.schemas.agents import AgentCreate, AgentRead, AgentUpdate
from app.schemas.approvals import ApprovalCreate, ApprovalRead, ApprovalUpdate

View File

@@ -1,12 +1,16 @@
"""Response schemas for activity events and task-comment feed items."""
from __future__ import annotations
from datetime import datetime
from uuid import UUID
from datetime import datetime # noqa: TCH003
from uuid import UUID # noqa: TCH003
from sqlmodel import SQLModel
class ActivityEventRead(SQLModel):
"""Serialized activity event payload returned by activity endpoints."""
id: UUID
event_type: str
message: str | None
@@ -16,6 +20,8 @@ class ActivityEventRead(SQLModel):
class ActivityTaskCommentFeedItemRead(SQLModel):
"""Denormalized task-comment feed item enriched with task and board fields."""
id: UUID
created_at: datetime
message: str | None

View File

@@ -1,16 +1,21 @@
"""Schemas for approval create/update/read API payloads."""
from __future__ import annotations
from datetime import datetime
from datetime import datetime # noqa: TCH003
from typing import Literal, Self
from uuid import UUID
from uuid import UUID # noqa: TCH003
from pydantic import model_validator
from sqlmodel import SQLModel
ApprovalStatus = Literal["pending", "approved", "rejected"]
STATUS_REQUIRED_ERROR = "status is required"
class ApprovalBase(SQLModel):
"""Shared approval fields used across create/read payloads."""
action_type: str
task_id: UUID | None = None
payload: dict[str, object] | None = None
@@ -20,20 +25,27 @@ class ApprovalBase(SQLModel):
class ApprovalCreate(ApprovalBase):
"""Payload for creating a new approval request."""
agent_id: UUID | None = None
class ApprovalUpdate(SQLModel):
"""Payload for mutating approval status."""
status: ApprovalStatus | None = None
@model_validator(mode="after")
def validate_status(self) -> Self:
"""Ensure explicitly provided `status` is not null."""
if "status" in self.model_fields_set and self.status is None:
raise ValueError("status is required")
raise ValueError(STATUS_REQUIRED_ERROR)
return self
class ApprovalRead(ApprovalBase):
"""Approval payload returned from read endpoints."""
id: UUID
board_id: UUID
agent_id: UUID | None = None

View File

@@ -1,13 +1,18 @@
"""Schemas for applying heartbeat settings to board-group agents."""
from __future__ import annotations
from typing import Any
from uuid import UUID
from uuid import UUID # noqa: TCH003
from sqlmodel import SQLModel
class BoardGroupHeartbeatApply(SQLModel):
# Heartbeat cadence string understood by the OpenClaw gateway (e.g. "2m", "10m", "30m").
"""Request payload for heartbeat policy updates."""
# Heartbeat cadence string understood by the OpenClaw gateway
# (e.g. "2m", "10m", "30m").
every: str
# Optional heartbeat target (most deployments use "none").
target: str | None = None
@@ -15,6 +20,8 @@ class BoardGroupHeartbeatApply(SQLModel):
class BoardGroupHeartbeatApplyResult(SQLModel):
"""Result payload describing agents updated by a heartbeat request."""
board_group_id: UUID
requested: dict[str, Any]
updated_agent_ids: list[UUID]

View File

@@ -1,14 +1,18 @@
"""Schemas for board-group memory create/read API payloads."""
from __future__ import annotations
from datetime import datetime
from uuid import UUID
from datetime import datetime # noqa: TCH003
from uuid import UUID # noqa: TCH003
from sqlmodel import SQLModel
from app.schemas.common import NonEmptyStr
from app.schemas.common import NonEmptyStr # noqa: TCH001
class BoardGroupMemoryCreate(SQLModel):
"""Payload for creating a board-group memory entry."""
# For writes, reject blank/whitespace-only content.
content: NonEmptyStr
tags: list[str] | None = None
@@ -16,9 +20,12 @@ class BoardGroupMemoryCreate(SQLModel):
class BoardGroupMemoryRead(SQLModel):
"""Serialized board-group memory entry returned from read endpoints."""
id: UUID
board_group_id: UUID
# For reads, allow legacy rows that may have empty content (avoid response validation 500s).
# For reads, allow legacy rows that may have empty content
# (avoid response validation 500s).
content: str
tags: list[str] | None = None
source: str | None = None

View File

@@ -1,28 +1,36 @@
"""Schemas for board-group create/update/read API operations."""
from __future__ import annotations
from datetime import datetime
from uuid import UUID
from datetime import datetime # noqa: TCH003
from uuid import UUID # noqa: TCH003
from sqlmodel import SQLModel
class BoardGroupBase(SQLModel):
"""Shared board-group fields for create/read operations."""
name: str
slug: str
description: str | None = None
class BoardGroupCreate(BoardGroupBase):
pass
"""Payload for creating a board group."""
class BoardGroupUpdate(SQLModel):
"""Payload for partial board-group updates."""
name: str | None = None
slug: str | None = None
description: str | None = None
class BoardGroupRead(BoardGroupBase):
"""Board-group payload returned from read endpoints."""
id: UUID
organization_id: UUID
created_at: datetime

View File

@@ -1,14 +1,18 @@
"""Schemas for board memory create/read API payloads."""
from __future__ import annotations
from datetime import datetime
from uuid import UUID
from datetime import datetime # noqa: TCH003
from uuid import UUID # noqa: TCH003
from sqlmodel import SQLModel
from app.schemas.common import NonEmptyStr
from app.schemas.common import NonEmptyStr # noqa: TCH001
class BoardMemoryCreate(SQLModel):
"""Payload for creating a board memory entry."""
# For writes, reject blank/whitespace-only content.
content: NonEmptyStr
tags: list[str] | None = None
@@ -16,9 +20,12 @@ class BoardMemoryCreate(SQLModel):
class BoardMemoryRead(SQLModel):
"""Serialized board memory entry returned from read endpoints."""
id: UUID
board_id: UUID
# For reads, allow legacy rows that may have empty content (avoid response validation 500s).
# For reads, allow legacy rows that may have empty content
# (avoid response validation 500s).
content: str
tags: list[str] | None = None
source: str | None = None

View File

@@ -1,14 +1,23 @@
"""Schemas for board create/update/read API operations."""
from __future__ import annotations
from datetime import datetime
from datetime import datetime # noqa: TCH003
from typing import Self
from uuid import UUID
from uuid import UUID # noqa: TCH003
from pydantic import model_validator
from sqlmodel import SQLModel
_ERR_GOAL_FIELDS_REQUIRED = (
"Confirmed goal boards require objective and success_metrics"
)
_ERR_GATEWAY_REQUIRED = "gateway_id is required"
class BoardBase(SQLModel):
"""Shared board fields used across create and read payloads."""
name: str
slug: str
gateway_id: UUID | None = None
@@ -22,17 +31,25 @@ class BoardBase(SQLModel):
class BoardCreate(BoardBase):
"""Payload for creating a board."""
gateway_id: UUID
@model_validator(mode="after")
def validate_goal_fields(self) -> Self:
if self.board_type == "goal" and self.goal_confirmed:
if not self.objective or not self.success_metrics:
raise ValueError("Confirmed goal boards require objective and success_metrics")
"""Require goal details when creating a confirmed goal board."""
if (
self.board_type == "goal"
and self.goal_confirmed
and (not self.objective or not self.success_metrics)
):
raise ValueError(_ERR_GOAL_FIELDS_REQUIRED)
return self
class BoardUpdate(SQLModel):
"""Payload for partial board updates."""
name: str | None = None
slug: str | None = None
gateway_id: UUID | None = None
@@ -46,13 +63,16 @@ class BoardUpdate(SQLModel):
@model_validator(mode="after")
def validate_gateway_id(self) -> Self:
"""Reject explicit null gateway IDs in patch payloads."""
# Treat explicit null like "unset" is invalid for patch updates.
if "gateway_id" in self.model_fields_set and self.gateway_id is None:
raise ValueError("gateway_id is required")
raise ValueError(_ERR_GATEWAY_REQUIRED)
return self
class BoardRead(BoardBase):
"""Board payload returned from read endpoints."""
id: UUID
organization_id: UUID
created_at: datetime

View File

@@ -1,3 +1,5 @@
"""Common reusable schema primitives and simple API response envelopes."""
from __future__ import annotations
from typing import Annotated
@@ -5,9 +7,12 @@ from typing import Annotated
from pydantic import StringConstraints
from sqlmodel import SQLModel
# Reusable string type for request payloads where blank/whitespace-only values are invalid.
# Reusable string type for request payloads where blank/whitespace-only values
# are invalid.
NonEmptyStr = Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)]
class OkResponse(SQLModel):
"""Standard success response payload."""
ok: bool = True

View File

@@ -1,12 +1,18 @@
"""Structured error payload schemas used by API responses."""
from __future__ import annotations
from sqlmodel import Field, SQLModel
class BlockedTaskDetail(SQLModel):
"""Error detail payload listing blocking dependency task identifiers."""
message: str
blocked_by_task_ids: list[str] = Field(default_factory=list)
class BlockedTaskError(SQLModel):
"""Top-level blocked-task error response envelope."""
detail: BlockedTaskDetail

View File

@@ -1,15 +1,21 @@
"""Schemas for gateway passthrough API request and response payloads."""
from __future__ import annotations
from sqlmodel import SQLModel
from app.schemas.common import NonEmptyStr
from app.schemas.common import NonEmptyStr # noqa: TCH001
class GatewaySessionMessageRequest(SQLModel):
"""Request payload for sending a message into a gateway session."""
content: NonEmptyStr
class GatewayResolveQuery(SQLModel):
"""Query parameters used to resolve which gateway to target."""
board_id: str | None = None
gateway_url: str | None = None
gateway_token: str | None = None
@@ -17,6 +23,8 @@ class GatewayResolveQuery(SQLModel):
class GatewaysStatusResponse(SQLModel):
"""Aggregated gateway status response including session metadata."""
connected: bool
gateway_url: str
sessions_count: int | None = None
@@ -28,20 +36,28 @@ class GatewaysStatusResponse(SQLModel):
class GatewaySessionsResponse(SQLModel):
"""Gateway sessions list response payload."""
sessions: list[object]
main_session_key: str | None = None
main_session: object | None = None
class GatewaySessionResponse(SQLModel):
"""Single gateway session response payload."""
session: object
class GatewaySessionHistoryResponse(SQLModel):
"""Gateway session history response payload."""
history: list[object]
class GatewayCommandsResponse(SQLModel):
"""Gateway command catalog and protocol metadata."""
protocol_version: int
methods: list[str]
events: list[str]

View File

@@ -1,24 +1,38 @@
"""Schemas for gateway-main and lead-agent coordination endpoints."""
from __future__ import annotations
from typing import Literal
from uuid import UUID
from uuid import UUID # noqa: TCH003
from sqlmodel import Field, SQLModel
from app.schemas.common import NonEmptyStr
from app.schemas.common import NonEmptyStr # noqa: TCH001
def _lead_reply_tags() -> list[str]:
return ["gateway_main", "lead_reply"]
def _user_reply_tags() -> list[str]:
return ["gateway_main", "user_reply"]
class GatewayLeadMessageRequest(SQLModel):
"""Request payload for sending a message to a board lead agent."""
kind: Literal["question", "handoff"] = "question"
correlation_id: str | None = None
content: NonEmptyStr
# How the lead should reply (defaults are interpreted by templates).
reply_tags: list[str] = Field(default_factory=lambda: ["gateway_main", "lead_reply"])
reply_tags: list[str] = Field(default_factory=_lead_reply_tags)
reply_source: str | None = "lead_to_gateway_main"
class GatewayLeadMessageResponse(SQLModel):
"""Response payload for a lead-message dispatch attempt."""
ok: bool = True
board_id: UUID
lead_agent_id: UUID | None = None
@@ -27,15 +41,19 @@ class GatewayLeadMessageResponse(SQLModel):
class GatewayLeadBroadcastRequest(SQLModel):
"""Request payload for broadcasting a message to multiple board leads."""
kind: Literal["question", "handoff"] = "question"
correlation_id: str | None = None
content: NonEmptyStr
board_ids: list[UUID] | None = None
reply_tags: list[str] = Field(default_factory=lambda: ["gateway_main", "lead_reply"])
reply_tags: list[str] = Field(default_factory=_lead_reply_tags)
reply_source: str | None = "lead_to_gateway_main"
class GatewayLeadBroadcastBoardResult(SQLModel):
"""Per-board result entry for a lead broadcast operation."""
board_id: UUID
lead_agent_id: UUID | None = None
lead_agent_name: str | None = None
@@ -44,6 +62,8 @@ class GatewayLeadBroadcastBoardResult(SQLModel):
class GatewayLeadBroadcastResponse(SQLModel):
"""Aggregate response for a lead broadcast operation."""
ok: bool = True
sent: int = 0
failed: int = 0
@@ -51,16 +71,21 @@ class GatewayLeadBroadcastResponse(SQLModel):
class GatewayMainAskUserRequest(SQLModel):
"""Request payload for asking the end user via a main gateway agent."""
correlation_id: str | None = None
content: NonEmptyStr
preferred_channel: str | None = None
# How the main agent should reply back into Mission Control (defaults interpreted by templates).
reply_tags: list[str] = Field(default_factory=lambda: ["gateway_main", "user_reply"])
# How the main agent should reply back into Mission Control
# (defaults interpreted by templates).
reply_tags: list[str] = Field(default_factory=_user_reply_tags)
reply_source: str | None = "user_via_gateway_main"
class GatewayMainAskUserResponse(SQLModel):
"""Response payload for user-question dispatch via gateway main agent."""
ok: bool = True
board_id: UUID
main_agent_id: UUID | None = None

View File

@@ -1,14 +1,17 @@
"""Schemas for gateway CRUD and template-sync API payloads."""
from __future__ import annotations
from datetime import datetime
from typing import Any
from uuid import UUID
from datetime import datetime # noqa: TCH003
from uuid import UUID # noqa: TCH003
from pydantic import field_validator
from sqlmodel import Field, SQLModel
class GatewayBase(SQLModel):
"""Shared gateway fields used across create/read payloads."""
name: str
url: str
main_session_key: str
@@ -16,11 +19,14 @@ class GatewayBase(SQLModel):
class GatewayCreate(GatewayBase):
"""Payload for creating a gateway configuration."""
token: str | None = None
@field_validator("token", mode="before")
@classmethod
def normalize_token(cls, value: Any) -> Any:
def normalize_token(cls, value: object) -> str | None | object:
"""Normalize empty/whitespace tokens to `None`."""
if value is None:
return None
if isinstance(value, str):
@@ -30,6 +36,8 @@ class GatewayCreate(GatewayBase):
class GatewayUpdate(SQLModel):
"""Payload for partial gateway updates."""
name: str | None = None
url: str | None = None
token: str | None = None
@@ -38,7 +46,8 @@ class GatewayUpdate(SQLModel):
@field_validator("token", mode="before")
@classmethod
def normalize_token(cls, value: Any) -> Any:
def normalize_token(cls, value: object) -> str | None | object:
"""Normalize empty/whitespace tokens to `None`."""
if value is None:
return None
if isinstance(value, str):
@@ -48,6 +57,8 @@ class GatewayUpdate(SQLModel):
class GatewayRead(GatewayBase):
"""Gateway payload returned from read endpoints."""
id: UUID
organization_id: UUID
token: str | None = None
@@ -56,6 +67,8 @@ class GatewayRead(GatewayBase):
class GatewayTemplatesSyncError(SQLModel):
"""Per-agent error entry from a gateway template sync operation."""
agent_id: UUID | None = None
agent_name: str | None = None
board_id: UUID | None = None
@@ -63,6 +76,8 @@ class GatewayTemplatesSyncError(SQLModel):
class GatewayTemplatesSyncResult(SQLModel):
"""Summary payload returned by gateway template sync endpoints."""
gateway_id: UUID
include_main: bool
reset_sessions: bool

View File

@@ -1,17 +1,23 @@
"""Dashboard metrics schemas for KPI and time-series API responses."""
from __future__ import annotations
from datetime import datetime
from datetime import datetime # noqa: TCH003
from typing import Literal
from sqlmodel import SQLModel
class DashboardSeriesPoint(SQLModel):
"""Single numeric time-series point."""
period: datetime
value: float
class DashboardWipPoint(SQLModel):
"""Work-in-progress point split by task status buckets."""
period: datetime
inbox: int
in_progress: int
@@ -19,28 +25,38 @@ class DashboardWipPoint(SQLModel):
class DashboardRangeSeries(SQLModel):
"""Series payload for a single range/bucket combination."""
range: Literal["24h", "7d"]
bucket: Literal["hour", "day"]
points: list[DashboardSeriesPoint]
class DashboardWipRangeSeries(SQLModel):
"""WIP series payload for a single range/bucket combination."""
range: Literal["24h", "7d"]
bucket: Literal["hour", "day"]
points: list[DashboardWipPoint]
class DashboardSeriesSet(SQLModel):
"""Primary vs comparison pair for generic series metrics."""
primary: DashboardRangeSeries
comparison: DashboardRangeSeries
class DashboardWipSeriesSet(SQLModel):
"""Primary vs comparison pair for WIP status series metrics."""
primary: DashboardWipRangeSeries
comparison: DashboardWipRangeSeries
class DashboardKpis(SQLModel):
"""Topline dashboard KPI summary values."""
active_agents: int
tasks_in_progress: int
error_rate_pct: float
@@ -48,6 +64,8 @@ class DashboardKpis(SQLModel):
class DashboardMetrics(SQLModel):
"""Complete dashboard metrics response payload."""
range: Literal["24h", "7d"]
generated_at: datetime
kpis: DashboardKpis

View File

@@ -1,12 +1,16 @@
"""Schemas for organization, membership, and invite API payloads."""
from __future__ import annotations
from datetime import datetime
from uuid import UUID
from datetime import datetime # noqa: TCH003
from uuid import UUID # noqa: TCH003
from sqlmodel import Field, SQLModel
class OrganizationRead(SQLModel):
"""Organization payload returned by read endpoints."""
id: UUID
name: str
created_at: datetime
@@ -14,14 +18,20 @@ class OrganizationRead(SQLModel):
class OrganizationCreate(SQLModel):
"""Payload for creating a new organization."""
name: str
class OrganizationActiveUpdate(SQLModel):
"""Payload for switching the active organization context."""
organization_id: UUID
class OrganizationListItem(SQLModel):
"""Organization list row for current user memberships."""
id: UUID
name: str
role: str
@@ -29,6 +39,8 @@ class OrganizationListItem(SQLModel):
class OrganizationUserRead(SQLModel):
"""Embedded user fields included in organization member payloads."""
id: UUID
email: str | None = None
name: str | None = None
@@ -36,6 +48,8 @@ class OrganizationUserRead(SQLModel):
class OrganizationMemberRead(SQLModel):
"""Organization member payload including board-level access overrides."""
id: UUID
organization_id: UUID
user_id: UUID
@@ -49,16 +63,22 @@ class OrganizationMemberRead(SQLModel):
class OrganizationMemberUpdate(SQLModel):
"""Payload for partial updates to organization member role."""
role: str | None = None
class OrganizationBoardAccessSpec(SQLModel):
"""Board access specification used in member/invite mutation payloads."""
board_id: UUID
can_read: bool = True
can_write: bool = False
class OrganizationBoardAccessRead(SQLModel):
"""Board access payload returned from read endpoints."""
id: UUID
board_id: UUID
can_read: bool
@@ -68,12 +88,16 @@ class OrganizationBoardAccessRead(SQLModel):
class OrganizationMemberAccessUpdate(SQLModel):
"""Payload for replacing organization member access permissions."""
all_boards_read: bool = False
all_boards_write: bool = False
board_access: list[OrganizationBoardAccessSpec] = Field(default_factory=list)
class OrganizationInviteCreate(SQLModel):
"""Payload for creating an organization invite."""
invited_email: str
role: str = "member"
all_boards_read: bool = False
@@ -82,6 +106,8 @@ class OrganizationInviteCreate(SQLModel):
class OrganizationInviteRead(SQLModel):
"""Organization invite payload returned from read endpoints."""
id: UUID
organization_id: UUID
invited_email: str
@@ -97,4 +123,6 @@ class OrganizationInviteRead(SQLModel):
class OrganizationInviteAccept(SQLModel):
"""Payload for accepting an organization invite token."""
token: str

View File

@@ -1,3 +1,5 @@
"""Shared pagination response type aliases used by API routes."""
from __future__ import annotations
from typing import TypeVar

View File

@@ -1,9 +1,13 @@
"""Schemas for souls-directory search and markdown fetch responses."""
from __future__ import annotations
from pydantic import BaseModel
class SoulsDirectorySoulRef(BaseModel):
"""Reference metadata for a soul entry in the directory index."""
handle: str
slug: str
page_url: str
@@ -11,10 +15,14 @@ class SoulsDirectorySoulRef(BaseModel):
class SoulsDirectorySearchResponse(BaseModel):
"""Response wrapper for directory search results."""
items: list[SoulsDirectorySoulRef]
class SoulsDirectoryMarkdownResponse(BaseModel):
"""Response payload containing rendered markdown for a soul."""
handle: str
slug: str
content: str

View File

@@ -1,18 +1,23 @@
"""Schemas for task CRUD and task comment API payloads."""
from __future__ import annotations
from datetime import datetime
from typing import Any, Literal, Self
from uuid import UUID
from datetime import datetime # noqa: TCH003
from typing import Literal, Self
from uuid import UUID # noqa: TCH003
from pydantic import field_validator, model_validator
from sqlmodel import Field, SQLModel
from app.schemas.common import NonEmptyStr
from app.schemas.common import NonEmptyStr # noqa: TCH001
TaskStatus = Literal["inbox", "in_progress", "review", "done"]
STATUS_REQUIRED_ERROR = "status is required"
class TaskBase(SQLModel):
"""Shared task fields used by task create/read payloads."""
title: str
description: str | None = None
status: TaskStatus = "inbox"
@@ -23,10 +28,14 @@ class TaskBase(SQLModel):
class TaskCreate(TaskBase):
"""Payload for creating a task."""
created_by_user_id: UUID | None = None
class TaskUpdate(SQLModel):
"""Payload for partial task updates."""
title: str | None = None
description: str | None = None
status: TaskStatus | None = None
@@ -38,7 +47,8 @@ class TaskUpdate(SQLModel):
@field_validator("comment", mode="before")
@classmethod
def normalize_comment(cls, value: Any) -> Any:
def normalize_comment(cls, value: object) -> object | None:
"""Normalize blank comment strings to `None`."""
if value is None:
return None
if isinstance(value, str) and not value.strip():
@@ -47,12 +57,15 @@ class TaskUpdate(SQLModel):
@model_validator(mode="after")
def validate_status(self) -> Self:
"""Ensure explicitly supplied status is not null."""
if "status" in self.model_fields_set and self.status is None:
raise ValueError("status is required")
raise ValueError(STATUS_REQUIRED_ERROR)
return self
class TaskRead(TaskBase):
"""Task payload returned from read endpoints."""
id: UUID
board_id: UUID | None
created_by_user_id: UUID | None
@@ -64,10 +77,14 @@ class TaskRead(TaskBase):
class TaskCommentCreate(SQLModel):
"""Payload for creating a task comment."""
message: NonEmptyStr
class TaskCommentRead(SQLModel):
"""Task comment payload returned from read endpoints."""
id: UUID
message: str | None
agent_id: UUID | None

View File

@@ -1,11 +1,15 @@
"""User API schemas for create, update, and read operations."""
from __future__ import annotations
from uuid import UUID
from uuid import UUID # noqa: TCH003
from sqlmodel import SQLModel
class UserBase(SQLModel):
"""Common user profile fields shared across user payload schemas."""
clerk_user_id: str
email: str | None = None
name: str | None = None
@@ -17,10 +21,12 @@ class UserBase(SQLModel):
class UserCreate(UserBase):
pass
"""Payload used to create a user record."""
class UserUpdate(SQLModel):
"""Payload for partial user profile updates."""
name: str | None = None
preferred_name: str | None = None
pronouns: str | None = None
@@ -30,5 +36,7 @@ class UserUpdate(SQLModel):
class UserRead(UserBase):
"""Full user payload returned by API responses."""
id: UUID
is_super_admin: bool

View File

@@ -1,25 +1,31 @@
"""Composite read models assembled for board and board-group views."""
from __future__ import annotations
from datetime import datetime
from uuid import UUID
from datetime import datetime # noqa: TCH003
from uuid import UUID # noqa: TCH003
from sqlmodel import Field, SQLModel
from app.schemas.agents import AgentRead
from app.schemas.approvals import ApprovalRead
from app.schemas.board_groups import BoardGroupRead
from app.schemas.board_memory import BoardMemoryRead
from app.schemas.boards import BoardRead
from app.schemas.agents import AgentRead # noqa: TCH001
from app.schemas.approvals import ApprovalRead # noqa: TCH001
from app.schemas.board_groups import BoardGroupRead # noqa: TCH001
from app.schemas.board_memory import BoardMemoryRead # noqa: TCH001
from app.schemas.boards import BoardRead # noqa: TCH001
from app.schemas.tasks import TaskRead
class TaskCardRead(TaskRead):
"""Task read model enriched with assignee and approval counters."""
assignee: str | None = None
approvals_count: int = 0
approvals_pending_count: int = 0
class BoardSnapshot(SQLModel):
"""Aggregated board payload used by board snapshot endpoints."""
board: BoardRead
tasks: list[TaskCardRead]
agents: list[AgentRead]
@@ -29,6 +35,8 @@ class BoardSnapshot(SQLModel):
class BoardGroupTaskSummary(SQLModel):
"""Task summary row used inside board-group snapshot responses."""
id: UUID
board_id: UUID
board_name: str
@@ -44,11 +52,15 @@ class BoardGroupTaskSummary(SQLModel):
class BoardGroupBoardSnapshot(SQLModel):
"""Board-level rollup embedded within a board-group snapshot."""
board: BoardRead
task_counts: dict[str, int] = Field(default_factory=dict)
tasks: list[BoardGroupTaskSummary] = Field(default_factory=list)
class BoardGroupSnapshot(SQLModel):
"""Top-level board-group snapshot response payload."""
group: BoardGroupRead | None = None
boards: list[BoardGroupBoardSnapshot] = Field(default_factory=list)