Skip to main content

จัดการกลุ่มเป้าหมาย (Audience Management)

ภาพรวม​

Audience คือ "กลุ่มรายชื่อผู้ใช้ LINE" ที่โมดูลอื่นนำไปอ้างอิงเพื่อกำหนดว่าจะส่งข้อความหรือแสดงเนื้อหาให้ใครเห็น เช่น Campaign, Rich Menu, Content Management, Trigger Rule, Workflow และ Bulletin

หน้าจอนี้เหมาะกับทีมการตลาดที่ต้องแบ่งกลุ่มลูกค้าตามพฤติกรรมจริง (คลิกแคมเปญ กดเมนู ตอบฟอร์ม ระดับสมาชิก) หรือทีมที่มีรายชื่อลูกค้าอยู่แล้วและต้องการนำเข้ามาใช้งานตรง ๆ

ระบบรองรับ audience 3 โหมด

โหมดเมนู / เส้นทางที่มาของรายชื่อ
อัปโหลด CSV/audience/csvไฟล์ CSV ที่มีคอลัมน์ Line UserID ที่ผู้ใช้อัปโหลดเอง
Filter แบบแหล่งเดียว/audience/filter/formเงื่อนไข 1 ประเภท เลือกจากแคมเปญ / Rich Menu / activity tag / Auto Response / ฟอร์ม
Filter แบบหลายแหล่ง/audience/filter/multi-source/formหลายแหล่งรวมกันเป็นกลุ่ม พร้อมกำหนด AND/OR ทั้งภายในกลุ่มและระหว่างกลุ่ม

จุดสำคัญที่ต้องทราบ

  • หน้ารายการของโหมด CSV และโหมด Filter ใช้หน้าจอเดียวกัน แต่สลับคอลัมน์และปุ่มดำเนินการตามโหมดที่เปิดอยู่
  • audience ที่มาจาก filter รองรับการคำนวณสมาชิกใหม่อัตโนมัติ (auto refresh) เป็นรอบ และสั่งคำนวณใหม่ทันที (refresh now) ได้ โดยรอบเวลาตั้งไว้ที่ระดับ LINE OA
  • audience ที่ถูกสร้างโดยระบบภายนอก (3rd party) จะถูกซ่อนปุ่มดำเนินการทั้งหมดและซ่อนสวิตช์ auto refresh เพื่อป้องกันการแก้ไขข้ามระบบ
  • หน้ารายละเอียดใช้ร่วมกันทุกโหมด แสดงกฎ filter ที่ใช้สร้าง กฎ Trigger Rule ที่ผูกอยู่ ตารางสมาชิก และปุ่ม export
  • ปุ่มสร้างกลุ่มใหม่ในหน้ารายการโหมด Filter จะพาไปฟอร์มแบบหลายแหล่งเป็นค่าเริ่มต้น ส่วนฟอร์มแบบแหล่งเดียวยังเข้าถึงได้จากลิงก์ในหน้าผลตอบแบบฟอร์มของ Form Builder

Business Flow​

1. หน้ารายการ (ใช้ร่วมกัน CSV และ Filter)​

  1. เปิดหน้ารายการตามโหมดที่ต้องการ ระบบเลือกชุดคอลัมน์และปุ่มให้อัตโนมัติจากโหมดนั้น
  2. โหมด Filter จะโหลดการตั้งค่ารอบ refresh ของ LINE OA เพิ่มด้วย แล้วแสดงป้ายข้างหัวข้อว่าเปิด auto refresh อยู่หรือไม่ และตั้งรอบไว้กี่นาที
  3. กรองข้อมูลได้ด้วยคำค้นและสถานะ (completed / processing) โดยการค้นหามีการหน่วงเวลาเล็กน้อยเพื่อลดจำนวนคำขอ และมีปุ่มล้างค่า
  4. คอลัมน์ร่วมของทั้งสองโหมด ได้แก่ ลำดับ ชื่อ audience (คลิกเข้าหน้ารายละเอียด) ระบบต้นทาง จำนวนสมาชิก (สำเร็จเทียบกับทั้งหมด) สถานะ วันที่สร้าง และปุ่มดำเนินการ
    • โหมด CSV เพิ่มคอลัมน์คำอธิบายและชื่อไฟล์
    • โหมด Filter เพิ่มคอลัมน์สวิตช์ auto refresh และเวลาที่คำนวณล่าสุด (แสดงสถานะกำลังประมวลผล หรือ "ยังไม่เคย" ถ้ายังไม่มีข้อมูล)
  5. ปุ่มดำเนินการต่างกันตามโหมด
    • CSV: แก้ไข และลบ
    • Filter: สั่งคำนวณใหม่ทันที ทำสำเนาไปยังฟอร์มแบบหลายแหล่ง และลบ (ลบได้เฉพาะรายการที่คำนวณเสร็จแล้ว)
  6. การเปิด/ปิด auto refresh บันทึกทันทีจากสวิตช์ในตาราง ส่วนการลบต้องยืนยันผ่านกล่องข้อความก่อน

