Skip to main content

LINE Webhook Processing

Overview

When a user sends a chat message, follows or unfollows the account, or taps a postback button on LINE, the resulting webhook arrives at line-management-webhook-go, which performs a light check and immediately pushes it onto the line_webhook queue. All real processing happens in this worker, making it the main entry point for every user interaction.

Its responsibilities fall into five parts: verify the signature, resolve the OA, warm the edge cache, upsert the line_user row, and dispatch each event to its destination queue or feature.

Business Flow

  1. Receive a payload made up of webhookId, headers, and body, where the body is the raw LINE webhook request.

  2. Read the x-line-signature header. If it is absent the handler returns an error, so the message is nacked and lands in the DLQ.

  3. getLineOAByWebhookId(webhookId) resolves the owning OA, backed by a Redis cache to spare the database.

  4. Verify the signature by computing HMAC-SHA256 over the body using oa.channelSecretId, base64-encoding it, and comparing against the header. A mismatch returns an error and the message goes to the DLQ.

  5. Warm the cache on a best-effort basis — a failure here does not affect the main flow. The worker writes a Redis hash at webhook_config:<webhookId> holding lineOaId, forwardWebhookUrl, and the full mbox configuration (enabled flag, keywords, and the greeting / warning / end / timeout messages) with a one-hour TTL, plus a mbox_inbox:<inboxId> mapping. This lets webhook-go read its configuration quickly without touching the database.

  6. Find or create the line_user row from the userId on the first event. For an unknown user the worker verifies the access token, fetches the profile from LINE, and calls createLineUser.

  7. Dispatch every event according to its type.

    Text messages — routed by line_oa.message_handling_config.priority:

    • auto_response_only (the default) publishes to line_auto_response.
    • ai_classifier_only publishes to message_received_trigger.
    • auto_response_first publishes to line_auto_response with fallbackToAi set to true.

    Special messages

    • The text member publishes a line_change_richmenu message of type member, switching the user to the member rich menu.
    • The text guest sets user_type to guest.

    Every message event also updates last_activity_type to message and last_activity_status to active.

    Other event types

    • postback sets logEventType to webhook and publishes the whole payload onto the tracking_log queue.
    • follow refreshes the profile, updates the user record, assigns the member rich menu, and runs friend-track attribution.
    • unfollow marks follow as no and records the unfollow event.
  8. Publishes on the message path are fire-and-forget: a failed publish is logged and processing continues with the next event, matching the legacy NestJS behaviour of not awaiting the result.

  9. Event-level errors are handled by handleWebhookError, which logs them, while ProcessLineWebhook always returns nil so the message is acked.

Key Files & Functions

  • internal/lineoa/webhook.go
    • Service.ProcessLineWebhook(ctx, payload) — entry point
    • warmWebhookConfigCache(), processEvents(), handleMessageEvent(), handleFollowEvent(), handleUnfollowEvent(), runFriendTrackAttribution(), handleWebhookError()
  • internal/lineoa/consumer.goConsumer.HandleLineWebhook, bound to the line_webhook queue
  • internal/lineoa/service.gogetLineOAByWebhookId(), findById(), issueAccessToken(), and verifyAccessToken(), with tokens cached for one hour under Redis keys prefixed LINE_OA:
  • internal/lineoa/lineuser.gofindByLineUserId(), createLineUser(), updateLineUser()
  • internal/lineoa/types.goLineForwardWebhookPayload, WebhookEvent, and the event-type and priority enums
  • Queues: consumes line_webhook; publishes to line_auto_response, message_received_trigger, line_change_richmenu, and tracking_log (runtime profile main)

Connections to Other Services

  • Job sourceline-management-webhook-go, the endpoint that receives webhooks from LINE.
  • Databaseline_oa (channel secret, access token, message_handling_config), line_user (find-or-create plus last-activity fields), and friend_track_event / friend_track_campaign.
  • Redis — the LINE_OA: key family for token caching, plus webhook_config:<webhookId> and mbox_inbox:<inboxId>.
  • LINE APIGET /v2/bot/profile/{userId} and the OAuth endpoints for issuing and verifying channel access tokens.
  • Downstream features triggered — auto response, AI message triggers, rich menu management, tracking log recording, and friend track.