นโยบายล็อกการเขียนผ่าน Query Gateway
ตารางที่เกี่ยวกับเงิน/สต็อก/GL ต้องถูกแก้ผ่าน endpoint /process ของ Go เท่านั้น (ทำกฎธุรกิจใน transaction เดียว) — ห้ามให้เบราว์เซอร์ INSERT/UPDATE/DELETE ตรงผ่าน /query/exec, /query/execBatch หรือ /blob/insert. ตารางอื่นระดับ level < 9 แก้ได้เฉพาะรายการใน allow-list เดิม ตามที่ตัดสินใจใน ADR-0011 ล็อก SQL เขียนจาก browser: ตารางเงิน/สต๊อก/GL ผ่าน /api/process เท่านั้น.
ทำงานอย่างไร
- handler ของ
/query/execและ/query/execBatchตั้งClientRequest: true(query/handler.go:245,299); handler ของโมดูลเรียก use case เดียวกันด้วยClientRequest=false/AllowDDL=trueจึง ไม่ผ่าน นโยบายนี้ (Query Gateway: /query/list, limit, batch, exec, execBatch). Service.Exec(application/query/service.go:95) และExecBatch(:137): ถ้าClientRequest→stmt.ValidateClientPolicy(userLevel); ล้ม → 403 (ใน batch ระบุstatement i).ValidateClientPolicy(write_policy.go:77):- เจอ identifier แบบ
U&"..."(ชื่อที่ regex อ่านไม่ได้) → ปฏิเสธErrAdminOnlyWrite. - ดึงตารางเป้าหมายด้วย
writeTargetsจากinsert into | delete from | update | merge intoรวมใน CTE (ข้ามคำที่ไม่ใช่ตารางอย่างset/of/nowait/skip,write_policy.go:44-58); หาเป้าหมายไม่ได้ = ปฏิเสธ. - ตารางเงิน (
isMoneyTable) หรือic_inventoryที่แตะคอลัมน์ยอดคงเหลือที่ระบบคำนวณเอง (balance_qty,accrued_in_qty,accrued_out_qty,book_out_qty,average_cost(_1),item_in_stock,last_movement_date) →ErrMoneyTableViaExecแม้ผู้ใช้เป็น Admin. userLevel < 9และตารางไม่อยู่ในlegacyClientWritable→ErrAdminOnlyWrite.
- เจอ identifier แบบ
ValidateUserLevel(query.go:363) เป็นด่านเก่าที่แยกต่างหาก: level < 9 แก้sml_user_list,sml_database_list*,erp_optionไม่ได้ (protectedSystemTablePattern,query.go:63) และใช้กับผู้เรียกทุกทางที่ไม่ใช่AllowDDL./blob/insertใช้ValidateClientInsert(table, columns, level)(write_policy.go:64) — กติกาเดียวกันแต่รับชื่อตาราง/คอลัมน์แทน SQL (แทรกแถวพร้อมรูปภาพ: POST /blob/insert + MinIO (Blob insert)).
ตารางเงิน (moneyTablePattern, write_policy.go:24)
ic_trans*, ap_ar_trans*, as_trans*, ap_ar_debt_*, ap_ar_deposit_money, ap_ar_pay_bill(_detail), cb_trans*, cb_chq_list, gl_journal*, gl_trans(_detail), gl_account_close*, gl_summary_*, gl_wht_list(_detail), etax_document_log, e_tax_transaction, ic_lot_manage. ข้อยกเว้น: gl_journal_book เป็น master (moneyTableMasters, :27) และ ap_ar_transport_label ไม่ตรง pattern เพราะเป็น master; ic_serial อยู่ใน allow-list.
Legacy allow-list
write_policy_legacy.go:9 legacyClientWritable = ชุดชื่อตาราง master ที่หน้าจอเก่ายังเขียนผ่าน /query/exec เพราะยังไม่มี endpoint ใน Go (เช่น กลุ่ม ap_*, ar_*, as_asset* ฯลฯ ตามไฟล์) — ตารางเงิน/สต็อก/GL จะไม่อยู่ในรายการนี้เด็ดขาด; ลบชื่อออกเมื่อหน้าจอย้ายไป Go. เพิ่มคำนำหน้า monitormap_ (cache ที่สร้างใหม่ได้) ใน legacyClientWritablePrefixes (:41-42).
ตัวอย่างผล
| ผู้เรียก | SQL | ผล |
|---|---|---|
| browser, level 5 | update ar_group set ... |
ผ่าน (อยู่ allow-list) ถ้ามีสิทธิ์ Edit (สิทธิ์เมนูและ middleware RequireRight (Menu rights / permission)) |
| browser, level 5 | update ic_customer_x ... (ไม่ใน list) |
403 ErrAdminOnlyWrite |
| browser, level 9 | update ap_ar_trans set ... |
403 ErrMoneyTableViaExec |
| browser, level 9 | update some_other_table ... |
ผ่าน |
โมดูล Go (AllowDDL) |
create table ... |
ผ่าน (ไม่ตรวจนโยบาย) |
ข้อควรระวัง
- นโยบายอาศัย regex บน SQL ที่ผ่าน
scanSQL(ตัด literal/คอมเมนต์แล้ว) ไม่ใช่ parser จริง — ตารางที่อยู่ในFROMของINSERT ... SELECTไม่ถูกนับเป็นเป้าหมายเขียน (ถูกต้องตามเจตนา). - batch ที่ปนกริยา (เช่น insert+delete) ถูกจัดสิทธิ์เมนูตามคำสั่งแรก แต่นโยบายตารางตรวจทุกคำสั่ง (สิทธิ์เมนูและ middleware RequireRight (Menu rights / permission)).
- ตารางเงินยังถูกแก้ได้จาก handler โมดูล/
/processโดยตั้งใจ. - ADR-0011 เป็นแหล่งเหตุผลหลัก; ADR-0006 (DML-only) ยังเป็นด่านแรกของ
NewWriteStatement.
ที่มาในโค้ด
backend/internal/domain/query/write_policy.go:12-110— error, pattern,ValidateClientInsert,ValidateClientPolicy.backend/internal/domain/query/write_policy_legacy.go:5-48— allow-list และ prefix.backend/internal/domain/query/query.go:325-395—NewWriteStatement,ValidateUserLevel,CheckWritePermission.backend/internal/application/query/service.go:95-130,137-170— จุดเรียกนโยบาย.backend/internal/adapter/inbound/http/query/handler.go:245,299—ClientRequest: true.
ดูเพิ่ม
ภาพรวม Backend Go ของ SML Ai Account (Backend overview) · Query Gateway: /query/list, limit, batch, exec, execBatch · แทรกแถวพร้อมรูปภาพ: POST /blob/insert + MinIO (Blob insert) · สิทธิ์เมนูและ middleware RequireRight (Menu rights / permission) · ADR-0006 /query/exec รับเฉพาะ DML + ตารางระบบต้อง level>=9 (ถูกแทนด้วย ADR-0011) · ADR-0011 ล็อก SQL เขียนจาก browser: ตารางเงิน/สต๊อก/GL ผ่าน /api/process เท่านั้น · สารบัญ ADR ของ backend (Architecture Decision Records)