2. โหมดอัปโหลด CSV​

  1. เปิดฟอร์มเพื่อสร้างใหม่หรือแก้ไขรายการเดิม โหมดแก้ไขจะโหลดชื่อ คำอธิบาย และข้อมูลไฟล์เดิมมาแสดง
  2. กรอกชื่อและคำอธิบาย (บังคับทั้งคู่) แล้วลากไฟล์ CSV ลงพื้นที่อัปโหลด (บังคับเฉพาะตอนสร้างใหม่) หน้าจอมีคำแนะนำการเตรียมไฟล์ 5 ข้อ พร้อมรูปตัวอย่างและปุ่มดาวน์โหลดไฟล์ต้นแบบ
  3. ระบบตรวจไฟล์ฝั่งหน้าจอทันทีก่อนส่ง โดยตรวจว่าเป็นไฟล์ CSV จริง แล้วอ่านทีละบรรทัดเพื่อหาแถวว่าง รหัสผู้ใช้ซ้ำ และรหัสผู้ใช้ผิดรูปแบบ (ต้องขึ้นต้นด้วย U และยาว 33 ตัวอักษร ส่วนแถวหัวตารางจะถูกข้าม)
  4. หากพบข้อผิดพลาด ระบบเปิดกล่องแสดงรายการแถวที่มีปัญหาพร้อมคำอธิบาย และไม่รับไฟล์นั้นไว้ ผู้ใช้ต้องแก้ไฟล์แล้วอัปโหลดใหม่
  5. เมื่อผ่านการตรวจ ระบบเปิดกล่องยืนยันที่ระบุจำนวนรหัสผู้ใช้ที่วิเคราะห์ได้ (โหมดแก้ไขจะถามยืนยันการแทนที่รายชื่อเดิมทั้งหมด)
  6. เมื่อยืนยัน ระบบส่งไฟล์พร้อมข้อมูลประกอบขึ้นเซิร์ฟเวอร์ แล้วพากลับหน้ารายการ
  7. กรณี backend ตรวจพบข้อผิดพลาดเพิ่มเติมในไฟล์ ระบบจะแปลงกลับเป็นรายการข้อผิดพลาดรายแถวและแสดงในกล่องเดียวกันกับการตรวจฝั่งหน้าจอ
note

โหมดแก้ไขออกแบบมาสำหรับการแนบไฟล์ใหม่ทับของเดิม การกดบันทึกโดยไม่แนบไฟล์ใหม่จึงควรหลีกเลี่ยง

