Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ and review dive sites and diving centers.

### **Admin Dashboard & System Monitoring**

- **System Overview Dashboard**: Real-time platform statistics including user
counts, content metrics, and engagement data
- **System Statistics & Metrics**: Real-time platform statistics including user
growth, geographic distribution, and system health monitoring.
- **System Health Monitoring**: CPU, memory, disk usage, and database
connectivity monitoring
- **Recent Activity Tracking**: Monitor user registrations, content creation,
Expand Down
169 changes: 1 addition & 168 deletions backend/app/routers/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
)
from app.auth import get_current_admin_user
from app.schemas import (
SystemOverviewResponse, SystemHealthResponse, PlatformStatsResponse,
SystemHealthResponse, PlatformStatsResponse,
NotificationAnalyticsResponse, GrowthResponse
)
from app.utils import get_client_ip, format_ip_for_logging
Expand Down Expand Up @@ -483,173 +483,6 @@ async def get_general_statistics(
"last_updated": now.isoformat()
}

@router.get("/overview", response_model=SystemOverviewResponse)
async def get_system_overview(
current_user: User = Depends(get_current_admin_user),
db: Session = Depends(get_db)
):
"""Get comprehensive system overview with platform statistics and health metrics (DEPRECATED: Use /metrics and /statistics instead)"""

# Calculate date ranges
now = datetime.utcnow()
thirty_days_ago = now - timedelta(days=30)
seven_days_ago = now - timedelta(days=7)
one_day_ago = now - timedelta(days=1)

# User Statistics
total_users = db.query(func.count(User.id)).scalar()
active_users_30d = db.query(func.count(User.id)).filter(
User.created_at >= thirty_days_ago
).scalar()
new_users_7d = db.query(func.count(User.id)).filter(
User.created_at >= seven_days_ago
).scalar()
new_users_30d = db.query(func.count(User.id)).filter(
User.created_at >= thirty_days_ago
).scalar()

# Calculate user growth rate (percentage change from previous 30 days)
sixty_days_ago = now - timedelta(days=60)
users_60d_ago = db.query(func.count(User.id)).filter(
User.created_at >= sixty_days_ago
).scalar()
users_30d_ago = db.query(func.count(User.id)).filter(
User.created_at >= thirty_days_ago
).scalar()

growth_rate = 0
if users_30d_ago > 0:
growth_rate = ((new_users_30d - (users_60d_ago - users_30d_ago)) / users_30d_ago) * 100

# Content Statistics
total_dive_sites = db.query(func.count(DiveSite.id)).scalar()
total_diving_centers = db.query(func.count(DivingCenter.id)).scalar()
total_dives = db.query(func.count(Dive.id)).scalar()
total_comments = db.query(func.count(SiteComment.id)).scalar() + db.query(func.count(CenterComment.id)).scalar()
total_ratings = db.query(func.count(SiteRating.id)).scalar() + db.query(func.count(CenterRating.id)).scalar()
total_media = db.query(func.count(SiteMedia.id)).scalar() + db.query(func.count(DiveMedia.id)).scalar()

# Engagement Metrics
avg_site_rating = db.query(func.avg(SiteRating.score)).scalar() or 0
avg_center_rating = db.query(func.avg(CenterRating.score)).scalar() or 0

# Recent activity (last 24 hours)
recent_comments = db.query(func.count(SiteComment.id)).filter(
SiteComment.created_at >= one_day_ago
).scalar() + db.query(func.count(CenterComment.id)).filter(
CenterComment.created_at >= one_day_ago
).scalar()

recent_ratings = db.query(func.count(SiteRating.id)).filter(
SiteRating.created_at >= one_day_ago
).scalar() + db.query(func.count(CenterRating.id)).filter(
CenterRating.created_at >= one_day_ago
).scalar()

recent_dives = db.query(func.count(Dive.id)).filter(
Dive.created_at >= one_day_ago
).scalar()

# Geographic Distribution
dive_sites_by_country = db.query(
DiveSite.country,
func.count(DiveSite.id).label('count')
).filter(
DiveSite.country.isnot(None)
).group_by(DiveSite.country).order_by(desc('count')).limit(10).all()

# System Usage (simplified - in production this would come from logs/analytics)
api_calls_today = 0 # This would be tracked in production
peak_usage_time = "14:00-16:00" # Placeholder
most_accessed_endpoint = "/api/v1/dive-sites" # Placeholder

