Skip to main content

การจัดการ Rich Menu

ภาพรวม

Rich Menu คือเมนูรูปภาพที่แสดงอยู่ด้านล่างหน้าจอแชท LINE ระบบรองรับเมนูหลายประเภท (default, member, guest, custom) และสามารถผูกเมนูคนละแบบให้ผู้ใช้แต่ละคนได้

งานนี้เป็น consumer ที่รับคำสั่งเปลี่ยน ผูก และลบ rich menu แล้วไปเรียก LINE Rich Menu API จริง โดยใช้ queue เดียวคือ line_change_richmenu ซึ่งรองรับคำสั่งได้ 6 รูปแบบ แยกกันด้วยฟิลด์ type ใน payload

Business Flow

Handler จะอ่านฟิลด์ type แล้วแตกไปยังสาขาการทำงานที่เกี่ยวข้อง

ค่า typeการทำงาน
memberchangeRichMenuFromWebhookId — กรณีผู้ใช้พิมพ์คำว่า "member" ในแชท ระบบจะ resolve OA จาก webhookId ค้นหา line_user เปลี่ยน user_type เป็น MEMBER แล้วผูก rich menu ประเภท member ให้ผู้ใช้รายนั้นผ่าน LINE API
setRichMenuMembersetRichMenuMemberByLineOaId — ผูก rich menu ประเภท member ให้สมาชิกทุกคนของ OA โดยทำงานเป็นชุด (chunk) และสร้าง CLS context ใหม่ต่อหนึ่ง message
setRichMenuMemberByLineUserIdผูก rich menu ให้ผู้ใช้ที่ระบุเป็นรายบุคคล
setRichMenuByTriggerRuleผูก rich menu ตามผลลัพธ์ของ trigger rule ซึ่งถูกสั่งมาจาก action switch_rich_menu
cronSetRichMenuCustomค้นหา rich menu ประเภท custom ที่มี status=active, complete_link_user=false และอยู่ในช่วงเวลา start_date <= now < end_date แล้วทยอยผูกให้สมาชิกกลุ่มเป้าหมาย เมื่อครบทุกคนจะ mark complete_link_user=true
deletedeleteRichMenu — unlink ผู้ใช้ทั้งหมด ลบ rich menu บน LINE แล้ว cascade สถานะไปยัง alias rich menu

หลักการที่ใช้ร่วมกันในทุกสาขา:

  • resolve channel_access_token ผ่าน LineOAResolver (คือ lineoa.Service ที่ทำหน้าที่ verify และ refresh token ให้) จากนั้นสร้าง LINE client แยกต่อ OA
  • การผูกผู้ใช้จำนวนมากจะถูกแบ่งเป็น chunk ด้วย chunkStrings เพื่อไม่ให้ยิง API รวดเดียว
  • ล้าง Redis cache ที่เกี่ยวข้องหลังการเปลี่ยนแปลงทุกครั้งด้วย delRedisAllCacheRelate
  • payload ที่ decode ไม่ได้จะคืน mq.Permanent เพื่อเข้า DLQ ทันที ส่วน type ที่ไม่รู้จักจะ return nil (ack เงียบ ๆ โดยไม่ retry)

ไฟล์และฟังก์ชันหลัก

  • internal/richmenu/consumer.goConsumer.HandleLineChangeRichMenu() ทำหน้าที่ dispatch ตามค่า type และ Register()
  • internal/richmenu/richmenu.goService, NewService(), enum typeOfRichMenuDefault/Member/Guest/Custom, chunkStrings(), delRedisAllCacheRelate()
  • internal/richmenu/service_methods.gochangeRichMenuFromWebhookId(), setRichMenuMemberByLineOaId(), setRichMenuMemberByLineUserId(), setRichMenuByTriggerRule(), deleteRichMenu()
  • internal/richmenu/service_cron.gocronSetRichMenuCustom(), cronDeleteRichMenuCustom(), findRichMenuMemberLineUserIds(), cascadeStatusToAliasRichMenus()
  • internal/line/richmenu.go — LINE Rich Menu API client
  • cmd/worker/integration.go — จุด wiring ของ lineOaForRichMenu และ lineUserForRichMenu
  • Queue: line_change_richmenu (profile main)

จุดเชื่อมต่อกับ Service อื่น

  • รับ job จาก: handler ของ line_webhook (กรณีผู้ใช้พิมพ์ "member"), cms-api-go โดเมน rich menu และ action executor ผ่าน action switch_rich_menu
  • ตารางที่เกี่ยวข้อง: rich_menu, rich_menu_action, rich_menu_archive, line_user (คอลัมน์ rich_menu_id และ user_type) และ line_oa
  • Redis: cache ของโดเมน rich menu โดยใช้ prefix ตามค่า MODULE_NAME
  • LINE API: create/delete rich menu, การ link ผ่าน POST /v2/bot/user/:userId/richmenu/:richMenuId, การ unlink และการจัดการ rich menu alias
  • สถิติการคลิกเมนูอยู่ในเอกสาร การคำนวณสถิติ Rich Menu