Skip to main content

Rich Menu

Overview

A rich menu is the image-based menu displayed beneath the LINE chat window. This is one of the most complex modules in the system, because it handles several concerns at once: managing the image and its tappable areas (the layout), linking and unlinking menus for users on LINE, setting the default menu, managing aliases for multi-level or tabbed menus, archiving previous versions, generating per-button tracking links (tracking tokens), and computing tap statistics.

Binding a menu to an audience requires reading a CSV of LINE users from object storage through the CSV engine.

Business Flow

Creating and publishing

  1. POST /api/rich-menu accepts multipart/form-data for the image upload, the layout, and the action assigned to each area.
    • Link actions are rewritten into token-based tracking URLs.
    • A duplicate name returns error RMN_001.
  2. The service calls LINE through the line message api in sequence: callCreateRichMenuOnLineOA, then setRichMenuImage, and where an alias is configured, the alias is created or updated.
  3. Targeting works in two ways:
    • Whole OA: setDefaultRichMenu.
    • Specific audience: processRichMenuAudience reads the audience CSV through Deps.CSVEngine and calls linkRichMenuIdToUsers in batches, recording results in rich_menu_member.
  4. The previous version is archived into rich_menu_archive before being replaced.

Day-to-day use

  1. GET /api/rich-menu returns a paginated list, and GET /api/rich-menu/find-all-object provides a dropdown shape with no policy attached.
  2. GET /api/rich-menu/:id returns the detail view including actions and statistics.
  3. PUT /api/rich-menu/:id accepts form-data for updates. It follows the same flow as creation but must also reconcile the existing menu on LINE.
  4. POST /api/rich-menu/:id/recalculate-stat triggers a recomputation of tap statistics by publishing to the calculate_rich_menu_stat_item queue for a worker to process.
  5. DELETE /api/rich-menu/:id soft-deletes and also calls deleteRichMenu on LINE, while DELETE /api/rich-menu/:id/hard?confirm=true deletes permanently and is restricted to super admins.
  6. Event-driven menu switching for individual users happens through the line_change_richmenu queue.

Key Files & Functions

The code lives in internal/modules/richmenu/.

FileRole
controller.goRoute registration
service.goCore logic, with the rich_menu, action, member, and archive repositories folded in
create_update.goThe create/update flow, including processRichMenuAudience
update.goThe flow for updating an already-published menu
tracking_adapter.goConverts link actions into tracking token URLs
util.go, js.go, dto.goHelpers and DTOs
MethodRouteHandlerPolicy (metadata)
GET/api/rich-menuct.findAllreadAll rich-menu
GET/api/rich-menu/find-all-objectct.findAllObject
GET/api/rich-menu/:idct.findByIdread rich-menu
POST/api/rich-menuct.createcreate rich-menu
POST/api/rich-menu/:id/recalculate-statct.recalcStatread rich-menu
PUT/api/rich-menu/:idct.updateupdate rich-menu
DELETE/api/rich-menu/:idct.deletedelete rich-menu
DELETE/api/rich-menu/:id/hardct.hardDeleteauth.SuperAdmin()

Every route is wrapped in modulegate.ModuleGate(d, "rich-menu").

Connections to Other Services

  • PermissionsModuleGate("rich-menu") is the guard that actually applies; PolicyModuleRichMenu is metadata only, and hard delete additionally requires auth.SuperAdmin().
  • Tablesrich_menu, rich_menu_action, rich_menu_member, rich_menu_archive, tracking_token, audience, line_oa
  • RabbitMQ — the line_change_richmenu and calculate_rich_menu_stat_item queues
  • Cross-modulelinemessageapi.Service, linemessageapi.RichMenuService, tracking.TrackingTokenService, and Deps.CSVEngine for reading audience CSVs
  • Note — the LINE OA record is read by querying entities.LineOa directly rather than through lineoa.Service.FindByID, because this module needs the channelAccessToken that the service strips out.
  • Error codeRMN_001 for a duplicate name