//! Governance Analytics API endpoints. use axum::{ extract::{Path, Query, State}, http::StatusCode, routing::get, Json, Router, }; use chrono::NaiveDate; use serde::Deserialize; use serde_json::Value; use sqlx::PgPool; use uuid::Uuid; use crate::auth::AuthUser; use crate::plugins::builtin::governance_analytics::{ AnalyticsService, GovernanceHealth, ParticipationSnapshot, }; // ============================================================================ // Query Parameters // ============================================================================ #[derive(Debug, Deserialize)] pub struct TrendsQuery { pub days: Option, } #[derive(Debug, Deserialize)] pub struct ExportQuery { pub start_date: NaiveDate, pub end_date: NaiveDate, } // ============================================================================ // Handlers // ============================================================================ /// Get participation trends for a community async fn get_participation_trends( _auth: AuthUser, Path(community_id): Path, Query(query): Query, State(pool): State, ) -> Result>, (StatusCode, String)> { let days = query.days.unwrap_or(30); let trends = AnalyticsService::get_participation_trends(&pool, community_id, days) .await .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?; Ok(Json(trends)) } /// Get current governance health for a community async fn get_health( _auth: AuthUser, Path(community_id): Path, State(pool): State, ) -> Result>, (StatusCode, String)> { let health = AnalyticsService::get_health(&pool, community_id) .await .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?; Ok(Json(health)) } /// Get delegation analytics for a community async fn get_delegation_analytics( _auth: AuthUser, Path(community_id): Path, State(pool): State, ) -> Result, (StatusCode, String)> { let analytics = AnalyticsService::get_delegation_analytics(&pool, community_id) .await .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?; Ok(Json(analytics)) } /// Get decision load metrics for a community async fn get_decision_load( _auth: AuthUser, Path(community_id): Path, State(pool): State, ) -> Result, (StatusCode, String)> { let load = AnalyticsService::get_decision_load(&pool, community_id) .await .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?; Ok(Json(load)) } /// Get voting method comparison for a community async fn get_voting_method_comparison( _auth: AuthUser, Path(community_id): Path, State(pool): State, ) -> Result>, (StatusCode, String)> { let comparison = AnalyticsService::get_voting_method_comparison(&pool, community_id) .await .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?; Ok(Json(comparison)) } /// Get full analytics dashboard for a community async fn get_dashboard( _auth: AuthUser, Path(community_id): Path, State(pool): State, ) -> Result, (StatusCode, String)> { let dashboard = AnalyticsService::get_dashboard(&pool, community_id) .await .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?; Ok(Json(dashboard)) } /// Export analytics data for a date range async fn export_data( _auth: AuthUser, Path(community_id): Path, Query(query): Query, State(pool): State, ) -> Result, (StatusCode, String)> { let data = AnalyticsService::export_data(&pool, community_id, query.start_date, query.end_date) .await .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?; Ok(Json(data)) } // ============================================================================ // Router // ============================================================================ pub fn router(pool: PgPool) -> Router { Router::new() .route("/api/communities/{community_id}/analytics/dashboard", get(get_dashboard)) .route("/api/communities/{community_id}/analytics/health", get(get_health)) .route("/api/communities/{community_id}/analytics/participation", get(get_participation_trends)) .route("/api/communities/{community_id}/analytics/delegation", get(get_delegation_analytics)) .route("/api/communities/{community_id}/analytics/decision-load", get(get_decision_load)) .route("/api/communities/{community_id}/analytics/voting-methods", get(get_voting_method_comparison)) .route("/api/communities/{community_id}/analytics/export", get(export_data)) .with_state(pool) }