Skip to main content

ระบบจองนัดหมาย

รายละเอียดคอลัมน์ของ schema appointment ทั้งหมด (location/service/staff/journey/booking)

ภาพรวม

Schema appointment มี 5 ตาราง เรียงตามลำดับการอ้างอิงคือ location (สาขา) → service (บริการที่จองได้) / staff (ผู้ให้บริการ) / journey (การตั้งค่า flow การจองพร้อม token สำหรับเปิด LIFF) แล้วปลายทางคือ booking (การจองจริง) schema นี้ apply แยกด้วย psql ไม่ผ่าน Prisma (migration 001-004)

ตาราง appointment.location

ColumnTypeNullableDefaultคำอธิบาย
idSERIALNOauto incrementPrimary key
line_oa_idINTEGERNO-LINE OA ที่สาขานี้สังกัด
organization_idINTEGERNO-องค์กรเจ้าของข้อมูล
nameVARCHAR(255)NO-ชื่อสาขา
descriptionTEXTYES-คำอธิบายสาขา
addressTEXTYES-ที่อยู่สาขา
phoneVARCHAR(50)YES-เบอร์โทรติดต่อ
working_hoursJSONBNO'{}'เวลาทำการรายวัน ใช้คำนวณ slot ที่จองได้
blocked_datesJSONBYES'[]'วันที่ปิดทำการ/ไม่รับจอง
timezoneVARCHAR(50)NO'Asia/Bangkok'ไทม์โซนของสาขา
statusVARCHAR(20)NO'active'สถานะการใช้งาน
sort_orderINTEGERNO0ลำดับการแสดงผล
created_byINTEGERYES-ผู้สร้างเรกคอร์ด
updated_byINTEGERYES-ผู้แก้ไขล่าสุด
created_dateTIMESTAMPTZ(3)NOCURRENT_TIMESTAMPวันเวลาที่สร้าง
updated_dateTIMESTAMPTZ(3)YES-วันเวลาที่แก้ไขล่าสุด
deleted_dateTIMESTAMPTZ(3)YES-วันเวลาที่ soft delete

ตาราง appointment.service

ColumnTypeNullableDefaultคำอธิบาย
idSERIALNOauto incrementPrimary key
location_idINTEGERNO-FK ไปยัง appointment.location(id) ลบแบบ CASCADE
line_oa_idINTEGERNO-LINE OA ที่บริการนี้สังกัด
organization_idINTEGERNO-องค์กรเจ้าของข้อมูล
nameVARCHAR(255)NO-ชื่อบริการ
descriptionTEXTYES-คำอธิบายบริการ
duration_minutesINTEGERNO30ระยะเวลาให้บริการ (นาที) ใช้คำนวณเวลาสิ้นสุด
max_bookings_per_slotINTEGERNO1จำนวนการจองสูงสุดต่อหนึ่งช่วงเวลา
requires_staffBOOLEANNOfalseบริการนี้ต้องระบุผู้ให้บริการหรือไม่
priceDECIMAL(10,2)YES-ราคาบริการ
currencyVARCHAR(10)YES'THB'สกุลเงินของราคา
statusVARCHAR(20)NO'active'สถานะการใช้งาน
sort_orderINTEGERNO0ลำดับการแสดงผล
created_byINTEGERYES-ผู้สร้างเรกคอร์ด
created_dateTIMESTAMPTZ(3)NOCURRENT_TIMESTAMPวันเวลาที่สร้าง
updated_dateTIMESTAMPTZ(3)YES-วันเวลาที่แก้ไขล่าสุด
deleted_dateTIMESTAMPTZ(3)YES-วันเวลาที่ soft delete

ตาราง appointment.staff

ColumnTypeNullableDefaultคำอธิบาย
idSERIALNOauto incrementPrimary key
location_idINTEGERNO-FK ไปยัง appointment.location(id) ลบแบบ CASCADE
line_oa_idINTEGERNO-LINE OA ที่ผู้ให้บริการนี้สังกัด
organization_idINTEGERNO-องค์กรเจ้าของข้อมูล
nameVARCHAR(255)NO-ชื่อผู้ให้บริการ
titleVARCHAR(255)YES-ตำแหน่ง/คำนำหน้าที่แสดงคู่กับชื่อ
avatar_urlVARCHAR(500)YES-URL รูปประจำตัว
service_idsJSONBYES'[]'รายการ id ของบริการที่ผู้ให้บริการรายนี้รับได้
statusVARCHAR(20)NO'active'สถานะการใช้งาน
sort_orderINTEGERNO0ลำดับการแสดงผล
created_byINTEGERYES-ผู้สร้างเรกคอร์ด
created_dateTIMESTAMPTZ(3)NOCURRENT_TIMESTAMPวันเวลาที่สร้าง
updated_dateTIMESTAMPTZ(3)YES-วันเวลาที่แก้ไขล่าสุด
deleted_dateTIMESTAMPTZ(3)YES-วันเวลาที่ soft delete

ตาราง appointment.journey

