Replace direct User database model imports in API endpoints with UserContext schema, following the architecture principle that API routes should not import database models directly. Changes: - Create UserContext schema in models/schema/auth.py with from_user() factory - Update app/api/deps.py to return UserContext from all auth dependencies - Add _get_user_model() helper for functions needing User model access - Update 58 API endpoint files to use UserContext instead of User - Add noqa comments for 4 legitimate edge cases (enums, internal helpers) Architecture validation: 0 errors (down from 61), 11 warnings remain Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
215 lines
5.9 KiB
Python
215 lines
5.9 KiB
Python
# app/api/v1/admin/platform_health.py
|
|
"""
|
|
Platform health and capacity monitoring endpoints.
|
|
|
|
Provides:
|
|
- Overall platform health status
|
|
- Capacity metrics and thresholds
|
|
- Scaling recommendations
|
|
"""
|
|
|
|
import logging
|
|
|
|
from fastapi import APIRouter, Depends
|
|
from pydantic import BaseModel
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.api.deps import get_current_admin_api
|
|
from app.core.database import get_db
|
|
from app.services.platform_health_service import platform_health_service
|
|
from models.schema.auth import UserContext
|
|
|
|
router = APIRouter()
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
# ============================================================================
|
|
# Schemas
|
|
# ============================================================================
|
|
|
|
|
|
class SystemMetrics(BaseModel):
|
|
"""System resource metrics."""
|
|
|
|
cpu_percent: float
|
|
memory_percent: float
|
|
memory_used_gb: float
|
|
memory_total_gb: float
|
|
disk_percent: float
|
|
disk_used_gb: float
|
|
disk_total_gb: float
|
|
|
|
|
|
class DatabaseMetrics(BaseModel):
|
|
"""Database metrics."""
|
|
|
|
size_mb: float
|
|
products_count: int
|
|
orders_count: int
|
|
vendors_count: int
|
|
inventory_count: int
|
|
|
|
|
|
class ImageStorageMetrics(BaseModel):
|
|
"""Image storage metrics."""
|
|
|
|
total_files: int
|
|
total_size_mb: float
|
|
total_size_gb: float
|
|
max_files_per_dir: int
|
|
products_estimated: int
|
|
|
|
|
|
class CapacityThreshold(BaseModel):
|
|
"""Capacity threshold status."""
|
|
|
|
name: str
|
|
current: float
|
|
warning: float
|
|
critical: float
|
|
limit: float
|
|
status: str # ok, warning, critical
|
|
percent_used: float
|
|
|
|
|
|
class ScalingRecommendation(BaseModel):
|
|
"""Scaling recommendation."""
|
|
|
|
priority: str # info, warning, critical
|
|
title: str
|
|
description: str
|
|
action: str | None = None
|
|
|
|
|
|
class PlatformHealthResponse(BaseModel):
|
|
"""Complete platform health response."""
|
|
|
|
timestamp: str
|
|
overall_status: str # healthy, degraded, critical
|
|
system: SystemMetrics
|
|
database: DatabaseMetrics
|
|
image_storage: ImageStorageMetrics
|
|
thresholds: list[CapacityThreshold]
|
|
recommendations: list[ScalingRecommendation]
|
|
infrastructure_tier: str
|
|
next_tier_trigger: str | None = None
|
|
|
|
|
|
class CapacityMetricsResponse(BaseModel):
|
|
"""Capacity-focused metrics."""
|
|
|
|
products_total: int
|
|
products_by_vendor: dict[str, int]
|
|
images_total: int
|
|
storage_used_gb: float
|
|
database_size_mb: float
|
|
orders_this_month: int
|
|
active_vendors: int
|
|
|
|
|
|
# ============================================================================
|
|
# Endpoints
|
|
# ============================================================================
|
|
|
|
|
|
@router.get("/health", response_model=PlatformHealthResponse)
|
|
async def get_platform_health(
|
|
db: Session = Depends(get_db),
|
|
current_admin: UserContext = Depends(get_current_admin_api),
|
|
):
|
|
"""Get comprehensive platform health status.
|
|
|
|
Returns system metrics, database stats, storage info, and recommendations.
|
|
"""
|
|
health_data = platform_health_service.get_full_health_report(db)
|
|
|
|
return PlatformHealthResponse(
|
|
timestamp=health_data["timestamp"],
|
|
overall_status=health_data["overall_status"],
|
|
system=SystemMetrics(**health_data["system"]),
|
|
database=DatabaseMetrics(**health_data["database"]),
|
|
image_storage=ImageStorageMetrics(**health_data["image_storage"]),
|
|
thresholds=[CapacityThreshold(**t) for t in health_data["thresholds"]],
|
|
recommendations=[ScalingRecommendation(**r) for r in health_data["recommendations"]],
|
|
infrastructure_tier=health_data["infrastructure_tier"],
|
|
next_tier_trigger=health_data["next_tier_trigger"],
|
|
)
|
|
|
|
|
|
@router.get("/capacity", response_model=CapacityMetricsResponse)
|
|
async def get_capacity_metrics(
|
|
db: Session = Depends(get_db),
|
|
current_admin: UserContext = Depends(get_current_admin_api),
|
|
):
|
|
"""Get capacity-focused metrics for planning."""
|
|
metrics = platform_health_service.get_capacity_metrics(db)
|
|
return CapacityMetricsResponse(**metrics)
|
|
|
|
|
|
@router.get("/subscription-capacity")
|
|
async def get_subscription_capacity(
|
|
db: Session = Depends(get_db),
|
|
current_admin: UserContext = Depends(get_current_admin_api),
|
|
):
|
|
"""
|
|
Get subscription-based capacity metrics.
|
|
|
|
Shows theoretical vs actual capacity based on all vendor subscriptions.
|
|
"""
|
|
return platform_health_service.get_subscription_capacity(db)
|
|
|
|
|
|
@router.get("/trends")
|
|
async def get_growth_trends(
|
|
days: int = 30,
|
|
db: Session = Depends(get_db),
|
|
current_admin: UserContext = Depends(get_current_admin_api),
|
|
):
|
|
"""
|
|
Get growth trends over the specified period.
|
|
|
|
Returns growth rates and projections for key metrics.
|
|
"""
|
|
from app.services.capacity_forecast_service import capacity_forecast_service
|
|
|
|
return capacity_forecast_service.get_growth_trends(db, days=days)
|
|
|
|
|
|
@router.get("/recommendations")
|
|
async def get_scaling_recommendations(
|
|
db: Session = Depends(get_db),
|
|
current_admin: UserContext = Depends(get_current_admin_api),
|
|
):
|
|
"""
|
|
Get scaling recommendations based on current capacity and growth.
|
|
|
|
Returns prioritized list of recommendations.
|
|
"""
|
|
from app.services.capacity_forecast_service import capacity_forecast_service
|
|
|
|
return capacity_forecast_service.get_scaling_recommendations(db)
|
|
|
|
|
|
@router.post("/snapshot")
|
|
async def capture_snapshot(
|
|
db: Session = Depends(get_db),
|
|
current_admin: UserContext = Depends(get_current_admin_api),
|
|
):
|
|
"""
|
|
Manually capture a capacity snapshot.
|
|
|
|
Normally run automatically by daily background job.
|
|
"""
|
|
from app.services.capacity_forecast_service import capacity_forecast_service
|
|
|
|
snapshot = capacity_forecast_service.capture_daily_snapshot(db)
|
|
db.commit()
|
|
|
|
return {
|
|
"id": snapshot.id,
|
|
"snapshot_date": snapshot.snapshot_date.isoformat(),
|
|
"total_vendors": snapshot.total_vendors,
|
|
"total_products": snapshot.total_products,
|
|
"message": "Snapshot captured successfully",
|
|
}
|