Skip to main content

แอปนัดหมาย (Appointment)

ภาพรวม

แอปนัดหมาย (Appointment) เป็นหนึ่งใน "Apps" ซึ่งเป็นโมดูลเสริมที่ผู้ดูแลระดับแพลตฟอร์มเปิดหรือปิดให้แต่ละองค์กรได้ ไม่ได้ควบคุมด้วยระบบสิทธิ์ตามบทบาทเหมือนโมดูลอื่น

หน้าที่ของแอปคือให้ธุรกิจตั้งระบบ จองนัดหมายผ่าน LINE โดยแบ่งเป็น 3 ส่วนหลัก

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

ผู้ใช้ฝั่ง CMS คือแอดมินที่ตั้งค่าสาขา บริการ พนักงาน ออกแบบเส้นทางการจอง และจัดการสถานะการนัดหมาย ส่วนลูกค้าเข้าใช้งานผ่าน token ของเส้นทางการจองที่เว็บฝั่งลูกค้า โดยข้อมูลผู้จองสามารถเติมจากชื่อที่แสดงบน LINE ให้อัตโนมัติได้

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

Business Flow

การเข้าถึงและการปรากฏของแอป

  1. เมนูด้านข้างเรียกทะเบียนแอปตอนโหลดหน้า เก็บเฉพาะแอปที่เปิดใช้งาน หากพบแอปนัดหมายจะเพิ่มรายการเมนูย่อยที่ชี้ตรงไปยังแท็บสาขา และเมนูแม่ "Apps" จะปรากฏก็ต่อเมื่อมีแอปที่เปิดอยู่อย่างน้อยหนึ่งตัว
  2. การมองเห็นเมนูไม่ขึ้นกับบทบาทหรือสิทธิ์ของผู้ใช้เลย แต่ขึ้นกับทะเบียนแอปเพียงอย่างเดียว และแอปนี้ไม่มีป้ายตัวเลขบนเมนูเหมือนแอปกระดานข่าว
  3. ทุกหน้าใต้กลุ่ม /apps ใช้ตัวป้องกันเส้นทางร่วมกัน ซึ่งอ่านรหัสแอปจาก URL ตรวจกับทะเบียน แล้วพากลับหน้าแรกหากแอปถูกปิด และ อนุญาตให้ผ่านหากเรียกทะเบียนไม่สำเร็จ เพราะฝั่งเซิร์ฟเวอร์ยังคุมข้อมูลอยู่ และการที่ทะเบียนล่มชั่วคราวไม่ควรล็อกผู้ใช้ออกจากแอปที่ตนมีสิทธิ์จริง
  4. โครงสร้างที่ขับเคลื่อนด้วยทะเบียนนี้ทำให้แอปใหม่ที่เพิ่มเข้ามาถูกควบคุมโดยอัตโนมัติ
  5. layout ของแอปเป็นเพียงตัววาดแท็บ 3 ตัว (สาขา / เส้นทางการจอง / การจอง) โดย breadcrumb และเมนูที่ active แต่ละหน้าตั้งเอง

สาขา

  1. หน้าสาขาโหลดรายการสาขาทั้งหมดแล้วแสดงเป็นตารางที่แบ่งหน้าฝั่งหน้าเว็บ คอลัมน์ประกอบด้วยลำดับ, ชื่อสาขา (คลิกเพื่อเข้าหน้ารายละเอียด), ที่อยู่, เบอร์โทร, สถานะ และปุ่มคำสั่ง
  2. หน้าต่างสร้างและแก้ไขสาขาประกอบด้วยชื่อ (บังคับ), ที่อยู่ (บังคับ), เบอร์โทร, เขตเวลา (บังคับ เลือกจากรายการที่กำหนดไว้ 6 รายการ) และสถานะ
  3. เวลาทำการทั้ง 7 วันจัดการเป็นสถานะแยกจากฟอร์มหลัก แต่ละวันมีสวิตช์เปิดปิดและช่องเลือกเวลาเริ่มกับเวลาสิ้นสุด โดยช่องเวลาจะใช้งานไม่ได้เมื่อสวิตช์ปิด
  4. ค่าเริ่มต้นคือเปิดทำการวันจันทร์ถึงศุกร์ ปิดวันเสาร์และอาทิตย์ โดยทุกวันตั้งเวลา 09:00 ถึง 18:00 น. และหากผู้ใช้ล้างค่าเวลาออก ระบบจะเติมค่าเริ่มต้นกลับให้แทนที่จะปล่อยเป็นค่าว่าง
  5. เมื่อบันทึก ระบบจะรวมข้อมูลฟอร์มกับเวลาทำการเข้าด้วยกันแล้วส่ง โดยข้อผิดพลาดจากการตรวจฟอร์มจะไม่แสดงข้อความแจ้งเตือนซ้ำ เพราะฟอร์มแสดงข้อความใต้ฟิลด์อยู่แล้ว
  6. การลบสาขาต้องยืนยันก่อน

