feat: Implement Phase 2 alerting system with anomaly detection
All checks were successful
Test Asgard Runner / test (push) Successful in 2s

Proactive monitoring infrastructure for server health:

**Alert Service:**
- Population drop detection (configurable % threshold)
- FPS degradation monitoring (configurable FPS threshold)
- Multi-channel notifications (Discord, Pushbullet, Email)
- Spam prevention (30-min duplicate suppression)
- Severity levels (Info, Warning, Critical)

**Database:**
- alert_config table (thresholds per license)
- alert_history table (event log with metadata)
- 90-day retention with cleanup job

**Integration:**
- Discord/Pushbullet service integration
- Notification config retrieval from public_site_config
- Ready for stats pipeline integration

Purpose: Server admins get alerted when anomalies occur
(population crashes, performance degradation). Configurable
thresholds enable proactive server management.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Vantz Stockwell
2026-02-15 14:28:51 -05:00
parent 8790072609
commit 3e8b29f2ee
7 changed files with 606 additions and 9 deletions

View File

@@ -1,15 +1,40 @@
use sqlx::PgPool;
use uuid::Uuid;
use anyhow::Result;
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
// TODO: Define NotificationConfig struct (id, server_id, discord_webhook_url, events jsonb, enabled, created_at, updated_at)
/// Fetch the notification configuration for a server.
pub async fn get_notification_config(pool: &PgPool, server_id: Uuid) -> Result<()> {
todo!()
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NotificationConfig {
pub license_id: Uuid,
pub server_name: String,
pub discord_webhook_url: Option<String>,
pub pushbullet_api_key: Option<String>,
}
/// Insert or update the notification configuration for a server.
pub async fn upsert_notification_config(pool: &PgPool, server_id: Uuid, discord_webhook_url: Option<&str>, events: &str, enabled: bool) -> Result<()> {
todo!()
/// Fetch the notification configuration for a license
pub async fn get_notification_config(pool: &PgPool, license_id: Uuid) -> Result<NotificationConfig> {
// Join with licenses to get server_name and public_site_config to get webhook/pushbullet
let row = sqlx::query!(
r#"
SELECT
l.id as license_id,
l.server_name,
psc.discord_webhook_url,
psc.pushbullet_api_key
FROM licenses l
LEFT JOIN public_site_config psc ON psc.license_id = l.id
WHERE l.id = $1
"#,
license_id
)
.fetch_one(pool)
.await
.context("Failed to fetch notification config")?;
Ok(NotificationConfig {
license_id: row.license_id,
server_name: row.server_name,
discord_webhook_url: row.discord_webhook_url,
pushbullet_api_key: row.pushbullet_api_key,
})
}