โครงสร้างข้อมูล
ดีไซน์ฐานข้อมูล — event-driven, multi-tenant และ config-driven เพื่อให้ข้อมูลนำไปใช้ต่อได้จริง
ทุกพฤติกรรมเขียนเป็น Event — วิเคราะห์ทั้งหมดต่อยอดจากตรงนี้ ไม่ต้องย้อนเติมข้อมูลทีหลัง
ทุกตารางมี orgId ทุก query ผ่าน forOrg(orgId) ข้อมูลข้ามองค์กรไม่หลุดหากัน
ความต่างของแต่ละองค์กรอยู่ใน settings และ FieldDefinition JSONB — รับลูกค้าใหม่ = ตั้งค่า ไม่ใช่ fork โค้ด
PointTransaction คือแหล่งความจริง Member.points เป็นแคชที่ sync ตลอด
ประวัติ Consent มีเวอร์ชัน + ความลับเข้ารหัส (LineChannel) ตั้งแต่วันแรก
องค์กร (MST Golf) — พฤติกรรมปรับผ่าน settings JSONB ไม่ต้องแก้โค้ด
idcuidPKslugstringuniqueplanenumSTARTER/GROWTH/PROsettingsjsonbแต้ม ระดับ ฟีเจอร์ ข้อความ crmลูกค้า 1 คน — โปรไฟล์กอล์ฟเก็บใน attributes JSONB (ไม่มีคอลัมน์ตายตัว)
idcuidPKorgIdcuid→ OrganizationlineUserIdstringunique ต่อ orgattributesjsonbแฮนดิแคป แบรนด์ ความสนใจ…pointsintแคชของ ledgertierstringconsentAtdatetimeธงย่อ PDPAทุกพฤติกรรม — RFM กรวย churn cohort คำนวณจากตรงนี้ทั้งหมด
idcuidPKorgIdcuid→ OrganizationmemberIdcuid→ MembertypeenumREGISTER, PURCHASE, VISIT…payloadjsonbPURCHASE = {amount, currency, items}occurredAtdatetimeแหล่งความจริงของแต้ม — Member.points เป็นแค่แคชของตารางนี้
idcuidPKorgIdcuid→ OrganizationmemberIdcuid→ Memberdeltaint+/- แต้มreasonstringsignup_bonus, purchase…ขับฟอร์มสมัครแบบ dynamic — เพิ่มฟิลด์ได้โดยไม่ต้องแก้โค้ด
orgIdcuid→ Organizationkeystringคีย์ใน attributestypeenumTEXT/NUMBER/SELECT/MULTISELECT…requiredbooloptionsjsonbประวัติความยินยอมแบบมีเวอร์ชัน — ตรวจสอบย้อนหลังและสิทธิ์ขอลบข้อมูล
orgIdcuid→ OrganizationmemberIdcuid→ MemberpurposestringversionstringtextSnapshotstringข้อความที่แสดงcredential LINE ต่อ org เข้ารหัส AES-256-GCM ตอนเก็บ
orgIdcuid→ OrganizationchannelSecretEncstringเข้ารหัสchannelAccessTokenEncstringเข้ารหัสบัญชีล็อกอิน dashboard (OWNER/ADMIN/STAFF)
orgIdcuid→ Organizationemailstringunique ต่อ orgroleenum