บริการและพนักงานของสาขา

  1. หน้ารายละเอียดสาขาอ่านรหัสสาขาจาก URL แล้วโหลดข้อมูลสาขาเพื่อนำชื่อไปใส่ในส่วนหัวและ breadcrumb พร้อมโหลดรายการบริการและรายการพนักงานของสาขานั้น
  2. หน้านี้แบ่งเป็น 2 แท็บภายใน โดยปุ่มมุมขวาบนจะเปลี่ยนตามแท็บที่เปิดอยู่ระหว่างเพิ่มบริการกับเพิ่มพนักงาน
  3. แท็บบริการ แสดงลำดับ, ชื่อบริการ, ระยะเวลา, ราคา, จำนวนที่รับได้ต่อช่วงเวลา, สถานะว่าต้องระบุพนักงานหรือไม่ และสถานะ โดยหน้าต่างเพิ่มและแก้ไขกำหนดชื่อ (บังคับ), ระยะเวลาเป็นนาที (บังคับ), จำนวนที่รับได้ต่อช่วงเวลา, ราคา, ตัวเลือกว่าต้องระบุพนักงานหรือไม่ และสถานะ
  4. แท็บพนักงาน แสดงลำดับ, ชื่อ, ตำแหน่ง และรายการบริการที่รับผิดชอบซึ่งแสดงเป็นป้ายหลายอัน โดยหน้าต่างเพิ่มและแก้ไขกำหนดชื่อ (บังคับ), ตำแหน่ง และรายการบริการที่เลือกได้หลายรายการจากบริการของสาขานั้น
  5. ข้อสังเกตเชิงโครงสร้างคือคำสั่งสร้างต้องระบุสาขากำกับ แต่คำสั่งแก้ไขไม่ต้อง เพราะใช้ endpoint คนละชุดกัน

เส้นทางการจอง

  1. หน้ารายการโหลดเส้นทางการจองพร้อมรายการสาขา (ใช้ทั้งเป็นตัวเลือกในฟอร์มและใช้เติมชื่อสาขาในตาราง)
  2. คอลัมน์ประกอบด้วยลำดับ, ชื่อ, สาขา, สถานะการยืนยันอัตโนมัติ, token, สถานะ และปุ่มคำสั่ง
  3. token แสดงเป็นข้อความแบบย่อพร้อมปุ่มคัดลอก และคัดลอกได้เฉพาะ token ดิบเท่านั้น แอปนี้ไม่ได้ประกอบ URL ที่ลูกค้ากดได้ให้ ต่างจากแอปกระดานข่าวและแอปสะสมแต้มที่มีตัวประกอบลิงก์ของตัวเอง การแปลง token ให้เป็นลิงก์ที่ใช้งานได้จึงต้องทำที่อื่น
  4. หน้าต่างสร้างและแก้ไขกำหนดได้เพียง 3 ฟิลด์ คือชื่อ (บังคับ), สาขา (บังคับ) และการยืนยันอัตโนมัติ ส่วนขั้นตอนของเส้นทางแก้ที่หน้าแยกต่างหาก
  5. ปุ่มคำสั่งต่อแถวมี 3 ปุ่ม คือเข้าหน้าแก้ไขขั้นตอน, เปิดหน้าต่างแก้ข้อมูลพื้นฐาน และลบ

