การออกแบบสถาปัตยกรรมฐานข้อมูลสำหรับ SaaS
การตัดสินใจเรื่องฐานข้อมูลที่ผิดพลาดในช่วงสัปดาห์แรกจะตามหลอกหลอนคุณไปอีกหลายปี
ผู้ก่อตั้ง SaaS ต้องการ Schema ที่รองรับ multi-tenancy, การเรียกเก็บเงิน (billing) และการเติบโต หากคุณทำพลาด คุณจะต้องเขียนระบบใหม่ทั้งหมดภายในหกเดือน
และนี่คือวิธีสร้าง Schema ที่พร้อมใช้งานจริง (production-ready)
- เลือกกลยุทธ์ Tenant ของคุณ
คุณต้องแยกข้อมูลระหว่างลูกค้าออกจากกัน
• Row-level (Shared DB): ความซับซ้อนต่ำ เหมาะที่สุดสำหรับสตาร์ทอัพส่วนใหญ่ ใช้ตัวกรอง WHERE organization_id = ? ในทุกๆ query
• Schema-level (Separate Schemas): ความซับซ้อนปานกลาง เหมาะสำหรับความต้องการด้านกฎระเบียบ (regulatory)
• Database-level (Separate DBs): ความซับซ้อนสูง เหมาะที่สุดสำหรับลูกค้ากลุ่มองค์กร (enterprise)
สำหรับผลิตภัณฑ์ใหม่ 90% การทำ multi-tenancy แบบ row-level คือทางเลือกที่ถูกต้อง
- ลำดับชั้นของ Entity ที่ถูกต้อง
อย่าเรียกเก็บเงินจากผู้ใช้ (user) โดยตรง เพราะผู้ใช้มีการเข้าและออก แต่ "องค์กร" (organization) จะยังคงอยู่
ลำดับชั้นควรเป็นดังนี้: User ── MemberOf ── Organization ── Subscription ── Invoice
• Users: เก็บตารางนี้ไว้สำหรับระบุตัวตนเท่านั้น ใช้ UUID เพื่อป้องกันการโจมตี • Organizations: นี่คือขอบเขตของ tenant ของคุณ ให้เชื่อมโยง subscription เข้ากับ organization เสมอ • Memberships: ใช้ join table เพื่อเชื่อมโยง users เข้ากับ organizations และเก็บ roles ไว้ที่นี่ ไม่ใช่ในตาราง user
- การเรียกเก็บเงินและการสมัครสมาชิก (Billing and Subscriptions)
อย่าใช้ค่า boolean ง่ายๆ อย่าง is_active เพราะจะทำให้ข้อมูลยุ่งเหยิง
ใช้ state machine สำหรับ subscriptions โดยสถานะ (states) ที่พบบ่อย ได้แก่: • trialing • active • past_due • canceled • expired • incomplete
วิธีนี้จะช่วยให้คุณจัดการกับความล้มเหลวในการชำระเงินและระยะเวลาผ่อนผัน (grace periods) ได้โดยไม่ต้องมาตามแก้ไขข้อมูลด้วยตัวเอง
- เรื่องเงินและการออกใบแจ้งหนี้ (Money and Invoicing)
ปฏิบัติตามกฎที่เข้มงวดเหล่านี้เพื่อหลีกเลี่ยงข้อผิดพลาดทางการเงิน:
• อย่าใช้ FLOAT หรือ REAL สำหรับข้อมูลการเงิน ให้ใช้ integer เพื่อเก็บหน่วยเป็นเซนต์ (cents) ตัวอย่างเช่น $29.99 จะกลายเป็น 2999
• ใช้ตาราง invoice_line_items คุณจำเป็นต้องใช้ตารางนี้สำหรับการทำรายงานภาษีและการคืนเงิน (refunds)
• ใช้ตาราง usage_events หากคุณเรียกเก็บเงินตามปริมาณการใช้งานผลิตภัณฑ์ของลูกค้า
- เคล็ดลับด้านประสิทธิภาพ (Performance Tips)
• ทำ Index ให้กับ foreign keys • ทำ Index ให้กับคอลัมน์ status • ทำ Index ให้กับคอลัมน์ timestamp • หลีกเลี่ยง N+1 queries ให้ใช้ JOIN เพื่อดึงข้อมูล organization และ subscription ในครั้งเดียว
Schema ที่ดีจะทำงานได้อย่างราบรื่นจนคุณไม่รู้สึกถึงมัน แต่หากมันล้มเหลว มันจะกลายเป็นหายนะ
จงสร้างระบบเพื่อองค์กร ใช้ state machines และเก็บข้อมูลเงินเป็น integer
Optional learning community: https://t.me/GyaanSetuAi
