Files
ANDREW HOSFORD 0e8978f48c Update project files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 11:59:48 -05:00

231 lines
6.7 KiB
Python

from datetime import datetime
from pydantic import BaseModel, Field
from .models import CodeLanguage, NodeType, Priority, Status, TestStatus
# ─── Requirement ─────────────────────────────────────────────────────────
class RequirementCreate(BaseModel):
id: str = Field(..., max_length=64)
title: str = Field(..., max_length=256)
description: str | None = None
priority: Priority = Priority.medium
phase: int | None = None
status: Status = Status.draft
node_type: NodeType = NodeType.requirement
parent_id: str | None = None
sort_order: int = 0
project_id: int | None = None
gitea_issue_number: int | None = None
gitea_repo: str | None = None
acceptance_criteria: str | None = None
test_spec: str | None = None
test_code: str | None = None
impl_code: str | None = None
code_language: CodeLanguage | None = None
target_test_file: str | None = None
target_impl_file: str | None = None
class RequirementUpdate(BaseModel):
title: str | None = None
description: str | None = None
priority: Priority | None = None
phase: int | None = None
status: Status | None = None
node_type: NodeType | None = None
parent_id: str | None = None
sort_order: int | None = None
gitea_issue_number: int | None = None
gitea_repo: str | None = None
acceptance_criteria: str | None = None
test_spec: str | None = None
test_code: str | None = None
impl_code: str | None = None
code_language: CodeLanguage | None = None
target_test_file: str | None = None
target_impl_file: str | None = None
measurable: bool | None = None
consistent: bool | None = None
single_purpose: bool | None = None
class QualityReport(BaseModel):
traceable: bool
measurable: bool
consistent: bool
single_purpose: bool
errors: list[str]
warnings: list[str]
valid: bool
class RequirementResponse(BaseModel):
id: str
title: str
description: str | None
priority: Priority
phase: int | None
status: Status
node_type: NodeType
parent_id: str | None
sort_order: int
project_id: int | None
gitea_issue_number: int | None
gitea_repo: str | None
traceable: bool
measurable: bool
consistent: bool
single_purpose: bool
acceptance_criteria: str | None
test_spec: str | None
test_code: str | None
impl_code: str | None
code_language: CodeLanguage | None
target_test_file: str | None
target_impl_file: str | None
test_status: TestStatus
created_at: datetime
updated_at: datetime
quality: QualityReport | None = None
children: list["RequirementResponse"] = []
model_config = {"from_attributes": True}
class RequirementTreeNode(BaseModel):
id: str
title: str
priority: Priority
phase: int | None
status: Status
node_type: NodeType
parent_id: str | None
child_count: int = 0
traceable: bool
measurable: bool
consistent: bool
single_purpose: bool
gitea_issue_number: int | None = None
children: list["RequirementTreeNode"] = []
model_config = {"from_attributes": True}
# ─── Requirement History ────────────────────────────────────────────────
class RequirementHistorySummary(BaseModel):
id: int
requirement_id: str
version: int
title: str
status: str
created_at: datetime
change_summary: str | None
model_config = {"from_attributes": True}
class RequirementHistoryDetail(RequirementHistorySummary):
description: str | None
priority: str
phase: int | None
node_type: str
acceptance_criteria: str | None
test_spec: str | None
test_code: str | None
impl_code: str | None
code_language: str | None
target_test_file: str | None
target_impl_file: str | None
measurable: bool
consistent: bool
single_purpose: bool
gitea_issue_number: int | None
gitea_repo: str | None
# ─── Graph Layouts ──────────────────────────────────────────────────────
class GraphLayoutCreate(BaseModel):
name: str = Field(..., max_length=128)
description: str | None = None
project_id: int | None = None
node_positions: dict[str, dict[str, float]]
viewport: dict[str, object]
is_default: bool = False
class GraphLayoutUpdate(BaseModel):
name: str | None = None
description: str | None = None
node_positions: dict[str, dict[str, float]] | None = None
viewport: dict[str, object] | None = None
is_default: bool | None = None
class GraphLayoutResponse(BaseModel):
id: int
name: str
description: str | None
project_id: int | None
is_default: bool
created_at: datetime
updated_at: datetime
model_config = {"from_attributes": True}
class GraphLayoutDetailResponse(GraphLayoutResponse):
node_positions: dict[str, dict[str, float]]
viewport: dict[str, object]
# ─── Cross-Pillar Links ─────────────────────────────────────────────────
class LinkCreate(BaseModel):
source_id: str
target_id: str
relationship_type: str = "shared_parent"
class LinkResponse(BaseModel):
source_id: str
target_id: str
relationship_type: str
model_config = {"from_attributes": True}
# ─── Project ────────────────────────────────────────────────────────────
class ProjectCreate(BaseModel):
name: str = Field(..., max_length=256)
description: str | None = None
repo_path: str | None = None
repo_url: str | None = None
requirements_yaml_path: str | None = None
class ProjectResponse(BaseModel):
id: int
name: str
description: str | None
repo_path: str | None
repo_url: str | None
requirements_yaml_path: str | None
created_at: datetime
model_config = {"from_attributes": True}
# ─── Stats ───────────────────────────────────────────────────────────────
class StatsResponse(BaseModel):
total_nodes: int
pillars: int
requirements: int
sub_requirements: int
leaves: int
orphaned: int
by_status: dict[str, int]
by_priority: dict[str, int]
quality_passing: int
quality_failing: int
coverage_percent: float