การแก้ขั้นตอนของเส้นทางการจอง

  1. หน้านี้อ่านรหัสเส้นทางจาก URL แล้วโหลดข้อมูล โดยดึงชื่อ, จำนวนชั่วโมงที่จะส่งการแจ้งเตือนล่วงหน้า และระยะเวลาผ่อนผันก่อนนับว่าไม่มาตามนัด
  2. หากเส้นทางนั้นยังไม่มีขั้นตอนใด ระบบจะสร้างชุดขั้นตอนเริ่มต้นให้ ทั้งในกรณีที่เป็นเส้นทางใหม่และกรณีที่โหลดข้อมูลไม่สำเร็จ
  3. หากเส้นทางผูกกับสาขาไว้ ระบบจะโหลดรายการบริการและพนักงานของสาขานั้นพร้อมกัน เพื่อนำไปแสดงเป็นข้อมูลอ้างอิงในการ์ดของแต่ละขั้นตอน
  4. ขั้นตอนมี 5 ประเภทตายตัว ได้แก่ เลือกบริการ, เลือกพนักงาน, เลือกวันเวลา, กรอกข้อมูลผู้จอง และยืนยัน โดยแต่ละประเภทมีสีประจำตัวเพื่อให้แยกออกจากกันได้ในสายตา
  5. ชุดขั้นตอนเริ่มต้นถูกสร้างจากข้อความที่แปลแล้ว เพื่อให้ทั้งหัวการ์ดและค่าตั้งต้นที่ระบบสร้างขึ้นพูดภาษาเดียวกับภาษาที่ผู้ใช้กำลังใช้อยู่ โดยขั้นตอนเลือกพนักงานถูกปิดไว้เป็นค่าเริ่มต้น และขั้นตอนกรอกข้อมูลผู้จองมาพร้อมฟิลด์ตั้งต้น 3 ช่อง คือชื่อ (เติมจาก LINE อัตโนมัติ), เบอร์โทร และหมายเหตุ
  6. การเรียงลำดับขั้นตอนใช้การลากวาง และรองรับการเรียงด้วยคีย์บอร์ดด้วย โดย ขั้นตอนยืนยันถูกแยกออกจากรายการที่ลากได้เสมอ และวาดต่อท้ายในฐานะขั้นตอนสุดท้ายที่ตายตัว
  7. แต่ละประเภทมีได้เพียงหนึ่งขั้นตอนเท่านั้น เนื่องจากระบบใช้ประเภทของขั้นตอนเป็นตัวระบุตัวตนในการลากวาง จึงไม่สามารถเพิ่มขั้นตอนประเภทเดียวกันซ้ำได้
  8. การ์ดของแต่ละขั้นตอนมีที่จับสำหรับลาก, เลขลำดับในวงกลมสีประจำขั้นตอน, ชื่อขั้นตอนพร้อมหัวข้อย่อย, สวิตช์เปิดปิด (ซ่อนสำหรับขั้นตอนยืนยัน) และปุ่มพับหรือกางเพื่อดูการตั้งค่า โดยกางพร้อมกันได้หลายการ์ด
  9. ฟอร์มการตั้งค่าแยกตามประเภทของขั้นตอน
    • เลือกบริการ — หัวข้อ, หัวข้อย่อย, รูปแบบการแสดงผล (การ์ดหรือรายการ), แสดงราคาหรือไม่, แสดงระยะเวลาหรือไม่ พร้อมแสดงรายการบริการจริงของสาขาให้เห็น หรือขึ้นคำเตือนหากยังไม่ได้ตั้งบริการไว้
    • เลือกพนักงาน — หัวข้อ, หัวข้อย่อย, แสดงรูปหรือไม่, แสดงตำแหน่งหรือไม่, อนุญาตให้เลือกพนักงานคนใดก็ได้หรือไม่ พร้อมแสดงรายชื่อพนักงานจริงหรือคำเตือนในทำนองเดียวกัน
    • เลือกวันเวลา — หัวข้อ, หัวข้อย่อย, จำนวนวันล่วงหน้าที่จองได้ และการแสดงช่วงเวลาที่เต็มแล้วหรือไม่
    • กรอกข้อมูลผู้จอง — หัวข้อ, หัวข้อย่อย และตัวจัดการฟิลด์แบบเพิ่มลบได้ โดยแต่ละฟิลด์กำหนดคีย์, ป้ายกำกับ, ชนิดของช่องกรอก, การเติมค่าอัตโนมัติจาก LINE และสถานะบังคับกรอก
    • ยืนยัน — หัวข้อ, ข้อความบนปุ่มยืนยัน และการแสดงสรุปรายการหรือไม่
  10. เหนือรายการขั้นตอนมีฟิลด์ระดับเส้นทาง 2 ตัว คือจำนวนชั่วโมงที่จะแจ้งเตือนล่วงหน้าและระยะเวลาผ่อนผันก่อนนับว่าไม่มาตามนัด
  11. การบันทึกส่งเฉพาะขั้นตอนและฟิลด์ระดับเส้นทาง 2 ตัวนี้เท่านั้น ไม่ได้ส่งชื่อ สาขา หรือการยืนยันอัตโนมัติ เพราะสามค่านั้นแก้จากหน้าต่างในหน้ารายการ

