ทะเบียน Provider แบบไฟล์ JSON
ข้อมูลการเชื่อมต่อฐานข้อมูลของแต่ละ Tenant ไม่ได้อยู่ใน DB แต่เก็บเป็นไฟล์ในโฟลเดอร์ CONFIG_DIR (default configs): ดัชนี providerlist.json หนึ่งไฟล์ + SMLConfig<CODE>.json หนึ่งไฟล์ต่อ Provider. ตัดสินใจไว้ใน ADR-0001 เก็บ config ของผู้เช่า (Provider) เป็นไฟล์ JSON ไม่ใช่ตาราง DB; รหัสผ่านใช้ base64 ไม่ใช่การเข้ารหัสจริง (ADR-0002 รหัสผ่าน DB ของผู้เช่าเก็บเป็น base64 ไม่ได้เข้ารหัส). ห้ามคัดลอกเนื้อหาไฟล์เหล่านี้ลงเอกสาร/แชท/git (มีรหัสผ่านฐานข้อมูลจริง).
ทำงานอย่างไร (สร้าง Provider)
POST /admin/providers(ต้องAdminAuth) →tenantHandler.Create→Service.CreateProvider(application/tenant/service.go:28).- ทดสอบเชื่อมต่อจริงก่อน:
ConnectionTester.TestConnectionเปิดpgx.Connectแล้วPing(adapter/outbound/tenant/connection_tester.go:26-34); ล้มเหลว →KindValidation("could not connect to the database with the given connection details"). - เข้ารหัสรหัสผ่านด้วย
codec.Encode= base64 มาตรฐาน (outbound/cryptoEncode, ไฟล์base64_codec.go:19-21). NewProviderตรวจ code^[A-Z0-9]{2,20}$, ชื่อไม่ว่าง, connection ครบ (host, port>0, database, user, password) แล้วตั้งStatus = active(domain/tenant/provider.go:70-92).repo.Save(jsonfile_repository.go:64): ล็อก mutex → อ่านดัชนี → ถ้า code ซ้ำคืนErrProviderCodeExists(แปลงเป็น 409) → เขียนไฟล์ connection ก่อน แล้วค่อยต่อท้ายดัชนี (ถ้าพังกลางคัน ได้ไฟล์กำพร้า ไม่ใช่ดัชนีชี้ไปที่ไม่มี).- ตอนใช้งาน
GetProviderConnection(service.go:66) อ่านแล้วcodec.Decodeคืน connection รหัสผ่านจริงให้ resolver ของ identity/query/blob (โมเดลผู้เช่าหลายราย: Tenant, Provider, Main DB, Company (Multi-tenant model)).
รูปแบบไฟล์
providerlist.json(ดัชนี): แต่ละแถวcode,name,status,createdAt(jsonfile_repository.go:22-28) —Listคืนเฉพาะข้อมูลนี้ ไม่แตะไฟล์ connection (:134).SMLConfig<CODE>.json:host,port,database,user,password(base64),sslmode(:30-37); ชื่อไฟล์มาจากProvider.ConfigFileName()(provider.go:96).- เขียนแบบ atomic: เขียน
*.tmpด้วยสิทธิ์0o600แล้วos.Renameทับ (writeJSONAtomic,:205-215). โฟลเดอร์สร้างด้วย0o755(:54-59). Getเทียบ code แบบไม่สนตัวพิมพ์ (strings.EqualFold,:94-108); ไม่พบ →ErrProviderNotFound→ 404.
ข้อจำกัด / ข้อควรระวัง
- ความปลอดภัยของ concurrent มาจาก
sync.Mutexในโปรเซสเดียวเท่านั้น (:44-48) → ใช้ได้กับ instance เดียว; K8sreplicas: 2ทำให้แต่ละ pod เห็นไฟล์ของตัวเอง (การ build และ deploy backend: Docker, Kubernetes, Makefile (Deployment)). - base64 อ่านรหัสผ่านออกได้ทันที — ปกป้องด้วยสิทธิ์ไฟล์
0o600และไม่ commit เท่านั้น. - ไม่มี API แก้ไข/ลบ Provider ที่ทำงานจริงในชั้น application (มีแค่
Save/Get/List);UpdateProvider/DeleteProviderใน admin API เป็น stub (Admin API สำหรับจัดการ Provider/ผู้ใช้/ฐานข้อมูล/สิทธิ์เมนู (Admin API)). Statusไม่ถูกตรวจตอน login (ดู โมเดลผู้เช่าหลายราย: Tenant, Provider, Main DB, Company (Multi-tenant model)).- โฟลเดอร์
CONFIG_DIRยังเก็บrevoked_sessions.jsonของ session ที่ถูกเพิกถอน (JWT session token และการเพิกถอน (JWT + revocation store)).
ที่มาในโค้ด
backend/internal/adapter/outbound/tenant/jsonfile_repository.go:20-60— ชื่อไฟล์ รูปแบบ และ constructor.backend/internal/adapter/outbound/tenant/jsonfile_repository.go:64-92—Save.backend/internal/adapter/outbound/tenant/jsonfile_repository.go:205-215— เขียนแบบ atomic.backend/internal/application/tenant/service.go:28-80—CreateProvider,ListProviders,GetProviderConnection.backend/internal/adapter/outbound/tenant/connection_tester.go:26-34— ทดสอบเชื่อมต่อ.backend/internal/domain/tenant/provider.go:70-97—NewProvider,ConfigFileName.
ดูเพิ่ม
ภาพรวม Backend Go ของ SML Ai Account (Backend overview) · โมเดลผู้เช่าหลายราย: Tenant, Provider, Main DB, Company (Multi-tenant model) · ตัวแปรสภาพแวดล้อมและการโหลด config ของ backend (Environment config) · ADR-0001 เก็บ config ของผู้เช่า (Provider) เป็นไฟล์ JSON ไม่ใช่ตาราง DB · ADR-0002 รหัสผ่าน DB ของผู้เช่าเก็บเป็น base64 ไม่ได้เข้ารหัส · สารบัญ ADR ของ backend (Architecture Decision Records)