Add notification channels and a provider abstraction

Users get a notification_channels table (replacing users.ntfy_topic); pages fan
out to every enabled channel through a notify.Provider registry, with ntfy as
the first provider. Fallbacks are typed {type, address}. Schema edited in place:
existing databases must be recreated.

Claude-Session: https://claude.ai/code/session_016mBLURvJoMuUEr9cB2RpUN
This commit is contained in:
Niklas Ye
2026-10-12 21:00:40 +02:00
parent 6292ad6708
commit b114251f45
42 changed files with 2200 additions and 611 deletions
+28 -3
View File
@@ -65,7 +65,8 @@ CREATE TABLE escalation_levels (
CREATE TABLE escalation_policies (
team_id bigint NOT NULL,
repeat_count bigint DEFAULT 0 NOT NULL,
fallback_topic text DEFAULT ''::text NOT NULL,
fallback_type text DEFAULT ''::text NOT NULL,
fallback_address text DEFAULT ''::text NOT NULL,
updated_at bigint DEFAULT (floor(EXTRACT(epoch FROM now())))::bigint NOT NULL,
CONSTRAINT escalation_policies_repeat_count_check CHECK (((repeat_count >= 0) AND (repeat_count <= 10)))
);
@@ -159,11 +160,22 @@ CREATE TABLE invites (
CONSTRAINT invites_role_check CHECK ((role = ANY (ARRAY['owner'::text, 'member'::text])))
);
CREATE TABLE notification_channels (
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
user_id bigint NOT NULL,
type text NOT NULL,
address text NOT NULL,
enabled boolean DEFAULT true NOT NULL,
created_at bigint DEFAULT (floor(EXTRACT(epoch FROM now())))::bigint NOT NULL
);
CREATE TABLE notifications (
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
incident_id bigint NOT NULL,
user_id bigint,
topic text NOT NULL,
channel_id bigint,
channel_type text NOT NULL,
address text NOT NULL,
kind text NOT NULL,
created_at bigint NOT NULL,
send_after bigint NOT NULL,
@@ -268,7 +280,6 @@ CREATE TABLE users (
username text NOT NULL,
email text NOT NULL,
created_at bigint DEFAULT (floor(EXTRACT(epoch FROM now())))::bigint NOT NULL,
ntfy_topic text,
password_hash text,
is_admin boolean DEFAULT false NOT NULL,
disabled_at bigint,
@@ -332,6 +343,12 @@ ALTER TABLE invites
ALTER TABLE invites
ADD CONSTRAINT invites_token_hash_key UNIQUE (token_hash);
ALTER TABLE notification_channels
ADD CONSTRAINT notification_channels_pkey PRIMARY KEY (id);
ALTER TABLE notification_channels
ADD CONSTRAINT notification_channels_user_type_address_key UNIQUE (user_id, type, address);
ALTER TABLE notifications
ADD CONSTRAINT notifications_pkey PRIMARY KEY (id);
@@ -452,6 +469,8 @@ CREATE UNIQUE INDEX deadman_switches_team_name_key ON deadman_switches (team_id,
CREATE INDEX invites_team_idx ON invites USING btree (team_id);
CREATE INDEX notification_channels_user_idx ON notification_channels USING btree (user_id);
CREATE INDEX notifications_incident_idx ON notifications USING btree (incident_id, id DESC);
CREATE INDEX notifications_pending_idx ON notifications USING btree (send_after) WHERE (sent_at IS NULL);
@@ -550,6 +569,12 @@ ALTER TABLE invites
ALTER TABLE invites
ADD CONSTRAINT invites_team_id_fkey FOREIGN KEY (team_id) REFERENCES teams(id) ON DELETE CASCADE;
ALTER TABLE notification_channels
ADD CONSTRAINT notification_channels_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
ALTER TABLE notifications
ADD CONSTRAINT notifications_channel_id_fkey FOREIGN KEY (channel_id) REFERENCES notification_channels(id) ON DELETE SET NULL;
ALTER TABLE notifications
ADD CONSTRAINT notifications_incident_id_fkey FOREIGN KEY (incident_id) REFERENCES incidents(id) ON DELETE CASCADE;