ระบบจองนัดหมาย
ภาพรวม
แอปเสริมสำหรับ จองคิวและนัดหมาย ผ่าน LIFF โดยลูกค้าเลือกสาขา ตามด้วยบริการ ผู้ให้บริการ และวันเวลา แล้วได้รับการจองพร้อมการแจ้งเตือนล่วงหน้า
จุดสำคัญเชิงสถาปัตยกรรมคือตารางทั้งหมดอยู่ใน PostgreSQL schema แยกชื่อ appointment
ไม่ได้อยู่ใน public และ ไม่มีนิยามอยู่ใน Prisma เลย โดยใช้ไฟล์ SQL ที่เรียงลำดับหมายเลขของตัวเอง
และ apply ด้วย psql ซึ่งเป็นแนวทางเดียวกับแอป bulletin และ loyalty
โครงสร้างข้อมูลหลัก
appointment.location — สาขาหรือสถานที่
- ข้อมูลพื้นฐาน:
name,description,address,phone working_hoursแบบ JSONB เก็บเวลาทำการรายวัน และblocked_datesเก็บวันหยุดtimezone(ค่าเริ่มต้นAsia/Bangkok),sort_order,statusและ soft deletedeleted_date- ผูกขอบเขตด้วย
line_oa_idและorganization_id
appointment.service — บริการที่จองได้
location_idเป็น FK แบบON DELETE CASCADEduration_minutes(ค่าเริ่มต้น 30),max_bookings_per_slot(ค่าเริ่มต้น 1) และrequires_staffสามค่านี้คือตัวกำหนดการคำนวณช่วงเวลาว่าง- ราคา:
priceแบบ DECIMAL(10,2) และcurrency(ค่าเริ่มต้น THB)
appointment.staff — ผู้ให้บริการ
location_idเป็น FK พร้อมname,titleและavatar_urlservice_idsแบบ JSONB เก็บรายการบริการที่พนักงานคนนี้ทำได้ในรูปแบบอาเรย์ แทนการใช้ตารางเชื่อมแยกต่างหาก
appointment.journey — คอนฟิกขั้นตอนการจอง
หนึ่ง journey เท่ากับหนึ่งลิงก์จอง
tokenVARCHAR(64) แบบ unique ทำหน้าที่เป็นคีย์ใน URL ของ LIFFauto_confirm(ค่าเริ่มต้น true) และstepsแบบ JSONB นิยามลำดับขั้นตอนที่ลูกค้าเห็นreminder_hours_before(ค่าเริ่มต้น 24) และno_show_grace_minutes(ค่าเริ่มต้น 30)
appointment.booking — การจองจริง
- FK:
journey_id,location_id,service_idและstaff_id(เว้นว่างได้) user_idVARCHAR(255) คือ LINE userId ของผู้จอง- เวลา:
booking_dateแบบ DATE พร้อมstart_timeและend_timeแบบ TIME - สถานะ:
status(ค่าเริ่มต้นpending),notes,form_dataแบบ JSONB และcancel_reasonพร้อม timestamp ครบทุกสถานะ ได้แก่confirmed_date,cancelled_date,completed_date reminder_sentมาพร้อม partial index(status, reminder_sent, booking_date) WHERE reminder_sent = falseทำให้ cron หาการจองที่ยังไม่ได้แจ้งเตือนได้เร็ว- index
(location_id, booking_date, status)รองรับหน้าปฏิทินฝั่ง CMS
Trigger แจ้งเหตุการณ์การจอง
trg_booking_event_insert และ trg_booking_event_update เรียกฟังก์ชัน
appointment.notify_booking_event() ซึ่งยิง pg_notify ไปที่ช่อง booking_event
พร้อมบันทึกลง event_outbox แบบ best-effort โดยดักจับ undefined_table แล้วข้ามไปหากยังไม่มีตาราง
เหตุการณ์จะถูกยิงเมื่อสร้างการจองใหม่ (booking_created) และเมื่อ สถานะเปลี่ยนเท่านั้น
(booking_status_changed) ไม่ยิงทุกครั้งที่มีการอัปเดตแถว
ไฟล์ที่เกี่ยวข้อง
apps/appointment/migrations/001_create_schema.sql— คำสั่งCREATE SCHEMA appointmentapps/appointment/migrations/002_create_tables.sql— ตารางหลักทั้ง 5 ตารางapps/appointment/migrations/003_add_reminder_columns.sql— คอลัมน์ที่เกี่ยวกับการแจ้งเตือนapps/appointment/migrations/004_add_booking_event_trigger.sql—pg_notifyและ outboxschema-dumps/2026-07-24/schema.sql:26(CREATE SCHEMA appointment) และช่วง:582–:807
จุดเชื่อมต่อกับ Service อื่น
- client-api-go ให้บริการฝั่ง LIFF ของลูกค้า โดยคำนวณช่วงเวลาว่างจาก
working_hoursประกอบกับblocked_dates,duration_minutesและmax_bookings_per_slotก่อนสร้างการจอง - cms-api-go จัดการสาขา บริการ พนักงาน journey และหน้าปฏิทินการจอง
- worker-go ฟังช่อง
booking_eventเพื่อส่งการแจ้งเตือนผ่าน LINE และเป็นจุดตั้งต้นของ trigger rule รวมถึงรัน cron ส่ง reminder ตามเวลาที่ตั้งไว้ - การเปิดใช้แอปควบคุมด้วย
line_oa_app.app_idใน ช่องทาง LINE OA ส่วนเหตุการณ์ทั้งหมดไหลไปที่ pg_notify และ Event Outbox