ColumnTypeNullableDefaultคำอธิบาย
idSERIALNOauto incrementPrimary key
location_idINTEGERNO-FK ไปยัง appointment.location(id) ลบแบบ CASCADE
line_oa_idINTEGERNO-LINE OA ที่ flow นี้สังกัด
organization_idINTEGERNO-องค์กรเจ้าของข้อมูล
nameVARCHAR(255)NO-ชื่อ flow การจอง
descriptionTEXTYES-คำอธิบาย flow
tokenVARCHAR(64)NO-โทเคนสาธารณะที่ใช้เปิดหน้าจองผ่าน LIFF (unique)
auto_confirmBOOLEANNOtrueยืนยันการจองอัตโนมัติหรือรอผู้ดูแลอนุมัติ
stepsJSONBYES-นิยามขั้นตอน/ฟอร์มระหว่างการจอง
statusVARCHAR(20)NO'active'สถานะการใช้งาน
created_byINTEGERYES-ผู้สร้างเรกคอร์ด
created_dateTIMESTAMPTZ(3)NOCURRENT_TIMESTAMPวันเวลาที่สร้าง
updated_dateTIMESTAMPTZ(3)YES-วันเวลาที่แก้ไขล่าสุด
deleted_dateTIMESTAMPTZ(3)YES-วันเวลาที่ soft delete
reminder_hours_beforeINTEGERYES24ส่งการแจ้งเตือนล่วงหน้ากี่ชั่วโมงก่อนถึงนัด (migration 003)
no_show_grace_minutesINTEGERYES30ผ่อนผันกี่นาทีก่อนถือว่าลูกค้าไม่มาตามนัด (migration 003)

ตาราง appointment.booking

ColumnTypeNullableDefaultคำอธิบาย
idSERIALNOauto incrementPrimary key
journey_idINTEGERNO-FK ไปยัง appointment.journey(id) — flow ที่ใช้จอง
location_idINTEGERNO-FK ไปยัง appointment.location(id) — สาขาที่จอง
service_idINTEGERNO-FK ไปยัง appointment.service(id) — บริการที่จอง
staff_idINTEGERYES-FK ไปยัง appointment.staff(id) — ผู้ให้บริการ (ถ้าระบุ)
user_idVARCHAR(255)NO-LINE user id ของผู้จอง
line_oa_idINTEGERNO-LINE OA ที่การจองนี้สังกัด
organization_idINTEGERNO-องค์กรเจ้าของข้อมูล
booking_dateDATENO-วันที่นัดหมาย
start_timeTIMENO-เวลาเริ่มนัด
end_timeTIMENO-เวลาสิ้นสุดนัด
statusVARCHAR(20)NO'pending'สถานะการจอง
notesTEXTYES-หมายเหตุจากผู้จองหรือผู้ดูแล
form_dataJSONBYES-คำตอบจากฟอร์มที่กำหนดไว้ใน journey.steps
cancel_reasonTEXTYES-เหตุผลการยกเลิก
created_dateTIMESTAMPTZ(3)NOCURRENT_TIMESTAMPวันเวลาที่สร้าง
updated_dateTIMESTAMPTZ(3)YES-วันเวลาที่แก้ไขล่าสุด
confirmed_dateTIMESTAMPTZ(3)YES-วันเวลาที่ยืนยันการจอง
cancelled_dateTIMESTAMPTZ(3)YES-วันเวลาที่ยกเลิกการจอง
completed_dateTIMESTAMPTZ(3)YES-วันเวลาที่ให้บริการเสร็จสิ้น
reminder_sentBOOLEANYESfalseส่งการแจ้งเตือนล่วงหน้าไปแล้วหรือยัง (migration 003)

หมายเหตุ

  • Foreign key: service.location_id, staff.location_id, journey.location_id ทั้งสามตัว ชี้ไปยัง appointment.location(id) แบบ ON DELETE CASCADE — ลบสาขาแล้วข้อมูลลูกหายตามทั้งหมด ส่วน FK ทั้ง 4 ตัวใน booking (journey_id, location_id, service_id, staff_id) ไม่ตั้ง cascade เพื่อไม่ให้ลบ master data ทิ้งการจองที่มีอยู่จริง
  • Unique: appointment.journey.token เป็น unique ทั้งใน column constraint และ index idx_appt_journey_token เพราะเป็นกุญแจสาธารณะที่ใช้เปิดหน้าจอง
  • Partial index: index ของ location, service, staff, journey ที่กรองสถานะทั้งหมด มีเงื่อนไข WHERE deleted_date IS NULL — ตรงกับ query ที่มองเฉพาะแถวที่ยังไม่ถูก soft delete ส่วน idx_appt_booking_reminder มีเงื่อนไข WHERE reminder_sent = false เพื่อให้ worker ที่ไล่ส่งการแจ้งเตือนสแกนเฉพาะแถวที่ยังไม่ได้ส่ง
  • Trigger (migration 004): trg_booking_event_insert และ trg_booking_event_update บน appointment.booking เรียกฟังก์ชัน appointment.notify_booking_event() ซึ่งส่ง pg_notify ไปยัง channel booking_event (ชนิด booking_created เมื่อ INSERT และ booking_status_changed เมื่อ status เปลี่ยน) โดย pg-listener worker เป็นผู้รับ พร้อมกันนั้นจะพยายาม INSERT ลงตาราง event_outbox เพื่อความน่าเชื่อถือ และข้ามไปเงียบๆ ถ้ายังไม่มีตารางนั้น
  • booking.user_id เก็บ LINE user id เป็นสตริง ไม่ใช่ FK ไปยังตาราง line_user ใน schema public