人工審批
在任意步驟加 manual_approval 門控:App 內、郵件、API 三條通道批覆,數值可編輯,逾時自動拒絕。
manual_approval 把「等某個人確認再繼續」編碼成步驟修飾符:執行到達設定了它的步驟時暫停,批准後才執行步驟本體。批准之前,系統不會執行該步驟及其下游的任何動作。
配置
- step: apply_changes
agent: executor
input: "把已审核的变更应用到线上"
manual_approval:
enabled: true
approvers: # 平台用户 ID;留空 = 发起人 / 有执行权限者可批
- "usr_team_lead"
timeout: 86400 # 秒;24 小时无人批复自动拒绝
approval_message: |
请确认是否应用本轮变更。
拒绝或超时不会做任何线上修改。它可以掛在任意步驟上(agent、code、sub_workflow 等),也常用於一個只列印狀態的輕量 code 步驟,作為純粹的「人工閘門」。
參數
| 字段 | 類型 | 默認 | 說明 |
|---|---|---|---|
enabled | boolean | — | 是否啟用審批門控(必填) |
approvers | string[] | [] | 指定審批人(平台使用者 ID)。非空時只有名單內的使用者與管理員能批復——執行發起人也不行,天然滿足職責分離;留空時執行發起人或對該工作流有執行權限的協作者都可批復 |
timeout | long | 3600 | 逾時秒數。到點無人批復則自動拒絕,狀態標 TIMED_OUT |
approval_message | string | null | 展示給審批人的說明,出現在審批卡片與通知郵件裡 |
reviewable_actions | array | [] | 可編輯審批表分組,審批人可勾選子集、編輯數值後再批准(見下文) |
審批流程
- 執行到達設定了 manual_approval 的步驟時暫停,執行狀態變為 AWAITING_APPROVAL
- 建立審批記錄並開始逾時計時;控制台透過 WebSocket 收到 approval_request 即時提醒,審批人可同時收到通知郵件
- 審批人從三條通道之一批復:App 內審批列表、訊息裡的一鍵連結、API
- 批准 → 步驟繼續;拒絕 → 步驟按失敗處理(可用 on_failure 接通知分支);逾時 → 自動拒絕
通道一:App 內審批列表
控制台的審批管理頁面列出你可見的全部審批,支援卡片/表格兩種檢視與狀態篩選。批准或拒絕時可附備註,備註會儲存在審批記錄裡。設定了 reviewable_actions 的審批會展開為可勾選、可編輯的表格。
通道二:郵件通知與一鍵連結
開啟郵件通知後,審批人(未指定 approvers 時為執行發起人)帳號電子郵件會收到郵件,內容包括:工作流與步驟名、執行 ID、可審核動作數量、逾時提示(「約 N 小時後自動拒絕」)、approval_message 的說明文字,以及進入審批列表的連結。
郵件、Slack、Telegram 這類無法自訂請求標頭的訊息裡,還可以嵌入一鍵批復連結:
GET https://braidrun.com/api/webhook-trigger/approval/{approvalId}/approve?api_key=dyk_...
GET https://braidrun.com/api/webhook-trigger/approval/{approvalId}/reject?api_key=dyk_...連結用 API Key 鑑權(APPROVAL_RESPOND 範圍),Key 放在 api_key 查詢參數裡。為防止連結預覽機器人(Slack 展開、郵件用戶端預抓取)誤觸,第一次開啟只渲染確認頁、不執行任何動作;點擊確認按鈕後帶 confirm=1 再次請求才真正批復。頁面帶 no-store 與 noindex 標頭,避免快取或搜尋引擎重放。
通道三:API
v1 開放 API 提供 5 個審批端點,全部要求 APPROVAL_RESPOND 權限範圍:
| 端點 | 作用 |
|---|---|
GET /api/v1/approvals | 審批列表,可按 status 篩選 |
GET /api/v1/approvals/{id} | 審批詳情 |
GET /api/v1/approvals/execution/{executionId} | 查某次執行關聯的審批 |
POST /api/v1/approvals/{id}/approve | 批准;body 可帶 comment 與 editedItems |
POST /api/v1/approvals/{id}/reject | 拒絕;body 可帶 comment |
# 批准(可附备注)
curl -X POST https://braidrun.com/api/v1/approvals/<approval-id>/approve \
-H "Authorization: Bearer dyk_..." \
-H "Content-Type: application/json" \
-d '{"comment": "确认执行"}'
# 拒绝
curl -X POST https://braidrun.com/api/v1/approvals/<approval-id>/reject \
-H "Authorization: Bearer dyk_..." \
-H "Content-Type: application/json" \
-d '{"comment": "本轮预算已用完"}'editedItems 按分組名提交勾選/編輯後的子集,結構與下節的可編輯審批表對應;不傳則視為原樣全部批准。
可編輯審批表(reviewable_actions)
有些審批的粒度落在單條建議上:一批建議裡只執行其中一部分,個別列還要改數值。reviewable_actions 把這類審批做成表格——審批人勾選要執行的列,直接編輯標了 editable: true 的欄位(例如改出價),然後再點批准。
manual_approval:
enabled: true
timeout: 86400
approval_message: |
请审核本轮调价建议:可勾选要执行的行,并直接修改建议出价。
reviewable_actions:
- name: raise_bid
title: 加价建议
source_var: raise_bid_file # 变量值 = 建议清单 JSON 数组文件路径
output_var: raise_bid_approved_file # 批准后 = 勾选/编辑后的子集文件路径
key_field: item_id
columns:
- { key: item_name, label: 名称, editable: false }
- { key: current_bid, label: 当前出价, type: number, editable: false }
- { key: proposed_bid, label: 建议出价, type: number, editable: true }
- { key: reason, label: 理由, editable: false }name— 分組內部名,同時用作輸出檔案前綴(批准後引擎寫出 reviewed_<name>.json)source_var— 指向一個變數,變數值是上游步驟產生的建議清單(JSON 陣列檔案路徑)output_var— 批准後設定的變數,值為勾選/編輯後的子集檔案路徑;下游執行步驟改讀它,就只會處理被批准的列key_field— 列身分欄位,編輯後按它對齊;預設按陣列索引對齊columns— 表格欄位定義;editable: true 的欄位審批人可改,type: number 渲染為數字輸入
提交的子集會在伺服器端校驗:不屬於任何分組的資料被過濾;定義了 key_field 時,每列必須能在原清單裡找到對應項,拼一列不存在的資料無法繞過;editable: false 的欄位以原值為準,改了也無效。某個分組一列都沒勾選時會寫出空陣列,下游步驟按「全空跳過」處理。
拒絕與逾時:零改動
審批門控的核心承諾是:批准之前系統不執行任何動作。拒絕或逾時時——
- 步驟本體不執行,相依它的下游步驟也不會觸發
- 可用 on_failure 分支接一個「審批被拒」的通知或封存步驟
- 逾時由系統自動拒絕,決策人記為 system;每次審批決定(含決策人、時間、備註)都會寫入稽核日誌
審批記錄持久化儲存。服務重啟後,待處理的審批原樣恢復,逾時計時按原始截止時間繼續,審批人照常批復即可。