Files
graph-requirements-planner/backend/app/routers/stats.py
2026-03-18 06:40:53 -05:00

56 lines
1.8 KiB
Python

from fastapi import APIRouter, Depends
from sqlalchemy import func
from sqlalchemy.orm import Session
from ..auth import verify_token
from ..database import get_db
from ..models import NodeType, RequirementNode
from ..schemas import StatsResponse
router = APIRouter(prefix="/api/stats", tags=["stats"], dependencies=[Depends(verify_token)])
@router.get("", response_model=StatsResponse)
def get_stats(project_id: int | None = None, db: Session = Depends(get_db)):
query = db.query(RequirementNode)
if project_id is not None:
query = query.filter(RequirementNode.project_id == project_id)
nodes = query.all()
total = len(nodes)
by_type = {}
by_status: dict[str, int] = {}
by_priority: dict[str, int] = {}
quality_passing = 0
leaves_with_tests = 0
total_leaves = 0
for n in nodes:
by_type[n.node_type.value] = by_type.get(n.node_type.value, 0) + 1
by_status[n.status.value] = by_status.get(n.status.value, 0) + 1
by_priority[n.priority.value] = by_priority.get(n.priority.value, 0) + 1
if n.traceable and n.measurable and n.consistent and n.single_purpose:
quality_passing += 1
if n.node_type == NodeType.leaf:
total_leaves += 1
if n.test_spec:
leaves_with_tests += 1
coverage = (leaves_with_tests / total_leaves * 100) if total_leaves > 0 else 0.0
return StatsResponse(
total_nodes=total,
pillars=by_type.get("pillar", 0),
requirements=by_type.get("requirement", 0),
sub_requirements=by_type.get("sub_requirement", 0),
leaves=by_type.get("leaf", 0),
by_status=by_status,
by_priority=by_priority,
quality_passing=quality_passing,
quality_failing=total - quality_passing,
coverage_percent=round(coverage, 1),
)