Skip to content

feat: marketing email campaign service#351

Merged
alanw707 merged 4 commits into
mainfrom
feature/marketing-email-service
Apr 10, 2026
Merged

feat: marketing email campaign service#351
alanw707 merged 4 commits into
mainfrom
feature/marketing-email-service

Conversation

@alanw707
Copy link
Copy Markdown
Owner

Summary

  • Full end-to-end marketing email system: campaign CRUD, scheduling, bulk delivery, bounce/unsubscribe handling
  • 5 user segments for targeting (no-uploads, stuck-under-minimum, has-uploads-no-model, inactive-30d, all-verified)
  • Admin UI at /admin/campaigns for creating, scheduling, previewing, and monitoring campaigns
  • Postmark webhook auto-unsubscribes users on hard bounce or spam complaint
  • First campaign content ready: "5 selfie minimum" re-engagement email for no-uploads + stuck-under-minimum users

Key files

Layer Files
Models MarketingCampaign, MarketingEmailLog, ApplicationUser (+opt-out fields)
Services MarketingEmailService, UserSegmentService, MarketingEmailBackgroundService, FirstCampaignContent
Controllers MarketingCampaignController, MarketingUnsubscribeController, PostmarkWebhookController
Frontend AdminCampaignsComponent, UnsubscribeComponent, MarketingService
Migration 20260408121713_AddMarketingEmailService

Test plan

  • Deploy and run dotnet ef database update to apply migration
  • Navigate to /admin/campaigns, create a campaign using the first-campaign defaults
  • Use "Count recipients" on no-uploads segment — verify a non-zero count
  • Send a test email to yourself — verify it arrives with correct formatting and unsubscribe link
  • Click unsubscribe link — verify /unsubscribe page shows success and MarketingOptOut is set in DB
  • Schedule campaign for 2 minutes in the future — verify background service picks it up and sends
  • Check delivery logs via the Logs view
  • Configure Postmark webhook to POST /api/webhooks/postmark with Authorization: Bearer {PostmarkWebhookSecret}

🤖 Generated with Claude Code

alanw707 and others added 4 commits April 7, 2026 04:57
Full end-to-end marketing email system:

Backend:
- MarketingCampaign + MarketingEmailLog EF models and migration
- ApplicationUser: add MarketingOptOut/MarketingOptOutAt fields
- UserSegmentService: 5 segments (no-uploads, stuck-under-minimum, has-uploads-no-model, inactive-30d, all-verified)
- MarketingEmailService: campaign CRUD, schedule, cancel, duplicate, test send, bulk execute with idempotent per-recipient guard
- MarketingEmailBackgroundService: polls every minute, picks up due campaigns
- MarketingCampaignController: full admin REST API including email preview endpoint
- MarketingUnsubscribeController: token-based unsubscribe + resubscribe + status
- PostmarkWebhookController: auto-unsubscribe on hard bounce / spam complaint
- SendMarketingEmailAsync + RenderMarketingEmailPreview in EmailNotificationService
- FirstCampaignContent: "5 selfie minimum" re-engagement email content

Frontend:
- AdminCampaignsComponent: list, create, detail, schedule, test send, logs views
- UnsubscribeComponent: handles token-based unsubscribe link from emails
- MarketingService: full Angular HTTP client for all campaign endpoints
- Routes: /admin/campaigns and /unsubscribe wired up

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
simple-deploy.yml and pr-code-review.yml were still referencing 8.0.x
after the .NET 10 upgrade, which would cause dotnet build/test steps to
fail due to global.json requiring 10.0.201.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Added SendMarketingEmailAsync and RenderMarketingEmailPreview no-op
implementations to CapturingEmailNotificationService (x2),
NoopEmailNotificationService, and DummyEmailNotificationService — all
broke when the interface was extended for marketing email support.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@alanw707 alanw707 merged commit 5c61da1 into main Apr 10, 2026
3 checks passed
@alanw707 alanw707 deleted the feature/marketing-email-service branch April 10, 2026 03:37
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