Files
flatrender/backend/db/migrations/18_notification_channels.sql
soroush.asadi 507ac7e6a4
Build backend images / build content-svc (push) Failing after 56s
Build backend images / build file-svc (push) Failing after 47s
Build backend images / build gateway (push) Failing after 1m0s
Build backend images / build identity-svc (push) Failing after 56s
Build backend images / build notification-svc (push) Failing after 11s
Build backend images / build render-svc (push) Failing after 4m5s
Build backend images / build studio-svc (push) Failing after 56s
feat(notifications+admin): SMS (Kavenegar) + Email (SMTP) channels & templates
Backend (notification-svc):
- channel_config table (per-tenant Kavenegar + SMTP settings) + migration 18
- sender pkg: Kavenegar SMS client + SMTP mailer (STARTTLS / implicit TLS), stdlib only
- endpoints: GET/PUT /v1/channels[/:channel], POST /v1/sms/send, POST /v1/email/send
  (template + {{var}} rendering); deliveries logged
- seeded 3 Persian email templates: welcome / account_verification / promotion
- gateway routes /v1/{channels,sms,email}/* → notification

Admin UI:
- /admin/messaging: SMS + Email provider config cards, test-send, email template editor
- nav link + fa/en labels

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 17:32:54 +03:30

33 lines
3.5 KiB
SQL

-- =====================================================================
-- NOTIFICATION SCHEMA — Part 18: channel provider config + seed email templates
-- Stores per-tenant SMS (Kavenegar) and Email (SMTP) provider settings, and seeds
-- the default Persian email templates (welcome / account verification / promotion).
-- =====================================================================
SET search_path TO notification, public;
CREATE TABLE IF NOT EXISTS channel_config (
tenant_id UUID NOT NULL,
channel TEXT NOT NULL, -- 'sms' | 'email'
settings JSONB NOT NULL DEFAULT '{}',-- kavenegar:{api_key,line_number} / smtp:{host,port,username,password,from_email,from_name,use_tls}
enabled BOOLEAN NOT NULL DEFAULT FALSE,
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (tenant_id, channel)
);
-- Seed default Email templates (idempotent; no dependency on a unique constraint).
INSERT INTO notification_templates (code, channel, locale, subject, body_html, is_active)
SELECT v.code, v.channel, v.locale, v.subject, v.body_html, TRUE
FROM (VALUES
('welcome', 'Email', 'fa', 'به فلت‌رندر خوش آمدید 🎉',
'<div dir="rtl" style="font-family:Tahoma,sans-serif;max-width:560px;margin:auto;padding:32px;background:#fff;color:#171717"><h1 style="color:#2563eb">به فلت‌رندر خوش آمدید!</h1><p>سلام {{name}}، خوشحالیم که به جمع سازندگان فلت‌رندر پیوستی. حالا می‌تونی با هوش مصنوعی و بیش از ۱٬۲۰۰ قالب، ویدیو و تصویر حرفه‌ای بسازی.</p><p style="text-align:center;margin:32px 0"><a href="{{app_url}}" style="background:linear-gradient(90deg,#7c3aed,#2563eb);color:#fff;padding:14px 28px;border-radius:12px;text-decoration:none;font-weight:bold">شروع ساخت</a></p><p style="color:#737373;font-size:13px">اگر این حساب را شما نساخته‌اید، این ایمیل را نادیده بگیرید.</p></div>'),
('account_verification', 'Email', 'fa', 'تأیید حساب کاربری فلت‌رندر',
'<div dir="rtl" style="font-family:Tahoma,sans-serif;max-width:560px;margin:auto;padding:32px;background:#fff;color:#171717"><h1 style="color:#2563eb">تأیید ایمیل</h1><p>سلام {{name}}، برای فعال‌سازی حساب خود کد زیر را وارد کنید:</p><p style="text-align:center;font-size:32px;font-weight:bold;letter-spacing:8px;color:#2563eb;margin:28px 0">{{code}}</p><p style="color:#737373;font-size:13px">این کد تا ۱۵ دقیقه معتبر است. اگر شما درخواست نداده‌اید، این پیام را نادیده بگیرید.</p></div>'),
('promotion', 'Email', 'fa', 'پیشنهاد ویژهٔ فلت‌رندر ✨',
'<div dir="rtl" style="font-family:Tahoma,sans-serif;max-width:560px;margin:auto;padding:32px;background:#fff;color:#171717"><h1 style="color:#7c3aed">{{title}}</h1><p>{{body}}</p><p style="text-align:center;margin:32px 0"><a href="{{cta_url}}" style="background:linear-gradient(90deg,#7c3aed,#2563eb);color:#fff;padding:14px 28px;border-radius:12px;text-decoration:none;font-weight:bold">{{cta_text}}</a></p><p style="color:#737373;font-size:13px">برای لغو دریافت این پیام‌ها از تنظیمات حساب خود اقدام کنید.</p></div>')
) AS v(code, channel, locale, subject, body_html)
WHERE NOT EXISTS (
SELECT 1 FROM notification_templates t
WHERE t.code = v.code AND t.channel = v.channel AND t.locale = v.locale
);