Broadcast Campaign Management
Overview
A campaign sends a rich message out to LINE friends according to a chosen target group, with optional scheduling. This module covers the whole lifecycle: creating the campaign, selecting recipients (either the entire OA or a specific audience), and reviewing the tracking report that shows who opened the message and which links they clicked.
The actual sending does not happen in this API. The API only persists the campaign and publishes a job to RabbitMQ for a worker to deliver, which keeps the request fast and makes large sends practical.
Business Flow
Creating and sending
-
GET /api/campaign/recipients-dropdownsupplies cms-web with the recipient options, such as the available audiences. -
POST /api/campaignaccepts multipart/form-data and stores the campaign: its name, the rich message to send, the recipient type (broadcast to the whole OA, or multicast to an audience), and the send time. -
The service checks whether the message contains merge tags such as
{{name}}usinghasMergeTags, because messages with merge tags must be personalised and sent per recipient. -
The job is published to RabbitMQ:
- No audience specified goes to the
line_broadcast_rich_messagequeue. - An audience specified goes to the
line_multicast_rich_messagequeue. - Scheduled or aggregate processing goes to the
process_campaignqueue.
The payload is built byte-identically to the TypeScript version, preserving key order, because the original worker still consumes it.
- No audience specified goes to the
-
The worker picks up the job and calls the LINE Messaging API.
Tracking results
GET /api/campaign/campaign-tracking/:idsummarises sends, opens, and clicks, computed with raw SQL aggregation.GET /api/campaign/campaign-tracking/:id/usersdrills into the list of people who performed a given action, accepting theactionType,originalUrl,richMessageIndex,page, andlimitquery parameters.- Links inside a campaign are rewritten into tracking URLs by the RedirectService on the worker side, which differs from rich menus and their token-based approach.
General management
GET /api/campaignreturns a paginated list; the repository spreads the audience'stargetvalues into each result.GET /api/campaign/:idandPUT /api/campaign/:idview and update a campaign, whileDELETE /api/campaign/:idsoft-deletes it.DELETE /api/campaign/:id/hard?confirm=truedeletes permanently and is restricted to super admins.
Key Files & Functions
The code lives in internal/modules/campaign/, consisting of controller.go, service.go,
tracking.go, and dto.go.
| Method | Route | Handler | Policy (metadata) |
|---|---|---|---|
| GET | /api/campaign | ct.findAll | readAll campaign |
| GET | /api/campaign/recipients-dropdown | ct.recipientsDropdown | readAll campaign |
| GET | /api/campaign/:id | ct.findByID | read campaign |
| GET | /api/campaign/campaign-tracking/:id | ct.trackingByID | read campaign |
| GET | /api/campaign/campaign-tracking/:id/users | ct.trackingUsersByID | read campaign |
| POST | /api/campaign | ct.create | create campaign |
| PUT | /api/campaign/:id | ct.update | update campaign |
| DELETE | /api/campaign/:id | ct.delete | delete campaign |
| DELETE | /api/campaign/:id/hard | ct.hardDelete | auth.SuperAdmin() |
Every route is wrapped in modulegate.ModuleGate(d, "campaign").
One function worth knowing is hasMergeTags, which uses the JavaScript-equivalent regex
/\{\{[^}]+\}\}/ — two closing braces must genuinely be adjacent for it to match.
Connections to Other Services
- Permissions —
ModuleGate("campaign")is the guard that actually applies;PolicyModuleCampaignis metadata only, and hard delete additionally requiresauth.SuperAdmin(). - Tables —
campaign,rich_message,audience,line_user,tracking_line_users,line_oa - RabbitMQ — the
process_campaign,line_broadcast_rich_message,line_multicast_rich_message, andcampaign_click_triggerqueues - Redis — caches both the list and the detail views
- Cross-module —
linemessageapifor validating and formatting messages, plusrichmessageandaudience - Related modules — rich messages, audience management, and trigger rules, which treat campaign clicks as a trigger source