54 lines
2.6 KiB
SQL
54 lines
2.6 KiB
SQL
-- ============================================================
|
|
-- Migration 009: Notification Channels + User Preferences
|
|
-- Phase 2: Channel-based opt-out system
|
|
-- ============================================================
|
|
|
|
-- 1. Notification channels (platform-managed)
|
|
-- Platform defines channels like "billing", "security", "marketing"
|
|
-- Users can opt out of non-mandatory channels
|
|
CREATE TABLE IF NOT EXISTS public.notification_channels (
|
|
channel_key VARCHAR(50) PRIMARY KEY,
|
|
name VARCHAR(100) NOT NULL,
|
|
description TEXT,
|
|
is_mandatory BOOLEAN NOT NULL DEFAULT false,
|
|
-- mandatory=true: users cannot opt out (e.g. security alerts)
|
|
-- mandatory=false: users can disable (e.g. marketing)
|
|
is_enabled BOOLEAN NOT NULL DEFAULT true,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
-- Seed default channels
|
|
INSERT INTO public.notification_channels (channel_key, name, description, is_mandatory) VALUES
|
|
('system', '系统通知', '平台级系统公告与维护通知', true),
|
|
('security', '安全告警', '账号安全、异常登录等安全相关通知', true),
|
|
('billing', '账单通知', '订阅续费、发票、扣款通知', false),
|
|
('feature', '新功能', '产品新功能与版本更新通知', false),
|
|
('marketing', '营销推广', '促销活动、优惠券、活动邀请', false),
|
|
('ops', '运维报警', '服务器异常、告警触发通知', false)
|
|
ON CONFLICT (channel_key) DO NOTHING;
|
|
|
|
-- 2. User notification preferences (per-user opt-out per channel)
|
|
-- Only non-mandatory channels can be opted out
|
|
CREATE TABLE IF NOT EXISTS public.user_notification_preferences (
|
|
user_id VARCHAR(100) NOT NULL,
|
|
channel_key VARCHAR(50) NOT NULL REFERENCES public.notification_channels(channel_key) ON DELETE CASCADE,
|
|
enabled BOOLEAN NOT NULL DEFAULT true,
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
PRIMARY KEY (user_id, channel_key)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_unp_user ON public.user_notification_preferences (user_id);
|
|
|
|
-- 3. Notification segment members (for BY_SEGMENT targeting, Phase 4)
|
|
-- Platform populates this table via ETL/cron jobs
|
|
CREATE TABLE IF NOT EXISTS public.notification_segment_members (
|
|
segment_key VARCHAR(100) NOT NULL,
|
|
tenant_id VARCHAR(100) NOT NULL,
|
|
synced_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
PRIMARY KEY (segment_key, tenant_id)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_nsm_segment ON public.notification_segment_members (segment_key);
|
|
CREATE INDEX IF NOT EXISTS idx_nsm_tenant ON public.notification_segment_members (tenant_id);
|