Keyword Auto-response
Overview
When a user sends a message, the system matches it against the keywords an administrator has configured. On a match, it immediately replies with the rich message bound to that keyword.
This is one of the most latency-sensitive features in the platform — the user is sitting there waiting — so it is designed so that keyword matching reads exclusively from a Redis hash and never touches the database. A cron job syncs keywords from the database into Redis every five minutes, and a lazy-warm path covers a cold cache, fixing the classic problem of "the first message after a restart goes unanswered".
Business Flow
- Receive a payload containing
keyword,lineOaId,organizationId,lineUserId,replyToken,payload, plus the optionalfallbackToAi,messageText, andtimestamp. - Match the keyword with an
HGETagainst that OA's Redis hash. - Lazy warm — if the keyword is not found, check whether the entire key is missing
(
HGETALLreturns empty).- A missing key means the cache is cold, so the OA's keywords are synced from the database immediately and the lookup is retried.
- A present key without this keyword simply means it was never configured, so there is no need to re-warm on every message.
- No keyword match
- If
fallbackToAi = true(theauto_response_firstmode), publish ontomessage_received_triggerso the AI classifier can take over. - Otherwise, finish and acknowledge.
- If
- Keyword matched — the value stored in Redis is JSON carrying
richMessageIdandautoResponseId.- Load the
rich_messageby id, scoped tolineOaId. - Verify the OA is still
active; if not, returnmq.Permanent(a 400-class error) and route the message to the DLQ. transformMessageObjectsconverts the content into LINE message objects.- If merge tags such as
{{display_name}}or{{custom.xxx}}are present, load theline_userand resolve them. - Attach quick replies when the rich message references a
quick_reply_id; if that fails to load, the message is still sent, just without the chips.
- Load the
- Delivery strategy, an improvement over the original system which only ever used reply:
- With a
replyToken, usereplyMessagefirst. If the reply fails — for instance because the token expired due to slow processing — fall back topushMessageso the user still gets an answer. - Without a
replyToken, which happens on standby events where LINE issues no token, usepushMessageonly when the OA has thepushOnStandbyflag enabled inmessage_handling_config.
- With a
- Record tracking by publishing to
tracking_logwithcontent_type = auto_response,action_type = send, andlogEventType = webhook.
Keyword sync cron (profile cron-scheduler)
Every five minutes (*/5 * * * *), AutoResponseSyncService.Run pulls all active OAs and
rebuilds each one's Redis hash. If a single OA fails, the loop uses continue rather than
return — one OA with an oversized or broken configuration must never leave every other OA's
keywords cold.
Key Files & Functions
internal/autoresponse/service.goService.ProcessAutoResponse(ctx, payload)— the full feature flowgetRedisKey(), which builds keys of the formAUTO_RESPONSE:LINE_OA_ID:plus the id;buildTrackingPayload(),attachQuickReplyAny(),standbyPushEnabled()- narrow dependency interfaces:
RichMessageFinder,LineOaFinder,LineUserFinder,QuickReplyLoader
internal/autoresponse/transform.go—transformMessageObjects(),resolveMergeTags(),hasMergeTags()internal/autoresponse/consumer.go—Consumer.OnProcessAutoResponseinternal/cronscheduler/auto_response_sync.go—AutoResponseSyncService.Run(),SyncKeywordsForLineOa(), and the prefixLINE_MANAGEMENT:AUTO_RESPONSE:LINE_OA_ID:cmd/worker/integration.go— wiring forlineOaForAutoResponse,lineUserFinder, andquickReplyForAutoResponse- Queue: consumes
line_auto_response; publishes tomessage_received_triggerandtracking_log(profilemain)
Connections to Other Services
- Receives jobs from: the worker's own
line_webhookhandler, on text message events - Redis (the critical dependency): a hash named
LINE_MANAGEMENT:AUTO_RESPONSE:LINE_OA_ID:plus the line OA id, where each field is a keyword and each value is JSON containingrichMessageIdandautoResponseId - Tables:
auto_response(the keyword source the cron syncs from),rich_message,line_oa(status, token, andmessage_handling_config.pushOnStandby),line_user(for merge tags), and the quick reply tables - LINE API:
POST /v2/bot/message/replyandPOST /v2/bot/message/push - Connects to: AI Message Intent Classification as the fallback path, and the tracking log pipeline