mirror of
https://github.com/koala73/worldmonitor.git
synced 2026-04-25 17:14:57 +02:00
* feat(email): add deliverability guards to reduce waitlist bounces Analyzed 1,276 bounced waitlist emails and found typos (gamil.com), disposable domains (passmail, guerrillamail), offensive submissions, and non-existent domains account for the majority. Four layers of protection: - Frontend: mailcheck.js typo suggestions on email blur - API: MX record check via Cloudflare DoH, disposable domain blocklist, offensive pattern filter, typo-TLD blocklist - Webhook: api/resend-webhook.js captures bounce/complaint events, stores in Convex emailSuppressions table, checked before sending - Tooling: import script for bulk-loading existing bounced emails * fix(email): address review - auth, retry, CSV parsing 1. Security: Convert suppress/bulkSuppress/remove to internalMutation. Webhook now runs as Convex httpAction (matching Dodo pattern) with direct access to internal mutations. Bulk import uses relay shared secret. Only isEmailSuppressed remains public (read-only query). 2. Retry: Convex httpAction returns 500 on any mutation failure so Resend retries the webhook instead of silently losing bounce events. 3. CSV: Replace naive comma-split with RFC 4180 parser that handles quoted fields. Import script now calls Convex HTTP action authenticated via RELAY_SHARED_SECRET instead of public mutation. * fix(email): make isEmailSuppressed internal, check inside mutation Move suppression check into registerInterest:register mutation (same transaction, no extra round-trip). Remove public query entirely so no suppression data is exposed to browser clients. * test(email): add coverage for validation, CSV parser, and suppressions - 19 tests for validateEmail: disposable domains, offensive patterns, typo TLDs, MX fail-open, case insensitivity, privacy relay allowance - 7 tests for parseCsvLine: RFC 4180 quoting, escaped quotes, empty fields, Resend CSV format with angle brackets and commas - 11 Convex tests for emailSuppressions: suppress idempotency, case normalization, bulk dedup, remove, and registerInterest integration (emailSuppressed flag in mutation return)