ติดตามการเพิ่มเพื่อน
ภาพรวม
ติดตามการเพิ่มเพื่อน (Friend Track) คือโมดูลสำหรับสร้างแคมเปญวัดผลการชวนเพิ่มเพื่อน แต่ละแคมเปญมี token ประจำตัวที่ใช้เป็นตัวระบุลิงก์ชวนเพิ่มเพื่อน เมื่อผู้ใช้เปิดลิงก์จะถูกนับเป็นการเข้าชม และเมื่อกดเพิ่มเพื่อนสำเร็จจะถูกนับเป็นการติดตาม ระบบจะเก็บข้อมูลทั้งสองส่วนไว้ให้ดูเป็นรายงานอัตราการเปลี่ยนเป็นเพื่อน (conversion) ต่อแคมเปญ
จุดเด่นของโมดูลนี้มี 2 อย่าง
- เขียนคุณสมบัติให้ผู้ใช้อัตโนมัติ แต่ละแคมเปญกำหนดชุดคู่คีย์-ค่าไว้ได้ ผู้ใช้ที่เข้ามาทางลิงก์นี้จะถูกเขียนค่าเหล่านั้นลงในคุณสมบัติเพิ่มเติมของโปรไฟล์ ทำให้แยกแยะที่มาของผู้ติดตามได้ในภายหลัง
- ลิงก์รายบุคคล หนึ่งแคมเปญสร้างลิงก์ย่อยได้หลายลิงก์ (เช่น แจกแยกตามพนักงานขายหรือสาขา) โดยอัปโหลดรายการรหัสอ้างอิงเป็นไฟล์ CSV แล้วดาวน์โหลดลิงก์ที่ระบบสร้างให้กลับมาเป็น CSV
โมดูลแบ่งเป็น 3 หน้า คือ หน้ารายการแคมเปญ, หน้าฟอร์มสร้างและแก้ไข และหน้ารายงานผล
Business Flow
หน้ารายการแคมเปญ
- เปิดหน้ารายการ ระบบตรวจสิทธิ์แล้วโหลดรายการแคมเปญโดยเรียงตามวันที่สร้างล่าสุด
- ตัวกรองมี 2 ตัว คือช่องค้นหาที่ยิงคำขอทันทีเมื่อพิมพ์ และตัวเลือกสถานะเปิด/ปิดใช้งาน ทั้งสองตัวจะรีเซ็ตกลับไปหน้าแรกของตารางเสมอ
- คอลัมน์ประกอบด้วย ลำดับ, ชื่อแคมเปญ (คลิกเพื่อเข้าไปแก้ไข), token, สถานะ, จำนวนการเข้าชม, จำนวนการติดตาม, อัตราการเปลี่ยนเป็นเพื่อน และวันที่สร้าง
- ปุ่มคำสั่งต่อแถวมี 3 ปุ่ม คือ ดูรายงาน, แก้ไข และลบ โดยการลบต้องยืนยันก่อนและแสดงผลลัพธ์ผ่านหน้าต่างสำเร็จหรือหน้าต่างล้มเหลว
หน้าฟอร์มสร้างและแก้ไข
- หน้าฟอร์มแยกโหมดจากพารามิเตอร์
idโดยไม่มีidคือสร้างใหม่ และมีidคือแก้ไข ทั้งสองโหมดใช้ตัวตรวจสิทธิ์ระดับ "ดูข้อมูล" ตัวเดียวกัน - ระบบโหลดข้อมูลประกอบ 2 ชุด คือ รายการ merge tag จากโมดูลข้อความเทมเพลต (ใช้เป็นตัวเลือกคีย์คุณสมบัติ) และข้อมูลแคมเปญเดิมในกรณีแก้ไข
- ฟิลด์ในฟอร์มประกอบด้วย
- ชื่อแคมเปญ (บังคับ)
- สถานะ เป็นสวิตช์เปิด/ปิด โดยค่าเริ่มต้นในโหมดสร้างคือเปิดใช้งาน
- token พร้อมปุ่มสร้างให้อัตโนมัติเป็นสตริง 16 ตัวอักษร ถ้าเว้นว่างไว้ระบบหลังบ้านจะสร้างให้เอง
- คำอธิบาย
- ตั้งค่าคุณสมบัติ เป็นรายการคู่คีย์-ค่าที่เพิ่มลบได้ โดยคีย์เลือกจากรายการ merge tag
- คีย์คุณสมบัติอ้างอิง เป็นตัวเลือกจากรายการคุณสมบัติที่ตั้งค่าไว้ ใช้ระบุว่าจะเก็บรหัสอ้างอิงของลิงก์ย่อยไว้ที่ช่องใด
- เมื่อกดบันทึก ระบบจะเปิดหน้าต่างยืนยันก่อน จากนั้นจึงประกอบข้อมูลส่ง โดยแปลงรายการคู่คีย์-ค่าเป็นวัตถุเดียว ตัดคำนำหน้า
custom.ออกจากคีย์ให้ตรงกับรูปแบบที่ระบบจัดเก็บ และแปลงสวิตช์สถานะเป็นข้อความ - เมื่อเปิดแคมเปญเดิมขึ้นมาแก้ไข ระบบจะแปลงข้อมูลกลับด้านตรงข้าม คือคลี่วัตถุกลับเป็นรายการ และเติมคำนำหน้า
custom.คืนให้กับคีย์ที่ไม่ใช่คุณสมบัติมาตรฐานของ LINE - หากบันทึกไม่สำเร็จและเซิร์ฟเวอร์ส่งข้อผิดพลาดรายฟิลด์กลับมา ระบบจะแสดงข้อความใต้ฟิลด์ที่เกี่ยวข้องโดยตรง
รหัสอ้างอิงและลิงก์รายบุคคล
การ์ดรหัสอ้างอิงจะปรากฏเฉพาะในโหมดแก้ไข เพราะต้องมีรหัสแคมเปญอยู่ก่อน
- รูปแบบไฟล์ที่รองรับคือ CSV ที่มีรหัสอ้างอิงหนึ่งรายการต่อหนึ่งแถว หัวตารางจะมีหรือไม่มีก็ได้ โดยหน้าจอแสดงตัวอย่างรูปแบบไว้ให้
- ปุ่มดาวน์โหลดเทมเพลตสร้างไฟล์ตัวอย่างขึ้นในเบราว์เซอร์ทันทีโดยไม่ต้องเรียกเซิร์ฟเวอร์
- การอัปโหลดส่งไฟล์เข้าสู่ระบบเพื่อประมวลผลเบื้องหลัง เมื่อสำเร็จหน้าจอจะแจ้งสถานะและจำนวนรายการที่บันทึกได้ การตรวจความถูกต้องของเนื้อไฟล์ทำที่ฝั่งเซิร์ฟเวอร์ทั้งหมด
- หลังอัปโหลด ระบบจะดึงสถานะงานมาแสดง เมื่อสถานะเป็นเสร็จสิ้นแล้วจึงจะเปิดใช้งานปุ่มดาวน์โหลดลิงก์ พร้อมแสดงจำนวนรายการที่บันทึกสำเร็จและที่ถูกข้าม โดยระบบจะตรวจสถานะเฉพาะตอนเปิดหน้าและหลังอัปโหลด หากงานยังประมวลผลไม่เสร็จผู้ใช้ต้องรีเฟรชหน้าเอง
- ปุ่มดาวน์โหลดลิงก์จะดึงไฟล์ CSV ที่มีลิงก์ tracking ของแต่ละรหัสอ้างอิงมาบันทึกลงเครื่อง
- ลิงก์จริงที่แจกให้ผู้ใช้ปลายทางถูกประกอบขึ้นที่ฝั่งเซิร์ฟเวอร์ และส่งกลับมาในไฟล์นี้เท่านั้น ต่างจากโมดูลลิงก์รวมเนื้อหาหรือตัวสร้างเมนูที่ประกอบ URL เองในหน้าเว็บ หน้ารายการจึงแสดงเพียง token ไม่ใช่ URL เต็ม
หน้ารายงานผล
- หน้ารายงานอ่านรหัสแคมเปญจาก URL แล้วโหลดข้อมูล 2 ชุด คือข้อมูลแคมเปญ (ใช้ชื่อเป็นหัวข้อหน้า) และข้อมูลรายงานตามช่วงเวลาที่เลือก
- ตัวเลือกช่วงเวลาอยู่บนหัวการ์ดกราฟ และควบคุมทั้งกราฟและตารางผู้ใช้พร้อมกัน โดยค่าเริ่มต้นคือดูข้อมูลทั้งช่วง
- การ์ดสถิติ 4 ใบ แสดงจำนวนการเข้าชมทั้งหมด, จำนวนการติดตามทั้งหมด, อัตราการเปลี่ยนเป็นเพื่อน และจำนวนการเลิกติดตาม
- กราฟเส้นรายวัน วาดจากข้อมูลจริงที่เซิร์ฟเวอร์ส่งมาเป็นชุดข้อมูลตามวันที่ แสดง 2 เส้นคือการเข้าชมและการติดตาม หากไม่มีข้อมูลในช่วงที่เลือกจะแสดงข้อความแจ้งแทน
- ตารางผู้ใช้ แสดงรายชื่อผู้ที่เข้ามาผ่านแคมเปญนี้ พร้อมชื่อที่แสดง, LINE user ID, วันที่เข้าชม, วันที่ติดตาม, สถานะ, รหัสอ้างอิงของลิงก์ย่อยที่ผู้ใช้เข้ามา และประเภทผู้ใช้ โดยแบ่งหน้าแยกจากกราฟ
สรุปวงจรการใช้งาน
- ผู้ดูแลสร้างแคมเปญ ได้ token และตั้งค่าคุณสมบัติที่จะเขียนให้ผู้ใช้
- หากต้องการลิงก์แยกรายบุคคล ให้กลับเข้าโหมดแก้ไข อัปโหลดรายการรหัสอ้างอิง รอสถานะเสร็จสิ้น แล้วดาวน์โหลดไฟล์ลิงก์ไปแจก
- ผู้ใช้ปลายทางเปิดลิงก์ ระบบหลังบ้านบันทึกการเข้าชม และเขียนคุณสมบัติกับรหัสอ้างอิงให้ผู้ที่กดเพิ่มเพื่อน
- ผู้ดูแลกลับมาดูผลที่หน้ารายงาน เลือกช่วงวันที่ แล้วอ่านตัวเลขสรุป กราฟ และรายชื่อผู้ใช้
- เมื่อจบแคมเปญสามารถปิดใช้งานหรือลบแคมเปญออกได้
หน้าจอและองค์ประกอบหลัก
Route ทั้งสาม — หน้ารายการ (src/app/friend-track/page.tsx), หน้าฟอร์ม (.../form/page.tsx) และหน้ารายงาน (.../report/page.tsx) ทั้งหมดห่อด้วยตัวตรวจสิทธิ์เดียวกัน
ตัวควบคุมรายการ (src/components/friend-track/list/friend-track-list.container.tsx) — ดูแลการโหลดตาราง ตัวกรอง และการลบพร้อมหน้าต่างแสดงผลลัพธ์
ตัวควบคุมฟอร์ม (src/components/friend-track/form/friend-track-form.container.tsx) — ดูแลการโหลดและบันทึกข้อมูลแคมเปญ รวมถึงการแปลงรูปแบบคุณสมบัติทั้งขาเข้าและขาออก ส่วนตัวฟอร์ม (friend-track-form.tsx) ดูแล UI ทั้งหมดรวมถึงการ์ดรหัสอ้างอิง
ตัวควบคุมรายงาน (src/components/friend-track/report/friend-track-report.container.tsx) — ประกอบการ์ดสถิติ กราฟเส้น และตารางผู้ใช้เข้าด้วยกัน โดยใช้ตัวลงทะเบียนกราฟร่วมกับโมดูลแดชบอร์ด
เซอร์วิสกลาง (src/services/friend-track.service.ts) — ครอบคลุมการอ่านรายการ, อ่านรายตัว, สร้าง, แก้ไข, ลบ, ดึงรายงาน, อัปโหลดรหัสอ้างอิง, ตรวจสถานะงานอัปโหลด และดาวน์โหลดไฟล์ลิงก์
โครงสร้างข้อมูลสำคัญ — ข้อมูลแคมเปญเก็บชื่อ, token, คำอธิบาย, สถานะ, ชุดคุณสมบัติที่จะเขียน, คีย์คุณสมบัติอ้างอิง และตัวเลขสรุป ส่วนข้อมูลรายงานแบ่งเป็น 3 ส่วน คือตัวเลขสรุป, ชุดข้อมูลรายวันสำหรับกราฟ และรายการผู้ใช้พร้อมข้อมูลการแบ่งหน้า
จุดเชื่อมต่อกับฟีเจอร์อื่น
- สิทธิ์การเข้าถึง — ใช้ subject
friend-trackโดยตรวจเฉพาะการกระทำ "ดูข้อมูล" ทุกหน้าใช้ตัวตรวจเดียวกัน รวมถึงหน้าฟอร์มที่สร้าง แก้ไข และอัปโหลดไฟล์ได้ - ข้อความเทมเพลต (Template Message) — เป็นแหล่งของรายการ merge tag ที่ใช้เป็นตัวเลือกคีย์คุณสมบัติ หากบริการนี้ไม่ตอบสนอง ตัวเลือกจะว่าง
- ตั้งค่าคุณสมบัติผู้ใช้ (Attribute Master) — เป็นแหล่งของตัวเลือกคีย์คุณสมบัติอ้างอิง โดยต้องสร้างคุณสมบัติไว้ก่อนจึงจะเลือกได้ ซึ่งหน้าจอมีคำแนะนำระบุไว้ชัดเจน
- ระบบหลังบ้านและ webhook — การนับการเข้าชม การนับการติดตาม และการสร้างลิงก์ต่อรหัสอ้างอิง เป็นงานฝั่งเซิร์ฟเวอร์ทั้งหมด CMS ทำหน้าที่ตั้งค่าและอ่านผลเท่านั้น
- โมดูลแดชบอร์ด — ใช้ตัวลงทะเบียนไลบรารีกราฟชุดเดียวกัน
- คอมโพเนนต์ร่วมของ CMS — ส่วนหัวหน้า, หน้าต่างยืนยัน, หน้าต่างผลลัพธ์, สถานะกำลังโหลดแบบเต็มจอ และพื้นที่เลื่อนตาราง ใช้ชุดเดียวกับหน้าอื่นทั้งระบบ
รายละเอียดฝั่ง Backend (CMS API)
ฟีเจอร์นี้พาดผ่าน 3 ส่วนของ backend คือ โมดูลแคมเปญติดตามเพื่อน (internal/modules/friendtrack/), โมดูลค้นหาผู้ใช้จาก tracking log และกลไกสร้างลิงก์ติดตามที่ไม่มี HTTP route ของตัวเอง
สิทธิ์ที่ต้องมี
- ทุก route ของ
/api/friend-trackถูกครอบด้วยModuleGate("friend-track")จริง ถ้าองค์กรไม่ได้เปิดโมดูลนี้ คำขอถูกปฏิเสธก่อนถึง handler - policy ที่ประกาศไว้แยกละเอียดกว่าที่หน้าเว็บตรวจ: การอ่านรายการเป็น
readAll, การอ่านรายตัว/รายงาน/ดาวน์โหลด/ดูสถานะเป็นread, การสร้างเป็นcreate, การอัปโหลดรหัสอ้างอิงถูกจัดเป็นupdate(ไม่ใช่create) และการลบเป็นdelete— หน้าเว็บตรวจแค่การกระทำ "ดูข้อมูล" การแยกจึงมีผลจริงที่ฝั่งเซิร์ฟเวอร์เท่านั้น - ข้อสังเกต: policy ของโมดูล friend-track ยังถูกนำไปใช้เป็น metadata ของ
GET /api/appsและPUT /api/apps/:appIdด้วย ซึ่งยกมาตามระบบเดิม จึงเป็นความผูกพันที่ไม่ตรงกับชื่อโมดูลและควรระวังเมื่อจะปรับสิทธิ์
การอัปโหลดรหัสอ้างอิงจำนวนมาก
POST /api/friend-track/:id/refs/uploadรับไฟล์แบบ multipart แล้วเขียนลงฐานข้อมูล ด้วยคำสั่ง SQL แบบ batch ที่มีเงื่อนไข "ถ้าซ้ำให้ข้าม" ออกแบบมารองรับ ref หลักพันถึงหลักหมื่นรายการ เช่น ref ต่อพนักงาน ต่อสาขา หรือต่อ QR แต่ละใบ- เพราะมีการกันซ้ำในตัว การอัปโหลดไฟล์เดิมซ้ำจึงไม่สร้างรายการซ้ำ และใช้เป็นวิธี "เติม ref เพิ่ม" ได้อย่างปลอดภัย
GET /api/friend-track/:id/refs/statusใช้ poll สถานะงานอัปโหลด (กำลังทำ / เสร็จ / ผิดพลาด) เพราะงานไม่ได้เสร็จภายในคำขอเดียวGET /api/friend-track/:id/refs/downloadสตรีมไฟล์ CSV ของลิงก์และ ref ทั้งหมดลง response โดยตรง ไม่โหลดทั้งก้อนเข้าหน่วยความจำ
รายงานและการนับ
GET /api/friend-track/:id/report กรองตามช่วงเวลาและ ref ได้ ข้อควรรู้ด้านประสิทธิภาพ: การนับจำนวนผู้ใช้ในรายงานทำโดยดึงแถวทั้งหมดออกมาแล้วนับความยาว ไม่ได้ใช้คำสั่งนับของฐานข้อมูล ซึ่งยกพฤติกรรมมาจากระบบเดิมตรง ๆ ผลคือแคมเปญที่มีผู้ใช้จำนวนมากจะทำให้รายงานหน่วงและกินหน่วยความจำมากกว่าที่ควร
ใครเป็นคนบันทึกว่า "เพื่อนคนนี้มาจาก ref ไหน"
CMS API ไม่ได้เป็นผู้บันทึกเหตุการณ์นี้ — เมื่อมีคนกดลิงก์แล้วเพิ่มเพื่อน บริการ webhook เป็นฝ่ายรับ event จาก LINE แล้วเขียนลงตาราง friend_track_event โดยผูกกับแคมเปญและ ref ที่ใช้ CMS ทำหน้าที่ตั้งค่าและอ่านผลเท่านั้น ผลที่ตามมาคือถ้าบริการ webhook มีปัญหา ตัวเลขในรายงานจะขาดหายโดยที่หน้า CMS ไม่แสดงความผิดพลาดใด ๆ
ค้นหาผู้ใช้จาก tracking log
POST /api/tracking-line-users เป็น endpoint เดียวที่ใช้เจาะจากพฤติกรรมกลับมาเป็นรายชื่อคน (เช่น "ใครกดลิงก์นี้บ้าง") โดยรับรายการ tracking key แล้วค้นตาราง tracking_line_users และเชื่อมกลับไปที่ข้อมูลผู้ใช้ LINE
- ขอบเขตข้อมูลอ่านจาก context ของ request จึงจำกัดอยู่ที่ OA ที่กำลังทำงานอยู่
- endpoint นี้ผ่านแค่
JwtAuthระดับ global ไม่มีModuleGateต่างจาก/api/friend-track - ผลลัพธ์ถูกส่งกลับตามที่ค้นได้โดยไม่แปลงรูป
- ข้อควรระวัง: ถ้าคำขอไม่ได้ส่งรายการ tracking key มา หรือส่งมาผิดชนิด backend จะตอบเป็นสถานะ 500 พร้อมรหัสข้อผิดพลาดทั่วไป ไม่ใช่ 400 พร้อมข้อความบอกว่าอะไรผิด — พฤติกรรมนี้จงใจคงไว้ให้ตรงกับระบบเดิม ฝั่งเรียกจึงต้องตรวจ payload ให้ครบก่อนส่ง
ลิงก์ติดตามถูกสร้างอย่างไร
กลไกสร้างลิงก์ติดตามอยู่ในโมดูล internal/modules/tracking/ ซึ่ง ไม่เปิด HTTP route ใด ๆ เลย เป็นเพียงบริการภายในที่โมดูลริชเมนูและโมดูลส่งข้อความเรียกใช้ ประเด็นที่ควรรู้:
- โหมดการทำงานเลือกด้วยตัวแปรสภาพแวดล้อม
TRACKING_REDIRECT_MODE— โหมดbuiltinใช้ token ที่ระบบเข้ารหัสเอง ส่วนค่าอื่น (ค่าเริ่มต้นคือโหมดเดิม) จะส่งต่อให้บริการ redirect ภายนอก - โหมด
builtinห่อข้อมูลไว้ในตัว token เองด้วยการเข้ารหัสแบบ AES-256-GCM แล้วเข้ารหัสเป็นข้อความ URL-safe ตัว token จึงระบุได้ว่ามาจากริชเมนูหรือจากฟอร์มเก็บข้อมูล โดยไม่ต้องค้นฐานข้อมูลก่อน - เมื่อผู้ใช้กดลิงก์ บริการ client-api เป็นฝ่ายถอดรหัส token บันทึกเหตุการณ์ลง
tracking_line_usersแล้วจึง redirect ไปยังปลายทาง - คำเตือนสำคัญ: ตัวเข้ารหัสฝั่ง CMS API กับตัวถอดรหัสฝั่ง client-api ถูกตรึงให้ตรงกัน ถ้าฝั่งใดฝั่งหนึ่งเปลี่ยนรูปแบบ token ลิงก์ที่ส่งออกไปแล้วทั้งหมดจะใช้ไม่ได้ทันที และไม่มีทางกู้คืนนอกจากออกลิงก์ใหม่
- ลิงก์ของแคมเปญ (campaign) ใช้คนละเส้นทาง คือใช้บริการ redirect ที่ฝั่ง worker ไม่ได้ผ่านกลไก token นี้
ตารางที่เกี่ยวข้อง
friend_track_campaign, friend_track_event, tracking_token, tracking_line_users, line_user และ line_oa