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.go — Consumer.HandleTrackingLog
  • internal/tracking/payloads.go — RedirectTrackingPayload และ UnmarshalRedirectTrackingPayload
  • internal/tracking/signature_test.go — ชุดทดสอบของการตรวจลายเซ็น
  • cmd/worker/integration.go — lineUserFinder ซึ่งเป็น 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