การจอง

  1. หน้านี้โหลดรายการสาขาครั้งเดียว และโหลดรายการจองใหม่ทุกครั้งที่ตัวกรองเปลี่ยน โดยส่งเฉพาะพารามิเตอร์ที่มีค่าจริง
  2. มุมมองมี 2 แบบ คือรายการและปฏิทิน โดยค่าเริ่มต้นคือปฏิทิน
  3. แถบตัวกรองประกอบด้วยชุดช่วงเวลาสำเร็จรูป (ทั้งหมด / เมื่อวาน / วันนี้ / พรุ่งนี้ / สัปดาห์นี้ / เดือนนี้), ตัวเลือกช่วงวันที่แบบกำหนดเอง, ตัวเลือกสาขา, ตัวเลือกสถานะ และปุ่มล้างตัวกรอง โดยเมื่อเปลี่ยนวันเริ่มต้นของช่วง ปฏิทินจะเลื่อนไปยังสัปดาห์ของวันนั้นให้อัตโนมัติ
  4. การแบ่งหน้าของตารางทำที่ฝั่งหน้าเว็บ และจะกลับไปหน้าแรกทุกครั้งที่ตัวกรองเปลี่ยน มิฉะนั้นเมื่อกรองให้แคบลงผู้ใช้จะเจอหน้าท้าย ๆ ที่ว่างเปล่า
  5. สถานะการจองมี 5 ค่า คือรอยืนยัน, ยืนยันแล้ว, เสร็จสิ้น, ยกเลิก และไม่มาตามนัด
  6. ปุ่มคำสั่งปรากฏตามสถานะปัจจุบัน โดยรายการที่รอยืนยันมีปุ่มยืนยันกับยกเลิก, รายการที่ยืนยันแล้วมีปุ่มปิดงาน ปุ่มไม่มาตามนัด และปุ่มยกเลิก ส่วนสถานะปลายทางทั้งสามไม่มีปุ่มใดเลย
  7. การยกเลิกต้องผ่านหน้าต่างที่ขอเหตุผล ต่างจากปุ่มอื่นที่ทำงานทันที แม้ว่าเหตุผลจะไม่ได้บังคับกรอกก็ตาม
  8. คลิกที่ชื่อลูกค้าในตารางหรือคลิกที่บล็อกในปฏิทินจะเปิดหน้าต่างรายละเอียด 2 คอลัมน์ ฝั่งซ้ายแสดงข้อมูลผู้จอง เลขที่การจอง สถานะ ช่องทางติดต่อ LINE user ID และ ข้อมูลที่ลูกค้ากรอกในขั้นตอนกรอกข้อมูลจริง ส่วนฝั่งขวาแสดงบริการ พนักงาน สาขา วันที่ ช่วงเวลา หมายเหตุ และวันที่สร้าง

