Broadcast Campaign Management
Overview
Campaign Management is the tool OA administrators use to push messages out to friends of their LINE OA. They can send to everyone (broadcast) or to a specific audience (multicast), and choose to send immediately, schedule for later, or save as a draft.
An important point up front: campaigns do not author their own content. They reference a Rich Message that was already created and activated in the Rich Message Management feature. The campaign form pulls that content in and previews it inside a chat frame before anything is sent.
Beyond sending, this feature is also where results are reviewed. Campaigns that have gone out show summary figures for delivery, reads and clicks, broken down per button and per link, with the ability to drill into the actual LINE users who read or clicked.
Campaigns have four statuses — sent, scheduled, cancelled and draft — and the list page is organised into tabs by status.
Business Flow
1. Campaign list
- On open, campaign view permission is checked, then two requests run in parallel:
- The recipient options for the filter. If broadcast campaigns actually exist, an "all friends on OA" option is prepended to the list — the principle being that the filter should never offer a choice with no data behind it.
- The campaign list itself, starting on the "sent" tab, newest first.
- Filter state is cached in sessionStorage, so returning to the page restores the previous filters.
- Switching status tabs resets the whole filter set and applies a sort order suited to that tab:
- Sent and scheduled sort by send date; the scheduled tab lists the nearest first so the upcoming queue is visible.
- Cancelled and draft sort by last-updated date, newest first.
- The date column changes meaning with the tab too: send date on the sent and scheduled tabs, cancellation date on the cancelled tab, and last-updated date on the draft tab — all labelled as Bangkok time.
- The sent tab adds a total-activity column, which is sortable and clicks through to that campaign's results.
- The filter offers three inputs: search by name, recipient, and date range. Dates entered are interpreted as Bangkok time and converted to UTC before the request is sent.
- Row actions depend on the campaign's status:
- Draft — edit and delete.
- Scheduled — cancel, via a confirmation dialog.
- Sent — view results.
- Any status — copy, to start a new campaign from an existing one.
2. Creating and editing a campaign
- The form supports four modes — create, edit, copy and view results — distinguished by the URL parameters.
- Supporting data is loaded up front: the list of active Rich Messages, and the list of audiences, which can be searched further with a debounced lookup.
- Choose recipients — either all friends on the OA, or a specific audience.
- Choose content — select a Rich Message from the list. The preview updates immediately in a chat frame, pulling in any Quick Reply attached to that Rich Message and generating a video thumbnail automatically when one is missing.
- Merge tag rule — when broadcasting, Rich Messages containing merge tags are filtered out of the list, because a send to everyone has no per-person data to substitute. For multicast sends with merge tags, an option appears asking whether to skip recipients whose data is incomplete.
- Choose how to send — send now, schedule, or save as draft.
- When scheduling — the date and time are prefilled to 35 minutes from now, while the actual validation rule requires at least 30 minutes' lead time. The five-minute gap is deliberate breathing room for filling in the form. Hours and minutes already past are disabled when today's date is selected, and a failed check is reported both under the time field and in a modal.
- Save conditions — a draft only requires a campaign name, so work can be prepared incrementally. A real send or a scheduled send requires the name, recipients, content and send method, plus the audience for multicast and the date and time when scheduling.
- On save, the app re-checks that the scheduled time is not in the past, then opens a confirmation dialog whose wording and button label change with the chosen send method.
- On confirmation, the app calls
POST /campaignfor new and copied campaigns orPUT /campaign/{id}for edits. If the server identifies invalid fields, errors are shown per field.
3. Reviewing results of a sent campaign
- In results mode every form field is read-only, and a tracking column is added on the right.
- Four summary cards report messages sent, reach, unique clicks and total clicks. The read and click cards can be clicked to drill down.
- A table per message — a Rich Message may contain several messages, each with its own table labelled Message A, B, C and so on. The columns vary with the message type:
- Text messages state that click tracking is not available.
- Images and videos use total views and unique views.
- Tappable images use spot, data, type, unique clicks and total clicks.
- Flex messages use the same columns without the spot column.
- The type column translates raw values into readable labels such as rich menu switch, link, text and phone number.
- Clicking a number in a table or a summary card opens a side panel listing the actual LINE users behind that figure, with profile picture, name, event count, first and last interaction, and pagination.
Key Screens & Components
List screen
All list logic lives in one container (src/components/campaign-management/list/campaign-management.container.tsx), covering status tabs, filters, pagination and sorting, cancellation and deletion. The table and filter form are separate presentational components.
Form screen
The form splits into a container that loads data, handles confirmation and performs the save, and a form component that combines the input fields, the message preview and the results tables in view mode.
Tracking users panel
The side panel listing users who read or clicked is its own component. It can target a specific button within a specific message using an index that encodes both the message position and the click position together.
API endpoints
| Operation | Endpoint |
|---|---|
| List campaigns | GET /campaign |
| Read one campaign | GET /campaign/{id} |
| Tracking data | GET /campaign/campaign-tracking/{id} |
| Users who read or clicked | GET /campaign/campaign-tracking/{id}/users |
| Recipient options for the filter | GET /campaign/recipients-dropdown |
| Create a campaign | POST /campaign |
| Update or cancel a campaign | PUT /campaign/{id} |
| Delete a draft | DELETE /campaign/{id} |
| Audience list | GET /audiences |
| Rich Message list | GET /rich-message/find-all-object |
| Quick Reply data for the preview | GET /quick-reply/{id} |
Dependencies
- Rich Message Management — a hard dependency: an active Rich Message must exist before a campaign can be created.
- Audiences — required for multicast sends, and the recipients column in the table links back to that audience's detail page.
- Quick Reply — read-only, used to show the reply buttons attached to a Rich Message in the preview.
- Campaign Planner — reads the same data as this page and links back into the results view.
- Dashboard — the upcoming activities card pulls scheduled campaigns from this module.
- Access control — the server-side
campaignmodule unlocks both this page and the Campaign Planner. - Data scope — every request is automatically scoped to the LINE OA the user selected, through the data carried in their token.
Backend Details (CMS API)
The API does not send the messages
The single most important thing about this module: cms-api never calls LINE itself. When a campaign is saved, the backend writes it to the database and publishes a job to RabbitMQ for a worker to send. That is why the request returns quickly even for enormous recipient lists.
The consequence worth internalizing: a successful send means "the job was queued", not "the message was delivered". If messages never arrive, the problem lies with the worker or with LINE, not with cms-api.
Queues are separated by job type:
| Case | Queue published to |
|---|---|
| Send to all friends on the OA (broadcast) | line_broadcast_rich_message |
| Send to specific audiences (multicast) | line_multicast_rich_message |
| Scheduled and aggregate processing jobs | process_campaign |
| Campaign clicks used as a trigger source | campaign_click_trigger |
A caution for developers: the published payload is byte-identical to the previous system's, key order included, because the original worker still consumes the same queues. Changing the payload shape breaks the worker immediately.
The merge tag rule the backend actually applies
The backend has a check for whether a message contains merge tags, which decides whether the send must be personalized per recipient. The rule to know: a genuine pair of closing braces must be present for something to count as a merge tag. A form such as {{name}} is detected, while text with unbalanced braces is not, and is sent through literally. This is why the frontend filters merge-tag Rich Messages out of the options when broadcast is selected.
Tracking
GET /api/campaign/campaign-tracking/:idcomputes its summary through SQL-level aggregation rather than pulling raw rows and counting in code, so it stays fast even for campaigns with very large recipient lists.GET /api/campaign/campaign-tracking/:id/userssupports filtering by action type, original URL and message index within the Rich Message, with pagination — matching the side panel that drills into per-button, per-link user lists.- Campaign links use a different tracking mechanism from rich menus. Campaigns rewrite links into tracking URLs through the worker's redirect service, whereas rich menus use the token-based tracking-link system. Knowing this helps when click figures do not reconcile.
Permissions and deletion
- Every route in this module is wrapped in ModuleGate for the
campaignmodule, which is genuinely enforced. If a platform administrator disables campaigns for an organization, its users get 403 even calling the API directly. - Per-action permission metadata (create, update, delete) exists but is not enforced.
DELETE /api/campaign/:idis a soft delete; a separate hard-delete route requires super admin plus an explicit confirmation parameter.
Side effects and related systems
- Redis cache — the backend caches both the campaign list and individual campaign details.
- Cross-module references — saving a campaign invokes the LINE message formatting and validation service alongside Rich Message and audience data, so editing a Rich Message after a campaign is created can change what actually gets sent.
- Campaign clicks can act as a trigger source — when a recipient clicks a link, the system can publish to the trigger queue so automation rules continue from there.