# System Health
db_connection_status = "healthy"
try:
db.execute(text("SELECT 1"))
except Exception:
db_connection_status = "unhealthy"

# Resource Utilization
cpu_usage = psutil.cpu_percent(interval=1)
memory_usage = psutil.virtual_memory().percent
disk_usage = psutil.disk_usage('/').percent

# External Services Status (placeholders)
google_oauth_status = "healthy"
geocoding_service_status = "healthy"

# Security Metrics (placeholder - would need to be implemented with login tracking)
failed_logins_24h = 0 # This would be tracked in production

return {
"platform_stats": {
"users": {
"total": total_users,
"active_30d": active_users_30d,
"new_7d": new_users_7d,
"new_30d": new_users_30d,
"growth_rate": round(growth_rate, 2)
},
"content": {
"dive_sites": total_dive_sites,
"diving_centers": total_diving_centers,
"dives": total_dives,
"comments": total_comments,
"ratings": total_ratings,
"media_uploads": total_media
},
"engagement": {
"avg_site_rating": round(avg_site_rating, 1),
"avg_center_rating": round(avg_center_rating, 1),
"recent_comments_24h": recent_comments,
"recent_ratings_24h": recent_ratings,
"recent_dives_24h": recent_dives
},
"geographic": {
"dive_sites_by_country": [
{"country": country, "count": count}
for country, count in dive_sites_by_country
]
},
"system_usage": {
"api_calls_today": api_calls_today,
"peak_usage_time": peak_usage_time,
"most_accessed_endpoint": most_accessed_endpoint
}
},
"system_health": {
"database": {
"status": db_connection_status,
"response_time": "fast" # Placeholder
},
"application": {
"status": "healthy",
"uptime": "99.9%", # Placeholder
"response_time": "fast" # Placeholder
},
"resources": {
"cpu_usage": cpu_usage,
"memory_usage": memory_usage,
"disk_usage": disk_usage
},
"external_services": {
"google_oauth": google_oauth_status,
"geocoding_service": geocoding_service_status
},
"security": {
"failed_logins_24h": failed_logins_24h,
"suspicious_activity": "none detected" # Placeholder
}
},
"alerts": {
"critical": [],
"warnings": [],
"info": []
},
"last_updated": now.isoformat()
}

@router.get("/health", response_model=SystemHealthResponse)
async def get_system_health(
current_user: User = Depends(get_current_admin_user),
Expand Down
78 changes: 0 additions & 78 deletions backend/app/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -949,84 +949,6 @@ class ParsedDiveTripUpdate(BaseModel):
trip_status: Optional[str] = Field(None, pattern=r"^(scheduled|confirmed|cancelled|completed)$")
dives: Optional[List[ParsedDiveCreate]] = None

# System Overview Schemas
class UserStats(BaseModel):
total: int
active_30d: int
new_7d: int
new_30d: int
growth_rate: float

class ContentStats(BaseModel):
dive_sites: int
diving_centers: int
dives: int
comments: int
ratings: int
media_uploads: int

class EngagementStats(BaseModel):
avg_site_rating: float
avg_center_rating: float
recent_comments_24h: int
recent_ratings_24h: int
recent_dives_24h: int

class GeographicStats(BaseModel):
dive_sites_by_country: List[dict]

class SystemUsageStats(BaseModel):
api_calls_today: int
peak_usage_time: str
most_accessed_endpoint: str

class PlatformStats(BaseModel):
users: UserStats
content: ContentStats
engagement: EngagementStats
geographic: GeographicStats
system_usage: SystemUsageStats

class DatabaseHealth(BaseModel):
status: str
response_time: str

class ApplicationHealth(BaseModel):
status: str
uptime: str
response_time: str

class ResourceHealth(BaseModel):
cpu_usage: float
memory_usage: float
disk_usage: float

class ExternalServicesHealth(BaseModel):
google_oauth: str
geocoding_service: str

class SecurityHealth(BaseModel):
failed_logins_24h: int
suspicious_activity: str

class SystemHealth(BaseModel):
database: DatabaseHealth
application: ApplicationHealth
resources: ResourceHealth
external_services: ExternalServicesHealth
security: SecurityHealth

class Alerts(BaseModel):
critical: List[str]
warnings: List[str]
info: List[str]

class SystemOverviewResponse(BaseModel):
platform_stats: PlatformStats
system_health: SystemHealth
alerts: Alerts
last_updated: str

class SystemHealthResponse(BaseModel):
status: str
database: dict
Expand Down
Loading
Loading