From 6688b3f88a4a1487c107d1e78ca891ba68fb7401 Mon Sep 17 00:00:00 2001 From: Steve Cliff Date: Mon, 4 May 2026 19:31:27 +0100 Subject: [PATCH] notification: payload + Channel interface --- internal/notification/channel.go | 20 ++++++++++++++++++ internal/notification/payload.go | 36 ++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 internal/notification/channel.go create mode 100644 internal/notification/payload.go diff --git a/internal/notification/channel.go b/internal/notification/channel.go new file mode 100644 index 0000000..b4ec257 --- /dev/null +++ b/internal/notification/channel.go @@ -0,0 +1,20 @@ +package notification + +import ( + "context" + "time" +) + +// Channel is the per-kind transport. Implementations live in +// webhook.go / ntfy.go / smtp.go. Send must respect ctx (5s for HTTP, +// 10s for SMTP) and never panic. +type Channel interface { + // Kind returns the kind string ("webhook", "ntfy", "smtp"). Used + // for log enrichment and dispatcher routing. + Kind() string + + // Send delivers one payload. Returns (statusCode, latency, err). + // statusCode is HTTP for HTTP channels, the SMTP final-line code + // (e.g. 250) for SMTP, 0 if the call didn't reach a wire response. + Send(ctx context.Context, p Payload) (statusCode int, latency time.Duration, err error) +} diff --git a/internal/notification/payload.go b/internal/notification/payload.go new file mode 100644 index 0000000..15c96c0 --- /dev/null +++ b/internal/notification/payload.go @@ -0,0 +1,36 @@ +// Package notification owns the fan-out of alert events to operator- +// configured channels. Three channels in v1: webhook, ntfy, smtp. +// Each channel implements Channel.Send for one Payload at a time; +// the Hub orchestrates fan-out, persists to notification_log. +package notification + +import "time" + +// Event identifies the lifecycle hook this notification is for. +type Event string + +const ( + // EventRaised occurs when an alert is first raised. + EventRaised Event = "alert.raised" + // EventAcknowledged occurs when an alert is acknowledged. + EventAcknowledged Event = "alert.acknowledged" + // EventResolved occurs when an alert is resolved. + EventResolved Event = "alert.resolved" + // EventTest is used for test notifications. + EventTest Event = "alert.test" +) + +// Payload is the per-event blob every channel renders into its own +// shape. Severity maps to channel-specific priority (ntfy) or stays +// in the body (webhook/smtp). +type Payload struct { + Event Event // alert.raised | … | alert.test + AlertID string // ULID + Severity string // info | warning | critical + Kind string // backup_failed | … + HostID string + HostName string + Message string + RaisedAt time.Time + Link string // Absolute URL to /alerts/; built by Hub +}