ปฏิทินรายสัปดาห์

  1. ปฏิทินรับรายการจองและวันเริ่มต้นของสัปดาห์เข้ามา ส่วนแถบควบคุมการเลื่อนสัปดาห์อยู่ที่หน้าหลักไม่ใช่ในตัวปฏิทิน
  2. แกนเวลาถูกกำหนดตายตัวไว้ที่ 07:00 ถึง 18:00 น. โดยไม่ได้อ่านจากเวลาทำการของสาขา การจองที่อยู่นอกช่วงนี้จึงถูกวางนอกกริด
  3. ความสูงของบล็อกคำนวณตามระยะเวลาจริงของการจอง โดยมีความสูงขั้นต่ำเพื่อให้ยังอ่านได้
  4. บล็อกแต่ละอันมีชุดสีตามสถานะ และ แสดงข้อมูลมากหรือน้อยตามความสูงของบล็อก โดยบรรทัดช่วงเวลากับชื่อบริการแสดงเสมอ ส่วนชื่อลูกค้า ชื่อพนักงาน และสาขาจะทยอยปรากฏเมื่อบล็อกสูงพอ
  5. วันปัจจุบันถูกไฮไลต์ด้วยสีเขียวและมีเส้นบอกเวลาปัจจุบันวาดอยู่ในคอลัมน์นั้น ส่วนวันหยุดสุดสัปดาห์ใช้พื้นสีเทาอ่อน

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

ตัวป้องกันเส้นทางร่วม (src/app/apps/layout.tsx) — ตรวจว่าแอปในเส้นทางนั้นถูกเปิดใช้งานหรือไม่ พร้อมพฤติกรรมอนุญาตให้ผ่านเมื่อเกิดข้อผิดพลาด

Layout ของแอป (src/app/apps/appointment/layout.tsx) — วาดแท็บ 3 ตัวเท่านั้น ไม่ได้ตั้ง breadcrumb ให้

หน้าสาขา (src/app/apps/appointment/locations/page.tsx) — ตาราง, หน้าต่างสาขา และตัวตั้งเวลาทำการรายวัน

หน้ารายละเอียดสาขา (.../locations/detail/page.tsx) — 2 แท็บภายในสำหรับบริการและพนักงาน พร้อมหน้าต่างจัดการของทั้งสองอย่าง โดยอ่านรหัสสาขาจาก query string

หน้าเส้นทางการจอง (.../journeys/page.tsx) — ตาราง, หน้าต่างข้อมูลพื้นฐาน, การคัดลอก token และทางเข้าสู่หน้าแก้ขั้นตอน

หน้าแก้ขั้นตอน (.../journeys/edit/page.tsx) — ตัวสร้างเส้นทางแบบลากวางพร้อมฟอร์มการตั้งค่าแยกตามประเภทขั้นตอน

หน้าการจอง (.../bookings/page.tsx และ .../bookings/WeeklyCalendar.tsx) — ตัวกรอง, การสลับมุมมอง, ปุ่มเปลี่ยนสถานะตามวงจร, หน้าต่างยกเลิกและหน้าต่างรายละเอียด รวมถึงตัวปฏิทินรายสัปดาห์

