-- +goose Up -- +goose StatementBegin -- Health-Alarme: Webhook + Email-Notification bei kritischen Events. -- Triggers leben im edgeguard-scheduler (cert-expiry, backup-fail, -- license-verify-fail). Pro Event wird optional in jeden aktiven -- Channel gepushed; das Ergebnis (success/error) landet in alert_events -- damit der Operator-UI History+Failure-Reason zeigen kann. CREATE TABLE IF NOT EXISTS alert_channels ( id BIGSERIAL PRIMARY KEY, name TEXT NOT NULL, kind TEXT NOT NULL, target TEXT NOT NULL, -- webhook-URL oder "to"-Email settings JSONB NOT NULL DEFAULT '{}'::jsonb, active BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), CONSTRAINT alert_channels_kind_check CHECK (kind IN ('webhook', 'email')) ); CREATE INDEX IF NOT EXISTS idx_alert_channels_active ON alert_channels (active) WHERE active; CREATE TABLE IF NOT EXISTS alert_events ( id BIGSERIAL PRIMARY KEY, kind TEXT NOT NULL, -- cert.expiring | backup.failed | license.invalid | test severity TEXT NOT NULL, -- info | warning | error | critical subject TEXT NOT NULL, message TEXT NOT NULL, sent_to JSONB NOT NULL DEFAULT '[]'::jsonb, -- [{channel_id, ok, error}, ...] fired_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), CONSTRAINT alert_events_severity_check CHECK (severity IN ('info', 'warning', 'error', 'critical')) ); CREATE INDEX IF NOT EXISTS idx_alert_events_fired_at ON alert_events (fired_at DESC); CREATE INDEX IF NOT EXISTS idx_alert_events_kind ON alert_events (kind); -- +goose StatementEnd -- +goose Down -- +goose StatementBegin DROP TABLE IF EXISTS alert_events; DROP TABLE IF EXISTS alert_channels; -- +goose StatementEnd