規則、觸發器與回呼
驗證寫入、自動化資料表事件、檢視階段性工作,並管理各範圍支援的回呼憑證。
/private/module/custom_tables/{scope}/tables/{table_id}/rules回傳資料表已正規化的規則定義(參照以顯示名稱呈現),並附上 `rules_digest`,作為之後 PUT 的前置條件權杖。
適合顯示規則編輯器,或在變更資料前檢查實際套用的寫入限制。
- 聊天室
/private/module/custom_tables/chatroom/{chatroom_id}/tables/{table_id}/rules - 部門
/private/module/custom_tables/department/{department_id}/tables/{table_id}/rules - 公司
/private/module/custom_tables/company/tables/{table_id}/rules
範圍
| 範圍 | 是否提供 | 驗證與權限 |
|---|---|---|
| 聊天室 | 可使用 | ChatroomTableMetadataReadRequired |
| 部門 | 可使用 | DepartmentTableMetadataReadRequired |
| 公司 | 可使用 | CompanyTableMetadataReadRequired |
參數
| 欄位 | 位置 | 型別 | 必填 | 說明 |
|---|---|---|---|---|
table_id | path | uuid | 是 | 要取得規則的資料表 UUID。 |
回應結構
TableRulesResponse| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
rules | object[] | 否 | 未指定 |
rules_digest | string | 是 | Stable digest of the stored normalized rule list, for expected_rules_digest on a later PUT. |
table_id | string | 是 | 未指定 |
warnings | string[] | 否 | Non-fatal notices about the saved rule set — e.g. a content-masking notice when a require_approval rule is saved on a table with column_acl or grant visible_columns restrictions (approval-gate spec §4). |
範例
取得資料表的唯一值規則
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222"
}
}{
"rules_digest": "3b7e9c0d4a1f2e8b6c5d9a0f1e2d3c4b5a69788796a5b4c3d2e1f0a9b8c7d6e5",
"table_id": "22222222-2222-4222-8222-222222222222",
"rules": [
{
"type": "unique",
"id": "rule_a1b2c3d4e5f6",
"name": "訂單編號不可重複",
"columns": [
"訂單編號"
],
"case_insensitive": true,
"when": null,
"constraint_id": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"
}
],
"warnings": []
}錯誤
驗證錯誤範例列出識別欄位;部署中的驗證器也可能回傳 input 與 ctx。錯誤訊息 URL 的版本由建置決定,因此使用 pydantic-version 佔位符。
| 狀態 | 發生條件 | 錯誤本文 |
|---|---|---|
| 404 | 資料表不存在或已在垃圾桶、屬於其他範圍,或你對它沒有任何權利——所有情況都回 `CustomTable Not found`,因此被隱藏的資料表看起來與未知 id 完全相同。其他公司的資料表也回同樣的 404(自後端 5.21.0 起)。 | |
/private/module/custom_tables/{scope}/tables/{table_id}/rules驗證並以原子方式取代後續資料表寫入所套用的完整規則集。
預覽完整的目標規則集後使用;PUT 會在單一交易中取代已儲存的規則清單。
- 聊天室
/private/module/custom_tables/chatroom/{chatroom_id}/tables/{table_id}/rules - 部門
/private/module/custom_tables/department/{department_id}/tables/{table_id}/rules - 公司
/private/module/custom_tables/company/tables/{table_id}/rules
範圍
| 範圍 | 是否提供 | 驗證與權限 |
|---|---|---|
| 聊天室 | 可使用 | CustomTableModeratorRequired |
| 部門 | 可使用 | CustomTableModeratorRequired |
| 公司 | 可使用 | CustomTableModeratorRequired |
參數
| 欄位 | 位置 | 型別 | 必填 | 說明 |
|---|---|---|---|---|
table_id | path | uuid | 是 | 要取代規則的資料表 UUID。 |
請求結構
TableRulesPayload| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
expected_rules_digest | string | null | 否 | Optional digest from GET rules. A changed stored rules list returns409 with no write; omission preserves unconditional replacement. |
rules | (AggregateLimitRuleSpec | SameDimensionReferenceRuleSpec | DateIntervalExclusionRuleSpec | PeriodFenceRuleSpec | object)[] | 是 | Full rules list (PUT semantics; max 10). Each rule: {"type": "compare" | "unique" | "unique_tuple" | "same_dimension_reference" | "date_interval_exclusion" | "no_overlap" | "exists" | "not_exists" | "count_limit" | "aggregate_limit" | "transition" | "check" | "require" | "require_approval" | "channel" | "invariant" | "immutable_when" | "period_fence", "name"?: str, "id"?: "rule_<hex>", "when"?: [predicates], ...type-specific fields}. An opt-in "unique_tuple" rule takes 1..16 ordered {"column": ref, "null_policy": "forbidden"|"equal"|"distinct"} components, "case_insensitive"?: boolean and "unicode_normalization"?: "none"|"NFC". A "count_limit" rule caps a live-row bucket at {"max": int >= 1}: with "table_id" + "match" it counts the exists-style cross-table bucket; without "table_id" it counts THIS table's rows matching "where" predicates ("$row.<col>" values partition per row, e.g. employee eq $row.employee). A "date_interval_exclusion" rule takes two distinct date columns and 1..2 cardinality-one native-link scopes; a create must supply its end as a date or explicit null, and [start,end) is non-overlapping within the partition. A "no_overlap" rule additionally takes "min_gap"?: number — minimum separation between intervals in the same scope partition (numeric bounds: plain number; datetime: minutes; date: days; touching at exactly min_gap is allowed) — and bounds its intervals EITHER with "start_column"+"end_column" OR with "interval_column" (ONE interval-type column whose {start, end} cell carries both bounds; datetime class, min_gap in minutes) — never both. A "channel" rule (SCP v1.3) takes EITHER {"column", "require_present", "read_op"?: "subset" | "overlaps"} or {"policy": <node tree>}, plus "enforcement": "observe" | "enforce" — see ChannelRuleFlat / ChannelRulePolicy. An "invariant" rule takes {"policy": <node tree>, "enforcement"} and is principal-blind: it holds for every writer on every path — see InvariantRule. An "immutable_when" rule takes {"prior_when": [predicates], "columns": [refs]} and takes no "when": prior_when is the lock condition evaluated against the row's PRE-image (the row before the write); while it matches, the listed columns may not change (400 on violation). Locks stored inline columns only (not computed/link). A "period_fence" rule (ct.calendars) refuses writes whose dated row falls in a closed or missing period — see PeriodFenceRuleSpec; at most 3 per table. |
回應結構
TableRulesResponse| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
rules | object[] | 否 | 未指定 |
rules_digest | string | 是 | Stable digest of the stored normalized rule list, for expected_rules_digest on a later PUT. |
table_id | string | 是 | 未指定 |
warnings | string[] | 否 | Non-fatal notices about the saved rule set — e.g. a content-masking notice when a require_approval rule is saved on a table with column_acl or grant visible_columns restrictions (approval-gate spec §4). |
範例
設定不分大小寫的唯一值規則
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222"
},
"body": {
"rules": [
{
"type": "unique",
"name": "訂單編號不可重複",
"columns": [
"訂單編號"
],
"case_insensitive": true
}
]
}
}{
"rules_digest": "3b7e9c0d4a1f2e8b6c5d9a0f1e2d3c4b5a69788796a5b4c3d2e1f0a9b8c7d6e5",
"table_id": "22222222-2222-4222-8222-222222222222",
"rules": [
{
"type": "unique",
"id": "rule_a1b2c3d4e5f6",
"name": "訂單編號不可重複",
"columns": [
"訂單編號"
],
"case_insensitive": true,
"when": null,
"constraint_id": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"
}
],
"warnings": []
}列一旦 posted 就凍結數量與單價
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222"
},
"body": {
"rules": [
{
"type": "immutable_when",
"name": "posted-locks-qty",
"prior_when": [
{
"column": "狀態",
"op": "eq",
"value": "posted"
}
],
"columns": [
"數量",
"單價"
]
}
]
}
}{
"rules_digest": "9f8e7d6c5b4a39281706f5e4d3c2b1a0f9e8d7c6b5a4938271605f4e3d2c1b0a",
"table_id": "22222222-2222-4222-8222-222222222222",
"rules": [
{
"type": "immutable_when",
"id": "rule_b2c3d4e5f6a7",
"name": "posted-locks-qty",
"prior_when": [
{
"column": "狀態",
"op": "eq",
"value": "posted"
}
],
"columns": [
"數量",
"單價"
],
"when": null
}
],
"warnings": []
}在 expected_rules_digest 前置條件下新增 unique_tuple 規則
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222"
},
"body": {
"expected_rules_digest": "3b7e9c0d4a1f2e8b6c5d9a0f1e2d3c4b5a69788796a5b4c3d2e1f0a9b8c7d6e5",
"rules": [
{
"type": "unique",
"id": "rule_a1b2c3d4e5f6",
"name": "訂單編號不可重複",
"columns": [
"訂單編號"
],
"case_insensitive": true,
"when": null,
"constraint_id": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"
},
{
"type": "unique_tuple",
"name": "每年度發票號碼不可重複",
"components": [
{
"column": "會計年度",
"null_policy": "forbidden"
},
{
"column": "發票號碼",
"null_policy": "equal"
}
],
"case_insensitive": true,
"unicode_normalization": "NFC"
}
]
}
}{
"rules_digest": "9f8e7d6c5b4a39281706f5e4d3c2b1a0f9e8d7c6b5a4938271605f4e3d2c1b0a",
"table_id": "22222222-2222-4222-8222-222222222222",
"rules": [
{
"type": "unique",
"id": "rule_a1b2c3d4e5f6",
"name": "訂單編號不可重複",
"columns": [
"訂單編號"
],
"case_insensitive": true,
"when": null,
"constraint_id": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"
},
{
"id": "rule_c3d4e5f6a7b8",
"type": "unique_tuple",
"name": "每年度發票號碼不可重複",
"when": null,
"components": [
{
"column": "會計年度",
"null_policy": "forbidden"
},
{
"column": "發票號碼",
"null_policy": "equal"
}
],
"case_insensitive": true,
"unicode_normalization": "NFC",
"constraint_id": "cccccccc-cccc-4ccc-8ccc-cccccccccccc"
}
],
"warnings": []
}錯誤
驗證錯誤範例列出識別欄位;部署中的驗證器也可能回傳 input 與 ctx。錯誤訊息 URL 的版本由建置決定,因此使用 pydantic-version 佔位符。
| 狀態 | 發生條件 | 錯誤本文 |
|---|---|---|
| 400 | 至少一筆規則的類型、欄位參照、運算式或選項無效。 | |
| 400 | immutable_when 規則缺少 prior_when 或 columns、帶了一般的 when、被鎖欄位超過 20 個,或鎖到計算欄/link 欄。detail 是純字串,有 hint 時會在句點後併入。 | |
| 409 | 仍有未解決的階段性變更依賴 require_approval 規則,因此不能變更該規則。 | |
| 403 | 你看得到這張資料表,但不是它的 moderator。訊息內容依資料表範圍而定:這是你自己部門內聊天室資料表的回應;其他部門的聊天室資料表會是 `…or management rights.`,部門資料表是 `…table moderator, department manager, or company management rights.` 或 `…table moderator or department management rights.`,公司資料表則是 `…table moderator or company management rights.` | |
| 404 | 沒有這個 id 的 live 資料表:它從未存在、已被永久清除,或正在垃圾桶中。其他公司的資料表也回同樣的結果(自後端 5.21.0 起,不再是 403)。在聊天室路徑上,屬於其他聊天室的資料表也回同樣的結果。 | |
| 404 | 資料表所屬的聊天室已被刪除。聊天室被軟刪除後,它自己的資料表仍是 live,但 moderator 閘門在每一種路徑(聊天室、部門或公司)都會拒絕它們——時間點在查到資料表與公司檢查之後(其他公司的資料表改為回 `CustomTable Not found`)、moderator 檢查之前。 | |
| 404 | 部門或公司路徑:資料表存在、你也是它的 moderator,但它屬於路徑以外的範圍(`Table not found in this department`/`… in this company`)。因為公司管理者是公司內每張資料表的 moderator,這個情況確實可能發生。在聊天室路徑上,同樣的情況會回 `CustomTable Not found`。 | |
| 409 | `expected_rules_digest` 與已儲存的規則不符:期間有其他編輯者存檔。沒有寫入任何東西(規則與 history 都沒有)。請重新載入、重新套用你的修改,並送出新的摘要。 | |
| 409 | 新增或修改的 `unique` 規則無法啟用,因為既有的 live 列已經重複。Body 會把最多五組碰撞樣本與其紀錄 id 列給讀得到每個 component 與每筆碰撞列的呼叫者(其他人只拿到衝突中繼資料);不會儲存任何東西。 | |
| 409 | 新增或修改的 `unique_tuple` 規則無法啟用,因為既有的 live 列已經重複。Body 不含任何值——只點名約束與欄位,不列出資料列——且不會儲存任何東西。 | |
| 409 | 既有的 live 列已經違反新的 `same_dimension_reference` 規則(參照或維度缺少、不是 live,或沒有共用)。不會儲存任何東西。 | |
| 409 | 既有的存活資料列已經違反新的 `date_interval_exclusion` 規則:沒有合法期間的資料列(起始日缺漏、結束日缺漏或不晚於起始日,或 scope link 沒有剛好指向一個目標)是 `date_interval_exclusion_invalid_period`,同一分割內期間重疊的兩列是 `date_interval_exclusion_overlap`。什麼都不會儲存。body 只有固定訊息,絕不指出資料列、日期或 scope 值;`rules.preview` 不會執行這項檢查。 | |
| 409 | 這份清單替某張資料表加上 `require_approval` 規則,但有 trigger action 會寫入這張表(create_record/update_record 的目標、自身表的 delete_record、materialize_slots 的目標,或所引用指令會寫入它的 invoke_command)。請先移除或改寫那個 action 的目標。 | |
| 422 | Request 驗證失敗:超過 10 條規則、`unique_tuple`、`same_dimension_reference` 或 `date_interval_exclusion` 的 shape 錯誤(例如 17 個 component、缺少 `null_policy`、參照或期間規則帶非空的 `when`)、`channel` 或 `invariant` 規則的 shape 錯誤、policy 超過上限,或 `expected_rules_digest` 不是 64 個小寫 hex 字元。 | |
| 423 | 資料表目前被結構遷移鎖定。 | |
| 409 | Rules transaction 中遇到 MySQL 1205 lock-wait timeout 或 1213 deadlock。所有變更都已回滾;請重試請求。 | |
| 500 | 其他資料庫錯誤讓整個 transaction 回滾;detail 是淨化後的 flat 字串 Database operation failed.。 | |
| 400 | 儲存時發生非預期、非資料庫錯誤的兜底回應(前綴之後是錯誤文字)。不會儲存任何東西。 | |
/private/module/custom_tables/{scope}/tables/{table_id}/rules/preview驗證候選規則集,並在有上限的樣本上評估,不儲存規則。
取代正式規則前使用,特別是 `channel`/`invariant` 規則(抽樣的資料列影響)與 `same_dimension_reference` 規則(既有列准入檢查)。它不會把 `exists`/`not_exists`/`count_limit`/`check` 或 unique 碰撞套到既有列上。
- 聊天室
/private/module/custom_tables/chatroom/{chatroom_id}/tables/{table_id}/rules/preview - 部門
/private/module/custom_tables/department/{department_id}/tables/{table_id}/rules/preview - 公司
/private/module/custom_tables/company/tables/{table_id}/rules/preview
範圍
| 範圍 | 是否提供 | 驗證與權限 |
|---|---|---|
| 聊天室 | 可使用 | CustomTableModeratorRequired |
| 部門 | 可使用 | CustomTableModeratorRequired |
| 公司 | 可使用 | CustomTableModeratorRequired |
參數
| 欄位 | 位置 | 型別 | 必填 | 說明 |
|---|---|---|---|---|
table_id | path | uuid | 是 | 要評估候選規則的資料表 UUID。 |
請求結構
TableRulesPreviewPayload| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
expected_rules_digest | string | null | 否 | Optional digest from GET rules. A changed stored rules list returns409 with no write; omission preserves unconditional replacement. |
rules | (AggregateLimitRuleSpec | SameDimensionReferenceRuleSpec | DateIntervalExclusionRuleSpec | PeriodFenceRuleSpec | object)[] | 是 | Full rules list (PUT semantics; max 10). Each rule: {"type": "compare" | "unique" | "unique_tuple" | "same_dimension_reference" | "date_interval_exclusion" | "no_overlap" | "exists" | "not_exists" | "count_limit" | "aggregate_limit" | "transition" | "check" | "require" | "require_approval" | "channel" | "invariant" | "immutable_when" | "period_fence", "name"?: str, "id"?: "rule_<hex>", "when"?: [predicates], ...type-specific fields}. An opt-in "unique_tuple" rule takes 1..16 ordered {"column": ref, "null_policy": "forbidden"|"equal"|"distinct"} components, "case_insensitive"?: boolean and "unicode_normalization"?: "none"|"NFC". A "count_limit" rule caps a live-row bucket at {"max": int >= 1}: with "table_id" + "match" it counts the exists-style cross-table bucket; without "table_id" it counts THIS table's rows matching "where" predicates ("$row.<col>" values partition per row, e.g. employee eq $row.employee). A "date_interval_exclusion" rule takes two distinct date columns and 1..2 cardinality-one native-link scopes; a create must supply its end as a date or explicit null, and [start,end) is non-overlapping within the partition. A "no_overlap" rule additionally takes "min_gap"?: number — minimum separation between intervals in the same scope partition (numeric bounds: plain number; datetime: minutes; date: days; touching at exactly min_gap is allowed) — and bounds its intervals EITHER with "start_column"+"end_column" OR with "interval_column" (ONE interval-type column whose {start, end} cell carries both bounds; datetime class, min_gap in minutes) — never both. A "channel" rule (SCP v1.3) takes EITHER {"column", "require_present", "read_op"?: "subset" | "overlaps"} or {"policy": <node tree>}, plus "enforcement": "observe" | "enforce" — see ChannelRuleFlat / ChannelRulePolicy. An "invariant" rule takes {"policy": <node tree>, "enforcement"} and is principal-blind: it holds for every writer on every path — see InvariantRule. An "immutable_when" rule takes {"prior_when": [predicates], "columns": [refs]} and takes no "when": prior_when is the lock condition evaluated against the row's PRE-image (the row before the write); while it matches, the listed columns may not change (400 on violation). Locks stored inline columns only (not computed/link). A "period_fence" rule (ct.calendars) refuses writes whose dated row falls in a closed or missing period — see PeriodFenceRuleSpec; at most 3 per table. |
回應結構
RulesPreviewResponse| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
aggregate_violations | integer | 否 | Violating aggregate groups in the full live population; includes exact current sums. |
invariant_violations | integer | 否 | Sampled rows that already fail the candidate INVARIANT rules. Reported once, not per room: an invariant has no principal. Such rows stay readable but become uneditable until repaired. |
rooms | RulesPreviewRoomImpact[] | 否 | Per acting room, for the CHANNEL rules. Empty when the candidate carries no channel rule or the table has no chatroom grants. |
sample_cap | integer | 是 | The sampling cap applied. |
sampled_rows | integer | 是 | Live rows actually evaluated (the first N by sort_order). EVERY count below is out of this number, not out of total_rows. |
table_id | string | 是 | The table previewed. |
total_rows | integer | 是 | Live rows in the table. Greater than sampled_rows ⇒ the preview was truncated and says so in warnings. |
warnings | string[] | 否 | Truncation notices and lockout alarms, in plain language. |
範例
預覽唯一值規則
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222"
},
"body": {
"rules": [
{
"type": "unique",
"name": "訂單編號不可重複",
"columns": [
"訂單編號"
],
"case_insensitive": true
}
]
}
}{
"table_id": "22222222-2222-4222-8222-222222222222",
"sampled_rows": 1,
"total_rows": 1,
"sample_cap": 200,
"rooms": [],
"invariant_violations": 0,
"warnings": []
}錯誤
驗證錯誤範例列出識別欄位;部署中的驗證器也可能回傳 input 與 ctx。錯誤訊息 URL 的版本由建置決定,因此使用 pydantic-version 佔位符。
| 狀態 | 發生條件 | 錯誤本文 |
|---|---|---|
| 400 | 候選規則的結構或語意不合法。 | |
| 403 | 你看得到這張資料表,但不是它的 moderator。訊息內容依資料表範圍而定:這是你自己部門內聊天室資料表的回應;其他部門的聊天室資料表會是 `…or management rights.`,部門資料表是 `…table moderator, department manager, or company management rights.` 或 `…table moderator or department management rights.`,公司資料表則是 `…table moderator or company management rights.` | |
| 404 | 沒有這個 id 的 live 資料表:它從未存在、已被永久清除,或正在垃圾桶中。其他公司的資料表也回同樣的結果(自後端 5.21.0 起,不再是 403)。在聊天室路徑上,屬於其他聊天室的資料表也回同樣的結果。 | |
| 404 | 資料表所屬的聊天室已被刪除。聊天室被軟刪除後,它自己的資料表仍是 live,但 moderator 閘門在每一種路徑(聊天室、部門或公司)都會拒絕它們——時間點在查到資料表與公司檢查之後(其他公司的資料表改為回 `CustomTable Not found`)、moderator 檢查之前。 | |
| 404 | 部門或公司路徑:資料表存在、你也是它的 moderator,但它屬於路徑以外的範圍(`Table not found in this department`/`… in this company`)。因為公司管理者是公司內每張資料表的 moderator,這個情況確實可能發生。在聊天室路徑上,同樣的情況會回 `CustomTable Not found`。 | |
| 422 | Request 驗證,與 PUT 相同:規則過多;unique_tuple、same_dimension_reference、date_interval_exclusion、channel 或 invariant 的 shape 錯誤;policy 超過上限;或 expected_rules_digest 不是 64 位小寫 hex——雖然 preview 不使用它的值,格式仍會被驗證。 | |
| 409 | 候選清單中的 `same_dimension_reference` 規則已被既有資料違反。Preview 會執行與 PUT 相同的既有列檢查(在會回滾的 guard 下進行),所以回相同的 409。 | |
/private/module/custom_tables/{scope}/tables/{table_id}/triggers回傳資料表的 trigger(事件與排程),參照以顯示名稱呈現,只有表格 moderator 能讀。每個 webhook/api_call 機密 slot 都顯示 "__SECRET__",並由型別化的 `secrets` 清單標出位置;絕不回傳儲存的值。
以表格 moderator 身分顯示自動化設定,或在整批取代前取得目前的 triggers、action id 與機密佔位符。
- 聊天室
/private/module/custom_tables/chatroom/{chatroom_id}/tables/{table_id}/triggers - 部門
/private/module/custom_tables/department/{department_id}/tables/{table_id}/triggers - 公司
/private/module/custom_tables/company/tables/{table_id}/triggers
範圍
| 範圍 | 是否提供 | 驗證與權限 |
|---|---|---|
| 聊天室 | 可使用 | ChatroomTableTriggerConfigReadRequired |
| 部門 | 可使用 | DepartmentTableTriggerConfigReadRequired |
| 公司 | 可使用 | CompanyTableTriggerConfigReadRequired |
參數
| 欄位 | 位置 | 型別 | 必填 | 說明 |
|---|---|---|---|---|
table_id | path | uuid | 是 | 要取得觸發器的資料表 UUID。 |
回應結構
TableTriggersResponse| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
secrets | TriggerSecretSlot[] | 否 | One entry per masked slot, locating each "__SECRET__" and whether a value is stored. |
table_id | string | 是 | 未指定 |
triggers | object[] | 否 | Trigger configuration with every webhook/api_call secret slot replaced by "__SECRET__" (for every reader, moderators included; the stored values are used only to fire). |
範例
取得資料列建立通知觸發器
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222"
}
}{
"table_id": "22222222-2222-4222-8222-222222222222",
"triggers": [
{
"id": "trg_666666666666",
"name": "通知新訂單",
"on": "created",
"created_by": "44444444-4444-4444-8444-444444444444",
"when": null,
"transition": null,
"schedule": null,
"actions": [
{
"id": "act_111111111111",
"type": "notify",
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"message": "已建立訂單:$row.訂單編號"
}
]
}
],
"secrets": []
}Moderator 讀取 api_call trigger:機密 slot 已遮罩
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222"
}
}{
"table_id": "22222222-2222-4222-8222-222222222222",
"triggers": [
{
"id": "trg_999999999999",
"name": "同步 ERP",
"on": "created",
"created_by": "44444444-4444-4444-8444-444444444444",
"when": null,
"transition": null,
"schedule": null,
"actions": [
{
"id": "act_444444444444",
"type": "api_call",
"method": "POST",
"url": "https://erp.example/orders?api_key=__SECRET__",
"headers": {
"Authorization": "__SECRET__"
},
"body": {
"order_no": "$row.訂單編號",
"source": "__SECRET__"
}
}
]
}
],
"secrets": [
{
"trigger_id": "trg_999999999999",
"action_id": "act_444444444444",
"action_index": 0,
"location": "url_query",
"name": "api_key",
"occurrence": 0,
"path": null,
"has_value": true
},
{
"trigger_id": "trg_999999999999",
"action_id": "act_444444444444",
"action_index": 0,
"location": "header",
"name": "Authorization",
"occurrence": null,
"path": null,
"has_value": true
},
{
"trigger_id": "trg_999999999999",
"action_id": "act_444444444444",
"action_index": 0,
"location": "body",
"name": null,
"occurrence": null,
"path": [
"source"
],
"has_value": true
}
]
}錯誤
驗證錯誤範例列出識別欄位;部署中的驗證器也可能回傳 input 與 ctx。錯誤訊息 URL 的版本由建置決定,因此使用 pydantic-version 佔位符。
| 狀態 | 發生條件 | 錯誤本文 |
|---|---|---|
| 403 | 你對這張資料表有權利(可讀、可新增或可編輯),但不是表格 moderator。Trigger 設定只限 moderator 讀取;確切訊息依資料表範圍與你的部門而定,與其他 moderator 閘門路由相同。 | |
| 404 | 資料表不存在或已在垃圾桶、屬於其他範圍或(自後端 5.21.0 起)其他公司,或你對它沒有任何權利——所有情況都回同樣的 `CustomTable Not found`,因此被隱藏的資料表看起來與未知 id 完全相同。 | |
/private/module/custom_tables/{scope}/tables/{table_id}/triggers驗證並以原子方式取代事件驅動通知、API/資料表動作、通道附件投遞與 Sandbox 工作提交。
要發佈資料表的完整目標觸發器設定時使用。
- 聊天室
/private/module/custom_tables/chatroom/{chatroom_id}/tables/{table_id}/triggers - 部門
/private/module/custom_tables/department/{department_id}/tables/{table_id}/triggers - 公司
/private/module/custom_tables/company/tables/{table_id}/triggers
範圍
| 範圍 | 是否提供 | 驗證與權限 |
|---|---|---|
| 聊天室 | 可使用 | CustomTableModeratorRequired |
| 部門 | 可使用 | CustomTableModeratorRequired |
| 公司 | 可使用 | CustomTableModeratorRequired |
參數
| 欄位 | 位置 | 型別 | 必填 | 說明 |
|---|---|---|---|---|
table_id | path | uuid | 是 | 要取代觸發器的資料表 UUID。 |
請求結構
TableTriggersPayload| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
triggers | object[] | 是 | Full triggers list (PUT replace semantics; at most 50 triggers). Each trigger authors 1 to 5 actions from the ten supported types: webhook, api_call, create_record, update_record, notify, send_channel_message, invoke_command, delete_record, materialize_slots, and submit_sandbox_job. Saved configs preserve exactly one stable identity per action; server-minted values use act_<12 hex>. GET echoes it as action.id, which clients must round-trip when replacing the list. materialize_slots fails closed before any slot insert when more than 1000 live source rows are scanned; truncating slot inserts at 1000 per tick remains success. |
回應結構
TableTriggersResponse| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
secrets | TriggerSecretSlot[] | 否 | One entry per masked slot, locating each "__SECRET__" and whether a value is stored. |
table_id | string | 是 | 未指定 |
triggers | object[] | 否 | Trigger configuration with every webhook/api_call secret slot replaced by "__SECRET__" (for every reader, moderators included; the stored values are used only to fire). |
範例
建立資料列時通知聊天室
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222"
},
"body": {
"triggers": [
{
"name": "通知新訂單",
"on": "created",
"actions": [
{
"type": "notify",
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"message": "已建立訂單:$row.訂單編號"
}
]
}
]
}
}{
"table_id": "22222222-2222-4222-8222-222222222222",
"triggers": [
{
"id": "trg_666666666666",
"name": "通知新訂單",
"on": "created",
"created_by": "44444444-4444-4444-8444-444444444444",
"when": null,
"transition": null,
"schedule": null,
"actions": [
{
"id": "act_111111111111",
"type": "notify",
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"message": "已建立訂單:$row.訂單編號"
}
]
}
],
"secrets": []
}傳送附件欄位並提交 pinned Sandbox task version
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222"
},
"body": {
"triggers": [
{
"name": "傳送附件並建立 Sandbox 工作",
"on": "created",
"actions": [
{
"type": "send_channel_message",
"recipient": "created_by_client",
"message": "訂單附件:$row.訂單編號",
"attachments": [
{
"column": "col_a1111111_1111_4111_8111_111111111111"
}
]
},
{
"type": "submit_sandbox_job",
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"task_version_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
"timeout_seconds": 900,
"input": {
"order_id": "$row.訂單編號"
}
}
]
}
]
}
}{
"table_id": "22222222-2222-4222-8222-222222222222",
"triggers": [
{
"id": "trg_777777777777",
"name": "傳送附件並建立 Sandbox 工作",
"on": "created",
"actions": [
{
"type": "send_channel_message",
"recipient": "created_by_client",
"message": "訂單附件:$row.訂單編號",
"attachments": [
{
"column": "附件"
}
],
"id": "act_222222222222"
},
{
"type": "submit_sandbox_job",
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"task_version_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
"timeout_seconds": 900,
"input": {
"order_id": "$row.訂單編號"
},
"id": "act_333333333333"
}
],
"created_by": "44444444-4444-4444-8444-444444444444",
"when": null,
"transition": null,
"schedule": null
}
],
"secrets": []
}把 GET 的回傳原封不動送回——每個佔位符都保留已儲存的值
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222"
},
"body": {
"triggers": [
{
"id": "trg_999999999999",
"name": "同步 ERP",
"on": "created",
"created_by": "44444444-4444-4444-8444-444444444444",
"when": null,
"transition": null,
"schedule": null,
"actions": [
{
"id": "act_444444444444",
"type": "api_call",
"method": "POST",
"url": "https://erp.example/orders?api_key=__SECRET__",
"headers": {
"Authorization": "__SECRET__"
},
"body": {
"order_no": "$row.訂單編號",
"source": "__SECRET__"
}
}
]
}
]
}
}{
"table_id": "22222222-2222-4222-8222-222222222222",
"triggers": [
{
"id": "trg_999999999999",
"name": "同步 ERP",
"on": "created",
"created_by": "44444444-4444-4444-8444-444444444444",
"when": null,
"transition": null,
"schedule": null,
"actions": [
{
"id": "act_444444444444",
"type": "api_call",
"method": "POST",
"url": "https://erp.example/orders?api_key=__SECRET__",
"headers": {
"Authorization": "__SECRET__"
},
"body": {
"order_no": "$row.訂單編號",
"source": "__SECRET__"
}
}
]
}
],
"secrets": [
{
"trigger_id": "trg_999999999999",
"action_id": "act_444444444444",
"action_index": 0,
"location": "url_query",
"name": "api_key",
"occurrence": 0,
"path": null,
"has_value": true
},
{
"trigger_id": "trg_999999999999",
"action_id": "act_444444444444",
"action_index": 0,
"location": "header",
"name": "Authorization",
"occurrence": null,
"path": null,
"has_value": true
},
{
"trigger_id": "trg_999999999999",
"action_id": "act_444444444444",
"action_index": 0,
"location": "body",
"name": null,
"occurrence": null,
"path": [
"source"
],
"has_value": true
}
]
}錯誤
驗證錯誤範例列出識別欄位;部署中的驗證器也可能回傳 input 與 ctx。錯誤訊息 URL 的版本由建置決定,因此使用 pydantic-version 佔位符。
| 狀態 | 發生條件 | 錯誤本文 |
|---|---|---|
| 400 | 觸發事件、條件或動作無效,或動作數量超出支援範圍。 | |
| 400 | 資料表帶有通道範圍限制政策,無法與觸發器併用。 | |
| 400 | 某個 trigger 保留原 id 卻更改了 schedule.type;schedule identity 依 kind 區分,請讓舊 id 退役,並用新 id 建立新 kind。 | |
| 400 | 寫入想保留一個無法綁定的已儲存機密;不會儲存任何東西。`code` 說明原因:`unknown_action_id`、`action_id_reused`、`trigger_id_reused`、`ambiguous_keep`、`no_stored_twin`、`type_changed`、`destination_changed`(URL 的 scheme/host/port 或 `Host` header 改變)、`nothing_to_keep` 或 `duplicate_header`。訊息只點名 slot,不含任何值。 | |
| 400 | 有一個 `"__SECRET__"` 佔位符沒有被任何保留綁定解析,例如夾在較長的值裡(`"Bearer __SECRET__"`)。佔位符永遠不會被當成憑證儲存。 | |
| 409 | `create_record`/`update_record` action 的目標表帶有 `require_approval` 規則(同一個 409 也擋下在自身表上的 `delete_record`、`materialize_slots` 的目標表,以及所引用指令會寫入受核准閘門資料表的 `invoke_command`)。 | |
| 409 | Locked-graph 重新驗證或非資料庫的 compile/refresh failure,使伺服器無法安全更新所有先前仍有效的相依 commands。這個結構化錯誤與下方 flat-detail database errors 不同;trigger JSON、schema history 紀錄與所有 command definition 更新會在同一個交易中一起回滾。 | |
| 409 | Trigger-update transaction 中遇到 MySQL 1205 lock-wait timeout 或 1213 deadlock。完整 transaction 已回滾;這個可重試 409 使用 flat string detail,不是 command_dependency_refresh_failed。 | |
| 422 | Body 未通過 request 驗證,例如超過 50 個 trigger。這條路由屬於機密寫入路徑,所以每筆錯誤只有 `loc`、`type` 與 `msg: "validation_error:<type>"`,絕不回顯送出的值。 | |
| 403 | 你看得到這張資料表,但不是它的 moderator。訊息內容依資料表範圍而定:這是你自己部門內聊天室資料表的回應;其他部門的聊天室資料表會是 `…or management rights.`,部門資料表是 `…table moderator, department manager, or company management rights.` 或 `…table moderator or department management rights.`,公司資料表則是 `…table moderator or company management rights.` | |
| 404 | 沒有這個 id 的 live 資料表:它從未存在、已被永久清除,或正在垃圾桶中。其他公司的資料表也回同樣的結果(自後端 5.21.0 起,不再是 403)。在聊天室路徑上,屬於其他聊天室的資料表也回同樣的結果。 | |
| 404 | 資料表所屬的聊天室已被刪除。聊天室被軟刪除後,它自己的資料表仍是 live,但 moderator 閘門在每一種路徑(聊天室、部門或公司)都會拒絕它們——時間點在查到資料表與公司檢查之後(其他公司的資料表改為回 `CustomTable Not found`)、moderator 檢查之前。 | |
| 404 | 部門或公司路徑:資料表存在、你也是它的 moderator,但它屬於路徑以外的範圍(`Table not found in this department`/`… in this company`)。因為公司管理者是公司內每張資料表的 moderator,這個情況確實可能發生。在聊天室路徑上,同樣的情況會回 `CustomTable Not found`。 | |
| 500 | 發生其他資料庫失敗——lock 衝突以外的 operational error,或 integrity/data error——整個 transaction 已回滾;detail 是淨化後的 flat 字串 Database operation failed.。 | |
| 500 | 非資料庫的失敗——例如伺服器沒有設定加上金鑰的摘要所需的金鑰——讓整個 transaction 回滾;detail 是純文字 Internal Server Error。 | |
/private/module/custom_tables/{scope}/tables/{table_id}/triggers/schedule-preview以 scheduler 自己的 evaluator 唯讀地評估這張表上每一個 schedule trigger,回傳每個 trigger 的機器可讀原因計數與時鐘狀態。
當 scheduler tick 健康卻一直回報零筆 run,而你需要知道資料列是缺日期、仍在未來、被 when 排除、已經消耗,還是真的到期時使用。
- 聊天室
/private/module/custom_tables/chatroom/{chatroom_id}/tables/{table_id}/triggers/schedule-preview - 部門
/private/module/custom_tables/department/{department_id}/tables/{table_id}/triggers/schedule-preview - 公司
/private/module/custom_tables/company/tables/{table_id}/triggers/schedule-preview
範圍
| 範圍 | 是否提供 | 驗證與權限 |
|---|---|---|
| 聊天室 | 可使用 | CustomTableModeratorRequired |
| 部門 | 可使用 | CustomTableModeratorRequired |
| 公司 | 可使用 | CustomTableModeratorRequired |
參數
| 欄位 | 位置 | 型別 | 必填 | 說明 |
|---|---|---|---|---|
table_id | path | uuid | 是 | 要評估其 schedule triggers 的資料表 UUID。 |
回應結構
TableSchedulePreviewResponse| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
evaluated_at | string (date-time) | 是 | 未指定 |
live_records | integer | 是 | 未指定 |
record_limit | integer | 否 | 未指定 |
table_id | string | 是 | 未指定 |
triggers | (InvalidSchedulePreview | DateColumnReachedSchedulePreview | IntervalSchedulePreview | DailySchedulePreview | CronSchedulePreview)[] | 否 | 未指定 |
範例
預覽一張含 date trigger、interval trigger 與一個損毀儲存 trigger 的表
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222"
}
}{
"table_id": "22222222-2222-4222-8222-222222222222",
"evaluated_at": "2026-08-27T05:02:13",
"live_records": 2,
"record_limit": 1000,
"triggers": [
{
"kind": "date_column_reached",
"trigger_id": "trg_666666666666",
"config_status": "valid",
"already_fired": 1,
"records_scanned": 2,
"missing_schedule_value": 0,
"invalid_schedule_value": 0,
"scheduled_for_future": 1,
"when_filter_mismatch": 0,
"due_now": 0,
"unscanned": 0,
"truncated": false,
"warnings": []
},
{
"kind": "interval",
"trigger_id": "trg_777777777777",
"config_status": "valid",
"last_consumed_window_at": "2026-08-27T05:00:00",
"due_at": null,
"due_now": false,
"active_run": false,
"warnings": [
"when_ignored_for_recordless_schedule"
]
},
{
"kind": "invalid",
"trigger_id": "trg_888888888888",
"stored_schedule_type": "monthly",
"config_status": "invalid",
"error_codes": [
"unsupported_schedule_type"
],
"warnings": []
}
]
}錯誤
驗證錯誤範例列出識別欄位;部署中的驗證器也可能回傳 input 與 ctx。錯誤訊息 URL 的版本由建置決定,因此使用 pydantic-version 佔位符。
| 狀態 | 發生條件 | 錯誤本文 |
|---|---|---|
| 403 | 你看得到這張資料表,但不是它的 moderator。訊息內容依資料表範圍而定:這是你自己部門內聊天室資料表的回應;其他部門的聊天室資料表會是 `…or management rights.`,部門資料表是 `…table moderator, department manager, or company management rights.` 或 `…table moderator or department management rights.`,公司資料表則是 `…table moderator or company management rights.` | |
| 404 | 沒有這個 id 的 live 資料表:它從未存在、已被永久清除,或正在垃圾桶中。其他公司的資料表也回同樣的結果(自後端 5.21.0 起,不再是 403)。在聊天室路徑上,屬於其他聊天室的資料表也回同樣的結果。 | |
| 404 | 資料表所屬的聊天室已被刪除。聊天室被軟刪除後,它自己的資料表仍是 live,但 moderator 閘門在每一種路徑(聊天室、部門或公司)都會拒絕它們——時間點在查到資料表與公司檢查之後(其他公司的資料表改為回 `CustomTable Not found`)、moderator 檢查之前。 | |
| 404 | 部門或公司路徑:資料表存在、你也是它的 moderator,但它屬於路徑以外的範圍(`Table not found in this department`/`… in this company`)。在聊天室路徑上,同樣的情況會和不存在或在垃圾桶的 id 一樣回 `CustomTable Not found`。 | |
/private/module/custom_tables/{scope}/tables/{table_id}/trigger-runs回傳資料表非同步觸發動作的分頁執行記錄。
適合監測自動化健康狀態、檢查失敗,或在重試前找到執行記錄。
- 聊天室
/private/module/custom_tables/chatroom/{chatroom_id}/tables/{table_id}/trigger-runs - 部門
/private/module/custom_tables/department/{department_id}/tables/{table_id}/trigger-runs - 公司
/private/module/custom_tables/company/tables/{table_id}/trigger-runs
範圍
| 範圍 | 是否提供 | 驗證與權限 |
|---|---|---|
| 聊天室 | 可使用 | CustomTableModeratorRequired |
| 部門 | 可使用 | CustomTableModeratorRequired |
| 公司 | 可使用 | CustomTableModeratorRequired |
參數
| 欄位 | 位置 | 型別 | 必填 | 說明 |
|---|---|---|---|---|
table_id | path | uuid | 是 | 要列出觸發器執行記錄的資料表 UUID。 |
status | query | enum:pending|running|done|failed|stuck | 否 | 選填的執行狀態:pending、running、done、failed 或 stuck。 |
skip | query | int >= 0 | 否 | 略過前幾筆符合條件的執行記錄,預設為 0。 |
limit | query | int 1..200 | 否 | 最多回傳幾筆執行記錄,可填 1 到 200。 |
回應結構
TriggerRunListResponse| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
runs | TriggerRunResponse[] | 是 | 未指定 |
total | integer | 是 | 未指定 |
範例
列出失敗的觸發器執行記錄
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222"
},
"query": {
"status": "failed",
"skip": "0",
"limit": "50"
}
}{
"runs": [
{
"id": "55555555-5555-4555-8555-555555555555",
"table_id": "22222222-2222-4222-8222-222222222222",
"trigger_id": "trg_999999999999",
"record_id": "33333333-3333-4333-8333-333333333333",
"record_version": 1,
"event": "created",
"status": "failed",
"attempts": 1,
"error": "api_call failed: HTTP 500",
"chain_id": "55555555-5555-4555-8555-555555555555",
"depth": 0,
"payload": {
"event": "created",
"table_id": "22222222-2222-4222-8222-222222222222",
"record_id": "33333333-3333-4333-8333-333333333333",
"record_version": 1,
"data": {
"col_b2222222_2222_4222_8222_222222222222": "ORD-1001"
},
"diff": null,
"fired_at": "2026-07-19T03:00:00.412000",
"trigger": {
"id": "trg_999999999999",
"name": "同步 ERP",
"created_by": "44444444-4444-4444-8444-444444444444"
},
"actor": {
"user_id": "44444444-4444-4444-8444-444444444444",
"client_id": null
},
"source_permission_context": {
"kind": "unroomed",
"principal_user_id": "44444444-4444-4444-8444-444444444444",
"principal_client_id": null
},
"chain_id": "55555555-5555-4555-8555-555555555555",
"depth": 0
},
"action_results": [
{
"type": "api_call",
"ok": false,
"detail": "HTTP 500",
"action_id": "act_444444444444"
}
],
"created_at": "2026-07-19T03:00:00",
"updated_at": "2026-07-19T03:05:00"
}
],
"total": 1
}錯誤
驗證錯誤範例列出識別欄位;部署中的驗證器也可能回傳 input 與 ctx。錯誤訊息 URL 的版本由建置決定,因此使用 pydantic-version 佔位符。
| 狀態 | 發生條件 | 錯誤本文 |
|---|---|---|
| 403 | 你看得到這張資料表,但不是它的 moderator。訊息內容依資料表範圍而定:這是你自己部門內聊天室資料表的回應;其他部門的聊天室資料表會是 `…or management rights.`,部門資料表是 `…table moderator, department manager, or company management rights.` 或 `…table moderator or department management rights.`,公司資料表則是 `…table moderator or company management rights.` | |
| 404 | 沒有這個 id 的 live 資料表:它從未存在、已被永久清除,或正在垃圾桶中。其他公司的資料表也回同樣的結果(自後端 5.21.0 起,不再是 403)。在聊天室路徑上,屬於其他聊天室的資料表也回同樣的結果。 | |
| 404 | 資料表所屬的聊天室已被刪除。聊天室被軟刪除後,它自己的資料表仍是 live,但 moderator 閘門在每一種路徑(聊天室、部門或公司)都會拒絕它們——時間點在查到資料表與公司檢查之後(其他公司的資料表改為回 `CustomTable Not found`)、moderator 檢查之前。 | |
| 404 | 部門或公司路徑:資料表存在、你也是它的 moderator,但它屬於路徑以外的範圍(`Table not found in this department`/`… in this company`)。在聊天室路徑上,同樣的情況會和不存在或在垃圾桶的 id 一樣回 `CustomTable Not found`。 | |
/private/module/custom_tables/{scope}/tables/{table_id}/trigger-runs/{run_id}/retry將符合條件的失敗、待執行或過期執行記錄重新放回觸發器佇列。
排除下游錯誤後,重排 failed、pending 或逾時 running 執行;已完成的 run 不能重試。
- 聊天室
/private/module/custom_tables/chatroom/{chatroom_id}/tables/{table_id}/trigger-runs/{run_id}/retry - 部門
/private/module/custom_tables/department/{department_id}/tables/{table_id}/trigger-runs/{run_id}/retry - 公司
/private/module/custom_tables/company/tables/{table_id}/trigger-runs/{run_id}/retry
範圍
| 範圍 | 是否提供 | 驗證與權限 |
|---|---|---|
| 聊天室 | 可使用 | CustomTableModeratorRequired |
| 部門 | 可使用 | CustomTableModeratorRequired |
| 公司 | 可使用 | CustomTableModeratorRequired |
參數
| 欄位 | 位置 | 型別 | 必填 | 說明 |
|---|---|---|---|---|
table_id | path | uuid | 是 | 擁有觸發器執行記錄的資料表 UUID。 |
run_id | path | uuid | 是 | 要重試的觸發器執行 UUID。 |
回應結構
TriggerRunResponse| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
action_results | object[] | null | 否 | Per-action results written by the worker |
attempts | integer | 是 | 未指定 |
chain_id | string | 是 | 未指定 |
created_at | string (date-time) | 是 | 未指定 |
depth | integer | 是 | 未指定 |
error | string | null | 是 | 未指定 |
event | string | 是 | 未指定 |
id | string | 是 | 未指定 |
payload | object | null | 否 | Trigger-time row snapshot + change metadata (the webhook payload) |
record_id | string | null | 是 | 未指定 |
record_version | integer | 是 | 未指定 |
status | string | 是 | pending | running | done | failed |
table_id | string | 是 | 未指定 |
trigger_id | string | 是 | 未指定 |
updated_at | string (date-time) | 是 | 未指定 |
範例
將失敗的觸發器執行重新排入佇列
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222",
"run_id": "55555555-5555-4555-8555-555555555555"
}
}{
"id": "55555555-5555-4555-8555-555555555555",
"table_id": "22222222-2222-4222-8222-222222222222",
"trigger_id": "trg_999999999999",
"record_id": "33333333-3333-4333-8333-333333333333",
"record_version": 1,
"event": "created",
"status": "pending",
"attempts": 1,
"error": null,
"chain_id": "55555555-5555-4555-8555-555555555555",
"depth": 0,
"payload": {
"event": "created",
"table_id": "22222222-2222-4222-8222-222222222222",
"record_id": "33333333-3333-4333-8333-333333333333",
"record_version": 1,
"data": {
"col_b2222222_2222_4222_8222_222222222222": "ORD-1001"
},
"diff": null,
"fired_at": "2026-07-19T03:00:00.412000",
"trigger": {
"id": "trg_999999999999",
"name": "同步 ERP",
"created_by": "44444444-4444-4444-8444-444444444444"
},
"actor": {
"user_id": "44444444-4444-4444-8444-444444444444",
"client_id": null
},
"source_permission_context": {
"kind": "unroomed",
"principal_user_id": "44444444-4444-4444-8444-444444444444",
"principal_client_id": null
},
"chain_id": "55555555-5555-4555-8555-555555555555",
"depth": 0
},
"action_results": [
{
"type": "api_call",
"ok": false,
"detail": "HTTP 500",
"action_id": "act_444444444444"
}
],
"created_at": "2026-07-19T03:00:00",
"updated_at": "2026-07-19T03:05:00"
}錯誤
驗證錯誤範例列出識別欄位;部署中的驗證器也可能回傳 input 與 ctx。錯誤訊息 URL 的版本由建置決定,因此使用 pydantic-version 佔位符。
| 狀態 | 發生條件 | 錯誤本文 |
|---|---|---|
| 404 | 這張資料表沒有指定觸發器執行記錄。 | |
| 404 | 沒有這個 id 的 live 資料表:它從未存在、已被永久清除,或正在垃圾桶中。其他公司的資料表也回同樣的結果(自後端 5.21.0 起,不再是 403)。在聊天室路徑上,屬於其他聊天室的資料表也回同樣的結果。 | |
| 404 | 資料表所屬的聊天室已被刪除。聊天室被軟刪除後,它自己的資料表仍是 live,但 moderator 閘門在每一種路徑(聊天室、部門或公司)都會拒絕它們——時間點在查到資料表與公司檢查之後(其他公司的資料表改為回 `CustomTable Not found`)、moderator 檢查之前。 | |
| 409 | 執行已完成,或處於其他不可重試的狀態。 | |
| 409 | 重試 interval、daily 或 cron run 會重新武裝該 trigger 的「同時只有一個 run」fence;這個 409 表示同一 trigger 的另一個 run 仍在 pending 或 running。請等它完成後再重試。 | |
/private/module/custom_tables/{scope}/tables/{table_id}/staged-changes列出被 require_approval 規則暫緩的寫入,以及審核與套用狀態。
適合監測需核准的寫入,或調查為何資料列被待審狀態擋住。
- 聊天室
/private/module/custom_tables/chatroom/{chatroom_id}/tables/{table_id}/staged-changes - 部門
/private/module/custom_tables/department/{department_id}/tables/{table_id}/staged-changes - 公司
/private/module/custom_tables/company/tables/{table_id}/staged-changes
範圍
| 範圍 | 是否提供 | 驗證與權限 |
|---|---|---|
| 聊天室 | 可使用 | ChatroomTableMetadataReadRequired |
| 部門 | 可使用 | DepartmentTableMetadataReadRequired |
| 公司 | 可使用 | CompanyTableMetadataReadRequired |
參數
| 欄位 | 位置 | 型別 | 必填 | 說明 |
|---|---|---|---|---|
table_id | path | uuid | 是 | 要列出階段性變更的資料表 UUID。 |
status | query | enum:pending|applying|applied|apply_failed|discarded | 否 | 選填的進程狀態:pending、applying、applied、apply_failed 或 discarded。 |
change_type | query | enum:create|update|delete|restore|revert|batch_actions|command_plan | 否 | 選填的暫緩操作類型:create、update、delete、restore、revert、batch_actions 或 command_plan。 |
skip | query | int >= 0 | 否 | 略過前幾筆符合條件的階段性變更,預設為 0。 |
limit | query | int 1..200 | 否 | 最多回傳幾筆階段性變更,可填 1 到 200;預設 50。 |
回應結構
StagedChangeListResponse| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
staged_changes | StagedChangeResponse[] | 是 | Visible staged changes, newest first |
total | integer | 是 | Total visible staged changes matching the filters (before pagination) |
範例
列出待審階段性變更
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222"
},
"query": {
"status": "pending",
"skip": "0",
"limit": "50"
}
}{
"staged_changes": [
{
"id": "88888888-8888-4888-8888-888888888888",
"table_id": "22222222-2222-4222-8222-222222222222",
"record_id": "33333333-3333-4333-8333-333333333333",
"process_id": "cccccccc-cccc-4ccc-8ccc-cccccccccccc",
"rule_id": "rule_5e6f7a8b9c0d",
"change_type": "update",
"status": "pending",
"snapshot_version": 3,
"attempts": 0,
"error": null,
"created_by": "44444444-4444-4444-8444-444444444444",
"created_at": "2026-07-19T03:00:00",
"updated_at": "2026-07-19T03:00:00",
"applied_at": null,
"payload": null,
"results": null
}
],
"total": 1
}錯誤
驗證錯誤範例列出識別欄位;部署中的驗證器也可能回傳 input 與 ctx。錯誤訊息 URL 的版本由建置決定,因此使用 pydantic-version 佔位符。
| 狀態 | 發生條件 | 錯誤本文 |
|---|---|---|
| 404 | 資料表不存在或已在垃圾桶、屬於其他範圍,或你對它沒有任何權利——所有情況都回 `CustomTable Not found`,因此被隱藏的資料表看起來與未知 id 完全相同。其他公司的資料表也回同樣的 404(自後端 5.21.0 起)。 | |
/private/module/custom_tables/{scope}/tables/{table_id}/staged-changes/discard嘗試將指定的未解決核准寫入標記為已捨棄。
被暫緩的寫入應直接作廢,而不是核准並套用時使用。
- 聊天室
/private/module/custom_tables/chatroom/{chatroom_id}/tables/{table_id}/staged-changes/discard - 部門
/private/module/custom_tables/department/{department_id}/tables/{table_id}/staged-changes/discard - 公司
/private/module/custom_tables/company/tables/{table_id}/staged-changes/discard
範圍
| 範圍 | 是否提供 | 驗證與權限 |
|---|---|---|
| 聊天室 | 可使用 | CustomTableModeratorRequired |
| 部門 | 可使用 | CustomTableModeratorRequired |
| 公司 | 可使用 | CustomTableModeratorRequired |
參數
| 欄位 | 位置 | 型別 | 必填 | 說明 |
|---|---|---|---|---|
table_id | path | uuid | 是 | 擁有階段性變更的資料表 UUID。 |
請求結構
StagedChangeDiscardRequest| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
staged_change_ids | string[] | 是 | Staged change ids to discard (1..50); each is looked up anchored to the path table_id |
回應結構
StagedChangeDiscardResponse| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
discarded | integer | 是 | How many ids were discarded this call |
results | StagedChangeDiscardResult[] | 是 | One result per requested id, in request order |
範例
捨棄一個階段性變更 ID
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222"
},
"body": {
"staged_change_ids": [
"88888888-8888-4888-8888-888888888888"
]
}
}{
"results": [
{
"staged_change_id": "88888888-8888-4888-8888-888888888888",
"ok": false,
"outcome": "not_found",
"status": null
}
],
"discarded": 0
}錯誤
驗證錯誤範例列出識別欄位;部署中的驗證器也可能回傳 input 與 ctx。錯誤訊息 URL 的版本由建置決定,因此使用 pydantic-version 佔位符。
| 狀態 | 發生條件 | 錯誤本文 |
|---|---|---|
| 403 | 你看得到這張資料表,但不是它的 moderator。訊息內容依資料表範圍而定:這是你自己部門內聊天室資料表的回應;其他部門的聊天室資料表會是 `…or management rights.`,部門資料表是 `…table moderator, department manager, or company management rights.` 或 `…table moderator or department management rights.`,公司資料表則是 `…table moderator or company management rights.` | |
| 404 | 沒有這個 id 的 live 資料表:它從未存在、已被永久清除,或正在垃圾桶中。其他公司的資料表也回同樣的結果(自後端 5.21.0 起,不再是 403)。在聊天室路徑上,屬於其他聊天室的資料表也回同樣的結果。 | |
| 404 | 資料表所屬的聊天室已被刪除。聊天室被軟刪除後,它自己的資料表仍是 live,但 moderator 閘門在每一種路徑(聊天室、部門或公司)都會拒絕它們——時間點在查到資料表與公司檢查之後(其他公司的資料表改為回 `CustomTable Not found`)、moderator 檢查之前。 | |
| 404 | 部門或公司路徑:資料表存在、你也是它的 moderator,但它屬於路徑以外的範圍(`Table not found in this department`/`… in this company`)。在聊天室路徑上,同樣的情況會和不存在或在垃圾桶的 id 一樣回 `CustomTable Not found`。 | |
| 422 | `staged_change_ids` 是空的,或超過 50 個 id。 | |
/private/module/custom_tables/{scope}/tables/{table_id}/callback-tokens建立綁定資料表的 token,供已驗證的公開回呼寫入,並只回傳一次密鑰。
要為外部回呼程式配置新增,或新增與更新能力時使用。
- 聊天室
/private/module/custom_tables/chatroom/{chatroom_id}/tables/{table_id}/callback-tokens - 部門
/private/module/custom_tables/department/{department_id}/tables/{table_id}/callback-tokens - 公司
/private/module/custom_tables/company/tables/{table_id}/callback-tokens
範圍
| 範圍 | 是否提供 | 驗證與權限 |
|---|---|---|
| 聊天室 | 可使用 | CustomTableModeratorRequired |
| 部門 | 可使用 | CustomTableModeratorRequired |
| 公司 | 可使用 | CustomTableModeratorRequired |
參數
| 欄位 | 位置 | 型別 | 必填 | 說明 |
|---|---|---|---|---|
table_id | path | uuid | 是 | 要綁定回呼 token 的資料表 UUID。 |
請求結構
CallbackTokenMintPayload| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
allowed_ops | "create" | "create,update" | 否 | Operations the token may perform |
name | string | null | 否 | Label shown in listings |
valid_until | string (date-time) | null | 否 | Expiry (UTC); null = no expiry. Expired tokens answer the uniform 404. |
回應結構
CallbackTokenMintResponse| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
allowed_ops | string | 是 | 未指定 |
secret | string | 是 | Bearer secret — shown ONCE, never retrievable again |
table_id | string | 是 | 未指定 |
token_id | string | 是 | The URL path segment: POST /public/module/custom_tables/callback/{token_id} |
valid_until | string (date-time) | null | 是 | 未指定 |
範例
簽發可新增與更新的回呼 token
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222"
},
"body": {
"name": "訂單系統回呼",
"allowed_ops": "create,update",
"valid_until": null
}
}{
"token_id": "99999999-9999-4999-8999-999999999999",
"secret": "catalog_example_only_0000000000000000000000",
"table_id": "22222222-2222-4222-8222-222222222222",
"allowed_ops": "create,update",
"valid_until": null
}錯誤
驗證錯誤範例列出識別欄位;部署中的驗證器也可能回傳 input 與 ctx。錯誤訊息 URL 的版本由建置決定,因此使用 pydantic-version 佔位符。
| 狀態 | 發生條件 | 錯誤本文 |
|---|---|---|
| 403 | 你看得到這張資料表,但不是它的 moderator。訊息內容依資料表範圍而定:這是你自己部門內聊天室資料表的回應;其他部門的聊天室資料表會是 `…or management rights.`,部門資料表是 `…table moderator, department manager, or company management rights.` 或 `…table moderator or department management rights.`,公司資料表則是 `…table moderator or company management rights.` | |
| 404 | 沒有這個 id 的 live 資料表:它從未存在、已被永久清除,或正在垃圾桶中。其他公司的資料表也回同樣的結果(自後端 5.21.0 起,不再是 403)。在聊天室路徑上,屬於其他聊天室的資料表也回同樣的結果。 | |
| 404 | 資料表所屬的聊天室已被刪除。聊天室被軟刪除後,它自己的資料表仍是 live,但 moderator 閘門在每一種路徑(聊天室、部門或公司)都會拒絕它們——時間點在查到資料表與公司檢查之後(其他公司的資料表改為回 `CustomTable Not found`)、moderator 檢查之前。 | |
| 404 | 部門或公司路徑:資料表存在、你也是它的 moderator,但它屬於路徑以外的範圍(`Table not found in this department`/`… in this company`)。在聊天室路徑上,同樣的情況會和不存在或在垃圾桶的 id 一樣回 `CustomTable Not found`。 | |
| 422 | token 名稱、允許的操作集合或到期時間不合法。 | |
/private/module/custom_tables/{scope}/tables/{table_id}/callback-tokens回傳資料表回呼 token 的基本資訊、能力、到期時間與撤銷狀態。
適合稽核整合,或在撤銷前找到 token ID。
- 聊天室
/private/module/custom_tables/chatroom/{chatroom_id}/tables/{table_id}/callback-tokens - 部門
/private/module/custom_tables/department/{department_id}/tables/{table_id}/callback-tokens - 公司
/private/module/custom_tables/company/tables/{table_id}/callback-tokens
範圍
| 範圍 | 是否提供 | 驗證與權限 |
|---|---|---|
| 聊天室 | 可使用 | CustomTableModeratorRequired |
| 部門 | 可使用 | CustomTableModeratorRequired |
| 公司 | 可使用 | CustomTableModeratorRequired |
參數
| 欄位 | 位置 | 型別 | 必填 | 說明 |
|---|---|---|---|---|
table_id | path | uuid | 是 | 要列出回呼 token 的資料表 UUID。 |
回應結構
CallbackTokenListResponse| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
tokens | CallbackTokenInfo[] | 是 | 未指定 |
範例
列出回呼 token 基本資訊
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222"
}
}{
"tokens": [
{
"id": "99999999-9999-4999-8999-999999999999",
"name": "訂單系統回呼",
"table_id": "22222222-2222-4222-8222-222222222222",
"allowed_ops": "create,update",
"valid_until": null,
"revoked": false,
"created_by": "44444444-4444-4444-8444-444444444444",
"created_at": "2026-07-19T03:00:00"
}
]
}錯誤
驗證錯誤範例列出識別欄位;部署中的驗證器也可能回傳 input 與 ctx。錯誤訊息 URL 的版本由建置決定,因此使用 pydantic-version 佔位符。
| 狀態 | 發生條件 | 錯誤本文 |
|---|---|---|
| 403 | 你看得到這張資料表,但不是它的 moderator。訊息內容依資料表範圍而定:這是你自己部門內聊天室資料表的回應;其他部門的聊天室資料表會是 `…or management rights.`,部門資料表是 `…table moderator, department manager, or company management rights.` 或 `…table moderator or department management rights.`,公司資料表則是 `…table moderator or company management rights.` | |
| 404 | 沒有這個 id 的 live 資料表:它從未存在、已被永久清除,或正在垃圾桶中。其他公司的資料表也回同樣的結果(自後端 5.21.0 起,不再是 403)。在聊天室路徑上,屬於其他聊天室的資料表也回同樣的結果。 | |
| 404 | 資料表所屬的聊天室已被刪除。聊天室被軟刪除後,它自己的資料表仍是 live,但 moderator 閘門在每一種路徑(聊天室、部門或公司)都會拒絕它們——時間點在查到資料表與公司檢查之後(其他公司的資料表改為回 `CustomTable Not found`)、moderator 檢查之前。 | |
| 404 | 部門或公司路徑:資料表存在、你也是它的 moderator,但它屬於路徑以外的範圍(`Table not found in this department`/`… in this company`)。在聊天室路徑上,同樣的情況會和不存在或在垃圾桶的 id 一樣回 `CustomTable Not found`。 | |
/private/module/custom_tables/{scope}/tables/{table_id}/callback-tokens/{token_id}永久停用一組資料表專屬憑證,使後續 public callback 寫入回傳與無效驗證相同的隱蔽 404。
輪替憑證、停用整合,或懷疑憑證外洩時使用。
- 聊天室
/private/module/custom_tables/chatroom/{chatroom_id}/tables/{table_id}/callback-tokens/{token_id} - 部門
/private/module/custom_tables/department/{department_id}/tables/{table_id}/callback-tokens/{token_id} - 公司
/private/module/custom_tables/company/tables/{table_id}/callback-tokens/{token_id}
範圍
| 範圍 | 是否提供 | 驗證與權限 |
|---|---|---|
| 聊天室 | 可使用 | CustomTableModeratorRequired |
| 部門 | 可使用 | CustomTableModeratorRequired |
| 公司 | 可使用 | CustomTableModeratorRequired |
參數
| 欄位 | 位置 | 型別 | 必填 | 說明 |
|---|---|---|---|---|
table_id | path | uuid | 是 | 擁有回呼 token 的資料表 UUID。 |
token_id | path | uuid | 是 | 要撤銷的回呼 token UUID。 |
回應結構
SuccessResponse| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
message | string | 否 | 未指定 |
範例
撤銷一組回呼 token
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222",
"token_id": "99999999-9999-4999-8999-999999999999"
}
}{
"message": "Callback token revoked"
}錯誤
驗證錯誤範例列出識別欄位;部署中的驗證器也可能回傳 input 與 ctx。錯誤訊息 URL 的版本由建置決定,因此使用 pydantic-version 佔位符。
| 狀態 | 發生條件 | 錯誤本文 |
|---|---|---|
| 403 | 你看得到這張資料表,但不是它的 moderator。訊息內容依資料表範圍而定:這是你自己部門內聊天室資料表的回應;其他部門的聊天室資料表會是 `…or management rights.`,部門資料表是 `…table moderator, department manager, or company management rights.` 或 `…table moderator or department management rights.`,公司資料表則是 `…table moderator or company management rights.` | |
| 404 | 這張資料表沒有該 id 的 token——包括其實屬於另一張資料表的 token。資料表不在指定範圍內時則回 `Table not found in this <scope>`。 | |
| 404 | 部門或公司路徑:資料表存在、你也是它的 moderator,但它屬於路徑以外的範圍(`Table not found in this department`/`… in this company`)。在聊天室路徑上,同樣的情況會回 `CustomTable Not found`。 | |
| 404 | 沒有這個 id 的 live 資料表:它從未存在、已被永久清除,或正在垃圾桶中。其他公司的資料表也回同樣的結果(自後端 5.21.0 起,不再是 403)。在聊天室路徑上,屬於其他聊天室的資料表也回同樣的結果。 | |
| 404 | 資料表所屬的聊天室已被刪除。聊天室被軟刪除後,它自己的資料表仍是 live,但 moderator 閘門在每一種路徑(聊天室、部門或公司)都會拒絕它們——時間點在查到資料表與公司檢查之後(其他公司的資料表改為回 `CustomTable Not found`)、moderator 檢查之前。 | |
| 409 | 撤銷在鎖競爭中落敗,「沒有」發生——token 仍然存活、仍接受 callback 寫入。重試直到拿到 200;只有 200 才確認撤銷完成。 | |
aggregate_limit 是第 18 種規則,支援精確群組 sum/count 與 Command 最終狀態檢查。