3. โหมด Filter แบบแหล่งเดียว​

  1. กรอกชื่อ audience แล้วเลือกประเภทเงื่อนไข 1 อย่างจาก 5 ตัวเลือก ได้แก่ แคมเปญ, Rich Menu, activity tag, Auto Response และฟอร์ม การเปลี่ยนประเภทจะล้างค่าที่กรอกไว้ของประเภทเดิม
  2. แต่ละประเภทจะแสดงส่วนตั้งค่าของตัวเองพร้อมโหลดตัวเลือกที่เกี่ยวข้อง
    • แคมเปญ — เลือกแคมเปญแล้วติ๊ก tracking spot ที่ต้องการ โดยแยกระหว่างการมองเห็น (รูป/วิดีโอ) กับการคลิก (ลิงก์/ปุ่ม) และเลือกความสัมพันธ์ AND/OR ระหว่าง spot
    • Rich Menu — เลือกชนิดเมนูก่อน (guest / member / custom / switch) แล้วจึงเลือกเมนูและ spot
    • Activity tag — ติ๊กช่วงความเคลื่อนไหว 4 แบบ ตั้งแต่ใช้งานวันนี้จนถึงไม่ใช้งานเกิน 30 วัน
    • Auto Response — เลือกกฎตอบกลับอัตโนมัติได้หลายรายการ
    • ฟอร์ม — เลือกฟอร์ม แล้วสร้างกลุ่มเงื่อนไขจากคำถามในฟอร์มได้สูงสุด 5 กลุ่ม
  3. ระบบแสดงตัวอย่างรายชื่อที่เข้าเงื่อนไขให้เห็นก่อนสร้าง โดยประเภททั่วไปจะคำนวณให้อัตโนมัติเมื่อเงื่อนไขเปลี่ยน ส่วนประเภทฟอร์มต้องกดปุ่มค้นหาในส่วนตั้งค่าเอง
  4. ตัวอย่างรายชื่อแสดงลำดับ รหัสผู้ใช้ ชื่อที่แสดง และประเภทผู้ใช้ พร้อมสรุปเงื่อนไขที่เลือกไว้ด้านบน
  5. ปุ่มสร้างจะใช้งานไม่ได้จนกว่าตัวอย่างรายชื่อจะมีอย่างน้อย 1 รายการ
  6. เมื่อกดสร้างสำเร็จ ระบบพากลับหน้ารายการ หากเซิร์ฟเวอร์แจ้งข้อผิดพลาดรายฟิลด์ ระบบจะแสดงข้อความใต้ฟิลด์ที่เกี่ยวข้อง

4. โหมด Filter แบบหลายแหล่ง​

  1. โครงสร้างข้อมูลคือ audience หนึ่งชุดประกอบด้วยหลาย กลุ่ม และแต่ละกลุ่มประกอบด้วยหลาย แหล่งข้อมูล (source) โดยกำหนดตัวเชื่อม AND/OR ได้ทั้งระหว่างกลุ่มและระหว่าง source ภายในกลุ่ม
  2. เพิ่ม source ได้ 7 ชนิด ได้แก่ แคมเปญ, Rich Menu, activity tag, Auto Response, ฟอร์ม, custom attribute และ Loyalty โดยแต่ละชนิดมีค่าตั้งต้นของตัวเอง
  3. แต่ละ source แสดงเป็นการ์ดที่พับเก็บได้ มีสวิตช์เปิด/ปิดใช้งานชั่วคราวและปุ่มลบ การ์ดจะโหลดตัวเลือกของตัวเองเมื่อถูกใช้งานเท่านั้น
    • แคมเปญ — ติ๊กการมองเห็นและเลือก spot ได้ทีละหลายรายการ พร้อมกำหนด AND/OR ภายใน source (spot ที่ติดตามไม่ได้จะถูกปิดไว้)
    • Rich Menu — เลือกชนิดเมนูแล้วเลือกเมนูและ spot
    • Activity tag — ติ๊กช่วงความเคลื่อนไหวพร้อมตัวเชื่อม AND/OR
    • Auto Response — เลือกได้หลายรายการแต่ไม่เกิน 5 รายการต่อ source
    • ฟอร์ม — เลือกฟอร์มแล้วสร้างเงื่อนไขจากคำถาม (คำถามที่นำมาสร้างเงื่อนไขไม่ได้จะถูกกรองออก) ชนิดของช่องกรอกค่าจะเปลี่ยนตามชนิดคำถาม เช่น วันที่ ตัวเลข ตัวเลือก หรือข้อความ และรองรับเงื่อนไขแบบช่วง
    • Custom attribute — เลือก attribute ที่เปิดให้กรองได้ แบ่งกลุ่มเป็นข้อมูลโปรไฟล์ผู้ใช้และ attribute ที่สร้างเอง โดยตัวดำเนินการเปลี่ยนตามชนิดข้อมูล (ข้อความ ตัวเลข วันที่ ค่าจริงเท็จ)
    • Loyalty — เลือกตัวชี้วัด 1 อย่างต่อ source เช่น ยอดคงเหลือ แต้มที่ได้รับ แต้มที่ใช้ ยอดใช้จ่าย ระดับสมาชิก จำนวนบัตรที่สะสมครบ หรือจำนวนวันตั้งแต่ได้แต้มล่าสุด พร้อมตัวดำเนินการเปรียบเทียบ
  4. แผงด้านขวาแสดงไดอะแกรมแบบ Venn ที่วาดใหม่ทันทีตามโครงสร้างที่กำลังสร้าง ช่วยให้เห็นชัดว่า AND/OR ที่เลือกไว้ให้ผลลัพธ์เป็นเซตแบบใด
  5. กดปุ่มดูตัวอย่างผลลัพธ์เพื่อคำนวณ ระบบจะคืนจำนวนรวม รายชื่อ 10 รายการแรก และจำนวนที่แต่ละ source เข้าเงื่อนไข
  6. ตารางตัวอย่างแสดงรูปโปรไฟล์ ชื่อที่แสดง รหัสผู้ใช้ที่คัดลอกได้ ป้ายบอกว่าตรงกับ source ใดบ้าง และประเภทผู้ใช้ หากมี source ประเภทฟอร์มเปิดใช้งานอยู่ จะมีคอลัมน์เพิ่มให้เปิดดูคำตอบล่าสุดของผู้ใช้รายนั้น
  7. ปุ่มสร้างจะเปิดใช้งานก็ต่อเมื่อกดดูตัวอย่างผลลัพธ์สำเร็จแล้ว และการสร้างต้องมีชื่อ audience พร้อม source ที่เปิดใช้งานอย่างน้อย 1 รายการ
  8. รองรับการเปิดฟอร์มพร้อมเงื่อนไขตั้งต้นที่ส่งมาจากหน้าอื่น (ปัจจุบันคือหน้า Segments ของโมดูล Loyalty) โดยระบบจะแจ้งเตือนเมื่อโหลดเงื่อนไขตั้งต้นสำเร็จ และเปิดฟอร์มเปล่าให้แทนหากข้อมูลไม่ถูกต้อง

