feat: add proper Pydantic response_model to all stats endpoints
- Create comprehensive stats schemas in models/schema/stats.py: - ImportStatsResponse, UserStatsResponse, ProductStatsResponse - PlatformStatsResponse, AdminDashboardResponse - VendorDashboardStatsResponse with nested models - VendorAnalyticsResponse, CodeQualityDashboardStatsResponse - Move DashboardStatsResponse from code_quality.py to schema file - Fix get_vendor_statistics() to return pending_vendors field - Fix get_vendor_stats() to return flat structure matching schema - Add response_model to all stats endpoints: - GET /admin/dashboard -> AdminDashboardResponse - GET /admin/dashboard/stats/platform -> PlatformStatsResponse - GET /admin/marketplace-import-jobs/stats -> ImportStatsResponse - GET /vendor/dashboard/stats -> VendorDashboardStatsResponse - GET /vendor/analytics -> VendorAnalyticsResponse - Enhance API-001 architecture rule with detailed guidance - Add SVC-007 rule for service/schema compatibility 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@ from app.core.database import get_db
|
||||
from app.exceptions import ViolationNotFoundException
|
||||
from app.services.code_quality_service import code_quality_service
|
||||
from models.database.user import User
|
||||
from models.schema.stats import CodeQualityDashboardStatsResponse
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@@ -107,25 +108,6 @@ class AddCommentRequest(BaseModel):
|
||||
comment: str = Field(..., min_length=1, description="Comment text")
|
||||
|
||||
|
||||
class DashboardStatsResponse(BaseModel):
|
||||
"""Response model for dashboard statistics"""
|
||||
|
||||
total_violations: int
|
||||
errors: int
|
||||
warnings: int
|
||||
open: int
|
||||
assigned: int
|
||||
resolved: int
|
||||
ignored: int
|
||||
technical_debt_score: int
|
||||
trend: list
|
||||
by_severity: dict
|
||||
by_rule: dict
|
||||
by_module: dict
|
||||
top_files: list
|
||||
last_scan: str | None = None
|
||||
|
||||
|
||||
# API Endpoints
|
||||
|
||||
|
||||
@@ -447,7 +429,7 @@ async def add_comment(
|
||||
}
|
||||
|
||||
|
||||
@router.get("/stats", response_model=DashboardStatsResponse)
|
||||
@router.get("/stats", response_model=CodeQualityDashboardStatsResponse)
|
||||
async def get_dashboard_stats(
|
||||
db: Session = Depends(get_db), current_user: User = Depends(get_current_admin_api)
|
||||
):
|
||||
@@ -463,4 +445,4 @@ async def get_dashboard_stats(
|
||||
"""
|
||||
stats = code_quality_service.get_dashboard_stats(db)
|
||||
|
||||
return DashboardStatsResponse(**stats)
|
||||
return CodeQualityDashboardStatsResponse(**stats)
|
||||
|
||||
@@ -13,28 +13,46 @@ from app.core.database import get_db
|
||||
from app.services.admin_service import admin_service
|
||||
from app.services.stats_service import stats_service
|
||||
from models.database.user import User
|
||||
from models.schema.stats import MarketplaceStatsResponse, StatsResponse
|
||||
from models.schema.stats import (
|
||||
AdminDashboardResponse,
|
||||
ImportStatsResponse,
|
||||
MarketplaceStatsResponse,
|
||||
OrderStatsBasicResponse,
|
||||
PlatformStatsResponse,
|
||||
ProductStatsResponse,
|
||||
StatsResponse,
|
||||
UserStatsResponse,
|
||||
VendorStatsResponse,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/dashboard")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@router.get("")
|
||||
@router.get("", response_model=AdminDashboardResponse)
|
||||
def get_admin_dashboard(
|
||||
db: Session = Depends(get_db),
|
||||
current_admin: User = Depends(get_current_admin_api),
|
||||
):
|
||||
"""Get admin dashboard with platform statistics (Admin only)."""
|
||||
return {
|
||||
"platform": {
|
||||
user_stats = stats_service.get_user_statistics(db)
|
||||
vendor_stats = stats_service.get_vendor_statistics(db)
|
||||
|
||||
return AdminDashboardResponse(
|
||||
platform={
|
||||
"name": "Multi-Tenant Ecommerce Platform",
|
||||
"version": "1.0.0",
|
||||
},
|
||||
"users": stats_service.get_user_statistics(db),
|
||||
"vendors": stats_service.get_vendor_statistics(db),
|
||||
"recent_vendors": admin_service.get_recent_vendors(db, limit=5),
|
||||
"recent_imports": admin_service.get_recent_import_jobs(db, limit=10),
|
||||
}
|
||||
users=UserStatsResponse(**user_stats),
|
||||
vendors=VendorStatsResponse(
|
||||
total=vendor_stats.get("total", vendor_stats.get("total_vendors", 0)),
|
||||
verified=vendor_stats.get("verified", vendor_stats.get("verified_vendors", 0)),
|
||||
pending=vendor_stats.get("pending", vendor_stats.get("pending_vendors", 0)),
|
||||
inactive=vendor_stats.get("inactive", vendor_stats.get("inactive_vendors", 0)),
|
||||
),
|
||||
recent_vendors=admin_service.get_recent_vendors(db, limit=5),
|
||||
recent_imports=admin_service.get_recent_import_jobs(db, limit=10),
|
||||
)
|
||||
|
||||
|
||||
@router.get("/stats", response_model=StatsResponse)
|
||||
@@ -75,16 +93,27 @@ def get_marketplace_stats(
|
||||
]
|
||||
|
||||
|
||||
@router.get("/stats/platform")
|
||||
@router.get("/stats/platform", response_model=PlatformStatsResponse)
|
||||
def get_platform_statistics(
|
||||
db: Session = Depends(get_db),
|
||||
current_admin: User = Depends(get_current_admin_api),
|
||||
):
|
||||
"""Get comprehensive platform statistics (Admin only)."""
|
||||
return {
|
||||
"users": stats_service.get_user_statistics(db),
|
||||
"vendors": stats_service.get_vendor_statistics(db),
|
||||
"products": stats_service.get_product_statistics(db),
|
||||
"orders": stats_service.get_order_statistics(db),
|
||||
"imports": stats_service.get_import_statistics(db),
|
||||
}
|
||||
user_stats = stats_service.get_user_statistics(db)
|
||||
vendor_stats = stats_service.get_vendor_statistics(db)
|
||||
product_stats = stats_service.get_product_statistics(db)
|
||||
order_stats = stats_service.get_order_statistics(db)
|
||||
import_stats = stats_service.get_import_statistics(db)
|
||||
|
||||
return PlatformStatsResponse(
|
||||
users=UserStatsResponse(**user_stats),
|
||||
vendors=VendorStatsResponse(
|
||||
total=vendor_stats.get("total", vendor_stats.get("total_vendors", 0)),
|
||||
verified=vendor_stats.get("verified", vendor_stats.get("verified_vendors", 0)),
|
||||
pending=vendor_stats.get("pending", vendor_stats.get("pending_vendors", 0)),
|
||||
inactive=vendor_stats.get("inactive", vendor_stats.get("inactive_vendors", 0)),
|
||||
),
|
||||
products=ProductStatsResponse(**product_stats),
|
||||
orders=OrderStatsBasicResponse(**order_stats),
|
||||
imports=ImportStatsResponse(**import_stats),
|
||||
)
|
||||
|
||||
@@ -109,11 +109,12 @@ def get_vendor_statistics_endpoint(
|
||||
"""Get vendor statistics for admin dashboard (Admin only)."""
|
||||
stats = stats_service.get_vendor_statistics(db)
|
||||
|
||||
# Use schema-compatible keys (with fallback to legacy keys)
|
||||
return VendorStatsResponse(
|
||||
total=stats.get("total_vendors", 0),
|
||||
verified=stats.get("verified_vendors", 0),
|
||||
pending=stats.get("pending_vendors", 0),
|
||||
inactive=stats.get("inactive_vendors", 0),
|
||||
total=stats.get("total", stats.get("total_vendors", 0)),
|
||||
verified=stats.get("verified", stats.get("verified_vendors", 0)),
|
||||
pending=stats.get("pending", stats.get("pending_vendors", 0)),
|
||||
inactive=stats.get("inactive", stats.get("inactive_vendors", 0)),
|
||||
)
|
||||
|
||||
|
||||
|
||||
20
app/api/v1/vendor/analytics.py
vendored
20
app/api/v1/vendor/analytics.py
vendored
@@ -15,16 +15,32 @@ from app.api.deps import get_current_vendor_api
|
||||
from app.core.database import get_db
|
||||
from app.services.stats_service import stats_service
|
||||
from models.database.user import User
|
||||
from models.schema.stats import (
|
||||
VendorAnalyticsCatalog,
|
||||
VendorAnalyticsImports,
|
||||
VendorAnalyticsInventory,
|
||||
VendorAnalyticsResponse,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/analytics")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@router.get("")
|
||||
@router.get("", response_model=VendorAnalyticsResponse)
|
||||
def get_vendor_analytics(
|
||||
period: str = Query("30d", description="Time period: 7d, 30d, 90d, 1y"),
|
||||
current_user: User = Depends(get_current_vendor_api),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""Get vendor analytics data for specified time period."""
|
||||
return stats_service.get_vendor_analytics(db, current_user.token_vendor_id, period)
|
||||
data = stats_service.get_vendor_analytics(db, current_user.token_vendor_id, period)
|
||||
|
||||
return VendorAnalyticsResponse(
|
||||
period=data["period"],
|
||||
start_date=data["start_date"],
|
||||
imports=VendorAnalyticsImports(count=data["imports"]["count"]),
|
||||
catalog=VendorAnalyticsCatalog(products_added=data["catalog"]["products_added"]),
|
||||
inventory=VendorAnalyticsInventory(
|
||||
total_locations=data["inventory"]["total_locations"]
|
||||
),
|
||||
)
|
||||
|
||||
58
app/api/v1/vendor/dashboard.py
vendored
58
app/api/v1/vendor/dashboard.py
vendored
@@ -17,12 +17,20 @@ from app.exceptions import VendorNotActiveException
|
||||
from app.services.stats_service import stats_service
|
||||
from app.services.vendor_service import vendor_service
|
||||
from models.database.user import User
|
||||
from models.schema.stats import (
|
||||
VendorCustomerStats,
|
||||
VendorDashboardStatsResponse,
|
||||
VendorInfo,
|
||||
VendorOrderStats,
|
||||
VendorProductStats,
|
||||
VendorRevenueStats,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/dashboard")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@router.get("/stats")
|
||||
@router.get("/stats", response_model=VendorDashboardStatsResponse)
|
||||
def get_vendor_dashboard_stats(
|
||||
request: Request,
|
||||
current_user: User = Depends(get_current_vendor_api),
|
||||
@@ -51,27 +59,27 @@ def get_vendor_dashboard_stats(
|
||||
# Get vendor-scoped statistics
|
||||
stats_data = stats_service.get_vendor_stats(db=db, vendor_id=vendor_id)
|
||||
|
||||
return {
|
||||
"vendor": {
|
||||
"id": vendor.id,
|
||||
"name": vendor.name,
|
||||
"vendor_code": vendor.vendor_code,
|
||||
},
|
||||
"products": {
|
||||
"total": stats_data.get("total_products", 0),
|
||||
"active": stats_data.get("active_products", 0),
|
||||
},
|
||||
"orders": {
|
||||
"total": stats_data.get("total_orders", 0),
|
||||
"pending": stats_data.get("pending_orders", 0),
|
||||
"completed": stats_data.get("completed_orders", 0),
|
||||
},
|
||||
"customers": {
|
||||
"total": stats_data.get("total_customers", 0),
|
||||
"active": stats_data.get("active_customers", 0),
|
||||
},
|
||||
"revenue": {
|
||||
"total": stats_data.get("total_revenue", 0),
|
||||
"this_month": stats_data.get("revenue_this_month", 0),
|
||||
},
|
||||
}
|
||||
return VendorDashboardStatsResponse(
|
||||
vendor=VendorInfo(
|
||||
id=vendor.id,
|
||||
name=vendor.name,
|
||||
vendor_code=vendor.vendor_code,
|
||||
),
|
||||
products=VendorProductStats(
|
||||
total=stats_data.get("total_products", 0),
|
||||
active=stats_data.get("active_products", 0),
|
||||
),
|
||||
orders=VendorOrderStats(
|
||||
total=stats_data.get("total_orders", 0),
|
||||
pending=stats_data.get("pending_orders", 0),
|
||||
completed=stats_data.get("completed_orders", 0),
|
||||
),
|
||||
customers=VendorCustomerStats(
|
||||
total=stats_data.get("total_customers", 0),
|
||||
active=stats_data.get("active_customers", 0),
|
||||
),
|
||||
revenue=VendorRevenueStats(
|
||||
total=stats_data.get("total_revenue", 0),
|
||||
this_month=stats_data.get("revenue_this_month", 0),
|
||||
),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user