ตั้งค่ายืนยัน OTP (OTP Verification Config)
ภาพรวม
หน้าตั้งค่ายืนยัน OTP (/otp-config) คือที่เก็บข้อมูลรับรอง (credential) และเทมเพลตข้อความสำหรับส่งรหัส OTP ในระดับ LINE OA หนึ่งบัญชี หน้านี้ไม่ได้กำหนดว่าฟอร์มใดต้องยืนยันตัวตน (การตั้งค่านั้นอยู่ในแท็บการยืนยันตัวตนของ Form Builder) แต่เป็นชั้นล่างที่ตอบคำถามว่า LINE OA นี้ "ส่ง OTP ออกไปได้ทางช่องทางใดบ้าง"
หน้าจอนี้เหมาะกับผู้ดูแลระบบที่ตั้งค่าครั้งเดียวให้ทั้งบัญชี เมื่อกำหนดเสร็จแล้วทีมที่สร้างฟอร์มจึงจะเปิดการยืนยันตัวตนในฟอร์มของตนได้
ระบบรองรับ 2 ช่องทาง
| ช่องทาง | ผู้ให้บริการ | ข้อมูลที่ต้องกรอก |
|---|---|---|
| SMS | ThaiBulkSMS | API Key และ Secret |
| อีเมล | SMTP ที่ตั้งไว้ระดับ channel | หัวข้ออีเมล และเนื้อหาอีเมลที่ต้องมีตัวแปร {otp} |
ลักษณะเฉพาะของฟีเจอร์ที่ควรทราบ
- เป็นการตั้งค่าชุดเดียวต่อ 1 LINE OA จึงไม่มีหน้ารายการ ไม่มีการสร้างใหม่ และไม่มีการลบ มีเพียงการอ่านค่าปัจจุบันและบันทึกทับ
- ระบบจะแสดงฟอร์มได้เสมอแม้ยังไม่เคยตั้งค่ามาก่อน โดยเติมค่าเริ่มต้นของหัวข้อและเนื้อหาอีเมลไว้ให้
- ค่า Secret ของ SMS ถูกอ่านกลับมาแบบปิดบังบางส่วนเท่านั้น (เช่น
ab****yz) และแสดงเป็นข้อความแนะนำในช่องกรอก การบันทึกโดยเว้นช่อง Secret ว่างไว้หมายถึง "คงค่าเดิมที่บันทึกไว้" ไม่ใช่การล้างค่า - ระบบสรุปสถานะความพร้อมของแต่ละช่องทางเป็นป้ายกำกับบนการ์ด คือ กำหนดค่าแล้ว หรือ ยังไม่ได้กำหนดค่า สถานะนี้เป็นตัวเดียวกับที่ Form Builder ใช้ตัดสินว่าช่องทางนั้นเลือกได้หรือไม่
- เมนูอยู่ใต้กลุ่ม Settings ของเมนูด้านข้าง และเข้าถึงได้จาก Quick Access
เงื่อนไขที่ทำให้แต่ละช่องทางถือว่าพร้อมใช้งาน
| ช่องทาง | ถือว่าพร้อมเมื่อ |
|---|---|
| SMS | เปิดสวิตช์ SMS มี API Key และมี Secret บันทึกไว้ในระบบแล้ว |
| อีเมล | เปิดสวิตช์อีเมล มีหัวข้ออีเมล และเนื้อหาอีเมลมีตัวแปร {otp} |
ตัวแปรที่ใช้ในเทมเพลตอีเมล
| ตัวแปร | บังคับ | ความหมาย |
|---|---|---|
{otp} | ใช่ | รหัส OTP ที่ระบบสร้างขึ้น ระบบตรวจสอบทั้งฝั่งหน้าจอและฝั่งเซิร์ฟเวอร์ |
{ref} | ไม่ | รหัสอ้างอิงของการส่งครั้งนั้น |
ระบบเตรียมหัวข้อและเนื้อหาอีเมลเริ่มต้นไว้ให้ตามภาษาที่ผู้ใช้งานเลือกอยู่ เพื่อให้เริ่มใช้งานได้ทันทีโดยไม่ต้องเขียนเทมเพลตเอง ตัวอย่างเนื้อหาเริ่มต้นภาษาไทย
รหัส OTP ของคุณคือ <b>{otp}</b> จะหมดอายุใน 3 นาที
ค่าเริ่มต้นเหล่านี้ถูกเติมลงฟอร์มเฉพาะตอนโหลดข้อมูล หากเปลี่ยนภาษาของระบบระหว่างอยู่ในหน้านี้ ควรโหลดหน้าใหม่เพื่อให้ได้ข้อความเริ่มต้นตามภาษาที่เลือก
ส่วนข้อความที่ปรากฏบนหน้ายืนยันตัวตนของผู้กรอกฟอร์ม เช่น หัวข้อ คำอธิบาย ปุ่มยืนยัน และปุ่มขอรหัสใหม่ ไม่ได้ตั้งที่หน้านี้ แต่ตั้งแยกรายฟอร์มในแท็บการยืนยันตัวตนของ Form Builder
Business Flow
ตั้งค่าข้อมูลรับรอง
- เข้าหน้า
/otp-configระบบตรวจสิทธิ์VIEWของโมดูล OTP Config ก่อนแสดงผล พร้อมตั้ง breadcrumb และไฮไลต์เมนู Settings - ระบบอ่านค่าการตั้งค่าปัจจุบันของ LINE OA และแสดงตัวหมุนรอโหลดจนกว่าข้อมูลจะพร้อม จึงจะ render ฟอร์ม
- เมื่อข้อมูลมาถึง ระบบเติมค่าลงฟอร์ม ได้แก่ สถานะเปิด/ปิดของทั้งสองช่องทาง API Key ของ SMS หัวข้ออีเมล และเนื้อหาอีเมล หากยังไม่เคยตั้งหัวข้อหรือเนื้อหา ระบบใช้ข้อความมาตรฐานที่เตรียมไว้ตามภาษาของผู้ใช้
- ช่อง Secret ของ SMS จะถูกล้างเป็นค่าว่างเสมอ ค่าที่ปิดบังบางส่วนจะไปแสดงเป็นข้อความแนะนำในช่องแทน เพื่อสื่อว่าเว้นว่างไว้ได้หากไม่ต้องการเปลี่ยน
- การ์ด SMS ประกอบด้วยสวิตช์เปิดใช้งาน ช่อง API Key และช่อง Secret แบบซ่อนข้อความ ส่วนการ์ดอีเมลประกอบด้วยสวิตช์เปิดใช้งาน ช่องหัวข้อ และช่องเนื้อหาแบบหลายบรรทัด พร้อมคำอธิบายตัวแปรที่ใช้ได้
- ระบบตรวจสอบความถูกต้องฝั่งหน้าจอเฉพาะช่องทางอีเมล และเฉพาะเมื่อเปิดสวิตช์อีเมลไว้ โดยหัวข้อต้องไม่ว่าง และเนื้อหาต้องไม่ว่างและต้องมีตัวแปร
{otp}อยู่ในข้อความ - ฝั่ง SMS ไม่มีการตรวจสอบก่อนส่ง หากเปิดสวิตช์แล้วไม่กรอก Key หรือ Secret ระบบจะปล่อยให้กดบันทึกได้ และเซิร์ฟเวอร์จะเป็นผู้ปฏิเสธพร้อมส่งข้อความอธิบายกลับมาแสดง
- กดปุ่มบันทึกการตั้งค่า ระบบประกอบข้อมูลแล้วส่งไปบันทึกทับค่าเดิม พร้อมแสดงสถานะกำลังโหลดระหว่างดำเนินการ
- เมื่อบันทึกสำเร็จ ระบบแจ้งผลและอ่านค่าใหม่กลับมาทันที ป้ายสถานะบนการ์ดและค่า Secret ที่ปิดบังจะอัปเดตตามค่าล่าสุด ส่วนช่อง Secret กลับไปเป็นค่าว่างอีกครั้ง
- หากบันทึกไม่สำเร็จ ระบบนำข้อความจาก API มาแสดงตรง ๆ เช่น กรณีเปิด SMS แต่ไม่มี Key หรือ Secret หรือกรณีเนื้อหาอีเมลไม่มีตัวแปร
{otp}หากไม่มีข้อความจาก API จะแสดงข้อความผิดพลาดมาตรฐานแทน
ข้อควรระวังในการใช้งาน
- หน้านี้ไม่มีการเตือนเมื่อออกจากหน้าโดยยังไม่บันทึก ค่าที่แก้ไว้จะหายไปทั้งหมด
- ไม่มีปุ่มทดสอบส่ง OTP และไม่มีหน้าดูประวัติการส่งในโมดูลนี้ การตรวจสอบความพร้อมทำได้จากป้ายสถานะบนการ์ดเท่านั้น
- ไม่มีทางอ่านค่า Secret เดิมกลับมาจากหน้าจอ หากจำค่าเดิมไม่ได้ต้องออก Key และ Secret ชุดใหม่จากผู้ให้บริการแล้วกรอกใหม่ทั้งคู่
- การปิดสวิตช์ช่องทางใดช่องทางหนึ่งมีผลทันทีกับทุกฟอร์มที่ใช้ช่องทางนั้น จึงควรตรวจสอบก่อนว่ามีฟอร์มที่กำลังเปิดใช้งานอยู่หรือไม่
ลำดับการใช้งานร่วมกับ Form Builder
- ผู้ดูแลระบบตั้งค่าข้อมูลรับรองที่หน้านี้ กรอก Key และ Secret ของ SMS และ/หรือหัวข้อกับเนื้อหาอีเมล แล้วเปิดสวิตช์ช่องทางที่ต้องการ จากนั้นบันทึก
- ระบบคำนวณสถานะความพร้อมของแต่ละช่องทางกลับมา ป้ายบนการ์ดเปลี่ยนเป็น กำหนดค่าแล้ว
- ผู้ดูแลฟอร์มเปิดฟอร์มที่ต้องการใน Form Builder แล้วเปิด Profile Mapping พร้อมเลือก Member Database ซึ่งเป็นเงื่อนไขบังคับ เพราะรหัส OTP จะถูกส่งไปยังคอลัมน์ของระเบียนที่ค้นหาเจอ ไม่ใช่ค่าที่ผู้ใช้กรอกในฟอร์ม
- ไปที่แท็บการยืนยันตัวตนแล้วเปิดสวิตช์ ระบบจะสร้างแถวตั้งค่าให้ 1 แถวโดยเลือกช่องทางที่พร้อมใช้งานให้อัตโนมัติ จากนั้นเลือกคอลัมน์ปลายทางที่จะส่งรหัสไป
- หากยังไม่มีช่องทางใดพร้อมใช้งาน แท็บดังกล่าวจะแสดงแถบเตือนพร้อมลิงก์กลับมายังหน้านี้ และปิดปุ่มเพิ่มฟิลด์ไว้ ส่วนช่องทางที่ยังไม่ตั้งค่าจะถูกปิดไม่ให้เลือกในดรอปดาวน์
- หากภายหลังปิดช่องทางที่หน้านี้ ฟอร์มที่เปิด OTP ไว้แล้วจะยังคงการตั้งค่าเดิมและแสดงแถบเตือนแทน ระบบไม่ปิด OTP ของฟอร์มให้อัตโนมัติ
หน้าจอและองค์ประกอบหลัก
หน้าจอเป็นฟอร์มหน้าเดียวประกอบด้วยการ์ด 2 ใบและปุ่มบันทึกด้านล่าง
การ์ดช่องทาง SMS
- ป้ายสถานะ — แสดงว่าช่องทางนี้พร้อมใช้งานแล้วหรือยัง คำนวณจากฝั่งเซิร์ฟเวอร์
- สวิตช์เปิดใช้งาน — เปิดหรือปิดการส่ง OTP ทาง SMS
- ช่อง API Key — ข้อมูลรับรองจาก ThaiBulkSMS อ่านกลับมาแสดงได้ตามปกติ
- ช่อง Secret — ช่องกรอกแบบซ่อนข้อความ แสดงค่าเดิมแบบปิดบังเป็นข้อความแนะนำ เว้นว่างไว้เพื่อคงค่าเดิม
การ์ดช่องทางอีเมล
- ป้ายสถานะ — เช่นเดียวกับการ์ด SMS
- สวิตช์เปิดใช้งาน — เปิดหรือปิดการส่ง OTP ทางอีเมล
- ช่องหัวข้ออีเมล — บังคับกรอกเมื่อเปิดใช้งาน
- ช่องเนื้อหาอีเมล — ช่องข้อความหลายบรรทัดแบบ monospace รองรับการเขียน HTML โดยตรง (ไม่ใช่ตัวแก้ไขแบบ rich text) และต้องมีตัวแปร
{otp} - คำอธิบายตัวแปร — ป้ายช่วยเหลือที่ระบุตัวแปรที่ใช้ได้ในเทมเพลต
ไฟล์อ้างอิงหลัก: src/app/otp-config/page.tsx, src/components/otp-config/otp-config-form.tsx
บริการฝั่ง API
รวมอยู่ที่ src/services/otp-config.service.ts ภายใต้ path หลัก otp-config
| ความสามารถ | Endpoint | หมายเหตุ |
|---|---|---|
| อ่านการตั้งค่าปัจจุบัน | GET /otp-config | ชุดเดียวต่อ LINE OA คืนค่าเริ่มต้นเมื่อยังไม่เคยตั้งค่า จึงไม่เกิดกรณีไม่พบข้อมูล |
| บันทึกการตั้งค่า | PUT /otp-config | บันทึกทับค่าเดิม เว้น Secret ว่างไว้เพื่อคงค่าเดิม และคืนข้อมูลรูปแบบเดียวกับการอ่าน |
ข้อมูลที่รับส่งประกอบด้วยสถานะเปิด/ปิดของทั้งสองช่องทาง API Key ของ SMS หัวข้อและเนื้อหาอีเมล และสถานะความพร้อมของแต่ละช่องทางที่คำนวณจากฝั่งเซิร์ฟเวอร์ โดยการอ่านค่าจะได้ Secret แบบปิดบังเท่านั้น ส่วนการบันทึกจึงจะส่ง Secret ตัวจริงขึ้นไป
จุดเชื่อมต่อกับฟีเจอร์อื่น
- สิทธิ์การใช้งาน — หน้านี้ถูกควบคุมด้วยโมดูล
form-builderเช่นเดียวกับ Form Builder ไม่มีโมดูลแยกเฉพาะสำหรับ OTP ดังนั้นการปิดโมดูล Form Builder จะทำให้เมนูนี้หายไปด้วย - Form Builder — เป็นผู้ใช้ค่าการตั้งค่านี้เพียงรายเดียวในฝั่ง CMS โดยแท็บการยืนยันตัวตนอ่านสถานะความพร้อมของช่องทางมาใช้เป็นเงื่อนไข ขณะที่หน้านี้เองไม่ทราบว่ามีฟอร์มใดเปิดใช้ OTP อยู่บ้าง
- Member Database — ไม่เกี่ยวข้องกับหน้านี้โดยตรง แต่เป็นเงื่อนไขจำเป็นของฝั่งฟอร์ม เพราะรหัส OTP ถูกส่งไปยังคอลัมน์ของระเบียนสมาชิกที่จับคู่ได้
- ThaiBulkSMS — ผู้ให้บริการ SMS ภายนอก ข้อมูลรับรองถูกเก็บไว้ฝั่งเซิร์ฟเวอร์ ระบบ CMS มองเห็นได้เพียงค่าที่ปิดบังแล้ว
- การตั้งค่า SMTP ระดับ channel — ช่องทางอีเมลใช้เซิร์ฟเวอร์ส่งอีเมลที่ตั้งไว้ในระดับ channel หน้านี้กำหนดได้เฉพาะหัวข้อและเนื้อหาเท่านั้น
- โครงสร้างพื้นฐานร่วม — ใช้ระบบยืนยันตัวตนและ HTTP client กลางของ CMS ซึ่งผูกข้อมูลไว้กับ LINE OA ที่ล็อกอินอยู่โดยอัตโนมัติ (ไม่ต้องส่งรหัส OA ใน URL) รวมถึงระบบ breadcrumb เมนูด้านข้าง และสถานะ loading กลางของแอปพลิเคชัน
รายละเอียดฝั่ง Backend (CMS API)
โค้ดฝั่ง backend อยู่ที่ internal/modules/otpconfig/ เป็น โมดูลที่เขียนขึ้นใหม่ ไม่ได้ย้ายมาจากระบบเดิม โครงสร้างโค้ดอ้างอิงรูปแบบของโมดูล Quick Reply แต่ต่างกันตรงที่โมดูลนี้เป็น singleton คือมีข้อมูลได้ชุดเดียวต่อ LINE OA ไม่ใช่ CRUD หลายแถว
ทำไมจึงมีแค่ 2 endpoint
- ตาราง
otp_configกำหนดให้ค่าอ้างอิง LINE OA เป็นค่าที่ห้ามซ้ำ (unique) จึงเป็นไปไม่ได้ที่จะมีการตั้งค่าสองชุดใน OA เดียว - ผลคือไม่มี endpoint สร้างและไม่มี endpoint ลบ มีเพียง
GET /api/otp-configสำหรับอ่าน และPUT /api/otp-configซึ่งเป็นการ upsert (มีแถวอยู่แล้วก็อัปเดต ไม่มีก็สร้างให้) - การยังไม่เคยตั้งค่าถือเป็นสถานะปกติ ไม่ใช่ข้อผิดพลาด backend จึงคืนโครงสร้างค่าว่าง/ค่าเริ่มต้นกลับมา ไม่ตอบว่า "ไม่พบข้อมูล" นี่คือเหตุผลที่หน้าจอ render ฟอร์มได้เสมอโดยไม่ต้องมีกรณีจัดการหน้าว่าง
สิทธิ์ที่ต้องมี
- ทั้งสอง route ต้องผ่านการยืนยันตัวตนกลาง (JWT) และ token ต้องมี LINE OA ที่เลือกไว้ เพราะ backend ใช้ค่านี้ในการหาแถวการตั้งค่าที่ถูกต้อง — ไม่มีการส่งรหัส OA มาทาง URL หรือ body เลย
- ข้อสังเกต — โมดูลนี้ ไม่ได้ครอบด้วย module gate และ policy ที่ประกาศไว้ยังเป็นเพียงข้อมูลกำกับที่ยังไม่บังคับใช้
- ที่น่าสนใจคือ backend ประกาศชื่อ policy แยกไว้เป็น
otp-configของตัวเอง (ตั้งให้ตรงกับชื่อเมนูฝั่ง CMS เผื่อเปิดใช้ในอนาคต) ขณะที่ ฝั่งหน้าจอกลับควบคุมเมนูนี้ด้วยสิทธิ์ของโมดูลform-builderทั้งสองฝั่งจึงยังมองการแบ่งสิทธิ์ของหน้านี้ไม่ตรงกัน
สิ่งที่บันทึกและผลข้างเคียง (Side Effect)
- ข้อมูลทั้งหมดอยู่ในตาราง
otp_configเพียงตารางเดียว โมดูลนี้ไม่เขียน cache และไม่ส่งงานเข้าคิว - การบันทึกมีผลทันทีกับทุกฟอร์มที่เปิด OTP ไว้ เพราะฟอร์มไม่ได้เก็บสำเนาข้อมูลรับรองไว้เอง แต่อ่านค่าจากตารางนี้ตอนใช้งานจริง
- ผู้ส่งและตรวจ OTP จริงคือ
line-management-client-api-goไม่ใช่cms-apiหน้านี้เป็นเพียงที่เก็บข้อมูลรับรองและเทมเพลต การกดบันทึกสำเร็จจึงไม่ได้พิสูจน์ว่าข้อมูลรับรองใช้ส่งได้จริง - เมื่อผู้กรอกยืนยัน OTP สำเร็จแล้วเท่านั้น ฝั่ง client-api จึงจะยอมรับการส่งฟอร์ม — ถ้าปิด OTP ฟอร์มจะรับคำตอบได้ทันทีโดยไม่ต้องยืนยัน
Edge Case และข้อสังเกตที่ควรรู้
- เพราะเป็น upsert ที่เขียนทับทั้งชุด การบันทึกทุกครั้งคือการแทนที่ค่าเดิมทั้งหมด ไม่ใช่การแก้ทีละฟิลด์ กติกาที่ว่า "เว้นช่อง Secret ว่างไว้เพื่อคงค่าเดิม" จึงเป็นตรรกะที่ backend ต้องจัดการให้ ไม่ใช่ผลข้างเคียงตามธรรมชาติของการเขียนทับ
- ไม่มี endpoint สำหรับทดสอบส่งจริง และไม่มีที่เก็บประวัติการส่งในโมดูลนี้ การยืนยันว่าข้อมูลรับรองถูกต้องจึงทำได้ทางเดียวคือทดลองส่งฟอร์มจริง
- โมดูลนี้ไม่รู้ว่ามีฟอร์มใดกำลังใช้ช่องทางใดอยู่ การปิดสวิตช์ช่องทางจึงไม่มีการเตือนใด ๆ จาก backend และไม่มีการปิด OTP ของฟอร์มให้อัตโนมัติ
- ข้อมูลถูกจำกัดขอบเขตตาม LINE OA ที่เลือกอยู่เสมอ การสลับ OA ในระบบ CMS จึงเท่ากับเปลี่ยนไปดูการตั้งค่าคนละชุดโดยสิ้นเชิง