เซอร์วิส (src/services/appointment.service.ts) — ครอบคลุมทุกคำสั่งของแอป ทั้งสาขา บริการ พนักงาน เส้นทางการจอง และการจอง โดยยังเป็นไฟล์ขนาดเล็กที่ยังไม่ได้ประกาศชนิดข้อมูลอย่างละเอียด

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

  • ทะเบียนแอปและผู้ดูแลระดับแพลตฟอร์ม — เป็นตัวกำหนดว่าแอปนี้จะปรากฏหรือไม่ CMS อ่านได้อย่างเดียว
  • สิทธิ์การเข้าถึง — มีการประกาศ subject ไว้แต่ไม่มีการแม็ปจากฝั่งหลังบ้าน จึงถูกใช้เป็นเพียงคีย์ของเมนูและ breadcrumb การควบคุมจริงอยู่ที่ทะเบียนแอปและตัวป้องกันฝั่ง API
  • เว็บฝั่งลูกค้าและ LIFF — เป็นที่ที่ลูกค้าเข้าจองผ่าน token ของเส้นทาง โดยการตั้งค่าของแต่ละขั้นตอนคือสิ่งที่ฝั่งนั้นนำไปแสดงผล
  • โปรไฟล์ LINE — ใช้เติมชื่อผู้จองอัตโนมัติในขั้นตอนกรอกข้อมูล และหน้าต่างรายละเอียดแสดง LINE user ID กับรูปของลูกค้า
  • ระบบแจ้งเตือนเบื้องหลัง — จำนวนชั่วโมงที่จะแจ้งเตือนล่วงหน้าและระยะเวลาผ่อนผันก่อนนับว่าไม่มาตามนัดถูกเก็บที่ระดับเส้นทางการจอง เพื่อให้ระบบหลังบ้านนำไปส่งการแจ้งเตือนและตัดสถานะ โดย CMS ทำหน้าที่เพียงตั้งค่า
  • คอมโพเนนต์ร่วมของ CMS — พื้นที่เลื่อนตาราง, ส่วนหัวหน้า, ขนาดหน้าตาราง และสไตล์ของ control ในแถบตัวกรอง
  • สถาปัตยกรรมภายใน — เช่นเดียวกับแอปอื่นในกลุ่ม หน้าทั้งหมดเรียกบริการตรงและจัดการสถานะเอง ไม่ได้ใช้ชั้นจัดการคำขอกลาง และแอปนี้ไม่มีการอัปโหลดรูปจึงไม่ได้พึ่งบริการของโมดูลจัดการเนื้อหา

ส่วนที่ยังไม่สมบูรณ์

เอกสารส่วนนี้ระบุไว้เพื่อให้ผู้อ่านทราบสถานะจริงของโมดูล

  • หน้าบริการและหน้าพนักงานที่อยู่ระดับบนสุดของแอปยังเป็นหน้าเปล่าที่ยังไม่ได้ต่อ API การจัดการจริงทำอยู่ในแท็บภายในหน้ารายละเอียดสาขา
  • ยังไม่มีตัวประกอบ URL สำหรับลูกค้า เส้นทางการจองจึงให้เพียง token ดิบสำหรับคัดลอก และปุ่มคัดลอกยังไม่ได้จัดการกรณีที่เบราว์เซอร์ไม่รองรับหรือไม่ได้อยู่ในบริบทที่ปลอดภัย
  • ปฏิทินครอบเวลา 07:00 ถึง 18:00 น. แบบตายตัว ไม่ได้อ่านจากเวลาทำการของสาขา และตำแหน่งของเส้นบอกเวลาปัจจุบันคำนวณด้วยอัตราส่วนที่ไม่ตรงกับการวางบล็อก
  • ตัวจัดการฟิลด์ในขั้นตอนกรอกข้อมูลยังไม่ตรวจว่าคีย์ว่างหรือซ้ำกันหรือไม่
  • หน้าแก้ขั้นตอนยังไม่มีการตรวจว่ามีการแก้ไขค้างอยู่ก่อนออกจากหน้า

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

โมดูลนี้อยู่ที่ internal/modules/apps/ (ไฟล์ service_appointment.go) ทุก endpoint อยู่ใต้ /api/apps/appointment/

การป้องกันแต่ละกลุ่ม endpoint ไม่เท่ากัน (ข้อสังเกตด้านความปลอดภัย)

นี่คือจุดที่ควรรู้ที่สุดของแอปนี้ — ระดับการป้องกันของแต่ละกลุ่มไม่สม่ำเสมอ ซึ่งยกมาจากระบบเดิมตรง ๆ

  • การจอง (bookings) — ป้องกันแน่นที่สุด ต้องผ่าน JwtAuth ระดับ global และ AppEnabledGuard และประกาศ policy แยกตามการกระทำ
  • ขั้นตอนการจอง (journeys), บริการ (services) และพนักงาน (staff) — อยู่บนกลุ่มสาธารณะและตรวจด้วย token ระดับ "ล็อกอินแล้ว" เท่านั้น ไม่ผ่าน AppEnabledGuard หมายความว่าองค์กรที่ยังไม่ได้เปิดแอปนี้ก็ยังยิง endpoint เหล่านี้ได้ถ้ามีบัญชีที่ล็อกอินได้
  • สาขา (locations) — อยู่บนกลุ่มที่ต้องล็อกอิน แต่ ไม่ได้ประกาศ policy ใด ๆ เลย

