SurePhone ERD — Domain 2: Customer (ลูกค้า)
ลูกค้า login ผ่าน LINE · ผูกระดับบ้าน (ทำสัญญาได้ทุกสาขาในบ้าน) · เกรดล่าสุดแยกตามบ้าน · ยืนยัน OTP/PDPA
[?]= รอ confirm business logic
DBML
//// audit_c, audit_cu (partials) + sys.r2_file นิยามใน 00-shared.dbml (concat ก่อน compile)
//// ───────── customer ─────────
Enum customer.grade {
"A"
"B"
"C"
}
Table customer.users {
id uuid [pk, default: `gen_random_uuid()`]
business_id uuid [not null, note: 'ลูกค้าผูกระดับบ้าน — เกรดแยกตามบ้าน (คนเดียวกันคนละบ้าน = คนละ row)']
registered_shop_id uuid [note: 'ร้านสาขาที่สมัครครั้งแรก (อ้างอิง) → shop.shops · ทำสัญญาได้ทุกสาขาในบ้าน']
line_user_id varchar(255) [note: 'จาก LINE Login — null จนกว่าจะผูก LINE']
first_name varchar(255) [not null]
last_name varchar(255) [not null]
phone_number varchar(10) [not null, note: 'ยืนยันด้วย OTP']
date_of_birth date [note: 'ใช้คำนวณอายุ']
email varchar(255)
facebook_link varchar(255)
line_id_display varchar(255) [note: 'Line ID ที่โชว์ในโปรไฟล์']
grade customer.grade [note: 'เกรดล่าสุดของลูกค้าในบ้านนี้ (materialized, ไม่เก็บประวัติ)']
grade_calculated_at timestamptz [note: 'เวลาคำนวณเกรดล่าสุด']
~audit_cu
indexes {
(business_id, line_user_id) [name: 'idx_customer_business_line', unique]
(business_id, phone_number) [name: 'idx_customer_business_phone']
}
checks {
`phone_number ~ '^[0-9]{10}$'`
}
Note: '''
ลูกค้า — ไม่ลบ/ไม่ปิดใช้งาน (ไม่มี is_active/is_deleted)
รูปโปรไฟล์ดึงจาก LINE avatar ผ่าน API — ไม่เก็บใน R2 (ไม่มี file_id)
[PARKED] ชื่อ first/last vs full_name + field "สถานะ" → รอ verify Figma หลังเคลียร์ shop+contract
[?] ตอนร้านทำสัญญาหน้าร้าน (SH5 ทาง A) record ลูกค้าไปอยู่ตารางนี้เลย หรือสร้างแยกผูก LINE ทีหลัง → เคลียร์ตอน Domain 6
'''
}
Ref fk_customer_business: customer.users.business_id > org.businesses.id [delete: restrict, update: no action]
Ref fk_customer_shop: customer.users.registered_shop_id > shop.shops.id [delete: set null, update: no action] // ร้านสาขา = shop.shops (Domain 3)
Table customer.consents {
id uuid [pk, default: `gen_random_uuid()`]
user_id uuid [not null]
terms_id uuid [not null, note: 'FK → org.terms_and_conditions (type=TERMS_OF_SERVICE)']
accepted_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
indexes {
(user_id, terms_id) [name: 'idx_customer_consent', unique]
}
Note: 'PDPA/Consent — บันทึกการยอมรับข้อตกลงแต่ละเวอร์ชัน'
}
Ref fk_consent_user: customer.consents.user_id > customer.users.id [delete: cascade, update: no action]
Ref fk_consent_terms: customer.consents.terms_id > org.terms_and_conditions.id [delete: restrict, update: no action]Mermaid ER
erDiagram businesses ||--o{ customer_users : "เป็นลูกค้าของ" shops ||--o{ customer_users : "สมัครที่ (อ้างอิง)" customer_users ||--o{ customer_consents : "ยอมรับ PDPA" terms_and_conditions ||--o{ customer_consents : "เวอร์ชัน" customer_users { uuid id PK uuid business_id FK uuid registered_shop_id FK varchar line_user_id UK varchar first_name varchar last_name varchar phone_number date date_of_birth varchar email varchar facebook_link varchar line_id_display enum grade timestamptz grade_calculated_at varchar created_by varchar updated_by timestamptz created_at timestamptz updated_at } customer_consents { uuid id PK uuid user_id FK uuid terms_id FK timestamptz accepted_at } businesses { uuid id PK varchar name } shops { uuid id PK varchar shop_name varchar branch_name } terms_and_conditions { uuid id PK enum type integer version }
✅ Resolved (Domain 2) — 16 มิ.ย. 2026
-
เกรดลูกค้า → A/B/C, เก็บแค่เกรดล่าสุดบน
customer.users(ไม่เก็บประวัติ) · เกรดแยกตามบ้านโดยปริยายเพราะลูกค้าผูกระดับบ้าน ✓ -
ขอบเขตลูกค้า → ระดับบ้าน (
business_id); ทำสัญญาได้ทุกสาขา ·registered_shop_id(→ shop.shops) เก็บแค่ร้านสาขาที่สมัครครั้งแรก ✓ -
ข้อมูลชาวต่างชาติ → เก็บที่ระดับสัญญา (signatory snapshot, Domain 6) ✓
-
ลูกค้าไม่ลบ/ไม่ปิด → ตัด
is_active+is_deletedออก ✓ (16 มิ.ย.) -
consistency → partials อยู่ 00-shared, รูปโปรไฟล์ = LINE avatar (ไม่เก็บ R2) ✓
⏸️ PARKED — กลับมาทำหลังเคลียร์ shop (Domain 3) + contract (Domain 6)
- ชื่อ:
first_name/last_name→ น่าจะเป็นfull_nameเหมือน staff/investor → verify ฟอร์ม CU จริง - field “สถานะ” (CU2 profile): ยังไม่รู้คืออะไร → ดู Figma
- อาชีพ/รายได้ (SH5): ตัดสินว่าอยู่ contract-level (Domain 6) ไม่ใช่ customer
- LINE customer = contract customer (ทาง A หน้าร้าน): ใช้
customer.usersเดียวกันไหม → เคลียร์ตอน contract