Initial commit of Descrybe v2 without local scratch artifacts.
Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
-- +goose Up
|
||||
-- Tenant email provider + unsubscribes + send log (Marketing suite).
|
||||
-- Secrets: AES-GCM ciphertext (enc:v1:...) of JSON {api_key,smtp_*}; never log plaintext.
|
||||
-- Prefer APP_ENCRYPTION_KEY for DeriveKey.
|
||||
|
||||
CREATE TABLE email_providers (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE,
|
||||
provider_type TEXT NOT NULL DEFAULT 'smtp'
|
||||
CHECK (provider_type IN ('smtp', 'resend', 'sendgrid')),
|
||||
from_email TEXT NOT NULL DEFAULT '',
|
||||
from_name TEXT NOT NULL DEFAULT '',
|
||||
secrets_enc TEXT NOT NULL DEFAULT '',
|
||||
config JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
status TEXT NOT NULL DEFAULT 'unverified'
|
||||
CHECK (status IN ('unverified', 'verified', 'error')),
|
||||
verified_at TIMESTAMPTZ,
|
||||
last_error TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
UNIQUE (company_id)
|
||||
);
|
||||
|
||||
CREATE INDEX email_providers_company_status_idx ON email_providers (company_id, status);
|
||||
|
||||
CREATE TABLE email_unsubscribes (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE,
|
||||
email TEXT NOT NULL,
|
||||
email_hash TEXT NOT NULL,
|
||||
token TEXT NOT NULL UNIQUE,
|
||||
reason TEXT,
|
||||
unsubscribed_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
UNIQUE (company_id, email_hash)
|
||||
);
|
||||
|
||||
CREATE INDEX email_unsubscribes_company_idx ON email_unsubscribes (company_id);
|
||||
|
||||
CREATE TABLE email_sends (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE,
|
||||
campaign_id UUID REFERENCES email_campaigns(id) ON DELETE SET NULL,
|
||||
version_id UUID REFERENCES email_campaign_versions(id) ON DELETE SET NULL,
|
||||
recipient_email TEXT NOT NULL,
|
||||
recipient_hash TEXT NOT NULL,
|
||||
kind TEXT NOT NULL DEFAULT 'blast'
|
||||
CHECK (kind IN ('test', 'blast')),
|
||||
status TEXT NOT NULL DEFAULT 'queued'
|
||||
CHECK (status IN ('queued', 'sent', 'failed', 'skipped', 'unsubscribed')),
|
||||
provider_message_id TEXT,
|
||||
error TEXT,
|
||||
sent_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX email_sends_company_created_idx ON email_sends (company_id, created_at DESC);
|
||||
CREATE INDEX email_sends_campaign_idx ON email_sends (campaign_id);
|
||||
|
||||
CREATE UNIQUE INDEX email_sends_blast_idempotent_idx
|
||||
ON email_sends (campaign_id, recipient_hash)
|
||||
WHERE kind = 'blast' AND status IN ('queued', 'sent');
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE IF EXISTS email_sends;
|
||||
DROP TABLE IF EXISTS email_unsubscribes;
|
||||
DROP TABLE IF EXISTS email_providers;
|
||||
Reference in New Issue
Block a user