Implement M3: expiration threshold alerting with dedup and status transitions

- Add alert_thresholds_days JSONB column to renewal_policies (default [30,14,7,0])
- Add RenewalPolicy.AlertThresholdsDays field + EffectiveAlertThresholds() helper
- Add RenewalPolicyRepository interface + postgres implementation
- Rewrite CheckExpiringCertificates with per-policy threshold alerting
- Add SendThresholdAlert + HasThresholdNotification for deduplication via [threshold:N] tags
- Add Type and MessageLike filters to NotificationFilter + postgres query support
- Auto-transition certs to Expiring (>0 days) or Expired (<=0 days) status
- Record expiration_alert_sent audit events per threshold crossing
- Fix .gitignore: allow SQL migration files, scope server/agent build artifact rules
- Track previously untracked cmd/ and migrations/ directories
- Update docs (README, architecture, demo-advanced) for threshold alerting

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Shankar
2026-03-15 00:03:43 -04:00
parent ab79dead13
commit 17a3e4a4b1
17 changed files with 1485 additions and 37 deletions
@@ -67,11 +67,21 @@ func (r *NotificationRepository) List(ctx context.Context, filter *repository.No
args = append(args, filter.CertificateID)
argCount++
}
if filter.Type != "" {
whereConditions = append(whereConditions, fmt.Sprintf("type = $%d", argCount))
args = append(args, filter.Type)
argCount++
}
if filter.Status != "" {
whereConditions = append(whereConditions, fmt.Sprintf("status = $%d", argCount))
args = append(args, filter.Status)
argCount++
}
if filter.MessageLike != "" {
whereConditions = append(whereConditions, fmt.Sprintf("message LIKE $%d", argCount))
args = append(args, filter.MessageLike)
argCount++
}
if filter.Channel != "" {
whereConditions = append(whereConditions, fmt.Sprintf("channel = $%d", argCount))
args = append(args, filter.Channel)