@@ -18,7 +18,7 @@ use services::analytics::{ActivityLogEntry, AnalyticsSummary, TopActiveUsersResp
1818use services:: bi_metrics:: {
1919 DeploymentFilter , DeploymentRecord , DeploymentSummary , StatusChangeRecord , TopConsumer ,
2020 TopConsumerFilter , TopConsumerGroupBy , UsageAggregation , UsageFilter , UsageGroupBy ,
21- UsageRankBy as BiUsageRankBy ,
21+ UsageRankBy as BiUsageRankBy , UserSummary ,
2222} ;
2323
2424/// Maximum rows for BI usage aggregation queries.
@@ -298,7 +298,7 @@ async fn list_users_bi_impl(
298298 } )
299299 . unwrap_or ( ( None , false , None ) ) ;
300300
301- let filter = services:: user :: ports :: AdminListUsersFilter {
301+ let filter = services:: bi_metrics :: ListUsersFilter {
302302 subscription_status,
303303 subscription_plan_price_ids,
304304 subscription_plan_none,
@@ -312,27 +312,27 @@ async fn list_users_bi_impl(
312312 } ) ,
313313 } ;
314314
315- let sort = services:: user :: ports :: AdminListUsersSort {
315+ let sort = services:: bi_metrics :: ListUsersSort {
316316 sort_by : match params. sort_by . as_str ( ) {
317- "created_at" => services:: user :: ports :: AdminUsersSortBy :: CreatedAt ,
318- "total_spent_nano" => services:: user :: ports :: AdminUsersSortBy :: TotalSpentNano ,
319- "agent_spent_nano" => services:: user :: ports :: AdminUsersSortBy :: AgentSpentNano ,
320- "agent_token_usage" => services:: user :: ports :: AdminUsersSortBy :: AgentTokenUsage ,
321- "last_activity_at" => services:: user :: ports :: AdminUsersSortBy :: LastActivityAt ,
322- "agent_count" => services:: user :: ports :: AdminUsersSortBy :: AgentCount ,
323- "email" => services:: user :: ports :: AdminUsersSortBy :: Email ,
324- "name" => services:: user :: ports :: AdminUsersSortBy :: Name ,
325- _ => services:: user :: ports :: AdminUsersSortBy :: CreatedAt ,
317+ "created_at" => services:: bi_metrics :: UsersSortBy :: CreatedAt ,
318+ "total_spent_nano" => services:: bi_metrics :: UsersSortBy :: TotalSpentNano ,
319+ "agent_spent_nano" => services:: bi_metrics :: UsersSortBy :: AgentSpentNano ,
320+ "agent_token_usage" => services:: bi_metrics :: UsersSortBy :: AgentTokenUsage ,
321+ "last_activity_at" => services:: bi_metrics :: UsersSortBy :: LastActivityAt ,
322+ "agent_count" => services:: bi_metrics :: UsersSortBy :: AgentCount ,
323+ "email" => services:: bi_metrics :: UsersSortBy :: Email ,
324+ "name" => services:: bi_metrics :: UsersSortBy :: Name ,
325+ _ => services:: bi_metrics :: UsersSortBy :: CreatedAt ,
326326 } ,
327327 sort_order : if params. sort_order == "asc" {
328- services:: user :: ports :: AdminUsersSortOrder :: Asc
328+ services:: bi_metrics :: UsersSortOrder :: Asc
329329 } else {
330- services:: user :: ports :: AdminUsersSortOrder :: Desc
330+ services:: bi_metrics :: UsersSortOrder :: Desc
331331 } ,
332332 } ;
333333
334334 let ( users, total) = app_state
335- . user_service
335+ . bi_metrics_service
336336 . list_users_with_stats ( params. limit , params. offset , & filter, & sort)
337337 . await
338338 . map_err ( |e| {
@@ -2102,6 +2102,36 @@ pub async fn bi_list_users(
21022102 list_users_bi_impl ( & app_state, params) . await
21032103}
21042104
2105+ /// User distribution by subscription plan and by deployed agent count (BI). Requires admin authentication.
2106+ #[ utoipa:: path(
2107+ get,
2108+ path = "/v1/admin/bi/users/summary" ,
2109+ tag = "Admin" ,
2110+ responses(
2111+ ( status = 200 , description = "User distribution summary" , body = UserSummary ) ,
2112+ ( status = 401 , description = "Unauthorized" , body = crate :: error:: ApiErrorResponse ) ,
2113+ ( status = 403 , description = "Forbidden - Admin access required" , body = crate :: error:: ApiErrorResponse ) ,
2114+ ( status = 500 , description = "Internal server error" , body = crate :: error:: ApiErrorResponse )
2115+ ) ,
2116+ security(
2117+ ( "session_token" = [ ] )
2118+ )
2119+ ) ]
2120+ pub async fn bi_users_summary (
2121+ State ( app_state) : State < AppState > ,
2122+ ) -> Result < Json < UserSummary > , ApiError > {
2123+ tracing:: info!( "BI: Getting user summary" ) ;
2124+ let summary = app_state
2125+ . bi_metrics_service
2126+ . get_user_summary ( )
2127+ . await
2128+ . map_err ( |e| {
2129+ tracing:: error!( "Failed to get user summary: {}" , e) ;
2130+ ApiError :: internal_server_error ( "Failed to get user distribution summary" )
2131+ } ) ?;
2132+ Ok ( Json ( summary) )
2133+ }
2134+
21052135/// List deployments with optional filters (BI). Requires admin authentication.
21062136#[ utoipa:: path(
21072137 get,
@@ -2389,6 +2419,7 @@ pub fn create_admin_router() -> Router<AppState> {
23892419 . nest (
23902420 "/bi" ,
23912421 Router :: new ( )
2422+ . route ( "/users/summary" , get ( bi_users_summary) )
23922423 . route ( "/users" , get ( bi_list_users) )
23932424 . route ( "/deployments" , get ( bi_list_deployments) )
23942425 . route ( "/deployments/summary" , get ( bi_deployment_summary) )
0 commit comments