feat(api,web): real-time newsletter progress via Durable Objects#6
Merged
Merged
Conversation
Add a realtime layer for newsletter sends and subscriber stats built on two SQLite-backed Cloudflare Durable Objects, surfaced over WebSockets. - CampaignProgress (per campaign): coordination point for a send. The email worker seeds totals via start(), each batch reports completion (idempotent by batchIndex), and analytics/unsubscribe feed engagement. When the final batch lands it marks the campaign SENT and records totalSent in D1 — the queue fan-out previously had no "all batches done" signal, so campaigns were stuck on SENDING and totalSent was 0. - WriterStats (per writer): subscriber lifecycle mutations re-read authoritative counts from D1 and broadcast them. Cookie-authenticated WS routes (/realtime/campaigns/:id, /realtime/ subscribers) forward to the DOs using the hibernation API. All notifiers are best-effort so realtime can never break a send or mutation. Frontend adds a reconnecting WS channel hook plus useCampaignRealtime / useSubscriberStatsRealtime: a live send progress bar + engagement on the campaign detail page, and live subscriber stat cards that refresh the list as people subscribe, confirm, and unsubscribe. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a real-time layer for newsletter sends and subscriber stats, built on two SQLite-backed Cloudflare Durable Objects surfaced over WebSockets.
start(), each batch reports completion (idempotent bybatchIndex), and analytics/unsubscribe feed engagement. When the final batch lands it marks the campaignSENTand recordstotalSentin D1 — the queue fan-out previously had no "all batches done" signal, so campaigns were stuck onSENDINGandtotalSentwas always0(click rate always 0%).Cookie-authenticated WS routes (
/realtime/campaigns/:id,/realtime/subscribers) forward to the DOs using the hibernation API. All notifiers are best-effort, so realtime can never break a send or mutation.Frontend adds a reconnecting WS channel hook plus
useCampaignRealtime/useSubscriberStatsRealtime: a live send progress bar + engagement on the campaign detail page, and live subscriber stat cards that refresh the list as people subscribe, confirm, and unsubscribe.Validation
tsc --noEmit: clean.wrangler --dry-runbundles the worker with both DOs registered;wrangler typesaccepted the bindings +v1migration.Notes
wrangler deploy --env staging, thev1DO migration applies on first deploy.open_eventstable), so the live Opens counter reflects pixel hits for the current send session only.🤖 Generated with Claude Code