Security Analytics - v1.0.0
Alerting
AlertManager routes alerts to one or more channels based on AlertRule definitions. Each alert delivery is captured in AlertHistory for audit.
Shipped channels
| Channel | Use case |
|---|---|
DatabaseChannel |
Default — stores in alert_history, no external system needed |
EmailChannel |
Sends via Laravel's mail layer |
SlackChannel |
Slack incoming webhook |
TeamsChannel |
Microsoft Teams incoming webhook |
PagerDutyChannel |
PagerDuty integration |
OpsGenieChannel |
OpsGenie integration |
SmsChannel |
SMS via configured driver (Twilio, etc.) |
WebhookChannel |
Generic HTTP POST |
Each channel is independently configured and toggled in config('artisanpack.security-analytics.alerting.channels').
Sending an alert
security_analytics()->alerts()->send(
channel: 'slack',
title: 'Suspicious activity detected',
message: 'User 42 attempted to escalate privileges.',
severity: 'high',
context: [ 'user_id' => 42, 'detector' => 'privilege_escalation' ],
);
To fan out to multiple channels:
security_analytics()->alerts()->broadcast(
channels: ['slack', 'email', 'pagerduty'],
title: '...',
message: '...',
);
Rule-driven alerts
For typical workflows, you don't send alerts manually — you define AlertRule records that fire on matching events:
use ArtisanPackUI\SecurityAnalytics\Models\AlertRule;
AlertRule::create([
'name' => 'Critical events to PagerDuty',
'matcher' => ['severity' => 'critical'],
'channels' => ['pagerduty', 'slack'],
'cooldown_minutes' => 30,
'enabled' => true,
]);
The bundled SendSecurityAlert job listens to SecurityEventOccurred / AnomalyDetected events and checks each rule. Matched rules dispatch to their channels (subject to the cooldown).
Cooldowns
Cooldowns prevent alert storms. If a rule has fired in the last cooldown_minutes for the same matcher key (e.g. same IP, same user, same event type), the duplicate fire is suppressed.
Alert history
AlertHistory records every fired alert with the channel, the rule that triggered it, the payload, and the delivery result. Query it via the dashboard at /security/alerts or directly:
use ArtisanPackUI\SecurityAnalytics\Models\AlertHistory;
AlertHistory::where('severity', 'critical')->latest()->limit(50)->get();
AlertHistory::where('channel', 'pagerduty')->where('created_at', '>=', now()->subDay())->get();
Acknowledgment
Alerts can be acknowledged (manually or via integration callback):
$alert->acknowledge( actor: $user, note: 'Investigated — false positive.' );
Sets acknowledged_at, acknowledged_by_id, and acknowledgment_note. The dashboard surfaces unacknowledged critical alerts prominently.
Building a custom channel
Implement AlertChannelInterface (send, isAvailable, getName) and register your class. See Custom channels.