6dbb14d146
Build backend images / build content-svc (push) Failing after 14s
Build backend images / build file-svc (push) Failing after 22s
Build backend images / build gateway (push) Failing after 1m21s
Build backend images / build identity-svc (push) Failing after 1m43s
Build backend images / build notification-svc (push) Failing after 1m6s
Build backend images / build render-svc (push) Failing after 53s
Build backend images / build studio-svc (push) Failing after 1m5s
- campaigns table (migration 19) + CRUD + send endpoint in notification-svc - audience resolution reads cross-schema from identity.users (all / verified / with_plan); send dispatches via the SMS or Email channel and logs deliveries - endpoints: GET/POST /v1/campaigns, POST /v1/campaigns/:id/send, DELETE - gateway route /v1/campaigns/* → notification - /admin/marketing: create campaign (channel, audience, template/subject/body), list with status + sent counts, send, delete Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
27 lines
1.3 KiB
SQL
27 lines
1.3 KiB
SQL
-- =====================================================================
|
|
-- NOTIFICATION SCHEMA — Part 19: marketing campaigns
|
|
-- A campaign sends an SMS or Email to a user segment (resolved from identity.users)
|
|
-- via the configured channel providers.
|
|
-- =====================================================================
|
|
|
|
SET search_path TO notification, public;
|
|
|
|
CREATE TABLE IF NOT EXISTS campaigns (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL,
|
|
name TEXT NOT NULL,
|
|
channel TEXT NOT NULL, -- 'sms' | 'email'
|
|
audience TEXT NOT NULL DEFAULT 'all', -- 'all' | 'verified' | 'with_plan'
|
|
subject TEXT, -- email only
|
|
body_html TEXT, -- email body / sms text
|
|
template_code TEXT, -- optional email template
|
|
status TEXT NOT NULL DEFAULT 'Draft', -- Draft | Sending | Sent | Failed
|
|
total_count INT NOT NULL DEFAULT 0,
|
|
sent_count INT NOT NULL DEFAULT 0,
|
|
failed_count INT NOT NULL DEFAULT 0,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
sent_at TIMESTAMPTZ
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_campaigns_tenant ON campaigns (tenant_id, created_at DESC);
|