mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-09 10:57:03 +08:00
feat: revamp analytics dashboards and harden database migrations
Add dashboard and overview analytics, health monitoring, provider expense tracking, and announcement updates across the gateway and frontend. Keep schema migrations free of historical backfills while preserving automatic backfill execution. Bound migration deadlines, run schema preparation before Compose replacement, and anonymize deleted dashboard users. Include the current documentation cleanup and regression coverage.
This commit is contained in:
@@ -7,6 +7,35 @@ pub(super) fn classify_admin_basic_family_route(
|
||||
normalized_path: &str,
|
||||
normalized_path_no_trailing: &str,
|
||||
) -> Option<ClassifiedRoute> {
|
||||
let finance_path = normalized_path_no_trailing;
|
||||
if (method == http::Method::GET
|
||||
&& matches!(
|
||||
finance_path,
|
||||
"/api/admin/billing/provider-accounts" | "/api/admin/billing/provider-expenses"
|
||||
))
|
||||
|| (method == http::Method::POST && finance_path == "/api/admin/billing/provider-expenses")
|
||||
|| (method == http::Method::POST
|
||||
&& finance_path
|
||||
.strip_prefix("/api/admin/billing/provider-expenses/")
|
||||
.and_then(|v| v.strip_suffix("/void"))
|
||||
.is_some_and(|id| !id.is_empty() && !id.contains('/')))
|
||||
{
|
||||
return Some(classified(
|
||||
"admin_proxy",
|
||||
"billing_manage",
|
||||
if finance_path.ends_with("/provider-accounts") {
|
||||
"provider_accounts"
|
||||
} else if method == http::Method::GET {
|
||||
"provider_expenses"
|
||||
} else if finance_path.ends_with("/void") {
|
||||
"void_provider_expense"
|
||||
} else {
|
||||
"create_provider_expense"
|
||||
},
|
||||
"admin:billing",
|
||||
false,
|
||||
));
|
||||
}
|
||||
if method == http::Method::GET
|
||||
&& matches!(
|
||||
normalized_path,
|
||||
|
||||
@@ -6,6 +6,33 @@ pub(super) fn classify_admin_endpoints_family_route(
|
||||
method: &http::Method,
|
||||
normalized_path: &str,
|
||||
) -> Option<ClassifiedRoute> {
|
||||
if normalized_path == "/api/admin/endpoints/health/v2/publication"
|
||||
&& (method == http::Method::GET || method == http::Method::PUT)
|
||||
{
|
||||
return Some(classified(
|
||||
"admin_proxy",
|
||||
"endpoints_health",
|
||||
"health_v2_publication",
|
||||
"admin:endpoints_health",
|
||||
false,
|
||||
));
|
||||
}
|
||||
if method == http::Method::GET
|
||||
&& (matches!(
|
||||
normalized_path,
|
||||
"/api/admin/endpoints/health/v2/summary" | "/api/admin/endpoints/health/v2/objects"
|
||||
) || normalized_path
|
||||
.strip_prefix("/api/admin/endpoints/health/v2/objects/")
|
||||
.is_some_and(|id| !id.is_empty() && !id.contains('/')))
|
||||
{
|
||||
return Some(classified(
|
||||
"admin_proxy",
|
||||
"endpoints_health",
|
||||
"health_v2",
|
||||
"admin:endpoints_health",
|
||||
false,
|
||||
));
|
||||
}
|
||||
if method == http::Method::GET && normalized_path == "/api/admin/endpoints/health/summary" {
|
||||
Some(classified(
|
||||
"admin_proxy",
|
||||
|
||||
@@ -7,6 +7,15 @@ pub(super) fn classify_admin_observability_family_route(
|
||||
normalized_path: &str,
|
||||
normalized_path_no_trailing: &str,
|
||||
) -> Option<ClassifiedRoute> {
|
||||
if let Some(kind) = classify_overview_route(method, normalized_path_no_trailing) {
|
||||
return Some(classified(
|
||||
"admin_proxy",
|
||||
"overview_manage",
|
||||
kind,
|
||||
"admin:stats",
|
||||
false,
|
||||
));
|
||||
}
|
||||
if method == http::Method::POST
|
||||
&& matches!(
|
||||
normalized_path,
|
||||
@@ -713,3 +722,32 @@ pub(super) fn classify_admin_observability_family_route(
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn classify_overview_route(method: &http::Method, path: &str) -> Option<&'static str> {
|
||||
if method != http::Method::GET {
|
||||
return None;
|
||||
}
|
||||
match path.strip_prefix("/api/admin/overview/")? {
|
||||
"dashboard" => Some("dashboard"),
|
||||
"dashboard/summary" => Some("dashboard_summary"),
|
||||
"dashboard/total" => Some("dashboard_total"),
|
||||
"dashboard/charts" => Some("dashboard_charts"),
|
||||
"summary" => Some("summary"),
|
||||
"timeseries" => Some("timeseries"),
|
||||
"breakdown" => Some("breakdown"),
|
||||
"users" => Some("users"),
|
||||
"consumption" => Some("consumption"),
|
||||
"costs" => Some("costs"),
|
||||
"operations/live" => Some("operations_live"),
|
||||
"operations/performance" => Some("operations_performance"),
|
||||
"operations/resources" => Some("operations_resources"),
|
||||
detail
|
||||
if detail
|
||||
.strip_prefix("users/")
|
||||
.is_some_and(|id| !id.is_empty() && !id.contains('/')) =>
|
||||
{
|
||||
Some("user_detail")
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,6 +146,36 @@ pub(super) fn classify_public_support_route(
|
||||
"public:announcements",
|
||||
false,
|
||||
))
|
||||
} else if method == http::Method::GET
|
||||
&& (matches!(
|
||||
normalized_path,
|
||||
"/api/users/me/health/v2/summary" | "/api/users/me/health/v2/objects"
|
||||
) || normalized_path
|
||||
.strip_prefix("/api/users/me/health/v2/objects/")
|
||||
.is_some_and(|id| !id.is_empty() && !id.contains('/')))
|
||||
{
|
||||
Some(classified(
|
||||
"public_support",
|
||||
"health_user",
|
||||
"health_v2",
|
||||
"user:health",
|
||||
false,
|
||||
))
|
||||
} else if method == http::Method::GET
|
||||
&& (matches!(
|
||||
normalized_path,
|
||||
"/api/public/health/v2/summary" | "/api/public/health/v2/objects"
|
||||
) || normalized_path
|
||||
.strip_prefix("/api/public/health/v2/objects/")
|
||||
.is_some_and(|id| !id.is_empty() && !id.contains('/')))
|
||||
{
|
||||
Some(classified(
|
||||
"public_support",
|
||||
"public_catalog",
|
||||
"health_v2",
|
||||
"public:catalog",
|
||||
false,
|
||||
))
|
||||
} else if method == http::Method::GET
|
||||
&& matches!(
|
||||
normalized_path,
|
||||
@@ -273,6 +303,19 @@ pub(super) fn classify_public_support_route(
|
||||
"user:monitoring",
|
||||
false,
|
||||
))
|
||||
} else if method == http::Method::GET
|
||||
&& matches!(
|
||||
normalized_path,
|
||||
"/api/announcements/users/me" | "/api/announcements/users/me/"
|
||||
)
|
||||
{
|
||||
Some(classified(
|
||||
"public_support",
|
||||
"announcement_user",
|
||||
"list",
|
||||
"user:announcements",
|
||||
false,
|
||||
))
|
||||
} else if method == http::Method::GET
|
||||
&& matches!(
|
||||
normalized_path,
|
||||
|
||||
Reference in New Issue
Block a user