diff --git a/backlog/tasks/task-015 - Set-up-Cloudflare-D1-email-collector-database-for-cross-site-subscriptions.md b/backlog/tasks/task-015 - Set-up-Cloudflare-D1-email-collector-database-for-cross-site-subscriptions.md index 1a6d36d..36d4729 100644 --- a/backlog/tasks/task-015 - Set-up-Cloudflare-D1-email-collector-database-for-cross-site-subscriptions.md +++ b/backlog/tasks/task-015 - Set-up-Cloudflare-D1-email-collector-database-for-cross-site-subscriptions.md @@ -4,6 +4,7 @@ title: Set up Cloudflare D1 email-collector database for cross-site subscription status: To Do assignee: [] created_date: '2025-12-04 12:00' +updated_date: '2025-12-04 12:03' labels: - infrastructure - cloudflare @@ -51,3 +52,95 @@ Create a standalone Cloudflare D1 database for collecting email subscriptions ac - [ ] #7 Rate limiting prevents spam submissions - [ ] #8 At least one site integrated and collecting emails + +## Implementation Plan + + +## Implementation Steps + +### 1. Create D1 Database +```bash +wrangler d1 create email-collector +``` + +### 2. Create Schema File +Create `worker/email-collector-schema.sql`: + +```sql +-- Email Collector Schema +-- Cross-site email subscription management + +CREATE TABLE IF NOT EXISTS subscribers ( + id TEXT PRIMARY KEY, + email TEXT NOT NULL, + email_hash TEXT NOT NULL, -- For duplicate checking + source_site TEXT NOT NULL, + source_page TEXT, + referrer TEXT, + ip_country TEXT, + subscribed_at TEXT DEFAULT (datetime('now')), + verified INTEGER DEFAULT 0, + verified_at TEXT, + unsubscribed INTEGER DEFAULT 0, + unsubscribed_at TEXT, + metadata TEXT -- JSON for custom fields +); + +CREATE TABLE IF NOT EXISTS verification_tokens ( + id TEXT PRIMARY KEY, + email TEXT NOT NULL, + token TEXT UNIQUE NOT NULL, + expires_at TEXT NOT NULL, + used INTEGER DEFAULT 0, + created_at TEXT DEFAULT (datetime('now')) +); + +-- Rate limiting table +CREATE TABLE IF NOT EXISTS rate_limits ( + ip_hash TEXT PRIMARY KEY, + request_count INTEGER DEFAULT 1, + window_start TEXT DEFAULT (datetime('now')) +); + +-- Indexes +CREATE INDEX IF NOT EXISTS idx_subs_email_hash ON subscribers(email_hash); +CREATE INDEX IF NOT EXISTS idx_subs_site ON subscribers(source_site); +CREATE INDEX IF NOT EXISTS idx_subs_page ON subscribers(source_site, source_page); +CREATE INDEX IF NOT EXISTS idx_subs_verified ON subscribers(verified); +CREATE UNIQUE INDEX IF NOT EXISTS idx_subs_unique ON subscribers(email_hash, source_site); +CREATE INDEX IF NOT EXISTS idx_tokens_token ON verification_tokens(token); +``` + +### 3. Create Worker Endpoints +Create `worker/emailCollector.ts`: + +```typescript +// POST /api/subscribe +// GET /api/verify/:token +// POST /api/unsubscribe +// GET /api/emails/export (auth required) +// GET /api/emails/stats +``` + +### 4. Export Formats +- CSV: `email,source_site,source_page,subscribed_at,verified` +- JSON: Full object array +- Mailchimp: CSV with required headers + +### 5. Admin Authentication +- Use simple API key for export endpoint +- Store in Worker secret: `EMAIL_ADMIN_KEY` + +### 6. Integration +Add to each site's signup form: +```javascript +fetch('https://canvas.jeffemmett.com/api/subscribe', { + method: 'POST', + body: JSON.stringify({ + email: 'user@example.com', + source_site: 'mycofi.earth', + source_page: '/newsletter' + }) +}) +``` +