Adds Discord direct messages as a notification channel. Users link their Discord account via OAuth2 (identify scope only, one-time server-side state rows); a bot delivers their inbox notifications as DMs. - Extract the email channel's watermark sweep into a generic account-channel engine; email and Discord are now thin adapters, so the SKIP LOCKED claim / watermark-after-send durability logic exists once. - New internal/discord REST client (token exchange, identity, open DM, send message) — no Gateway connection, no new dependencies. - Opt-in master switch (notifications.discord_enabled, default off) gates delivery, linking, capability, and the admin settings reveal. - Admin UI: credentials (secret + bot token encrypted at rest), dev portal setup checklist, bot invite link buttons, and a test button that bypasses the settings read cache and is disabled while credential edits are unsaved. - DM failures from missing shared guild (Discord 50007) surface as link health in user settings and self-heal via capped backoff. - New combined mode (per_episode_and_digest) for email and Discord: instant sends all day plus a daily digest recapping the whole window since the previous digest. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
40 lines
1.7 KiB
SQL
40 lines
1.7 KiB
SQL
-- +goose Up
|
|
-- +goose StatementBegin
|
|
-- Adds the combined account-channel mode: per-episode sends all day plus a
|
|
-- daily digest recapping everything since the previous digest. Applies to
|
|
-- both account-level channels (email, Discord DMs).
|
|
ALTER TABLE public.notification_email_prefs
|
|
DROP CONSTRAINT notification_email_prefs_mode_check;
|
|
ALTER TABLE public.notification_email_prefs
|
|
ADD CONSTRAINT notification_email_prefs_mode_check
|
|
CHECK (mode IN ('off', 'per_episode', 'daily_digest', 'per_episode_and_digest'));
|
|
|
|
ALTER TABLE public.notification_discord_prefs
|
|
DROP CONSTRAINT notification_discord_prefs_mode_check;
|
|
ALTER TABLE public.notification_discord_prefs
|
|
ADD CONSTRAINT notification_discord_prefs_mode_check
|
|
CHECK (mode IN ('off', 'per_episode', 'daily_digest', 'per_episode_and_digest'));
|
|
-- +goose StatementEnd
|
|
|
|
-- +goose Down
|
|
-- +goose StatementBegin
|
|
-- Coerce combined-mode rows to per_episode before restoring the narrower
|
|
-- constraint, so the rollback cannot fail on existing data.
|
|
UPDATE public.notification_email_prefs
|
|
SET mode = 'per_episode' WHERE mode = 'per_episode_and_digest';
|
|
UPDATE public.notification_discord_prefs
|
|
SET mode = 'per_episode' WHERE mode = 'per_episode_and_digest';
|
|
|
|
ALTER TABLE public.notification_email_prefs
|
|
DROP CONSTRAINT notification_email_prefs_mode_check;
|
|
ALTER TABLE public.notification_email_prefs
|
|
ADD CONSTRAINT notification_email_prefs_mode_check
|
|
CHECK (mode IN ('off', 'per_episode', 'daily_digest'));
|
|
|
|
ALTER TABLE public.notification_discord_prefs
|
|
DROP CONSTRAINT notification_discord_prefs_mode_check;
|
|
ALTER TABLE public.notification_discord_prefs
|
|
ADD CONSTRAINT notification_discord_prefs_mode_check
|
|
CHECK (mode IN ('off', 'per_episode', 'daily_digest'));
|
|
-- +goose StatementEnd
|