5. หน้ารายละเอียด audience​

  1. เปิดจากชื่อ audience ในหน้ารายการ ระบบโหลดข้อมูล 3 ส่วนพร้อมกัน ได้แก่ ข้อมูล audience, Trigger Rule ที่อ้างถึง audience นี้ และรายชื่อสมาชิก
  2. ถ้า audience สร้างจาก filter จะมีการ์ด "กฎที่ใช้กรอง" อธิบายเงื่อนไขเป็นข้อความอ่านง่าย กรณีหลายแหล่งจะไล่แสดงทีละกลุ่มพร้อมตัวเชื่อมระหว่างกลุ่ม และมีปุ่มเปิดเงื่อนไขชุดนั้นในตัวสร้าง filter ต่อได้
  3. ถ้ามี Trigger Rule ผูกอยู่ จะมีการ์ดแสดงรายการกฎพร้อมลิงก์ไปยังกฎนั้นและป้ายบอกชนิด action กับสถานะ
  4. ตารางสมาชิกแสดงลำดับ รหัสผู้ใช้ (ลิงก์ไปหน้ารายละเอียดเพื่อนใน Report) ชื่อที่แสดงพร้อมรูป ชื่อ นามสกุล และสถานะการเป็นเพื่อน โดยกรองด้วยคำค้นและสถานะได้
  5. ส่งออกข้อมูลได้ 2 แบบ คือ export รายชื่อพื้นฐาน และ export พร้อม attribute ของผู้ใช้เป็นไฟล์ CSV

6. การเลือก audience จากโมดูลอื่น​

  1. โมดูลปลายทางเรียกรายการ audience ทั้งหมดผ่านบริการกลางเดียวกัน จึงเห็น audience ทุกโหมดเหมือนกัน
  2. มีคอมโพเนนต์ตัวเลือก audience แบบเลือกหลายรายการให้ใช้ร่วม (src/components/common/audience-select.tsx) โดยผู้เรียกกำหนดข้อความ placeholder เองได้ เพราะความหมายของ "ไม่เลือกอะไรเลย" ต่างกันในแต่ละบริบท
  3. บางโมดูลที่ต้องการค้นหาแบบแบ่งหน้า เช่น Campaign Management จะเรียกรายการ audience ด้วยบริการของตัวเองแทน

หน้าจอและองค์ประกอบหลัก​

