ADR-0011 ล็อกการเขียนผ่าน /query/exec จาก browser
สถานะ: accepted และเป็น ADR ล่าสุด/ปัจจุบัน ที่แทน ADR-0006 /query/exec รับเฉพาะ DML + ตารางระบบต้อง level>=9 (ถูกแทนด้วย ADR-0011) (backend/docs/adr/0011-query-exec-write-lockdown.md:3). แนวคิด: กฎธุรกิจ/GL/สต๊อกอยู่ใน Go backend, browser เป็น thin client — จึงห้าม browser ใช้ SQL เขียนตารางเงินตรง ๆ.
ทำงานอย่างไร
/query/list|limit|batchรับSELECT/WITHทุก session;/query/exec|execBatchรับเฉพาะINSERT/UPDATE/DELETE(หรือWITHที่ห่อ DML) อย่างเดียว — อย่างอื่นรวมถึงSELECTได้ 400ErrNotWriteOnly(...0011...md:15-17).- handler ตั้ง
ExecInput.ClientRequest = true(query/handler.go:245,299); service เรียกWriteStatement.ValidateClientPolicy(userLevel)เมื่อClientRequest(application/query/service.go:105,146;write_policy.go:77). - กฎเรียงตามลำดับ:
- ตารางเงิน/สต๊อก/GL ถูกปฏิเสธ ทุกคนแม้ level 9 →
ErrMoneyTableViaExec(HTTP 403):ic_trans*,as_trans*,ap_ar_trans*,ap_ar_debt_*,ap_ar_deposit_money,ap_ar_pay_bill*,cb_trans*,cb_chq_list,gl_journal*(ยกเว้นมาสเตอร์gl_journal_book),gl_trans*,gl_account_close*,gl_summary_*,gl_wht_list*,etax_document_log,e_tax_transaction,ic_lot_manage, และic_inventoryที่แตะคอลัมน์ derived (balance_qty,accrued_*_qty,book_out_qty,average_cost*,item_in_stock,last_movement_date) —write_policy.go:24-31. - level >= 9 (SQL Studio) เขียนตารางอื่นได้.
- level < 9 เขียนได้เฉพาะ allow-list
legacyClientWritable(มาสเตอร์ลูกค้า/ผู้ขาย/คลัง/หน่วย/โปรไฟล์บริษัท ฯลฯ) —write_policy_legacy.go:9. - ตารางระบบ
erp_option,sml_user_list,sml_database_list*เป็น admin-only ผ่านValidateUserLevel; statement ที่หาเป้าหมายเขียนไม่เจอ → admin-only. - DDL,
MERGEและชื่อ identifier แบบU&"..."ถูกปฏิเสธ/จำกัด admin (write_policy.go:35).
- ตารางเงิน/สต๊อก/GL ถูกปฏิเสธ ทุกคนแม้ level 9 →
- caller ภายใน Go (crm, etax, market, monitormap, procure, tms, wms) ใช้
ClientRequest = falseจึงไม่ถูกกระทบ (...0011...md:39).
ที่ย้ายออกจาก SQL ในเบราว์เซอร์แล้ว
stock beginning, point docs (flag 801/802), check price, ฟังก์ชัน system process (check-ic-trans, point-recal, import-transport-label), และ docnonext → ทั้งหมดเป็น /api/process/... (ตารางใน ...0011...md:44-50) — โค้ดอยู่ใน application/process ซึ่งอยู่นอกโน้ตชุดนี้ ดู ภาพรวมกลุ่ม process ของ Backend (Process overview).
วิธีหดรายการ allow-list (ratchet)
ย้ายหน้าจอไป endpoint Go (parameterized, 1 transaction, เงินเป็น string) → เปลี่ยนหน้าจอเป็น apiPost → ลบตารางออกจาก legacyClientWritable → เพิ่มเคสใน write_policy_test.go (...0011...md:54-56). ตารางใหม่เป็น admin-only จนกว่าจะมีคนเพิ่มโดยตั้งใจ.
ข้อควรระวัง
erp_user_datalist_config,erp_option_etax_inet,erp_option_mobillyst,erp_thai_qr_configตั้งใจ ไม่ อยู่ใน allow-list.- ตารางใหม่ที่ขึ้นต้นเหมือนตารางเงินจะถูกบล็อกโดย regex อัตโนมัติ (
moneyTablePattern,write_policy.go:24) — ถ้าต้องการเขียนจริงต้องทำ endpoint ใน/api/process. - แยกจาก
/blob/insertซึ่งใช้ValidateClientInsertเช็กกฎเดียวกันที่ระดับตาราง/คอลัมน์ (แทรกแถวพร้อมรูปภาพ: POST /blob/insert + MinIO (Blob insert)).
ที่มาในโค้ด
backend/docs/adr/0011-query-exec-write-lockdown.md:15— ส่วน Decision.backend/internal/domain/query/write_policy.go:14,24,77— error ใหม่, regex ตารางเงิน,ValidateClientPolicy.backend/internal/domain/query/write_policy_legacy.go:9—legacyClientWritable.backend/internal/adapter/inbound/http/query/handler.go:245— ตั้งClientRequest: true.
ดูเพิ่ม
นโยบายล็อกการเขียนผ่าน Query Gateway (Query write policy / lockdown) · Query Gateway: /query/list, limit, batch, exec, execBatch · สิทธิ์เมนูและ middleware RequireRight (Menu rights / permission) · สารบัญ ADR ของ backend (Architecture Decision Records)