#backend#tenant#multi-tenant#database#identity
โมเดลผู้เช่าหลายราย (Multi-tenant)
ระบบแยกลูกค้าแต่ละรายเป็น Tenant โดยแต่ละ Tenant มีฐานข้อมูล PostgreSQL ของตัวเอง ไม่ใช้ตารางร่วมกัน. ตัวระบุ Tenant คือ Provider Code (ตัวพิมพ์ใหญ่/เลข 2-20 ตัว) ซึ่งตรงกับ claim tenantId ใน JWT. ฐานข้อมูลมี 2 ระดับ: Main Database (ผู้ใช้/สิทธิ์/รายชื่อบริษัท) และ Company Database (ข้อมูลบัญชีของแต่ละบริษัท).
ทำงานอย่างไร
- ผู้ดูแลลงทะเบียน Provider (code + ชื่อ + connection ไปยัง PostgreSQL ของ Tenant) → เก็บเป็นไฟล์ ดู ทะเบียน Provider แบบไฟล์ JSON (Provider registry).
- ตอน login ระบบรับ
provider+dataGroup+username+passwordแล้ว:- ดึง connection ของ Provider (
ResolveConnection) → คืน host/port/user/password ที่ถอดรหัสแล้ว. - คำนวณชื่อ Main Database =
"smlerpmain" + lower(providerCode)(application/identity/service.go:20,57) — สูตรตายตัว ไม่เก็บในไฟล์ config. admin ใช้สูตรเดียวกัน (admin/handler.go:55,105,128). - อ่านผู้ใช้จาก Main DB (
sml_user_list) แล้วหาบริษัทที่ผู้ใช้เข้าได้ (ขั้นตอน login / เลือกบริษัท / refresh / logout (Identity login flow)).
- ดึง connection ของ Provider (
- บริษัทที่เลือก →
DatabaseName=sml_database_list.data_database_name(ชื่อฐานข้อมูลของบริษัท) ถูกฝังใน access token claimdatabaseName(JWT session token และการเพิกถอน (JWT + revocation store)). - คำขอ
/query,/blob,/processใช้ claimdatabaseNameนี้เปิด pool ไปยัง Company DB ด้วย connection ของ Provider เดิม (เปลี่ยนแค่ชื่อฐานข้อมูล) (ตัวจัดการ connection pool ต่อฐานข้อมูล (PoolManager)).
ตารางใน Main Database ที่โค้ด backend ใช้
| ตาราง | ใช้ทำอะไร | ที่มา |
|---|---|---|
sml_user_list |
ผู้ใช้: user_code, user_name, user_password, user_level, active_status |
postgres_repository.go:50-53 |
sml_database_list |
รายชื่อบริษัท: data_code, data_group, data_name, data_database_name, roworder |
postgres_repository.go:138-145 |
sml_database_list_user_and_group |
สิทธิ์เข้าบริษัท: user_or_group_code, user_or_group_status |
postgres_repository.go:138-145 |
sml_permissions_user / sml_permissions_group / sml_user_and_group |
สิทธิ์เมนู (blob image_file) ของผู้ใช้/กลุ่ม |
สิทธิ์เมนูและ middleware RequireRight (Menu rights / permission) |
คำศัพท์ (ตาม CONTEXT.md)
- Tenant / Provider: ลูกค้าหนึ่งรายที่ลงทะเบียนไว้; Provider Code เป็นตัวระบุหลัก (
CONTEXT.md:7). - Main Database: ฐานข้อมูลควบคุมของ Tenant (ผู้ใช้ กลุ่ม สิทธิ์ รายชื่อบริษัท).
- Company / Company Database: บริษัทหนึ่งแห่งที่ผู้ใช้เลือกทำงานด้วย.
- DataGroup: ตัวกรองกลุ่มของ
sml_database_list.data_group(เทียบแบบไม่สนตัวพิมพ์UPPER(...)). - Pre-auth token: โทเค็นสั้นหลังรหัสผ่านถูก แต่ยังไม่เลือกบริษัท (JWT session token และการเพิกถอน (JWT + revocation store)).
กติกา/ข้อควรระวัง
- Provider Code ต้องตรง
^[A-Z0-9]{2,20}$(domain/tenant/provider.go:21) และถูกToUpper(TrimSpace)ก่อนตรวจ (:70-74). - admin ห้ามสร้างฐานข้อมูลบริษัทที่ชื่อขึ้นต้น
smlerpmain(admin/handler.go:480) เพื่อกันชนกับ Main DB (Admin API สำหรับจัดการ Provider/ผู้ใช้/ฐานข้อมูล/สิทธิ์เมนู (Admin API)). - ไม่มีการบังคับที่ชั้น DB ว่า token ของ Tenant A เข้าฐาน Tenant B ไม่ได้ — การแยกเกิดจาก claim
tenantId/databaseNameที่เซ็นด้วยJWT_SIGNING_KEYเท่านั้น (อนุมานจากโค้ด). Provider.Statusมีค่าactive/suspendedแต่คอมเมนต์โค้ดบอกว่า login ควรปฏิเสธ suspended — ในโค้ดที่อ่าน (identity/service.go,tenant/service.go) ไม่พบการตรวจ Status จึงยังไม่บังคับจริง (provider.go:12-18).- ADR ที่เกี่ยวข้อง: ADR-0003 ข้อมูลผู้ใช้และสิทธิ์อยู่ใน DB ของแต่ละผู้เช่า ไม่ใช่ control-plane, ADR-0001 เก็บ config ของผู้เช่า (Provider) เป็นไฟล์ JSON ไม่ใช่ตาราง DB.
ที่มาในโค้ด
backend/CONTEXT.md:7-41— คำศัพท์โดเมน.backend/internal/application/identity/service.go:17-20,57,123,182,199— สูตรชื่อ Main DB.backend/internal/domain/tenant/provider.go:21,70-97— รูปแบบ code และProvider.backend/internal/adapter/outbound/identity/postgres_repository.go:42,132— query ผู้ใช้/บริษัท.backend/internal/adapter/inbound/http/admin/handler.go:55,105,480— admin ใช้สูตร Main DB และห้ามชื่อซ้ำ.
ดูเพิ่ม
ภาพรวม Backend Go ของ SML Ai Account (Backend overview) · ทะเบียน Provider แบบไฟล์ JSON (Provider registry) · ขั้นตอน login / เลือกบริษัท / refresh / logout (Identity login flow) · ตัวจัดการ connection pool ต่อฐานข้อมูล (PoolManager) · สารบัญ ADR ของ backend (Architecture Decision Records)