Audience Processing (Create/Edit/Delete/Mookept)
Overview
An audience is the target group used for multicast campaign delivery. The CMS side only records the request in the database and pushes a job onto a queue — all of the heavy lifting happens in this worker: reading LINE User IDs from the uploaded file, validating their format, fetching profiles from LINE and upserting them into line_user, generating a summary CSV, and writing the resulting statistics back to the audience table.
Four separate queues handle the four commands: create, update, delete, and mookept (bulk add or remove of members).
Business Flow
Create Audience (create_audience)
- Receive an
AudienceQueueTypepayload containingaudienceId,lineOaId,organizationId, and the uploaded file path. processValidationPayloadloads theaudiencerow along with the associated OA data —lineOaHash, access token, and login channel.- Read the uploaded file from S3 and split it into a list of LINE User IDs.
- Filter the list with the regular expression
^U[a-f0-9]{32}$viaisValidLineUserID, discarding malformed entries and duplicates. - For each valid ID, fetch the profile from LINE with
GetProfileand find-or-create theline_userrow — creating it if it does not exist, or refreshing the display name, picture, and language if it does. - Generate a single-column CSV with the header
Line UserID, namedaudience-<id>-<timestamp>.csv, and upload it to S3 underprivate/<lineOaHash>/audience/. - Merge the statistics (total, valid, invalid) and the new file path into the
audience.infojsonb column. - Call the trigger evaluator to evaluate
audience_membershiprules for the members who were added or removed.
Update Audience (update_audience)
Follows the same flow as create, with one addition: the old and new member lists are diffed to determine who was added and who was removed, and both sets are passed to the trigger evaluator.
Delete Audience (delete_audience)
Clears all memberships by removing the audience id from line_user.audience_ids, then marks the audience row as deleted.
Mookept (mookept_audience)
The payload carries an actionType field that selects the direction: add invokes AppendMembersByAudienceID, anything else invokes RemoveMembersByAudienceID. Both methods handle their own errors internally — they log and return — so the handler always acks, matching the behaviour of the legacy system.
Key Files & Functions
internal/audience/consumer.go—Consumer.Register()binds handlers to all four queues:OnAudienceCreateProcess,OnAudienceUpdateProcess,OnAudienceDeleteProcess, andOnMookeptAudienceUpdateProcess.internal/audience/service.go— the domain's core logicCreateAudience(),UpdateAudience(),DeleteAudience()AppendMembersByAudienceID(),RemoveMembersByAudienceID()processCreateFileData(),processUpsertLineUserByLineUserID(),processValidationPayload()mergeStatsIntoInfo(),diff(),isValidLineUserID()
internal/audience/interfaces.go— narrow interfaces that keep responsibilities separated:CSVReader,Storage,LineOaLookup,LineProfileFetcher,LineUserUpserter, andAudienceTriggerEvaluator.internal/audience/repository.goandinternal/audience/payloads.gocmd/worker/integration.go— the concrete adapters behind those interfaces:audienceStorage,lineOaForAudience,lineProfileForAudience,lineUserRepo, andaudienceTriggerAdapter.- Queues:
create_audience,update_audience,delete_audience, andmookept_audience(runtime profilemain).
Connections to Other Services
- Job source — cms-api-go (audience domain) enqueues work whenever a user creates, edits, or deletes a target group.
- Database —
audience(theinfojsonb column),line_user(upsert plusaudience_ids), andline_oa. - S3 — reads the uploaded source file and writes the result CSV to
private/<lineOaHash>/audience/. - LINE API —
GET /v2/bot/profile/{userId}for profile lookups. - Trigger engine — calls
EvaluateAudienceTriggerson every membership change. - Downstream consumer of the CSV — the file produced here is exactly what the multicast campaign delivery job reads at send time.