หน้ารายการ (/audience/csv, /audience/filter)​

  • แถบกรอง — ช่องค้นหาชื่อและตัวเลือกสถานะ พร้อมปุ่มค้นหาและล้างค่า
  • ป้ายสถานะ auto refresh — แสดงข้างหัวข้อในโหมด Filter บอกว่ารอบคำนวณอัตโนมัติเปิดอยู่หรือไม่
  • ตารางรายการ — คอลัมน์ร่วมพร้อมคอลัมน์เฉพาะโหมด และปุ่มดำเนินการที่ต่างกันตามโหมด

ไฟล์อ้างอิงหลัก: src/app/audience/csv/page.tsx, src/app/audience/filter/page.tsx, src/components/audience/csv/csv-table.container.tsx

ฟอร์มอัปโหลด CSV (/audience/csv/form)​

  • ฟอร์มข้อมูลหลัก — ชื่อและคำอธิบาย
  • พื้นที่ลากวางไฟล์ — รับเฉพาะไฟล์ CSV พร้อมส่วนคำแนะนำและปุ่มดาวน์โหลดไฟล์ต้นแบบ
  • กล่องแสดงข้อผิดพลาดของไฟล์ — ตารางระบุแถวและสาเหตุ
  • กล่องยืนยันก่อนบันทึก — สรุปจำนวนรหัสผู้ใช้ที่อ่านได้

ไฟล์อ้างอิงหลัก: src/components/audience/csv/csv-form.container.tsx, src/components/audience/csv/csv-form.tsx

ฟอร์ม Filter แบบแหล่งเดียว (/audience/filter/form)​

  • ส่วนหัวฟอร์ม — ชื่อ audience และตัวเลือกประเภทเงื่อนไข
  • ส่วนตั้งค่าตามประเภท — คอมโพเนนต์แยกต่อประเภท (section-campaign.tsx, section-rich-menu.tsx, section-activity-tag.tsx, section-auto-response.tsx, section-form-builder.tsx)
  • ตารางตัวอย่างรายชื่อ — พร้อมส่วนสรุปเงื่อนไขที่เลือก

ไฟล์อ้างอิงหลัก: src/components/audience/filter/filter-form.container.tsx, src/components/audience/filter/filter-table.tsx

ฟอร์ม Filter แบบหลายแหล่ง (/audience/filter/multi-source/form)​

  • ตัวสร้างเงื่อนไข (ซ้าย) — ชื่อ audience, ตัวเชื่อมระหว่างกลุ่ม, การ์ดกลุ่ม และเมนูเพิ่ม source
  • การ์ด source — ฟอร์มย่อยที่เปลี่ยนตามชนิดของ source (source-entry-card.tsx)
  • ไดอะแกรม Venn (ขวา) — ภาพประกอบเซตที่วาดด้วย SVG อัปเดตสดตามเงื่อนไข
  • ตารางตัวอย่างผลลัพธ์ — สรุปจำนวนต่อ source, รายชื่อ 10 รายการแรก และกล่องดูคำตอบฟอร์ม

ไฟล์อ้างอิงหลัก: src/components/audience/filter/multi-source-filter-form.container.tsx, src/components/audience/filter/multi-source-filter-table.tsx, src/components/audience/filter/components/multi-source-visualizer.tsx

หน้ารายละเอียด (/audience/csv/detail)​

  • การ์ดกฎที่ใช้กรอง — สรุปเงื่อนไขเป็นข้อความ พร้อมปุ่มเปิดในตัวสร้าง filter
  • การ์ด Trigger Rule — กฎที่อ้างถึง audience นี้
  • ตารางสมาชิก — พร้อมตัวกรองและปุ่ม export 2 แบบ

ไฟล์อ้างอิงหลัก: src/components/audience/csv-detail-table/filter-detail-table.container.tsx

บริการฝั่ง API​

src/services/audience.service.ts — จัดการตัว audience เอง

ความสามารถEndpoint
ดึงรายการ audienceGET /audiences
ดึงข้อมูลรายตัวGET /audiences/{id}
สร้าง / แก้ไข / ลบPOST /audiences, PUT /audiences/{id}, DELETE /audiences/{id}
เปิด/ปิด auto refreshPATCH /audiences/{id}/auto-refresh
สั่งคำนวณใหม่ทันทีPOST /audiences/{id}/refresh
อ่านรอบ refresh ของ LINE OAGET /line-oa/{lineOaId}/audience-refresh-settings
ดึงรายชื่อสมาชิกGET /audiences/{id}/member
ส่งออกสมาชิกพร้อม attributeGET /audiences/{id}/export-detail

src/services/audience-filter.service.ts — สร้างและ preview เงื่อนไข filter

ความสามารถEndpoint
ตัวเลือกแคมเปญ / Rich Menu / Auto Response / ฟอร์มGET /audiences-filter/list-dropdown-campaign, .../list-dropdown-richmenu, .../list-dropdown-auto-response, .../list-dropdown-form-builder
preview เงื่อนไขจากฟอร์มPOST /audiences-filter/preview-form-filter
สร้าง filter แบบแหล่งเดียวPOST /audiences-filter/create-filter
สร้าง filter จากฟอร์มPOST /audiences-filter/create-form-filter
preview filter หลายแหล่งPOST /audiences-filter/preview-multi-source-filter
สร้าง filter หลายแหล่งPOST /audiences-filter/create-multi-source-filter
ดูคำตอบฟอร์มของผู้ใช้GET /audiences-filter/form-response

นอกจากนี้โมดูลยังเรียกใช้บริการอื่นเพื่อประกอบข้อมูล ได้แก่ การ preview รายชื่อของ filter แบบแหล่งเดียว (POST /tracking-line-users), รายการ attribute ที่กรองได้ (GET /attribute-master/filterable), ระดับสมาชิก Loyalty (GET /loyalty/tiers) และ Trigger Rule ที่ผูกกับ audience (GET /trigger-rule/by-audience/{audienceId})

จุดเชื่อมต่อกับฟีเจอร์อื่น​

  • สิทธิ์การใช้งาน — เมนู Audience และเมนูย่อยทั้งสามโหมดปลดล็อกพร้อมกันจากสิทธิ์โมดูล audiences ฝั่ง backend โดยเมนูด้านข้างและ Quick Access ตรวจสิทธิ์นี้ก่อนแสดงผล
  • ฟีเจอร์ที่เป็นแหล่งข้อมูลเข้า (ใช้สร้าง audience)
    • Campaign และ Rich Message — ให้ข้อมูล tracking spot ทั้งฝั่งการมองเห็นและการคลิก
    • Rich Menu — ให้รายการเมนูและ spot แยกตามชนิดเมนู
    • Auto Response — ให้รายการกฎตอบกลับที่ใช้เป็นเงื่อนไขได้
    • Form Builder — ให้คำถามและคำตอบสำหรับสร้างเงื่อนไข รวมถึงลิงก์เข้าฟอร์ม filter จากหน้าผลตอบแบบฟอร์ม
    • Attribute Setup — ให้รายการ custom attribute ที่เปิดให้กรองได้
    • Loyalty — ให้ตัวชี้วัดและระดับสมาชิก รวมถึงส่งเงื่อนไขตั้งต้นมาจากหน้า Segments
  • ฟีเจอร์ที่นำ audience ไปใช้ต่อ — Campaign Management, Trigger Rule, Workflow Automation, Rich Menu (เมนูเริ่มต้น), Content Management, Content Links, Menu Builder, หมวดหมู่ Bulletin และรายงานเพื่อนทั้งหมด
  • Trigger Rule — หน้ารายละเอียด audience แสดงกฎที่อ้างถึง audience นี้ เพื่อให้เห็นผลกระทบก่อนแก้ไขหรือลบ
  • โครงสร้างพื้นฐานร่วม — ใช้ระบบยืนยันตัวตนและ HTTP client กลางของ CMS (ออกจากระบบอัตโนมัติเมื่อ token หมดอายุ) ระบบ breadcrumb และเมนูด้านข้าง ชุด modal มาตรฐาน และข้อมูลโปรไฟล์ผู้ใช้สำหรับอ้างอิง LINE OA ปัจจุบัน
  • ไฟล์ประกอบแบบ static — ไฟล์ต้นแบบ CSV ที่ /template/audiences_template.csv และรูปตัวอย่างในส่วนคำแนะนำการอัปโหลด

รายละเอียดฝั่ง Backend (CMS API)​

ฝั่ง backend แยกเป็นสองโมดูลที่ทำงานร่วมกัน คือ internal/modules/audience/ (ตัว audience และรายชื่อสมาชิก) และ internal/modules/audiencefilter/ (เครื่องมือสร้าง audience จากเงื่อนไข)

จุดสำคัญที่สุด — สมาชิกไม่ได้เก็บเป็นแถวในฐานข้อมูล​

รายชื่อสมาชิกของ audience ถูกเก็บเป็นไฟล์ CSV บน object storage (MinIO/S3) ไม่ใช่แถวในตาราง เพื่อรองรับสมาชิกจำนวนมหาศาลโดยไม่ทำให้ฐานข้อมูลบวม สิ่งที่ตามมาคือ

  • การเปิดดูสมาชิกในหน้ารายละเอียด (GET /api/audiences/:id/member) เป็นการ อ่านไฟล์ CSV กลับมาแบ่งหน้า ผ่านเครื่องมืออ่าน CSV ของระบบ ไม่ใช่การ query ฐานข้อมูล และผลลัพธ์ถูก cache ไว้ราว 30 วินาที การกดรีเฟรชถี่ ๆ จึงอาจเห็นตัวเลขเดิม
  • การ export (GET /api/audiences/:id/export และ export-detail) เป็นการ stream ข้อมูลตรงลง response ไม่ได้สร้างไฟล์รอไว้ให้ดาวน์โหลดทีหลัง
  • ตัวเลข "จำนวนสมาชิก" ที่เห็นในตารางมาจากข้อมูลสรุปที่บันทึกไว้ตอนคำนวณ ไม่ได้นับใหม่ทุกครั้งที่เปิดหน้า

สิทธิ์ที่ต้องมี​

  • route ของโมดูล audience ถูกครอบด้วย module gate ของโมดูล audiences ทั้งหมด
  • policy แยกตามการกระทำ โดยมี export เป็นสิทธิ์แยกต่างหาก จาก read — ผู้ที่ดูรายชื่อได้ไม่จำเป็นต้องส่งออกไฟล์ได้
  • การเปิด/ปิด auto refresh และการสั่งคำนวณใหม่ทันที ใช้สิทธิ์ update เพราะถือเป็นการแก้ไข audience
  • ข้อสังเกต — route ของโมดูล audience filter อยู่บนกลุ่มที่ต้องผ่าน JWT กลางเท่านั้น ไม่ได้ครอบด้วย module gate และ policy ที่ประกาศไว้ยังเป็นเพียงข้อมูลกำกับ นอกจากนี้ endpoint สร้าง audience จากเงื่อนไขแบบฟอร์มยังประกาศ policy เป็น read ทั้งที่ผลลัพธ์คือการสร้างข้อมูลใหม่ ต่างจาก endpoint สร้างแบบหลายแหล่งที่ใช้ create — เป็นความไม่สอดคล้องที่ควรทราบ

Validation และ Business Rule ที่ backend ตรวจ​

  • ตรวจโควตาจำนวน audience ก่อนสร้างเสมอ (ค่า maxSegments ของแพ็กเกจ) ทั้งการสร้างจาก CSV และการสร้างจากเงื่อนไข การสร้างจึงถูกปฏิเสธได้แม้ข้อมูลถูกต้องครบ
  • ชื่อ audience ห้ามซ้ำ ถ้าซ้ำ backend ตอบกลับด้วยรหัสข้อผิดพลาดเฉพาะ (AUD_001)
  • การเปิด auto refresh ต้องได้รับสิทธิ์จากแพ็กเกจด้วย ไม่ใช่แค่มีสิทธิ์แก้ไข ถ้าแพ็กเกจไม่รวมความสามารถนี้ สวิตช์จะเปิดไม่ได้
  • endpoint สร้าง audience รับข้อมูลแบบ multipart/form-data เพราะต้องรับไฟล์ CSV มาพร้อมข้อมูลฟอร์ม
  • ระบบมีรหัสข้อผิดพลาดเฉพาะเพื่อให้หน้าจอแยกกรณีได้: ชื่อซ้ำ, รายการที่อ้างไม่ใช่ audience, ไฟล์ CSV ไม่ถูกต้อง, ส่งออกไม่ได้ และไม่พบผู้ใช้ LINE

สิ่งที่บันทึกและผลข้างเคียง (Side Effect)​

  • การสร้าง แก้ไข และลบ audience ไม่ได้ทำงานให้เสร็จในทันที แต่ publish งานลงคิว (create_audience, update_audience, delete_audience) ให้ line-management-worker-go เป็นผู้สร้างหรือปรับไฟล์สมาชิกจริง นี่คือเหตุผลที่สถานะของ audience มีค่า "กำลังประมวลผล" และรายการที่ยังไม่เสร็จจึงลบไม่ได้
  • มีงานตามเวลาทำงานทุกนาที เพื่อหาว่ามี audience ใดครบกำหนด auto refresh แล้วส่งงานลงคิว audience_refresh งานนี้ใช้ ล็อกบน Redis เพื่อกันไม่ให้ระบบที่รันหลายชุดพร้อมกัน (replica) ทำงานซ้อนกัน
  • การเข้า/ออกของสมาชิกถูกบันทึกเป็น audit log ในตาราง audience_member_log และยัง publish เป็นเหตุการณ์ลงคิว audience_membership_trigger ให้ Trigger Rule และ Workflow นำไปสั่งงานต่อ การแก้สมาชิก audience จึงอาจกระตุ้นการส่งข้อความออกไปโดยอ้อม
  • ตารางที่เกี่ยวข้องหลัก ๆ ได้แก่ audience, audience_member_log, line_user, line_oa และ organization
  • ฝั่ง audience filter ผลลัพธ์ที่คำนวณได้จะถูกเขียนเป็นไฟล์ CSV ลง storage แล้วกลายเป็น audience ปกติที่โมดูล audience ดูแลต่อ (มี auto refresh ได้เหมือนกัน)

เส้นทางภายในระบบที่ไม่ผ่านการล็อกอิน​

  • โมดูล audience filter เปิด endpoint POST /api/audiences-filter/internal/refresh ไว้สำหรับ service อื่นเรียก ไม่ใช่ผู้ใช้ เช่นตอน worker หรือ webhook ต้องสั่งคำนวณสมาชิกของ audience ที่มาจากเงื่อนไขใหม่
  • endpoint นี้ ไม่ได้ป้องกันด้วย JWT แต่ใช้กุญแจลับที่ส่งมาทาง header (X-Internal-Key) เทียบกับค่าที่ตั้งไว้ในตัวแปรสภาพแวดล้อม
  • ข้อสังเกตด้านความปลอดภัย — เพราะเป็นการยืนยันตัวตนด้วยคีย์เดียวที่ใช้ร่วมกัน หากคีย์นี้รั่ว ผู้ที่ได้ไปจะสั่งคำนวณ audience ขององค์กรใดก็ได้โดยไม่ต้องล็อกอิน จึงไม่ควรเปิด endpoint นี้ออกสู่อินเทอร์เน็ตสาธารณะ

Edge Case และข้อสังเกตที่ควรรู้​

  • เพราะการสร้างและอัปเดตเป็นงานที่วิ่งผ่านคิว การกดบันทึกสำเร็จไม่ได้แปลว่ารายชื่อสมาชิกพร้อมใช้แล้ว โมดูลที่นำ audience ไปยิงข้อความต่อควรตรวจสถานะว่าคำนวณเสร็จก่อน
  • ถ้า worker ไม่ทำงานหรือคิวติดขัด audience จะค้างอยู่ในสถานะกำลังประมวลผลตลอดไป โดยที่ฝั่ง CMS ไม่มีอาการผิดพลาดใด ๆ ให้เห็น
  • งาน auto refresh ทำงานทุกนาทีสำหรับทั้งระบบ ไม่ใช่ต่อ audience — audience ที่ตั้งรอบถี่มากจำนวนมากจะแย่งทรัพยากรกันในรอบเดียวกัน
  • โมดูล audience filter เรียกใช้ข้อมูลฟอร์มจาก Form Builder ผ่านหน้าตัดที่ประกาศไว้เฉพาะ เพื่อเลี่ยงการอ้างอิงวนกันระหว่างโมดูล การเพิ่มความสามารถที่ต้องใช้ข้อมูลฟอร์มเพิ่มจึงต้องขยายหน้าตัดนี้ด้วย