Skip to main content

การบันทึก Tracking Log

ภาพรวม

ทุกการอ่าน การคลิก และการส่งข้อความในระบบสุดท้ายแล้วจะถูกบันทึกลงตาราง tracking_log เพียงตารางเดียว ตารางนี้จึงเป็นแหล่งข้อมูลจริงของรายงานแคมเปญและสถิติ rich menu รวมถึงเป็นตัวจุดชนวน trigger ประเภท campaign_click ผ่านกลไก Postgres trigger ร่วมกับ pg-listener

Consumer ตัวนี้รับ event ได้จากสองแหล่ง คือ webhook ซึ่งเป็น postback ที่มาจาก LINE และ redirect ซึ่งเกิดจากการที่ผู้ใช้กดลิงก์ผ่าน redirect service โดยแหล่งหลังต้องผ่านการตรวจลายเซ็น HMAC ก่อนจึงจะบันทึกได้

Business Flow

  1. รับ payload ชนิด RedirectTrackingPayload ซึ่งมีฟิลด์ logEventType, headers, body และ bodyRaw
  2. ตรวจความถูกต้องของ payload
    • logEventType ต้องมีค่าเป็น webhook หรือ redirect เท่านั้น
    • กรณี webhook ต้องมีค่า user id อยู่ในโครงสร้าง event ตัวแรกของ body และต้องไม่ว่าง หากรูปแบบผิดไปจากมาตรฐานระบบจะบันทึก log ระดับ warning แต่ยังทำงานต่อ
    • กรณี redirect ต้องมี header x-bank-signature และต้องผ่านการตรวจ HMAC-SHA256 ที่คำนวณบน raw bytes ของ body ด้วยค่า REDIRECT_API_SECRET โดยเปรียบเทียบแบบ timing-safe เหตุผลที่ต้องใช้ raw bytes คือการ re-marshal ใน Go จะเรียงลำดับคีย์ใหม่และ escape อักขระ HTML ซึ่งทำให้ลายเซ็นไม่ตรงกัน
  3. SaveTrackingLog แปลงข้อมูลให้อยู่ในโครงสร้างของตาราง tracking_log
    • getActionType() แยกประเภทการกระทำออกเป็น read, click หรือ send
    • handlePostbackEvent() แกะข้อมูลจาก postback ส่วน handleAutoResponseEvent() จัดการกรณีบันทึก log ของ auto response
    • เติมข้อมูลบริบทเข้าไป ได้แก่ campaign_id, rich_message_id, rich_message_index, line_uid, content_type และ type ซึ่งมีค่าเป็น uri, asset, postback หรือ message
  4. insertTrackingLog เขียนแถวใหม่ลงตาราง tracking_log
  5. saveTrackingLineUsers อัปเดตแถว line_user ทั้งฟิลด์ last_activity_type และ last_activity_status และหากผู้ใช้เงียบไปเกิน 1 ชั่วโมงจะอัปเดต last_activity_period ด้วย
  6. checkAndCompleteDelayWait ตรวจว่าผู้ใช้รายนี้มี scheduled action ที่ตั้งไว้แบบรอจนกว่าจะมีการคลิกหรือไม่ (waitForTracking) หากมี การคลิกครั้งนี้จะปลดล็อกให้ action นั้นทำงานต่อทันที โดยตรวจผ่านการ join จาก trigger_rule ไปยัง workflow_id และ scheduled_action
  7. การ INSERT ที่เกิดขึ้นจะทำให้ Postgres trigger ยิง pg_notify ด้วย channel campaign_click ซึ่ง pg-listener จะรับต่อและส่งเข้าคิว campaign_click_trigger ให้ trigger engine ประมวลผล

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

  • internal/tracking/service.go
    • Service.ProcessTrackingLog(ctx, payload) — entry point ที่รวมทั้งการ validate และการตรวจลายเซ็น
    • verifyXBankSignature(), getActionType(), initializeTrackingData()
    • SaveTrackingLog(), saveTrackingLogInner(), insertTrackingLog(), saveTrackingLineUsers()
    • handlePostbackEvent(), handleAutoResponseEvent(), checkAndCompleteDelayWait()
    • ค่าคงที่ moduleName มีค่าเป็น TRACKING ใช้เป็น prefix ของ Redis key
  • internal/tracking/consumer.goConsumer.HandleTrackingLog
  • internal/tracking/payloads.goRedirectTrackingPayload และ UnmarshalRedirectTrackingPayload
  • internal/tracking/signature_test.go — ชุดทดสอบของการตรวจลายเซ็น
  • cmd/worker/integration.golineUserFinder ซึ่งเป็น adapter ของ tracking.LineUserService
  • คิวที่เกี่ยวข้อง: tracking_log (runtime profile main)

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

  • ต้นทางของงานline-management-webhook-go ทั้งจาก postback และ callback ของ redirect service รวมถึง handler ของคิว line_webhook ภายใน worker เองในกรณี event ชนิด postback
  • ฐานข้อมูลtracking_log (INSERT), line_user (UPDATE ข้อมูลกิจกรรมล่าสุด) และ trigger_rule กับ scheduled_action สำหรับกรณี delay-wait
  • Redis — key ที่ขึ้นต้นด้วย TRACKING: และเป็นจุดที่ตั้ง dirty flag กลุ่ม CAMPAIGN_STAT_DIRTY: กับ RICH_MENU_STAT_DIRTY: ให้ scanner นำไปคำนวณสถิติต่อ
  • ตัวแปรสภาพแวดล้อมREDIRECT_API_SECRET สำหรับตรวจ x-bank-signature
  • ผลลัพธ์ต่อเนื่อง — งานคำนวณสถิติแคมเปญ งานคำนวณสถิติ rich menu และ trigger engine ในส่วนของ campaign click