แคมเปญส่งข้อความ
ภาพรวม
Domain นี้มี 2 ตาราง คือ campaign ซึ่งเก็บนิยามแคมเปญส่งข้อความ (ผู้รับ เนื้อหา เวลาส่ง สถานะ
และตัวเลขสรุปผล) และ campaign_delivery_batch ซึ่งเป็นตารางที่สร้างด้วย manual SQL สำหรับติดตาม
การส่งแบบแบ่ง batch ของแคมเปญ multicast โดยมี 1 แถวต่อ 1 batch
ตาราง campaign
| Column | Type | Nullable | Default | คำอธิบาย |
|---|---|---|---|---|
id | SERIAL (INTEGER) | NO | nextval(...) | รหัสอ้างอิงหลักของแคมเปญ |
name | TEXT | NO | - | ชื่อแคมเปญ |
broadcast_now | BOOLEAN | NO | - | ส่งทันทีหรือไม่ (false = ตั้งเวลาส่งตาม start_date) |
start_date | TIMESTAMPTZ(3) | NO | - | วันเวลาที่กำหนดให้เริ่มส่ง |
cast_type | "CastType" | YES | broadcast | รูปแบบการส่ง: broadcast, multicast, narrowcast |
audience_id | INTEGER | YES | - | กลุ่มเป้าหมายผู้รับ (FK ไป audience.id; NULL เมื่อส่ง broadcast ทั้งหมด) |
rich_message_id | INTEGER | NO | - | ข้อความที่ใช้ส่ง (FK ไป rich_message.id) |
line_oa_id | INTEGER | NO | - | รหัส LINE OA ที่ส่งแคมเปญ (FK ไป line_oa.id) |
organization_id | INTEGER | YES | 0 | รหัสองค์กรเจ้าของข้อมูล (FK ไป organization.id) |
status | "CampaignStatus" | NO | - | สถานะแคมเปญ: sent, scheduled, cancel, draft, failed, sending |
created_date | TIMESTAMPTZ(3) | NO | now() | วันเวลาที่สร้างรายการ |
created_by | INTEGER | NO | 0 | รหัสผู้ใช้ที่สร้างรายการ |
updated_date | TIMESTAMPTZ(3) | YES | - | วันเวลาที่แก้ไขล่าสุด (อัปเดตอัตโนมัติ) |
updated_by | INTEGER | YES | 0 | รหัสผู้ใช้ที่แก้ไขล่าสุด |
deleted_date | TIMESTAMPTZ(3) | YES | - | วันเวลาที่ลบแบบ soft delete |
reason | TEXT | YES | '' | เหตุผลประกอบสถานะ เช่น สาเหตุที่ยกเลิกหรือส่งไม่สำเร็จ |
rich_message_content | JSONB | YES | - | สำเนาเนื้อหาข้อความ ณ เวลาที่ส่ง (snapshot กันเนื้อหาต้นทางถูกแก้ภายหลัง) |
line_message_object | JSONB | YES | - | payload ที่ส่งเข้า LINE Messaging API จริง |
template_tracking | JSONB | YES | - | ข้อมูล mapping สำหรับติดตามการคลิกในแต่ละส่วนของข้อความ |
end_tracking_date | TIMESTAMPTZ(3) | YES | - | วันเวลาสิ้นสุดการเก็บสถิติการคลิกของแคมเปญ |
has_merge_tags | BOOLEAN | NO | false | ข้อความมีการใช้ merge tag (ตัวแปรส่วนบุคคล) หรือไม่ |
skip_merge_tag_missing | BOOLEAN | NO | false | ข้ามผู้รับที่ไม่มีค่าของ merge tag แทนที่จะส่งด้วยค่าว่าง |
total_activity | INTEGER | NO | 0 | จำนวน activity ที่เกิดจากแคมเปญนี้ทั้งหมด |
total_recipient | INTEGER | NO | 0 | จำนวนผู้รับที่ตั้งเป้าจะส่ง |
total_reach | INTEGER | NO | 0 | จำนวนผู้รับที่ส่งถึงจริง |
total_unique_click | INTEGER | NO | 0 | จำนวนผู้คลิกแบบไม่นับซ้ำ |
total_first_click | INTEGER | NO | 0 | จำนวนการคลิกครั้งแรกของผู้รับแต่ละคน |
claimed_at | TIMESTAMPTZ | YES | - | เวลาที่ worker จับจอง (claim) แคมเปญไปส่ง ใช้เป็นตัวจับ lease ของสถานะ sending |
ตาราง campaign_delivery_batch
ตารางนี้ไม่ได้อยู่ใน Prisma schema — สร้างด้วย manual-sql/8.campaign_delivery_batch.sql
เก็บ 1 แถวต่อ 1 batch การส่งของแคมเปญแบบ multicast โดย planner ของ worker เป็นผู้ insert,
worker ฝั่งส่งเป็นผู้ claim และอัปเดต และ batch สุดท้ายที่เสร็จจะเป็นตัวปิดงานแคมเปญ
| Column | Type | Nullable | Default | คำอธิบาย |
|---|---|---|---|---|
id | BIGSERIAL (BIGINT) | NO | nextval(...) | รหัสอ้างอิงหลักของ batch |
campaign_id | INTEGER | NO | - | รหัสแคมเปญที่ batch นี้สังกัด |
batch_no | INTEGER | NO | - | ลำดับที่ของ batch ภายในแคมเปญ |
user_count | INTEGER | NO | - | จำนวนผู้รับใน batch นี้ |
status | VARCHAR | NO | 'pending' | สถานะของ batch: pending, sending, done, failed |
sent_count | INTEGER | NO | 0 | จำนวนที่ส่งสำเร็จใน batch นี้ |
error_count | INTEGER | NO | 0 | จำนวนที่ส่งไม่สำเร็จ |
skipped_count | INTEGER | NO | 0 | จำนวนที่ถูกข้าม (เช่น merge tag ไม่ครบ) |
created_date | TIMESTAMPTZ | NO | now() | วันเวลาที่สร้าง batch |
updated_date | TIMESTAMPTZ | NO | now() | วันเวลาที่อัปเดต batch ล่าสุด |
หมายเหตุ
- FK ของ
campaign:audience_idไปaudience.id,rich_message_idไปrich_message.id,line_oa_idไปline_oa.id,organization_idไปorganization.idและถูกอ้างอิงกลับโดยtracking_log.campaign_id - Index ของ
campaign:line_oa_id,deleted_date - คอลัมน์
claimed_atเพิ่มภายหลังผ่านmanual-sql/8.campaign_claim.sqlพร้อมกับการเพิ่มค่าsendingเข้าไปใน enumCampaignStatus— สถานะsendingหมายถึงถูก worker จับจองแล้ว และclaimed_atเป็นตัวให้ reaper ตรวจว่าแถวไหนค้างเกิน lease แล้วดึงกลับไปเป็นscheduled campaign_delivery_batchมี unique constraintcampaign_delivery_batch_campaign_batch_uqบน (campaign_id,batch_no) — ใช้กันการ claim ซ้ำและทำให้ redelivery ส่งซ้ำได้ไม่เกิน 1 batchcampaign_delivery_batchมี indexcampaign_delivery_batch_campaign_status_idxบน (campaign_id,status) สำหรับตรวจว่าแคมเปญยังมี batch ค้างอยู่หรือไม่campaign_delivery_batch.campaign_idไม่ได้ประกาศเป็น FK constraint ในสคริปต์ (อ้างถึงcampaign.idเชิงตรรกะ)