Skip to content

Add email campaign pipeline, recipient resolution, delete endpoint, email send scheduler - #365

Open
williamchiii wants to merge 5 commits into
devfrom
wchi/email_campaigns_backend
Open

Add email campaign pipeline, recipient resolution, delete endpoint, email send scheduler#365
williamchiii wants to merge 5 commits into
devfrom
wchi/email_campaigns_backend

Conversation

@williamchiii

@williamchiii williamchiii commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

This pull request introduces significant improvements to the email campaign system, focusing on enabling scheduled campaign sending, expanding recipient resolution, and enhancing repository and SQL support for these features. The changes span new SQL queries, repository methods, background worker scheduling, and service wiring.

Summary of Most Important Changes:

Scheduled Email Campaigns

  • Added support for scheduled email campaigns, including a background scheduler that periodically enqueues tasks to sweep and send due campaigns. This ensures campaigns set for future delivery are automatically processed when their scheduled time arrives. (apps/api/cmd/email_worker/main.go

Email Campaign Recipient Resolution

  • Introduced new SQL queries and repository methods to resolve recipient groups for campaigns:
    • Applicants by status (e.g., accepted applicants)
    • Users by roles (e.g., admins, staff)
    • Interest subscribers (public signups)
      These methods ensure campaigns reach the correct audience segments. (apps/api/internal/database/queries/email_campaigns.sql

Email Campaign State Management

  • Added atomic "claim for sending" logic to ensure that only one worker can transition a campaign to "sending" at a time, preventing duplicate sends in concurrent environments. (apps/api/internal/database/queries/email_campaigns.sql

  • Added deletion support for email campaigns, scoped by hackathon to prevent cross-event data issues. (apps/api/internal/database/queries/email_campaigns.sql

Application and User Model Enhancements

  • Extended application and user models/queries to include an is_fake flag, allowing filtering of test or fake users/applications from recipient lists. (apps/api/internal/database/sqlc/applications.sql.go

Service Wiring and Handler Updates

  • Updated service and handler wiring to inject the new EmailCampaignService with its dependencies, ensuring campaign logic is available in both the API and worker processes. (apps/api/cmd/email_worker/main.go

These changes collectively enable robust, scheduled, and targeted email campaigns, while laying groundwork for further automation and reliability in campaign delivery.

Resolves applicant recipient groups to deduped contact emails (excluding
is_fake seeded rows), adds raw-HTML task type and SES send methods, registers
all task types in the email worker mux, and adds SendCampaign with
draft/scheduled -> sending -> sent/failed transitions plus an admin-gated
POST /email/campaigns/{campaignId}/send endpoint.
Adds GetUserContactEmailsByRoles (role-based lookup on users, excluding
is_fake rows) and a recipientRoles map, so resolveRecipients now dispatches
applicant groups by application status and role groups by user role.
Only interest_subscribers remains unsupported.
Introduces campaignStore and campaignMailer interfaces in the email package
so the campaign service can be tested with fakes (concrete repository and
email service satisfy them unchanged). Adds 8 tests covering per-recipient
queueing, format routing, cross-group dedup, status transitions including
sending->failed with last_error, and the guard paths.
test: cover SendCampaign send pipeline

Introduces campaignStore and campaignMailer interfaces in the email package
so the campaign service can be tested with fakes (concrete repository and
email service satisfy them unchanged). Adds 8 tests covering per-recipient
queueing, format routing, cross-group dedup, status transitions including
sending->failed with last_error, and the guard paths.
Adds DeleteEmailCampaign query, repo method, and a DeleteCampaign service
method guarded by canDeleteCampaign so draft, scheduled, and failed campaigns
can be removed while sent and sending ones stay on the record. Exposes
DELETE /email/campaigns/{campaignId} with OpenAPI docs.
@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
core Ready Ready Preview Aug 12, 2026 2:43am
xii-front-page Error Error Aug 12, 2026 2:43am

Adds an asynq Scheduler in cmd/email_worker that sweeps every minute for
campaigns whose scheduled_at has passed, failing any more than two hours
late so an outage cannot trigger a surprise blast.

Sends are now claimed with a conditional UPDATE, so overlapping ticks or a
double-clicked Send cannot dispatch the same campaign twice. Also resolves
interest_subscribers, completing all seven recipient types.
@williamchiii williamchiii changed the title Add email campaign pipeline, recipient resolution, and delete endpoint Add email campaign pipeline, recipient resolution, delete endpoint, email send scheduler Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant