Compare commits
6 Commits
cd58b1c1cd
...
60a6825dfd
| Author | SHA1 | Date |
|---|---|---|
|
|
60a6825dfd | |
|
|
0edac2968b | |
|
|
1ccaf32d1a | |
|
|
a6f2d6e015 | |
|
|
f5c775e417 | |
|
|
7191e2543d |
|
|
@ -4,6 +4,7 @@ title: Set up Cloudflare D1 email-collector database for cross-site subscription
|
||||||
status: To Do
|
status: To Do
|
||||||
assignee: []
|
assignee: []
|
||||||
created_date: '2025-12-04 12:00'
|
created_date: '2025-12-04 12:00'
|
||||||
|
updated_date: '2025-12-04 12:03'
|
||||||
labels:
|
labels:
|
||||||
- infrastructure
|
- infrastructure
|
||||||
- cloudflare
|
- cloudflare
|
||||||
|
|
@ -51,3 +52,95 @@ Create a standalone Cloudflare D1 database for collecting email subscriptions ac
|
||||||
- [ ] #7 Rate limiting prevents spam submissions
|
- [ ] #7 Rate limiting prevents spam submissions
|
||||||
- [ ] #8 At least one site integrated and collecting emails
|
- [ ] #8 At least one site integrated and collecting emails
|
||||||
<!-- AC:END -->
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
## 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'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
```
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
---
|
|
||||||
id: task-016
|
|
||||||
title: Create Cloudflare D1 cryptid-auth database
|
|
||||||
status: To Do
|
|
||||||
assignee: []
|
|
||||||
created_date: '2025-12-04 12:00'
|
|
||||||
labels:
|
|
||||||
- infrastructure
|
|
||||||
- cloudflare
|
|
||||||
- d1
|
|
||||||
- cryptid
|
|
||||||
- auth
|
|
||||||
- security
|
|
||||||
dependencies: []
|
|
||||||
priority: high
|
|
||||||
---
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
|
||||||
Create the D1 database on Cloudflare for CryptID authentication system. This is the first step before deploying the email recovery feature.
|
|
||||||
|
|
||||||
**Database Purpose:**
|
|
||||||
- Store user accounts linked to CryptID usernames
|
|
||||||
- Store device public keys for multi-device auth
|
|
||||||
- Store verification tokens for email/device linking
|
|
||||||
- Enable account recovery via verified email
|
|
||||||
|
|
||||||
**Security Considerations:**
|
|
||||||
- Emails should be encrypted at rest (Phase 2)
|
|
||||||
- Public keys are safe to store (not secrets)
|
|
||||||
- Tokens are time-limited and single-use
|
|
||||||
- No passwords stored (WebCrypto key-based auth)
|
|
||||||
<!-- SECTION:DESCRIPTION:END -->
|
|
||||||
|
|
||||||
## Acceptance Criteria
|
|
||||||
<!-- AC:BEGIN -->
|
|
||||||
- [ ] #1 D1 database 'cryptid-auth' created via wrangler d1 create
|
|
||||||
- [ ] #2 D1 database 'cryptid-auth-dev' created for dev environment
|
|
||||||
- [ ] #3 Database IDs added to wrangler.toml (replacing placeholders)
|
|
||||||
- [ ] #4 Schema from worker/schema.sql deployed to both databases
|
|
||||||
- [ ] #5 Verified tables exist: users, device_keys, verification_tokens
|
|
||||||
<!-- AC:END -->
|
|
||||||
|
|
@ -4,6 +4,7 @@ title: Deploy CryptID email recovery to dev branch and test
|
||||||
status: To Do
|
status: To Do
|
||||||
assignee: []
|
assignee: []
|
||||||
created_date: '2025-12-04 12:00'
|
created_date: '2025-12-04 12:00'
|
||||||
|
updated_date: '2025-12-04 12:02'
|
||||||
labels:
|
labels:
|
||||||
- feature
|
- feature
|
||||||
- cryptid
|
- cryptid
|
||||||
|
|
@ -11,8 +12,8 @@ labels:
|
||||||
- testing
|
- testing
|
||||||
- dev-branch
|
- dev-branch
|
||||||
dependencies:
|
dependencies:
|
||||||
- task-015
|
- task-018
|
||||||
- task-016
|
- task-019
|
||||||
priority: high
|
priority: high
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
---
|
||||||
|
id: task-018
|
||||||
|
title: Create Cloudflare D1 cryptid-auth database
|
||||||
|
status: To Do
|
||||||
|
assignee: []
|
||||||
|
created_date: '2025-12-04 12:02'
|
||||||
|
updated_date: '2025-12-04 12:02'
|
||||||
|
labels:
|
||||||
|
- infrastructure
|
||||||
|
- cloudflare
|
||||||
|
- d1
|
||||||
|
- cryptid
|
||||||
|
- auth
|
||||||
|
dependencies: []
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
Create the D1 database on Cloudflare for CryptID authentication system. This is the first step before deploying the email recovery feature.
|
||||||
|
|
||||||
|
**Database Purpose:**
|
||||||
|
- Store user accounts linked to CryptID usernames
|
||||||
|
- Store device public keys for multi-device auth
|
||||||
|
- Store verification tokens for email/device linking
|
||||||
|
- Enable account recovery via verified email
|
||||||
|
|
||||||
|
**Security Considerations:**
|
||||||
|
- Emails should be encrypted at rest (task-016)
|
||||||
|
- Public keys are safe to store (not secrets)
|
||||||
|
- Tokens are time-limited and single-use
|
||||||
|
- No passwords stored (WebCrypto key-based auth)
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [ ] #1 D1 database 'cryptid-auth' created via wrangler d1 create
|
||||||
|
- [ ] #2 D1 database 'cryptid-auth-dev' created for dev environment
|
||||||
|
- [ ] #3 Database IDs added to wrangler.toml (replacing placeholders)
|
||||||
|
- [ ] #4 Schema from worker/schema.sql deployed to both databases
|
||||||
|
- [ ] #5 Verified tables exist: users, device_keys, verification_tokens
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
<!-- SECTION:PLAN:BEGIN -->
|
||||||
|
## Implementation Steps
|
||||||
|
|
||||||
|
### 1. Create D1 Databases
|
||||||
|
Run from local machine or Netcup (requires wrangler CLI):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jeffe/Github/canvas-website
|
||||||
|
|
||||||
|
# Create production database
|
||||||
|
wrangler d1 create cryptid-auth
|
||||||
|
|
||||||
|
# Create dev database
|
||||||
|
wrangler d1 create cryptid-auth-dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Update wrangler.toml
|
||||||
|
Replace placeholder IDs with actual database IDs from step 1:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[[d1_databases]]
|
||||||
|
binding = "CRYPTID_DB"
|
||||||
|
database_name = "cryptid-auth"
|
||||||
|
database_id = "<PROD_ID_FROM_STEP_1>"
|
||||||
|
|
||||||
|
[[env.dev.d1_databases]]
|
||||||
|
binding = "CRYPTID_DB"
|
||||||
|
database_name = "cryptid-auth-dev"
|
||||||
|
database_id = "<DEV_ID_FROM_STEP_1>"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Deploy Schema
|
||||||
|
```bash
|
||||||
|
# Deploy to dev first
|
||||||
|
wrangler d1 execute cryptid-auth-dev --file=./worker/schema.sql
|
||||||
|
|
||||||
|
# Then production
|
||||||
|
wrangler d1 execute cryptid-auth --file=./worker/schema.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Verify Tables
|
||||||
|
```bash
|
||||||
|
# Check dev
|
||||||
|
wrangler d1 execute cryptid-auth-dev --command="SELECT name FROM sqlite_master WHERE type='table';"
|
||||||
|
|
||||||
|
# Expected output:
|
||||||
|
# - users
|
||||||
|
# - device_keys
|
||||||
|
# - verification_tokens
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Commit wrangler.toml Changes
|
||||||
|
```bash
|
||||||
|
git add wrangler.toml
|
||||||
|
git commit -m "chore: add D1 database IDs for cryptid-auth"
|
||||||
|
```
|
||||||
|
<!-- SECTION:PLAN:END -->
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
---
|
---
|
||||||
id: task-016
|
id: task-019
|
||||||
title: Configure CryptID secrets and environment variables
|
title: Configure CryptID secrets and SendGrid integration
|
||||||
status: To Do
|
status: To Do
|
||||||
assignee: []
|
assignee: []
|
||||||
created_date: '2025-12-04 12:00'
|
created_date: '2025-12-04 12:02'
|
||||||
labels:
|
labels:
|
||||||
- infrastructure
|
- infrastructure
|
||||||
- cloudflare
|
- cloudflare
|
||||||
- cryptid
|
- cryptid
|
||||||
- secrets
|
- secrets
|
||||||
- email
|
- sendgrid
|
||||||
dependencies:
|
dependencies:
|
||||||
- task-015
|
- task-018
|
||||||
priority: high
|
priority: high
|
||||||
---
|
---
|
||||||
|
|
||||||
Loading…
Reference in New Issue