likwid/backend/src/api/analytics.rs

148 lines
4.8 KiB
Rust
Raw Normal View History

//! 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<i32>,
}
#[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<Uuid>,
Query(query): Query<TrendsQuery>,
State(pool): State<PgPool>,
) -> Result<Json<Vec<ParticipationSnapshot>>, (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<Uuid>,
State(pool): State<PgPool>,
) -> Result<Json<Option<GovernanceHealth>>, (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<Uuid>,
State(pool): State<PgPool>,
) -> Result<Json<Value>, (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<Uuid>,
State(pool): State<PgPool>,
) -> Result<Json<Value>, (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<Uuid>,
State(pool): State<PgPool>,
) -> Result<Json<Vec<Value>>, (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<Uuid>,
State(pool): State<PgPool>,
) -> Result<Json<Value>, (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<Uuid>,
Query(query): Query<ExportQuery>,
State(pool): State<PgPool>,
) -> Result<Json<Value>, (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)
}