Phase 6 - Database-driven tiers: - Update subscription_service to query database first with legacy fallback - Add get_tier_info() db parameter and _get_tier_from_legacy() method Phase 7 - Platform health integration: - Add get_subscription_capacity() for theoretical vs actual capacity - Include subscription capacity in full health report Phase 8 - Background subscription tasks: - Add reset_period_counters() for billing period resets - Add check_trial_expirations() for trial management - Add sync_stripe_status() for Stripe synchronization - Add cleanup_stale_subscriptions() for maintenance - Add capture_capacity_snapshot() for daily metrics Phase 10 - Capacity planning & forecasting: - Add CapacitySnapshot model for historical tracking - Create capacity_forecast_service with growth trends - Add /subscription-capacity, /trends, /recommendations endpoints - Add /snapshot endpoint for manual captures Also includes billing API enhancements from phase 4: - Add upcoming-invoice, change-tier, addon purchase/cancel endpoints - Add UsageSummary schema for billing page - Enhance billing.js with addon management functions 🤖 Generated with [Claude Code](https://claude.com/claude-code) 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.database.user import User
|
|
|
|
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: User = 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: User = 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: User = 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: User = 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: User = 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: User = 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",
|
|
}
|