Aggiunge newsletter custom con D1, double opt-in e invio campagne.

Attiva il form footer, API subscribe/confirm/unsubscribe e endpoint admin protetti, riusando Resend per le email.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Javaxman
2026-07-28 23:23:19 +02:00
parent 9a8566a3f5
commit 7aff1abcfb
27 changed files with 1008 additions and 18 deletions

View File

@ -0,0 +1,49 @@
-- Newsletter subscribers and campaign send log
CREATE TABLE IF NOT EXISTS newsletter_subscribers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT NOT NULL COLLATE NOCASE,
status TEXT NOT NULL CHECK (status IN ('pending', 'active', 'unsubscribed')),
locale TEXT NOT NULL DEFAULT 'it',
confirm_token TEXT,
unsubscribe_token TEXT NOT NULL,
source TEXT NOT NULL DEFAULT 'footer',
created_at TEXT NOT NULL DEFAULT (datetime('now')),
confirmed_at TEXT,
unsubscribed_at TEXT,
UNIQUE (email)
);
CREATE INDEX IF NOT EXISTS idx_newsletter_subscribers_status
ON newsletter_subscribers (status);
CREATE INDEX IF NOT EXISTS idx_newsletter_subscribers_confirm_token
ON newsletter_subscribers (confirm_token);
CREATE INDEX IF NOT EXISTS idx_newsletter_subscribers_unsubscribe_token
ON newsletter_subscribers (unsubscribe_token);
CREATE TABLE IF NOT EXISTS newsletter_campaigns (
id INTEGER PRIMARY KEY AUTOINCREMENT,
subject TEXT NOT NULL,
body_text TEXT NOT NULL,
body_html TEXT,
status TEXT NOT NULL DEFAULT 'draft' CHECK (status IN ('draft', 'sending', 'sent', 'failed')),
created_at TEXT NOT NULL DEFAULT (datetime('now')),
sent_at TEXT,
created_by TEXT
);
CREATE TABLE IF NOT EXISTS newsletter_campaign_sends (
id INTEGER PRIMARY KEY AUTOINCREMENT,
campaign_id INTEGER NOT NULL,
subscriber_id INTEGER NOT NULL,
email TEXT NOT NULL,
status TEXT NOT NULL CHECK (status IN ('queued', 'sent', 'failed', 'skipped')),
error TEXT,
sent_at TEXT,
FOREIGN KEY (campaign_id) REFERENCES newsletter_campaigns (id),
FOREIGN KEY (subscriber_id) REFERENCES newsletter_subscribers (id)
);
CREATE INDEX IF NOT EXISTS idx_newsletter_campaign_sends_campaign
ON newsletter_campaign_sends (campaign_id);