diff --git a/migrations/ch/2026-04-17_email_events.sql b/migrations/ch/2026-04-17_email_events.sql new file mode 100644 index 0000000..35bc3d9 --- /dev/null +++ b/migrations/ch/2026-04-17_email_events.sql @@ -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); diff --git a/migrations/pg/2026-04-17_campaigns.sql b/migrations/pg/2026-04-17_campaigns.sql new file mode 100644 index 0000000..05054f9 --- /dev/null +++ b/migrations/pg/2026-04-17_campaigns.sql @@ -0,0 +1,42 @@ +-- Wird pro Tenant-Schema ausgeführt (SET search_path = tenant_, 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();