notification

package
v0.0.0-...-8d3d8c4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 1, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package notification implements the notification service for Arkeep. It is the single component responsible for persisting in-app notifications, publishing them to the WebSocket Hub, and delivering them via external channels (email, webhook). No other package should write to the notifications table or call hub.Publish on notification topics directly.

Index

Constants

View Source
const (
	KeySMTPHost     = "smtp.host"
	KeySMTPPort     = "smtp.port"
	KeySMTPUsername = "smtp.username"
	KeySMTPPassword = "smtp.password" // stored encrypted via EncryptedString
	KeySMTPFrom     = "smtp.from"
	KeySMTPFromName = "smtp.from_name" // optional display name for the From header
	KeySMTPTLS      = "smtp.tls"       // "true" or "false"

	KeyWebhookURL     = "webhook.url"
	KeyWebhookSecret  = "webhook.secret"  // HMAC secret, stored encrypted
	KeyWebhookEnabled = "webhook.enabled" // "true" or "false"

	// KeyNotificationRecipients is a comma-separated list of email addresses
	// that receive email notifications. When empty the service falls back to
	// all active admin users' email addresses.
	KeyNotificationRecipients = "notification.recipients"

	// Per-event toggle keys — "true" or "false", default true except agent_online.
	KeyEventJobSuccess   = "notification.events.job_success"
	KeyEventJobFailure   = "notification.events.job_failure"
	KeyEventAgentOffline = "notification.events.agent_offline"
	KeyEventAgentOnline  = "notification.events.agent_online"
)

Setting keys used by the notification service. All keys are namespaced to avoid collisions with future config namespaces.

View Source
const DefaultFromName = "Arkeep"

DefaultFromName is used as the email sender display name when smtp.from_name is not configured, so notifications read as "Arkeep <address>" out of the box.

Variables

View Source
var (
	// ErrSendFailed is returned when a notification could not be delivered
	// through one or more channels (email, webhook). It wraps the underlying
	// cause and is non-fatal — the in-app notification is still persisted even
	// if external delivery fails.
	ErrSendFailed = errors.New("notification: send failed")

	// ErrConfigNotFound is returned when a required configuration key is
	// missing from the settings table (e.g. SMTP not configured yet).
	ErrConfigNotFound = errors.New("notification: configuration not found")

	// ErrInvalidConfig is returned when settings exist but contain invalid or
	// incomplete values (e.g. SMTP host present but port missing).
	ErrInvalidConfig = errors.New("notification: invalid configuration")
)

Sentinel errors returned by the notification service and its senders. Callers should use errors.Is for comparison.

Functions

This section is empty.

Types

type Config

type Config struct {
	NotifRepo    repositories.NotificationRepository
	UserRepo     repositories.UserRepository
	SettingsRepo repositories.SettingsRepository
	Hub          *websocket.Hub
	Logger       *zap.Logger
}

Config holds the dependencies required to build a notification Service.

type NotificationEventsConfig

type NotificationEventsConfig struct {
	JobSuccess   bool
	JobFailure   bool
	AgentOffline bool
	AgentOnline  bool
}

NotificationEventsConfig holds the per-event enable/disable toggles for external deliveries (email + webhook). In-app notifications are unaffected. Default: all true except AgentOnline.

type NotificationService

type NotificationService struct {
	// contains filtered or unexported fields
}

NotificationService is the concrete implementation of Service. It is exported so that main.go can call Start(ctx) to launch the retrier.

func NewService

func NewService(cfg Config) *NotificationService

NewService creates a new NotificationService. The email and webhook senders are wired internally — callers only need to provide the Config dependencies.

The returned *NotificationService satisfies the Service interface. To start the background delivery retrier, call Start(ctx) after creation.

func (*NotificationService) NotifyAgentOffline

func (s *NotificationService) NotifyAgentOffline(ctx context.Context, agentID uuid.UUID, agentName string) error

func (*NotificationService) NotifyAgentOnline

func (s *NotificationService) NotifyAgentOnline(ctx context.Context, agentID uuid.UUID, agentName string) error

func (*NotificationService) NotifyJobFailed

func (s *NotificationService) NotifyJobFailed(ctx context.Context, jobID, policyID uuid.UUID, policyName, errMsg string) error

func (*NotificationService) NotifyJobSucceeded

func (s *NotificationService) NotifyJobSucceeded(ctx context.Context, jobID, policyID uuid.UUID, policyName string) error

func (*NotificationService) SMTPConfigured

func (s *NotificationService) SMTPConfigured(ctx context.Context) bool

SMTPConfigured reports whether a usable SMTP configuration exists. The password reset flow uses this to decide between offering the email-based reset and instructing the user to contact an administrator. A configuration that exists but is incomplete (ErrInvalidConfig) counts as not configured.

func (*NotificationService) SendEmail

func (s *NotificationService) SendEmail(ctx context.Context, to []string, subject, body string) error

SendEmail delivers a one-off email through the configured SMTP server. Unlike the notification fan-out, this is a direct send for transactional flows such as password reset. If SMTP is not configured the send is skipped silently (see emailSender.Send) — callers should gate on SMTPConfigured first.

func (*NotificationService) Start

func (s *NotificationService) Start(ctx context.Context)

Start launches the background delivery retrier. It runs until ctx is cancelled (i.e. server shutdown). Call it as a goroutine:

go notifSvc.Start(ctx)

The retrier polls every 30 seconds for pending deliveries whose next_retry_at is in the past and attempts to resend them.

type SMTPConfig

type SMTPConfig struct {
	Host     string
	Port     int
	Username string
	Password string // decrypted at load time by EncryptedString.Scan
	From     string
	FromName string // display name for the From header; defaults to DefaultFromName
	TLS      bool   // true = STARTTLS / implicit TLS
}

SMTPConfig holds the configuration needed to send emails via SMTP.

type Service

type Service interface {
	// NotifyJobSucceeded creates a success notification for the given job.
	// policyName is included in the message body for human readability.
	NotifyJobSucceeded(ctx context.Context, jobID, policyID uuid.UUID, policyName string) error

	// NotifyJobFailed creates a failure notification for the given job.
	// errMsg is the error string from the backup engine, included in the body.
	NotifyJobFailed(ctx context.Context, jobID, policyID uuid.UUID, policyName, errMsg string) error

	// NotifyAgentOffline creates a notification when an agent stops sending
	// heartbeats and is marked offline by the agent manager.
	NotifyAgentOffline(ctx context.Context, agentID uuid.UUID, agentName string) error

	// NotifyAgentOnline creates a notification when an agent reconnects.
	NotifyAgentOnline(ctx context.Context, agentID uuid.UUID, agentName string) error
}

Service is the single entry point for creating and delivering notifications. It persists in-app notifications to the database, publishes them to the WebSocket Hub, and fans out to external channels (email, webhook).

Callers (scheduler, gRPC handlers, etc.) should use the typed methods (NotifyJobSucceeded, NotifyJobFailed, NotifyAgentOffline) rather than constructing events manually, so that notification content stays consistent across the codebase.

type WebhookConfig

type WebhookConfig struct {
	URL     string
	Secret  string // optional HMAC-SHA256 signing secret, decrypted at load time
	Enabled bool
}

WebhookConfig holds the configuration for the outbound HTTP webhook channel.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL