feat: Migrationen für campaigns-Tabellen (PostgreSQL) und email_events (ClickHouse)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
11
migrations/ch/2026-04-17_email_events.sql
Normal file
11
migrations/ch/2026-04-17_email_events.sql
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS newsletter.email_events (
|
||||||
|
event_type LowCardinality(String),
|
||||||
|
tenant_id String,
|
||||||
|
campaign_id UUID,
|
||||||
|
recipient_hash String,
|
||||||
|
timestamp DateTime64(3, 'UTC'),
|
||||||
|
metadata Map(String, String)
|
||||||
|
)
|
||||||
|
ENGINE = MergeTree()
|
||||||
|
PARTITION BY toYYYYMM(timestamp)
|
||||||
|
ORDER BY (tenant_id, campaign_id, event_type, timestamp);
|
||||||
42
migrations/pg/2026-04-17_campaigns.sql
Normal file
42
migrations/pg/2026-04-17_campaigns.sql
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
-- Wird pro Tenant-Schema ausgeführt (SET search_path = tenant_<id>, public vorher)
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS campaigns (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
subject TEXT NOT NULL,
|
||||||
|
html_body TEXT NOT NULL,
|
||||||
|
plain_body TEXT NOT NULL,
|
||||||
|
status TEXT NOT NULL DEFAULT 'draft'
|
||||||
|
CHECK (status IN ('draft','scheduled','sending','sent','paused','cancelled')),
|
||||||
|
scheduled_at TIMESTAMPTZ,
|
||||||
|
cron_expression TEXT,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS campaign_recipients (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
campaign_id UUID NOT NULL REFERENCES campaigns(id) ON DELETE CASCADE,
|
||||||
|
list_id UUID,
|
||||||
|
segment_id UUID,
|
||||||
|
CONSTRAINT recipient_has_one CHECK (
|
||||||
|
(list_id IS NOT NULL AND segment_id IS NULL) OR
|
||||||
|
(segment_id IS NOT NULL AND list_id IS NULL)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS campaign_triggers (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
campaign_id UUID NOT NULL REFERENCES campaigns(id) ON DELETE CASCADE,
|
||||||
|
trigger_type TEXT NOT NULL CHECK (trigger_type IN ('cron', 'event')),
|
||||||
|
trigger_value TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION update_updated_at()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
BEGIN NEW.updated_at = now(); RETURN NEW; END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
CREATE TRIGGER campaigns_updated_at
|
||||||
|
BEFORE UPDATE ON campaigns
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
|
||||||
Reference in New Issue
Block a user