velxio/backend/app/schemas/admin.py

199 lines
4.7 KiB
Python

from datetime import datetime
from pydantic import BaseModel, EmailStr
class AdminSetupRequest(BaseModel):
username: str
email: EmailStr
password: str
class AdminUserResponse(BaseModel):
id: str
username: str
email: str
avatar_url: str | None
is_active: bool
is_admin: bool
created_at: datetime
project_count: int = 0
# Usage metrics
total_compiles: int = 0
total_compile_errors: int = 0
total_runs: int = 0
last_active_at: datetime | None = None
boards_used: list[str] = [] # distinct board families this user has compiled
signup_country: str | None = None
last_country: str | None = None
model_config = {"from_attributes": True}
class AdminUserUpdateRequest(BaseModel):
username: str | None = None
email: EmailStr | None = None
password: str | None = None
is_active: bool | None = None
is_admin: bool | None = None
class AdminProjectResponse(BaseModel):
id: str
name: str
slug: str
description: str | None
is_public: bool
board_type: str
owner_username: str
owner_id: str
created_at: datetime
updated_at: datetime
# Usage metrics
compile_count: int = 0
compile_error_count: int = 0
run_count: int = 0
update_count: int = 0
last_compiled_at: datetime | None = None
last_run_at: datetime | None = None
model_config = {"from_attributes": True}
# ── Dashboard / metrics responses ────────────────────────────────────────────
class OverviewResponse(BaseModel):
total_users: int
total_projects: int
public_projects: int
private_projects: int
total_compiles: int
total_compile_errors: int
total_runs: int
compile_success_rate: float # 0..1
dau: int # active users in last 24h
wau: int # active users in last 7d
mau: int # active users in last 30d
new_users_30d: int
new_projects_30d: int
class TimeseriesPoint(BaseModel):
bucket: str # ISO date / hour
value: int
class TimeseriesResponse(BaseModel):
metric: str
bucket: str # 'day' | 'hour' | 'week'
range_days: int
points: list[TimeseriesPoint]
class BoardBreakdown(BaseModel):
board_family: str | None
board_fqbn: str | None
compile_count: int
compile_error_count: int
run_count: int
distinct_users: int
distinct_projects: int
class BoardsResponse(BaseModel):
families: list[BoardBreakdown]
fqbns: list[BoardBreakdown]
class BoardDiversityBucket(BaseModel):
bucket: str # '1', '2', '3+'
user_count: int
class BoardDiversityResponse(BaseModel):
buckets: list[BoardDiversityBucket]
total_users_with_compiles: int
class TopUserEntry(BaseModel):
user_id: str
username: str
value: int
class TopProjectEntry(BaseModel):
project_id: str
project_name: str
owner_username: str
value: int
class UserMetricsResponse(BaseModel):
user_id: str
username: str
total_compiles: int
total_compile_errors: int
total_runs: int
last_active_at: datetime | None
boards_used: list[str]
fqbns_used: list[str]
project_count: int
timeseries: list[TimeseriesPoint]
class CountryEntry(BaseModel):
country: str | None # ISO-3166 alpha-2 (or None for unknown / dev)
user_count: int # users currently or recently in this country (last_country)
signup_count: int # users who signed up from this country
compile_count: int
run_count: int
distinct_users_active: int # distinct users with any UsageEvent from this country
class CountriesResponse(BaseModel):
range_days: int
entries: list[CountryEntry]
class DailyProjectActivity(BaseModel):
"""One row per (day, project) for a given user."""
date: str # YYYY-MM-DD
project_id: str | None # None for events without a project association
project_name: str | None # None when the project was deleted
compiles: int # successful compiles
compile_errors: int
runs: int
saves: int
class UserDailyActivityResponse(BaseModel):
user_id: str
username: str
range_days: int
entries: list[DailyProjectActivity]
# Pre-aggregated totals per day (across all projects) for at-a-glance KPIs
daily_totals: list["DailyTotals"]
class DailyTotals(BaseModel):
date: str
compiles: int
compile_errors: int
runs: int
saves: int
distinct_projects: int
class ProjectMetricsResponse(BaseModel):
project_id: str
project_name: str
owner_username: str
compile_count: int
compile_error_count: int
run_count: int
update_count: int
last_compiled_at: datetime | None
last_run_at: datetime | None
timeseries: list[TimeseriesPoint]