Flow: สมัคร & พิจารณาร้านค้าพาร์ทเนอร์ (Shop Partner Onboarding)
กระบวนการตั้งแต่ร้านกดสมัคร จนพนักงานบ้านอนุมัติและผูก LINE กลุ่ม อ้างอิงตาราง: ดู 03-shop.md · ข้อตกลง:
org.terms_and_conditionsวันที่: 16 มิ.ย. 2026
Actors
| Actor | บทบาท |
|---|---|
| เจ้าของร้าน | ผู้สมัคร — กรอกฟอร์ม, รับข้อตกลง, ยืนยัน OTP, ส่งรหัสเชื่อมในกลุ่ม LINE |
| พนักงานบ้าน (ADMIN) | พิจารณาคำขอ (อนุมัติ/ตีกลับ/ไม่อนุมัติ), สร้างรหัสเชื่อม LINE |
| ระบบ (Backend) | เช็คเบอร์ซ้ำ, จัดการ OTP (Redis), gen เอกสารสัญญา, บันทึก DB |
| LINE Webhook | ดักข้อความรหัสในกลุ่ม → จับ groupId → ผูกกับร้าน |
Flow หลัก
flowchart TD A([เจ้าของร้าน: หน้า Login]) --> B[กด สมัครเลย] B --> C[รับข้อตกลงล่าสุด<br/>org.terms_and_conditions type=TERMS_OF_SERVICE] C --> D[กรอกเบอร์โทร] D --> E{เบอร์ซ้ำในบ้านนี้?} E -- ซ้ำ --> D E -- ไม่ซ้ำ --> F[ส่ง OTP - Redis ephemeral] F --> G{ยืนยัน OTP} G -- ผิด --> F G -- ผ่าน --> H[กรอกฟอร์ม 7 ขั้น<br/>ผู้สมัคร→ร้าน→ที่อยู่→บัญชี→account→ลายเซ็น→รีวิว] H --> I[[Submit ใบสมัคร]] I --> J[ระบบสร้าง:<br/>shops status=PENDING<br/>shop_users OWNER<br/>shop_consents<br/>gen contract_file] J --> K([เข้าคิวพิจารณา - รออนุมัติ]) K --> L[พนักงานเปิดดูรายละเอียด<br/>บุคคล/ร้าน/บัญชี + ดูไฟล์สัญญา] L --> M[สร้างรหัสเชื่อม LINE - Redis<br/>+ กรอกชื่อไลน์กลุ่ม] M --> N{ผลพิจารณา} N -- อนุมัติ --> O[status=ACTIVE + log] N -- ตีกลับแก้ไข --> P[status=RETURNED + log<br/>เลือกหัวข้อแก้ไข + หมายเหตุ] N -- ไม่อนุมัติ --> Q[status=REJECTED + log<br/>เลือกเหตุผล + หมายเหตุ] O --> R[เจ้าของส่งรหัสในกลุ่ม LINE] R --> S[Webhook จับ groupId<br/>set line_group_id + line_connected_at] S --> T([ร้านใช้งานได้]) P --> U[แจ้งเจ้าของผ่าน LINE<br/>เด้งไปฟอร์มที่ต้องแก้] U --> H Q --> V([จบ - ไม่อนุมัติ])
State ของสถานะพาร์ทเนอร์ (shop.partner_status)
stateDiagram-v2 [*] --> PENDING: submit ใบสมัคร PENDING --> RETURNED: ตีกลับแก้ไข RETURNED --> PENDING: แก้แล้วส่งใหม่ (badge "แก้ไข") RETURNED --> CANCELED: ไม่แก้ใน 14 วัน (auto) PENDING --> ACTIVE: อนุมัติ PENDING --> REJECTED: ไม่อนุมัติ ACTIVE --> INACTIVE: ยกเลิกพาร์ทเนอร์ INACTIVE --> ACTIVE: คืนสถานะ REJECTED --> [*]: ลบประวัติ (ปล่อยเบอร์) CANCELED --> [*]: ลบประวัติ (ปล่อยเบอร์)
badge “ใหม่” vs “แก้ไข” ในรายการ → derive จาก
partner_status_logs(เคยมี RETURNED = “แก้ไข”)
Map แต่ละ step → ตาราง/คอลัมน์
| Step | การกระทำ | ตาราง / คอลัมน์ | หมายเหตุ |
|---|---|---|---|
| 1 | รับข้อตกลง | org.terms_and_conditions (อ่าน is_latest, type=TERMS_OF_SERVICE) | บันทึกจริงตอน submit |
| 2 | เช็คเบอร์ + OTP | — (Redis) | เบอร์ unique ต่อบ้าน เช็คกับ shop.shops(business_id, phone_number) |
| 3 | กรอกฟอร์ม 1–7 | (buffer ฝั่ง client/Redis) | ยังไม่ลง DB จน submit |
| 4 | Submit | shop.shops (status=PENDING) + shop.users(OWNER) + shop.consents | gen contract_file_id (เอกสารสัญญา) |
| 5 | สร้างรหัสเชื่อม LINE | — (Redis OTP) + shops.line_group_name | ทำก่อนทุกผลพิจารณา |
| 6a | อนุมัติ | partner_status_logs(to=ACTIVE) → shops.status=ACTIVE | |
| 6b | ตีกลับ | partner_status_logs(to=RETURNED) + partner_log_reasons (reasons applicable_to=RETURNED) + log.note | |
| 6c | ไม่อนุมัติ | partner_status_logs(to=REJECTED) + partner_log_reasons (REJECTED) + log.note | |
| 7 | ผูก LINE กลุ่ม | shops.line_group_id + line_connected_at | webhook จับ groupId |
หมายเหตุสำคัญ (business logic)
- OTP ทั้งหมดผ่าน Redis (สมัคร + รหัสเชื่อม LINE) — ephemeral ไม่เก็บใน DB
- เอกสารสัญญา
contract_file_idระบบ gen ตอน submit และ regenerate เมื่อข้อมูลเปลี่ยน (เช่น ตีกลับแล้วแก้) - ผูก LINE กลุ่มผ่าน webhook: เจ้าของส่ง “รหัสเชื่อม” ในกลุ่ม → ระบบ map รหัส↔ร้าน (Redis) + จับ
groupIdจาก event → เขียนline_group_id(unique 1 กลุ่ม = 1 ร้านสาขา) - ตีกลับ: เลือกได้หลายหัวข้อ (form sections) → UI เด้งเจ้าของไปฟอร์มแรกที่ต้องแก้
- 1 ร้านสาขา = 1 row ใน
shop.shops· เจ้าของ 1 + พนักงาน ≤5 ในshop.users
Lifecycle (สถานะ)
- ไม่อนุมัติ (REJECTED) → ประวัติ · กดลบประวัติได้ = hard-delete row ⇒ ปล่อยเบอร์ (unique ต่อบ้าน) ให้สมัครใหม่ด้วยเบอร์เดิม
- ตีกลับ (RETURNED) ไม่แก้ใน 14 วัน → batch job auto →
CANCELED→ ประวัติ (ลบได้เช่นกัน) - ยกเลิกพาร์ทเนอร์ (ACTIVE → INACTIVE): เมนู “ประวัติการยกเลิก” → กดเพิ่มรายการยกเลิก → Modal (ค้นหาร้านที่จะยกเลิก + เลือกเหตุผล + หมายเหตุ) →
partner_status_logs(to=INACTIVE) +partner_log_reasons(reasons applicable_to=INACTIVE) + log.note · ปรับกลับACTIVEได้ - คอลัมน์ “วันที่อนุมัติ” ในหน้าประวัติ → derive จาก
partner_status_logs(log ที่ to_status=ACTIVE) · “พนักงานที่ดำเนินการ” →partner_status_logs.created_by
การแก้ไขข้อมูลร้าน (หลังเป็นพาร์ทเนอร์ · SH3)
- เปลี่ยน ธนาคาร + เลขที่บัญชี ได้ (
bank_code,bank_account_number) — ชื่อบัญชี (bank_account_name) ห้ามเปลี่ยน - เปลี่ยน เบอร์ร้าน (
shops.phone_number) ได้ — เป็นเบอร์เดียวกับ owner (shop.usersrole=OWNER) → ต้อง sync กัน shop.usersเปลี่ยน username / password / display_name / เบอร์ ได้เสมอ (username ยัง unique ต่อกิจการ) · พนักงานร้าน soft-delete ได้ (ไม่มีปิดใช้งาน)