สรุปคือการควบคุมที่พึ่งพาได้จริงมีเฉพาะกลุ่มการจอง ส่วนกลุ่มการตั้งค่าควรถือว่าเข้าถึงได้ด้วยสิทธิ์ที่ต่ำกว่าที่คาด เป็นรายการที่ควรจัดการเมื่อจะปรับสิทธิ์ทั้งระบบ

สิ่งที่เกิดขึ้นเมื่อเปลี่ยนสถานะการจอง

PUT /api/apps/appointment/bookings/:id/status ไม่ได้แค่เขียนสถานะลงฐานข้อมูล แต่ยัง ประกาศข้อความลงคิว booking_event_trigger บน RabbitMQ ด้วย ผลที่ตามมาคือ

  • ระบบกฎอัตโนมัติ (Trigger Rule) รับเหตุการณ์นี้ไปสั่งส่งข้อความแจ้งผู้จองต่อได้ เช่น แจ้งยืนยันการจองหรือแจ้งยกเลิก การตั้งค่าข้อความจึงไม่ได้อยู่ในแอปนี้ แต่อยู่ที่หน้ากฎอัตโนมัติ
  • ถ้าคิวมีปัญหาหรือ worker ไม่ทำงาน สถานะการจองจะเปลี่ยนสำเร็จแต่ผู้จองไม่ได้รับข้อความ โดยหน้า CMS ไม่แสดงความผิดพลาดใด ๆ
  • รูปของข้อความที่ประกาศลงคิวถูกตรึงให้ตรงกับระบบเดิมทุกไบต์ เพราะผู้บริโภคเดิมยังอ่านอยู่

พฤติกรรมร่วมของทุกกลุ่ม CRUD

  • ขอบเขตข้อมูล (lineOaId, organizationId, ผู้ใช้ปัจจุบัน และภาษา) อ่านจาก context ของ request ทั้งหมด ไม่ได้รับจาก payload
  • การอ่านรายตัวตรวจทั้งรหัสและ LINE OA ประกอบกัน ถ้ารหัสนั้นเป็นของ OA อื่นจะได้ 404 เหมือนกับกรณีไม่มีอยู่จริง จึงไม่รั่วข้อมูลว่ามีระเบียนนั้นอยู่ที่อื่น
  • การอ่านรายการคืนเป็น array ตรง ๆ ไม่ได้ห่อในโครงสร้างมาตรฐาน และไม่รวมรายการที่ถูกลบไปแล้ว
  • การลบเป็น soft delete ที่ผูกกับกลไกอัตโนมัติของ ORM จริง ต่างจากหลายโมดูลในระบบที่ต้องเขียนเงื่อนไขกรองเอง คำสั่งอ่านจึงกรองรายการที่ลบแล้วให้อัตโนมัติโดยไม่ต้องระวัง

สิ่งที่ CMS ทำไม่ได้

การจองจริงของลูกค้า ไม่ได้เกิดที่ CMS API แต่เกิดที่ client-api ผ่านหน้า LIFF ซึ่งลูกค้าเลือกสาขา บริการ พนักงาน และเวลา แล้วยืนยัน หน้าหลังบ้านนี้ทำหน้าที่ตั้งค่าโครงสร้าง (สาขา บริการ พนักงาน ขั้นตอนการจอง) แล้วดูแลรายการจองที่เกิดขึ้นแล้ว

ตารางและระบบภายนอกที่เกี่ยวข้อง

ตาราง booking, location, service, staff, journey ร่วมกับ line_oa_app และ line_oa ส่วนระบบภายนอกคือ RabbitMQ (คิว booking_event_trigger)