Analytics aggregation
Mailgun webhook /api/email/webhooks/mailgun (already exists) currently handles delivered/bounce. Extend to consume: opened, clicked, complained, unsubscribed.
For each event:
Look up
Campaign.mailgunId(stored at send time).Resolve
CampaignLogby(campaignId, subscriberId)— Mailgun event payload includes recipient +message-id-> tag mapping.Set the matching boolean + timestamp column on
CampaignLog.Recompute the per-campaign rollups on
Campaign(opened,clicked,bounced, ...) using:const rollup = await prisma.campaignLog.groupBy({ by: ['campaignId'], where: { campaignId }, _count: { opened: true, clicked: true, bounced: true, delivered: true, unsubscribed: true, complained: true }, }) await prisma.campaign.update({ where: { id: campaignId }, data: { opened: rollup[0]._count.opened, clicked: rollup[0]._count.clicked, bounced: rollup[0]._count.bounced, delivered: rollup[0]._count.delivered, unsubscribed: rollup[0]._count.unsubscribed, complained: rollup[0]._count.complained, }})Subscribe to Mailgun event types:
delivered, opened, clicked, bounced, complained, unsubscribed(via dashboard orPOST /v3/domains/{domain}/webhooks/{hookid}).
Engagement rollups on Subscriber (emailsOpened, linksClicked, lastOpenedAt, lastClickedAt) can be updated in the same handler keyed off subscriberId.