feat(newsletter): add delivery pipeline #70
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "exe-dev-bot/market:feat/newsletter-delivery"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Implements the Newsletter Delivery section of spec-003, adding the complete email delivery pipeline for the weekly newsletter system.
Changes
New Files
src/lib/email.ts-- SMTP email utility usingcloudflare:socketsTCP API. Implements the full SMTP protocol (EHLO, STARTTLS, AUTH LOGIN, MIME multipart) directly sincenodemaileris unavailable on Cloudflare Workers. Auto-detects server capabilities: skips STARTTLS and AUTH when not advertised (e.g. local Mailpit).src/lib/jwt.ts-- JWT sign/verify using Web Crypto API (HS256). No Node.js crypto dependency. Used for unsubscribe tokens.src/lib/newsletter-delivery.ts-- Core delivery logic: iterates all users, generates personalized newsletters, sends emails to opted-in contacts, logs results, and cleans up old newsletters (keeps 4 most recent per user).src/worker.ts-- Custom Cloudflare Worker entry point withscheduledhandler for cron triggers.src/pages/newsletter/unsubscribe.astro-- Public unsubscribe page. Validates JWT token, disablesnewsletter_enabledon the contact record. Shows success/error UI.src/pages/api/newsletter/trigger.ts-- Manual trigger endpoint for the newsletter delivery, protected byNEWSLETTER_SECRETbearer token. Works aroundwrangler --test-scheduledissue with Astro adapter.Modified Files
src/components/react/ContactInfoForm.tsx-- Added newsletter preference checkbox (email contacts only)src/pages/api/user/contact-info.ts-- Handlenewsletter_enabledin create/update operationssrc/lib/auth.ts-- Added/newsletter/unsubscribeand/api/newsletter/triggertopublicRoutesastro.config.mjs-- ConfiguredworkerEntryPointfor custom worker withscheduledexportwrangler.jsonc-- Added cron trigger (0 12 * * 1-- Monday 12:00 UTC).env.example-- Documented new env vars:SUPABASE_SERVICE_ROLE_KEY,SMTP_*,NEWSLETTER_SECRET,SITE_URLspecs/003-weekly-newsletter.md-- Marked 10 delivery tasks as completeSpec Progress
After this PR, spec-003 has all Database Schema, Newsletter Generation, and Newsletter Delivery tasks complete. Remaining: Testing (3 tasks) and Rollout (2 tasks).
Testing
Code quality
just lintjust test-unitNewsletter preference toggle
newsletter_enabled = truein Supabase Studio (contact_infotable)Unsubscribe page
/newsletter/unsubscribewith no token -- verify error page shows/newsletter/unsubscribe?token=<jwt>-- verify success page andnewsletter_enabledis set to falseCron job (local testing)
just start-backend.envwith the required vars (SUPABASE_SERVICE_ROLE_KEY,SMTP_*,NEWSLETTER_SECRET,SITE_URL). Defaults in.env.examplepoint to local Mailpit.newsletter_enabled = trueon at least one email-type contact in thecontact_infotableOriginheader is required to bypass Astro's CSRF protection for non-browser requests.newslettertable in Supabase Studio -- a new row per usernewsletter_send_logtable -- a row per opted-in email contact withstatus: sent{"success": true}with status 200newsletterrows created (one per user)newsletter_send_logrows created withstatus: sentNew Environment Variables
SUPABASE_SERVICE_ROLE_KEYSMTP_HOSTSMTP_PORTSMTP_USERSMTP_PASSSMTP_FROMNEWSLETTER_SECRETSITE_URL18b87971dc4a2a919744579d9766542ebe15f1d5Squashed locally.
Pull request closed