建立自訂資料表核准流程
本指南把 require_approval、Review 模組與 staged changes 串成一條可運作的流程。關鍵觀念是:符合規則的 write 會先建立 immutable intent 與 review process;只有最終核准後,worker 才用真正 CRUD 路徑套用,當時的 record version、資料表規則(immutable_when 除外,核准會刻意越過它)、unique key、channel floor(重新綁回暫存時記錄的操作身分)與 invariant 仍會再判斷。列與欄的 ACL 只在暫存時判斷一次。
1. 取得 Review template
require_approval rule 以一個 Review template 的 id 作為它的 template_id。具備 Review manager 權限的人(company manager 隱含具備)在 Review 模組中建立 template,該模組不在本手冊範圍內。只有當該 id 對應到同公司、未刪除且 gate 仍有效的 template 時,規則才能儲存;之後修改 template 只影響之後建立的 process。
2. 加入 require_approval rule
Table moderator 先 GET 完整 rules、加入候選規則、preview,再整份 PUT:
{
"type": "require_approval",
"name": "高額訂單需核准",
"label": "高額訂單變更",
"events": ["create", "update", "delete", "restore"],
"template_id": "44444444-4444-4444-8444-444444444444",
"when": [
{ "column": "金額", "op": "gte", "value": 100000 }
]
}每張表最多一條 approval rule。有 pending staged changes 時不能修改或移除它;任何 trigger 的 create_record/update_record action、自身表的 delete_record、materialize_slots action,或所引用指令會寫入這張表的 invoke_command,都不能指向它(409 approval_trigger_conflict)。完整欄位見 require_approval 與 rules.set。
3. Writer 送出變更
Writer 照常呼叫 record create/update/delete/restore。若規則命中,private API 回 409:
{
"detail": {
"error": "approval_required",
"process_id": "55555555-5555-4555-8555-555555555555",
"rule_id": "rule_a1b2c3d4",
"rule_label": "高額訂單變更",
"staged_change_id": "66666666-6666-4666-8666-666666666666"
}
}把這個 response 當作「已送審」而非一般失敗。保存兩個 IDs、停止自動 retry,並顯示 pending 狀態。同一目標已 pending 時是 approval_pending;每位 actor 在每張表的 500 筆 pending bucket,或整張表的 50 筆 pending create bucket 滿時,會回 structured 429 staged_cap_exceeded。前端應直接用 response 的 detail.scope 與 detail.limit 顯示佇列已滿:scope: "actor", limit: 500 是 actor/table 額度,scope: "table", limit: 50 是 pending-create 額度;不要把數字寫死,也不要從本次操作自行猜 scope。
自動建立的 Review process 已針對審核中心在地化。Title 為 表格「<table name>」<operation label>審核,例如 表格「訂單」修改資料審核;content 直接帶出渲染 held change 所需的 context,不必再逐筆查 table/scope:
{
"record_id": "33333333-3333-4333-8333-333333333333",
"change_type": "update",
"change_type_label": "修改資料",
"table": {
"id": "22222222-2222-4222-8222-222222222222",
"name": "訂單",
"scope": "chatroom",
"scope_label": "聊天室",
"scope_id": "11111111-1111-4111-8111-111111111111",
"scope_name": "訂單客服"
},
"requester": {
"type": "user",
"id": "44444444-4444-4444-8444-444444444444",
"name": "王小明",
"channel_label": "內部使用者",
"department_id": "55555555-5555-4555-8555-555555555555",
"department_name": "財務部"
},
"diff": { "金額": { "old": 1000, "new": 1200 } }
}若寫入來自 external client,content.requester 改為帶 type: "external_client"、id、name、platform、在地化 channel_label、chatroom_id 與 chatroom_name。名稱 enrichment 由 tenant 錨定並 fail-soft。這個 content-level requester 描述「誰造成 custom-table change」。
Moderator 可用 stagedChanges.list 依 pending / applying / applied / apply_failed / discarded 追蹤 table-side 狀態。
一批就是一次覆核,不是每個動作一次。 當規則命中同步的 POST .../records/bulk——或與它對應的 AI 工具 custom_tables_bulk_record_actions——gate 會在動作迴圈之前先跑,並只暫存一筆 change_type: "batch_actions" 的 staged change 與一個 Review process,涵蓋整批動作。決定之前沒有任何一半會先執行,而覆核者的一個決定就放行或作廢整批。核准後整批會逐列套用:成功的列維持已套用,失敗的列會讓整批以 apply_failed 結束,並附上逐列的 results。不要預期每一列都有一筆 staged change,也不要在整批 pending 時單獨重送其中的動作。
受審核的寫入也可能在暫存之前就被拒絕——請求途中開始 schema 遷移時回 423 table_locked,規則的 Review 範本已不存在時回 409 approval_template_unusable——而超過 1000 個 action 的受審核佇列式批次工作會以 gated_batch_too_large 結束為 failed。審核者看到的內容會省略受限欄位,過大的內容也會被截斷。見其他拒絕與上限。
非同步的 bulk insert(排隊的 ticket)在暫存任何東西之前,會先在 worker 裡重新授權:若送出者已經失去 insert 權限,ticket 會以 failed 結束,error_code 為 custom_table_bulk_insert_authorization_denied,也不會建立 Review process。
在 AI 這一側,這些結果是終局的,不是暫時性的。 佇列滿的拒絕以前是最大的陷阱:staged_cap_exceeded 是 HTTP 429,落在工具箱只解讀 400/409/422 的範圍之外,傳到 AI 手上變成通用的「發生內部錯誤」。於是它不斷重試一個在簽核人清空佇列前不可能成功的寫入,而使用者完全沒被告知這跟核准有關。現在 AI 拿到的是帶著上限值的政策訊息——簽核佇列已滿:這張表待審核的變更已達上限(<limit>)…——與「變更已送審」「該記錄已有變更在審」並列,成為它在同一輪內不該重試的三種結果。詳見 Agent 工具箱。
4. Reviewer 作 assignment decision
Reviewer 在 Review 模組中作決定,該模組不在本手冊範圍內:每位 reviewer 在那裡看到自己的 pending assignments,對每筆 assignment 投一票,拒絕時 comment 必須非空。最後一個 gate 核准時,staged change 會被釋放(下一步);gate denied 或 process cancelled 則走 discard 路徑。
5. Release 或 discard
最後一個 gate 核准後,Review process 變成 approved,內部 consumer 會 claim staged change 並以真實 CRUD 套用:
pending → applying → applied
↘ apply_failed此時不會沿用送審當下的「已通過」假設;record version 改變、規則否決(compare、check、require、transition、count_limit、unique/unique_tuple、same_dimension_reference、date_interval_exclusion…)、schema 漂移、channel scope 或 invariant,都可能讓套用進入 apply_failed;列與欄的 ACL 在套用時不會重新判斷。產品應同時觀察 Review process 與 staged-change status,不能只看到 approved 就立即顯示資料已落地。
任何 gate denied 或 process cancelled 時,變更不落地並進入 discard 路徑。Table moderator 也可對不再需要或需人工清理的 IDs 呼叫 stagedChanges.discard;回應是逐 ID outcome,請逐筆檢查,不要只看 top-level HTTP 200。
若 approved apply 因 queue 交付卡住,平台 operator 使用 staged-change requeue,而不是替 reviewer 再投一次票。
要在不手寫整套導覽 UI 的情況下練習規則與暫存寫入,請開啟流程精靈。