สมัครใช้งานและยืนยันอีเมล
ภาพรวม
หน้าสมัครใช้งานเป็น self-service signup ที่สร้าง organization และผู้ใช้คนแรก ขององค์กรพร้อมกันในคำขอเดียว โดยไม่ต้องรอให้ใครส่งคำเชิญ เหมาะกับลูกค้าใหม่ที่ต้องการเริ่มทดลองใช้ระบบด้วยตนเอง
เส้นทางการสมัครประกอบด้วยสองหน้า
/register— ฟอร์มกรอกข้อมูลองค์กรและข้อมูลผู้ใช้ พร้อมการตรวจสอบอีเมลซ้ำแบบเรียลไทม์และตัววัดความแข็งแรงของรหัสผ่าน/verify-email— หน้าที่ผู้ใช้เข้ามาจากลิงก์ในอีเมล เพื่อยืนยันตัวตนด้วย token
ทั้งสองหน้าเป็นหน้าสาธารณะที่เข้าถึงได้โดยไม่ต้องมี token และแสดงผลด้วย layout แบบ authentication ที่ไม่มีแถบเมนูด้านข้างหรือแถบด้านบน
เมื่อสมัครสำเร็จ ระบบจะ ไม่ พาเข้าสู่ระบบให้อัตโนมัติ ผู้ใช้ต้องยืนยันอีเมลก่อน และองค์กรที่สร้างใหม่ยังต้องรอผู้ดูแลระบบอนุมัติจึงจะเข้าใช้งานได้จริง
Business Flow
การสมัครใช้งาน
- ผู้ใช้เปิดหน้า
/registerและกรอกข้อมูลตามฟิลด์ต่อไปนี้- ชื่อองค์กร (บังคับ)
- ชื่อและนามสกุล (บังคับ)
- อีเมล (บังคับ และต้องอยู่ในรูปแบบอีเมลที่ถูกต้อง)
- รหัสผ่าน (บังคับ ความยาวอย่างน้อย 8 ตัวอักษร)
- ยืนยันรหัสผ่าน (ต้องตรงกับรหัสผ่าน)
- ระหว่างที่ผู้ใช้พิมพ์อีเมล ระบบจะตรวจสอบความซ้ำแบบ debounce 600 มิลลิวินาที โดยเรียก
GET /auth/check-emailแล้วแสดงสถานะใต้ช่องกรอกเป็น กำลังตรวจสอบ / ใช้ได้ / ถูกใช้แล้ว ระบบจะเริ่มตรวจสอบก็ต่อเมื่อรูปแบบอีเมลผ่านเกณฑ์เบื้องต้นแล้วเท่านั้น - ระบบคำนวณความแข็งแรงของรหัสผ่านฝั่งหน้าเว็บจากเกณฑ์ 4 ข้อ ได้แก่ ความยาวอย่างน้อย 8 ตัวอักษร มีตัวพิมพ์ใหญ่ มีตัวเลข และมีอักขระพิเศษ แล้วแสดงเป็นแถบสี 4 ระดับ (Weak / Fair / Good / Strong)
- เมื่อกดยืนยัน ระบบจะตรวจก่อนว่าสถานะอีเมลไม่ได้เป็น "ถูกใช้แล้ว" หากซ้ำจะแสดงข้อความผิดพลาดที่ช่องอีเมลโดยไม่ยิงคำขอไปยังเซิร์ฟเวอร์
- หากข้อมูลผ่านทั้งหมด ระบบส่งข้อมูลไปยัง
POST /auth/registerเพื่อสร้างองค์กรและผู้ใช้คนแรกในคราวเดียว - เมื่อสำเร็จ หน้าจอจะเปลี่ยนจากฟอร์มเป็นหน้ายืนยันผลที่แจ้งว่าได้ส่งอีเมลไปแล้ว พร้อมลิงก์กลับไปหน้าเข้าสู่ระบบ
- หากไม่สำเร็จ ระบบจะแสดง modal พร้อมข้อความจากเซิร์ฟเวอร์ (กรณีที่เซิร์ฟเวอร์ส่งข้อผิดพลาดมาหลายรายการจะถูกรวมเป็นข้อความเดียว)
การยืนยันอีเมล
- ผู้ใช้กดลิงก์ในอีเมลซึ่งพาไปที่
/verify-emailพร้อมพารามิเตอร์ token - หน้าจอเรียก
GET /auth/verify-emailทันทีที่เปิด และแสดงสถานะกำลังตรวจสอบระหว่างรอผล - หากไม่พบ token ใน URL หน้าจอจะแสดงข้อผิดพลาดทันทีโดยไม่เรียกเซิร์ฟเวอร์
- สำเร็จ — แสดงสัญลักษณ์ยืนยันสีเขียวและปุ่มไปยังหน้าเข้าสู่ระบบ
- ไม่สำเร็จ — แสดงสัญลักษณ์แจ้งเตือนสีแดงพร้อมข้อความจากเซิร์ฟเวอร์ หรือข้อความมาตรฐานว่าลิงก์ไม่ถูกต้อง พร้อมปุ่มกลับไปหน้าสมัครใหม่
- เมื่อยืนยันอีเมลแล้วจึงจะเข้าสู่ระบบได้ หากองค์กรยังไม่ถูกอนุมัติ การเข้าสู่ระบบจะถูกปฏิเสธพร้อมข้อความ "รออนุมัติ"
หน้าจอและองค์ประกอบหลัก
หน้าสมัครใช้งาน
หน้า /register แยกความรับผิดชอบเป็นสองส่วน คือส่วน container ที่ดูแลตรรกะทั้งหมด (debounce ตรวจอีเมล การส่งฟอร์ม การสลับไปหน้าผลลัพธ์ และ modal แจ้งข้อผิดพลาด) และส่วนฟอร์มที่ดูแลการแสดงผล ได้แก่ ช่องกรอกข้อมูล ป้ายสถานะอีเมล และแถบวัดความแข็งแรงของรหัสผ่าน
เมื่อสมัครสำเร็จ container จะเปลี่ยนไปแสดงหน้าผลลัพธ์แทนฟอร์มเดิม โดยยังคงอยู่ที่ URL เดิม
หน้ายืนยันอีเมล
หน้า /verify-email เป็นหน้าเดียวจบที่รองรับสามสถานะ คือ กำลังตรวจสอบ สำเร็จ และผิดพลาด แต่ละสถานะมีสัญลักษณ์ ข้อความ และปุ่มดำเนินการต่อที่ต่างกัน
ชั้นบริการสำหรับการสมัคร
บริการด้านการสมัคร (src/services/registration.service.ts) รวมสามฟังก์ชันหลักไว้ด้วยกัน ได้แก่ การสมัครสมาชิก การตรวจสอบอีเมลซ้ำ และการยืนยันอีเมล
จุดที่ควรทราบคือบริการนี้ใช้ axios instance แยกของตัวเอง ไม่ผ่าน instance กลางของระบบ เพราะขั้นตอนนี้ยังไม่มี token และไม่ต้องการให้ตัวดักจับ HTTP 401 บังคับออกจากระบบโดยไม่จำเป็น
เส้นทางสาธารณะ
/register และ /verify-email ถูกกำหนดไว้ในรายการเส้นทางสาธารณะของแอปพลิเคชัน จึงเข้าถึงได้โดยไม่ต้องผ่านการตรวจสอบ token
จุดเชื่อมต่อกับฟีเจอร์อื่น
- เข้าสู่ระบบ — เส้นทางการสมัครจบลงที่หน้า
/loginเสมอ และการเข้าสู่ระบบจะสำเร็จก็ต่อเมื่อยืนยันอีเมลแล้วและองค์กรถูกอนุมัติ - จัดการรหัสผ่าน — ใช้กลไก token ที่เข้ารหัสจากฝั่งเซิร์ฟเวอร์ในลักษณะเดียวกัน โดยมีธง
isNewAccountแยกกรณีที่ผู้ใช้ตั้งรหัสผ่านครั้งแรก - ตั้งค่าโมดูลของ Organization — องค์กรที่สมัครเข้ามาใหม่ต้องถูกเปิดใช้งานโมดูลและกำหนดโควตาโดยผู้ดูแลระบบระดับสูงก่อนใช้งานจริง
- ข้อควรระวังเรื่องเกณฑ์รหัสผ่าน — เกณฑ์ความแข็งแรงในหน้าสมัคร (4 ข้อ) แตกต่างจากรายการตรวจสอบ 6 ข้อที่ใช้ในหน้าตั้งรหัสผ่านใหม่และ modal เปลี่ยนรหัสผ่าน
รายละเอียดฝั่ง Backend (CMS API)
โมดูล registration ฝั่ง cms-api เป็นโมดูลที่ ไม่ใช้ route group ที่ต้องมี token เลย ทุก endpoint เป็น public เพราะขั้นตอนนี้ผู้ใช้ยังไม่มี token
Endpoint ที่หน้านี้เรียกใช้
| จุดที่หน้าเว็บเรียก | Endpoint | หมายเหตุ |
|---|---|---|
| ตรวจอีเมลซ้ำแบบเรียลไทม์ | GET /api/auth/check-email | รับอีเมลผ่าน query string |
| ส่งฟอร์มสมัคร | POST /api/auth/register | ตอบกลับสถานะ 201 เมื่อสำเร็จ |
| ยืนยันอีเมลจากลิงก์ | GET /api/auth/verify-email | รับ token ผ่าน query string |
สิ่งที่ backend ทำเมื่อรับคำขอสมัคร
การเรียก POST /api/auth/register หนึ่งครั้งทำงานหลายอย่างต่อเนื่องกัน
- เข้ารหัสรหัสผ่านด้วย bcrypt ก่อนบันทึก — ไม่มีการเก็บรหัสผ่านแบบข้อความธรรมดาในระบบ
- สร้างแถวใหม่ในตาราง
organizationและตารางuserพร้อมผูก role เริ่มต้นของลูกค้า ให้ผู้ใช้คนแรกอัตโนมัติ ผู้ใช้จึงไม่ต้องรอให้ใครกำหนดบทบาทให้ก่อน - สร้าง verification token แบบสุ่มด้วย generator ระดับ cryptographic แล้วแปลงเป็นสตริง hex
- ตอบกลับสถานะ 201 ซึ่งเป็นสัญญาณที่หน้าเว็บใช้สลับไปแสดงหน้าผลลัพธ์
จากนั้นระบบส่งอีเมลยืนยันออกไปผ่าน Mailer ที่แชร์ร่วมกันทั้งระบบ (ตั้งค่าจาก env กลุ่ม MAIL_SMTP_*) ไม่ได้สร้าง transport แยกต่อโมดูล
ประเด็นที่ควรรู้
- การตรวจอีเมลซ้ำเป็นเพียงตัวช่วยฝั่ง UX ไม่ใช่การจอง —
GET /api/auth/check-emailบอกสถานะ ณ เวลาที่ถาม แต่ไม่ได้กันอีเมลไว้ให้ ระหว่างที่ผู้ใช้กรอกฟอร์มต่ออีกครึ่งนาที คนอื่นยังสมัครด้วยอีเมลนั้นได้ ดังนั้นการสมัครก็ยังอาจล้มเหลวตอนกด submit แม้ป้ายสถานะจะขึ้นว่า "ใช้ได้" - สมัครสำเร็จไม่ได้แปลว่าเข้าใช้งานได้ — backend สร้างองค์กรใหม่ในสถานะที่ยังใช้งานไม่ได้ การเข้าสู่ระบบจะถูกปฏิเสธจนกว่าผู้ดูแลระดับสูงจะเปิดใช้งานองค์กรและตั้งค่าโมดูล/โควตาให้ ซึ่งเป็นเหตุที่หน้า login แสดงข้อความ "รออนุมัติ" แยกจากข้อผิดพลาดทั่วไป
- การยืนยันอีเมลเป็นการเปลี่ยนสถานะผู้ใช้เท่านั้น —
GET /api/auth/verify-emailทำเครื่องหมายว่าผู้ใช้ยืนยันแล้ว ไม่ได้ออก token ให้ ผู้ใช้จึงต้องกลับไปล็อกอินที่หน้า/loginเองตามที่ปุ่มบนหน้ายืนยันพาไป - ตาราง
password_historyถูกเขียนตั้งแต่ตอนสมัคร — รหัสผ่านชุดแรกถูกบันทึกลงประวัติด้วย ทำให้กลไกกันใช้รหัสผ่านซ้ำมีผลย้อนไปถึงรหัสผ่านที่ตั้งครั้งแรก - เกณฑ์รหัสผ่านฝั่ง backend ไม่เท่ากับตัววัดฝั่งหน้าเว็บ — แถบ Weak/Fair/Good/Strong เป็นการคำนวณของหน้าเว็บเพื่อแนะนำผู้ใช้ ส่วนกฎที่บังคับจริงคือกฎที่ backend ตรวจตอนรับคำขอ