歷程與版本
稽核資料表變更、檢視資料列快照與差異,並安全還原歷史標量資料。
/private/module/custom_tables/{scope}/tables/{table_id}/records/{record_id}/as-of回傳已儲存歷史版本、生命週期旗標與依目前權限篩選的已擷取 link。
檢視歷史快照,不還原、不重建計算值。
- 聊天室
/private/module/custom_tables/chatroom/{chatroom_id}/tables/{table_id}/records/{record_id}/as-of - 部門
/private/module/custom_tables/department/{department_id}/tables/{table_id}/records/{record_id}/as-of - 公司
/private/module/custom_tables/company/tables/{table_id}/records/{record_id}/as-of
範圍
| 範圍 | 是否提供 | 驗證與權限 |
|---|---|---|
| 聊天室 | 可使用 | CustomTableReadRequired |
| 部門 | 可使用 | CustomTableReadRequired |
| 公司 | 可使用 | CustomTableReadRequired |
參數
| 欄位 | 位置 | 型別 | 必填 | 說明 |
|---|---|---|---|---|
table_id | path | uuid | 是 | 目前可讀資料表的 UUID。 |
record_id | path | uuid | 是 | 位於呼叫者目前可讀範圍的現有資料列 UUID。 |
as_of | query | RFC3339 timestamp with timezone | 是 | 必填,帶明確時區的 RFC3339 時間戳記;包含截止值,先取最新歷史時間,再取最高 version。 |
回應結構
RecordAsOfResponse| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
as_of | string (date-time) | 是 | 未指定 |
change_type | "create" | "update" | "delete" | "restore" | "revert" | "schema_add_column" | "schema_remove_column" | "schema_type_change" | 是 | 未指定 |
data | object | 是 | 未指定 |
is_deleted | boolean | 是 | 未指定 |
links | Record<string, string[]> | 是 | 未指定 |
record_id | string | 是 | Custom-table or tag canonical UUID |
recorded_at | string (date-time) | 是 | 未指定 |
table_id | string | 是 | Custom-table or tag canonical UUID |
version | integer | 是 | 未指定 |
範例
讀取包含截止時間的儲存 scalar 值
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222",
"record_id": "33333333-3333-4333-8333-333333333333"
},
"query": {
"as_of": "2026-07-19T04:06:00Z"
}
}{
"record_id": "33333333-3333-4333-8333-333333333333",
"table_id": "22222222-2222-4222-8222-222222222222",
"version": 2,
"as_of": "2026-07-19T04:06:00Z",
"recorded_at": "2026-07-19T04:05:00Z",
"change_type": "update",
"is_deleted": false,
"data": {
"col_77777777_7777_4777_8777_777777777777": "ORD-1001",
"col_88888888_8888_4888_8888_888888888888": "已確認"
},
"links": {}
}錯誤
驗證錯誤範例列出識別欄位;部署中的驗證器也可能回傳 input 與 ctx。錯誤訊息 URL 的版本由建置決定,因此使用 pydantic-version 佔位符。
| 狀態 | 發生條件 | 錯誤本文 |
|---|---|---|
| 404 | 目前列不存在/隱藏,或截止時間沒有歷史;均回 Record not found。資料表/範圍權限錯誤另計。 | |
| 409 | 目前有可見 link 欄位,但此歷史項目沒有已擷取 link 狀態;不能改用現在的 link。 | |
/private/module/custom_tables/{scope}/tables/{table_id}/period-events以 {table_id, events, total} 列出期間狀態與邊界變更,以及已稽核的 Command 例外覆寫。
檢視 period_fence 使用的期間歷史;三種資料表範圍皆支援。
- 聊天室
/private/module/custom_tables/chatroom/{chatroom_id}/tables/{table_id}/period-events - 部門
/private/module/custom_tables/department/{department_id}/tables/{table_id}/period-events - 公司
/private/module/custom_tables/company/tables/{table_id}/period-events
範圍
| 範圍 | 是否提供 | 驗證與權限 |
|---|---|---|
| 聊天室 | 可使用 | CustomTableReadRequired |
| 部門 | 可使用 | CustomTableReadRequired |
| 公司 | 可使用 | CustomTableReadRequired |
參數
| 欄位 | 位置 | 型別 | 必填 | 說明 |
|---|---|---|---|---|
table_id | path | uuid | 是 | 要讀取 append-only 事件的期間資料表 UUID。 |
record_id | query | string | 否 | 可選的期間紀錄 ID 篩選;仍套用一般的可讀資料範圍。 |
limit | query | int (1–1000) | 否 | 每頁筆數,預設 100,範圍 1 到 1000。 |
offset | query | int (≥0) | 否 | 不可為負數的位移,預設 0。 |
回應結構
CtPeriodEventsResponse| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
events | CtPeriodEvent[] | 是 | 未指定 |
table_id | string | 是 | 未指定 |
total | integer | 是 | 未指定 |
範例
讀取已授權、尚無事件的一頁
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222"
},
"query": {
"limit": "100",
"offset": "0"
}
}{
"table_id": "22222222-2222-4222-8222-222222222222",
"events": [],
"total": 0
}/private/module/custom_tables/{scope}/tables/{table_id}/history由新至舊回傳涵蓋資料列與結構變更的資料表稽核記錄(依 `created_at`、`version`、再依歷程 id 排序)。觸發器設定的變更只顯示給資料表版主。
適合製作稽核時間軸,或在深入某筆資料列版本前先篩選變更。
- 聊天室
/private/module/custom_tables/chatroom/{chatroom_id}/tables/{table_id}/history - 部門
/private/module/custom_tables/department/{department_id}/tables/{table_id}/history - 公司
/private/module/custom_tables/company/tables/{table_id}/history
範圍
| 範圍 | 是否提供 | 驗證與權限 |
|---|---|---|
| 聊天室 | 可使用 | CustomTableReadRequired (+ CustomTableTriggerConfigVisible) |
| 部門 | 可使用 | CustomTableReadRequired (+ CustomTableTriggerConfigVisible) |
| 公司 | 可使用 | CustomTableReadRequired (+ CustomTableTriggerConfigVisible) |
參數
| 欄位 | 位置 | 型別 | 必填 | 說明 |
|---|---|---|---|---|
table_id | path | uuid | 是 | 要列出稽核記錄的資料表 UUID。 |
change_type | query | string | 否 | 選填,精確比對的變更類型:`create`、`update`、`delete`、`restore`、`revert`、`schema_add_column`、`schema_remove_column`、`schema_type_change`、`schema_update_column`、`schema_rules_update` 或 `schema_triggers_update`(只列給資料表版主)。其他值不會命中任何項目。 |
record_id | query | uuid | 否 | 選填的資料列 UUID;會排除其他資料列與整張表的結構記錄。 |
limit | query | int 1..1000 | 否 | 最多回傳幾筆歷程,可填 1 到 1,000,預設為 100。 |
offset | query | int >= 0 | 否 | 略過前幾筆符合條件的歷程,預設為 0。`total` 是符合篩選且你看得到的全部項目數,即使 offset 已超過最後一頁、回傳空頁也一樣;回應沒有 `has_more`——只要 offset 加上本頁筆數小於 total,就還有更多項目。 |
回應結構
TableHistoryListResponse| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
history | RecordHistoryEntry[] | 是 | History entries, newest first |
table_id | string | 是 | Table UUID |
total | integer | 是 | Total number of history entries |
範例
列出某筆資料列的更新記錄
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222"
},
"query": {
"change_type": "update",
"record_id": "33333333-3333-4333-8333-333333333333",
"limit": "50",
"offset": "0"
}
}{
"history": [
{
"id": "44444444-4444-4444-8444-444444444444",
"record_id": "33333333-3333-4333-8333-333333333333",
"table_id": "22222222-2222-4222-8222-222222222222",
"version": 2,
"data": {
"id": "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee",
"col_77777777_7777_4777_8777_777777777777": "ORD-1001",
"col_88888888_8888_4888_8888_888888888888": "已確認"
},
"diff": {
"col_88888888_8888_4888_8888_888888888888": {
"old": "草稿",
"new": "已確認"
}
},
"change_type": "update",
"changed_by": {
"id": "55555555-5555-4555-8555-555555555555",
"created_at": "2026-01-15T01:00:00",
"expired_at": "2027-01-15T01:00:00",
"photo_url": null,
"enabled": true,
"is_verified": true,
"username": "catalog.operator",
"email": "operator@example.invalid",
"nickname": "陳小安",
"department_id": "66666666-6666-4666-8666-666666666666",
"department_name": "營運部"
},
"changed_by_client": null,
"changed_by_ai": false,
"reverted_to": null,
"created_at": "2026-07-19T04:05:00",
"trigger_secrets": null
}
],
"total": 1,
"table_id": "22222222-2222-4222-8222-222222222222"
}錯誤
驗證錯誤範例列出識別欄位;部署中的驗證器也可能回傳 input 與 ctx。錯誤訊息 URL 的版本由建置決定,因此使用 pydantic-version 佔位符。
| 狀態 | 發生條件 | 錯誤本文 |
|---|---|---|
| 404 | 資料表 id 不存在或已在垃圾桶(讀取門檻,任何 scope),或——chatroom 路由——資料表不在路徑指定的聊天室中(路由自己的查詢,回應相同)。 | |
| 404 | Department 或 company 路由:路徑 scope 之外的現行資料表。 | |
/private/module/custom_tables/{scope}/tables/{table_id}/records/{record_id}/history由新至舊回傳某筆資料列所有保留的版本快照——資料列在垃圾桶中時也一樣(歷程仍可讀取;但要還原它的某個版本,必須先把資料列從垃圾桶救回)。
適合製作資料列時間軸,或挑選要檢視、比對或還原的版本。
- 聊天室
/private/module/custom_tables/chatroom/{chatroom_id}/tables/{table_id}/records/{record_id}/history - 部門
/private/module/custom_tables/department/{department_id}/tables/{table_id}/records/{record_id}/history - 公司
/private/module/custom_tables/company/tables/{table_id}/records/{record_id}/history
範圍
| 範圍 | 是否提供 | 驗證與權限 |
|---|---|---|
| 聊天室 | 可使用 | CustomTableReadRequired |
| 部門 | 可使用 | CustomTableReadRequired |
| 公司 | 可使用 | CustomTableReadRequired |
參數
| 欄位 | 位置 | 型別 | 必填 | 說明 |
|---|---|---|---|---|
table_id | path | uuid | 是 | 上層資料表 UUID。 |
record_id | path | uuid | 是 | 要列出版本的資料列 UUID。 |
change_type | query | string | 否 | 選填,精確比對此資料列版本的變更類型:`create`、`update`、`delete`、`restore`、`revert`,或改寫過這列資料的結構操作(`schema_add_column`、`schema_remove_column`、`schema_type_change`)。 |
limit | query | int 1..1000 | 否 | 最多回傳幾筆歷程,可填 1 到 1,000,預設為 100。 |
offset | query | int >= 0 | 否 | 略過前幾個符合條件的版本,預設為 0。`total` 是符合 `change_type` 的全部版本數,即使 offset 已超過最後一頁、回傳空頁也一樣;回應沒有 `has_more`——只要 offset 加上本頁筆數小於 total,就還有更多版本。 |
回應結構
RecordHistoryListResponse| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
history | RecordHistoryEntry[] | 是 | History entries, newest first |
record_id | string | 是 | Record UUID |
total | integer | 是 | Total number of history entries |
範例
列出某筆資料列的版本
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222",
"record_id": "33333333-3333-4333-8333-333333333333"
},
"query": {
"limit": "50",
"offset": "0"
}
}{
"history": [
{
"id": "44444444-4444-4444-8444-444444444444",
"record_id": "33333333-3333-4333-8333-333333333333",
"table_id": "22222222-2222-4222-8222-222222222222",
"version": 2,
"data": {
"id": "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee",
"col_77777777_7777_4777_8777_777777777777": "ORD-1001",
"col_88888888_8888_4888_8888_888888888888": "已確認"
},
"diff": {
"col_88888888_8888_4888_8888_888888888888": {
"old": "草稿",
"new": "已確認"
}
},
"change_type": "update",
"changed_by": {
"id": "55555555-5555-4555-8555-555555555555",
"created_at": "2026-01-15T01:00:00",
"expired_at": "2027-01-15T01:00:00",
"photo_url": null,
"enabled": true,
"is_verified": true,
"username": "catalog.operator",
"email": "operator@example.invalid",
"nickname": "陳小安",
"department_id": "66666666-6666-4666-8666-666666666666",
"department_name": "營運部"
},
"changed_by_client": null,
"changed_by_ai": false,
"reverted_to": null,
"created_at": "2026-07-19T04:05:00",
"trigger_secrets": null
},
{
"id": "ffffffff-ffff-4fff-8fff-ffffffffffff",
"record_id": "33333333-3333-4333-8333-333333333333",
"table_id": "22222222-2222-4222-8222-222222222222",
"version": 1,
"data": {
"id": "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee",
"col_77777777_7777_4777_8777_777777777777": "ORD-1001",
"col_88888888_8888_4888_8888_888888888888": "草稿"
},
"diff": null,
"change_type": "create",
"changed_by": {
"id": "55555555-5555-4555-8555-555555555555",
"created_at": "2026-01-15T01:00:00",
"expired_at": "2027-01-15T01:00:00",
"photo_url": null,
"enabled": true,
"is_verified": true,
"username": "catalog.operator",
"email": "operator@example.invalid",
"nickname": "陳小安",
"department_id": "66666666-6666-4666-8666-666666666666",
"department_name": "營運部"
},
"changed_by_client": null,
"changed_by_ai": false,
"reverted_to": null,
"created_at": "2026-07-19T04:00:00",
"trigger_secrets": null
}
],
"total": 2,
"record_id": "33333333-3333-4333-8333-333333333333"
}錯誤
驗證錯誤範例列出識別欄位;部署中的驗證器也可能回傳 input 與 ctx。錯誤訊息 URL 的版本由建置決定,因此使用 pydantic-version 佔位符。
| 狀態 | 發生條件 | 錯誤本文 |
|---|---|---|
| 404 | 資料表 id 不存在或已在垃圾桶(讀取門檻),或——chatroom 路由——資料表不在路徑指定的聊天室中(路由自己的查詢,回應相同)。 | |
| 404 | Department 或 company 路由:路徑 scope 之外的現行資料表。 | |
| 404 | 這張資料表中沒有此 id 的資料列(或它屬於其他資料表)。 | |
| 404 | 資料列存在,但被資料列層級存取權對你隱藏。 | |
/private/module/custom_tables/{scope}/tables/{table_id}/records/{record_id}/history/{version}回傳某個資料列版本的不可變快照與變更資訊。
適合在比對或還原前,先檢視確切的歷史狀態。
- 聊天室
/private/module/custom_tables/chatroom/{chatroom_id}/tables/{table_id}/records/{record_id}/history/{version} - 部門
/private/module/custom_tables/department/{department_id}/tables/{table_id}/records/{record_id}/history/{version} - 公司
/private/module/custom_tables/company/tables/{table_id}/records/{record_id}/history/{version}
範圍
| 範圍 | 是否提供 | 驗證與權限 |
|---|---|---|
| 聊天室 | 可使用 | CustomTableReadRequired |
| 部門 | 可使用 | CustomTableReadRequired |
| 公司 | 可使用 | CustomTableReadRequired |
參數
| 欄位 | 位置 | 型別 | 必填 | 說明 |
|---|---|---|---|---|
table_id | path | uuid | 是 | 上層資料表 UUID。 |
record_id | path | uuid | 是 | 擁有該版本的資料列 UUID。 |
version | path | int | 是 | 要取得的正整數資料列版本號。 |
回應結構
RecordHistoryEntry| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
change_type | string | 是 | Open-ended change discriminator, not a closed enum. Includes row create/update/delete/revert and schema changes such as schema_add_column, schema_remove_column, schema_type_change, schema_rules_update and schema_triggers_update. Table-history responses omit trigger-configuration rows for non-moderators. |
changed_by | BaseUserInfo | null | 否 | User who made the change (null for external client changes) |
changed_by_ai | boolean | 是 | Whether the change was made by an AI agent |
changed_by_client | SocialMediaClientBasicInfo | null | 否 | Social media client who made the change (null for internal user changes) |
created_at | string (date-time) | 是 | Timestamp of the change |
data | object | 是 | Full record data snapshot at this version |
diff | object | null | 否 | Field-level diff: {column_id: {old: ..., new: ...}} |
id | string | 是 | History entry UUID |
record_id | string | null | 否 | Record UUID (null for table-wide schema changes) |
reverted_to | integer | null | 否 | Target version (only present for revert operations) |
table_id | string | 是 | Parent table UUID |
trigger_secrets | TriggerHistorySecretSlots | null | 否 | Trigger-configuration rows (change_type "schema_triggers_update") only: the typed slot list of every "__SECRET__" in `data.triggers`, `diff.old` and `diff.new` (never a value, hash or prefix). Null on every other row. |
version | integer | 是 | Record version at the time of this change |
範例
取得資料列的第 2 版
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222",
"record_id": "33333333-3333-4333-8333-333333333333",
"version": "2"
}
}{
"id": "44444444-4444-4444-8444-444444444444",
"record_id": "33333333-3333-4333-8333-333333333333",
"table_id": "22222222-2222-4222-8222-222222222222",
"version": 2,
"data": {
"id": "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee",
"col_77777777_7777_4777_8777_777777777777": "ORD-1001",
"col_88888888_8888_4888_8888_888888888888": "已確認"
},
"diff": {
"col_88888888_8888_4888_8888_888888888888": {
"old": "草稿",
"new": "已確認"
}
},
"change_type": "update",
"changed_by": {
"id": "55555555-5555-4555-8555-555555555555",
"created_at": "2026-01-15T01:00:00",
"expired_at": "2027-01-15T01:00:00",
"photo_url": null,
"enabled": true,
"is_verified": true,
"username": "catalog.operator",
"email": "operator@example.invalid",
"nickname": "陳小安",
"department_id": "66666666-6666-4666-8666-666666666666",
"department_name": "營運部"
},
"changed_by_client": null,
"changed_by_ai": false,
"reverted_to": null,
"created_at": "2026-07-19T04:05:00",
"trigger_secrets": null
}錯誤
驗證錯誤範例列出識別欄位;部署中的驗證器也可能回傳 input 與 ctx。錯誤訊息 URL 的版本由建置決定,因此使用 pydantic-version 佔位符。
| 狀態 | 發生條件 | 錯誤本文 |
|---|---|---|
| 404 | 資料表 id 不存在或已在垃圾桶(讀取門檻),或——chatroom 路由——資料表不在路徑指定的聊天室中(路由自己的查詢,回應相同)。 | |
| 404 | Department 或 company 路由:路徑 scope 之外的現行資料表。 | |
| 404 | 這張資料表中沒有此 id 的資料列(或它屬於其他資料表)。 | |
| 404 | 資料列存在,但被資料列層級存取權對你隱藏。 | |
| 404 | 這筆資料列不存在指定版本。 | |
/private/module/custom_tables/{scope}/tables/{table_id}/records/{record_id}/history/{version}/diff回傳路徑版本與指定比較版本之間的欄位級差異,由兩份儲存的快照計算:快照相同時 `diff` 為 `{}`;連結變更永遠不會出現——連結不在 `data` 中,改動連結的那筆歷程會在自己的 `diff` 裡記錄新舊目標 id 清單。
適合在使用者決定要還原的版本前,說明究竟改了什麼。
- 聊天室
/private/module/custom_tables/chatroom/{chatroom_id}/tables/{table_id}/records/{record_id}/history/{version}/diff - 部門
/private/module/custom_tables/department/{department_id}/tables/{table_id}/records/{record_id}/history/{version}/diff - 公司
/private/module/custom_tables/company/tables/{table_id}/records/{record_id}/history/{version}/diff
範圍
| 範圍 | 是否提供 | 驗證與權限 |
|---|---|---|
| 聊天室 | 可使用 | CustomTableReadRequired |
| 部門 | 可使用 | CustomTableReadRequired |
| 公司 | 可使用 | CustomTableReadRequired |
參數
| 欄位 | 位置 | 型別 | 必填 | 說明 |
|---|---|---|---|---|
table_id | path | uuid | 是 | 上層資料表 UUID。 |
record_id | path | uuid | 是 | 要比對版本的資料列 UUID。 |
version | path | int | 是 | URL 中的來源版本號。 |
compare_to | query | int | 是 | 要比較的目標版本號;聊天室路由必填。 |
回應結構
RecordDiffResponse| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
diff | object | 是 | Field-level changes: {column_id: {old: ..., new: ...}} |
from_version | integer | 是 | Source version number |
to_version | integer | 是 | Target version number |
範例
將第 2 版與第 1 版比較
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222",
"record_id": "33333333-3333-4333-8333-333333333333",
"version": "2"
},
"query": {
"compare_to": "1"
}
}{
"from_version": 2,
"to_version": 1,
"diff": {
"col_88888888_8888_4888_8888_888888888888": {
"old": "已確認",
"new": "草稿"
}
}
}錯誤
驗證錯誤範例列出識別欄位;部署中的驗證器也可能回傳 input 與 ctx。錯誤訊息 URL 的版本由建置決定,因此使用 pydantic-version 佔位符。
| 狀態 | 發生條件 | 錯誤本文 |
|---|---|---|
| 404 | 資料表 id 不存在或已在垃圾桶(讀取門檻),或——chatroom 路由——資料表不在路徑指定的聊天室中(路由自己的查詢,回應相同)。 | |
| 404 | Department 或 company 路由:路徑 scope 之外的現行資料表。 | |
| 404 | 這張資料表中沒有此 id 的資料列(或它屬於其他資料表)。 | |
| 404 | 資料列存在,但被資料列層級存取權對你隱藏。 | |
| 404 | 指定的一個或兩個版本不存在。 | |
| 422 | 僅聊天室路由:缺少 `compare_to`(如上所示);部門與公司路由預設為 1。`compare_to` 或 `version` 不是整數時,任何路由都回 422 `int_parsing`。 | |
/private/module/custom_tables/{scope}/tables/{table_id}/records/{record_id}/history/{version}/restore將歷史的標量快照複製到現行資料列,並把結果記錄為新的 revert 版本。
檢視目標快照與差異,並確認目前連結與結構相容後使用。
- 聊天室
/private/module/custom_tables/chatroom/{chatroom_id}/tables/{table_id}/records/{record_id}/history/{version}/restore - 部門
/private/module/custom_tables/department/{department_id}/tables/{table_id}/records/{record_id}/history/{version}/restore - 公司
/private/module/custom_tables/company/tables/{table_id}/records/{record_id}/history/{version}/restore
範圍
| 範圍 | 是否提供 | 驗證與權限 |
|---|---|---|
| 聊天室 | 可使用 | CustomTableEditRequired |
| 部門 | 可使用 | CustomTableEditRequired |
| 公司 | 可使用 | CustomTableEditRequired |
參數
| 欄位 | 位置 | 型別 | 必填 | 說明 |
|---|---|---|---|---|
table_id | path | uuid | 是 | 上層資料表 UUID。 |
record_id | path | uuid | 是 | 要還原的資料列 UUID。 |
version | path | int | 是 | 要還原標量資料的歷史版本號。 |
回應結構
RestoreResponse| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
links_not_restored | boolean | 否 | True when the table has link columns: version restore reverts only scalar cells — the record's CURRENT link relations were NOT reverted to the target version. Surface this so the user knows relations differ. |
message | string | 是 | Status message |
new_version | integer | 是 | The new version number after restore |
record | CustomTableRecordResponse | 是 | The restored record (now at a new version) |
restored_from_version | integer | 是 | The version that was restored from |
範例
還原第 1 版的標量資料
{
"pathParams": {
"chatroom_id": "11111111-1111-4111-8111-111111111111",
"table_id": "22222222-2222-4222-8222-222222222222",
"record_id": "33333333-3333-4333-8333-333333333333",
"version": "1"
}
}{
"record": {
"id": "33333333-3333-4333-8333-333333333333",
"data": {
"id": "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee",
"訂單編號": "ORD-1001",
"狀態": "草稿"
},
"version": 3,
"is_deleted": false,
"created_by_ai": false,
"created_by": {
"id": "55555555-5555-4555-8555-555555555555",
"created_at": "2026-01-15T01:00:00",
"expired_at": "2027-01-15T01:00:00",
"photo_url": null,
"enabled": true,
"is_verified": true,
"username": "catalog.operator",
"email": "operator@example.invalid",
"nickname": "陳小安",
"department_id": "66666666-6666-4666-8666-666666666666",
"department_name": "營運部"
},
"created_by_client": null,
"sort_order": 1,
"table_id": "22222222-2222-4222-8222-222222222222",
"created_at": "2026-07-19T04:00:00",
"updated_at": "2026-07-19T04:10:00",
"expanded": null,
"incoming_links": null,
"can_edit": true,
"pending_approval": null
},
"restored_from_version": 1,
"new_version": 3,
"message": "Record restored to version 1",
"links_not_restored": false
}錯誤
驗證錯誤範例列出識別欄位;部署中的驗證器也可能回傳 input 與 ctx。錯誤訊息 URL 的版本由建置決定,因此使用 pydantic-version 佔位符。
| 狀態 | 發生條件 | 錯誤本文 |
|---|---|---|
| 403 | 資料表的 `write_policy` 是 `commands_only`:任何不在 Command 之內的主體所做的資料列寫入,都會在任何東西被暫存、排入佇列或 commit 之前,以 typed 的 `governed_context_required` 被拒絕(不會產生版本、history、receipt、token 或 Review process)。`operation` 指出是哪種寫入,若該通道有名稱則以 `surface` 指出;請改用被允許寫入該資料表的 Command。讀取不受影響。 | |
| 409 | `date_interval_exclusion` 規則拒絕此次寫入:`date_interval_exclusion_invalid_period`(建立時省略 end key、結束日為空字串或不晚於起始日,或 scope link 沒有恰好一個目標)、`date_interval_exclusion_overlap`(另一筆 live 資料列涵蓋了這段期間的一部分),或 `date_interval_exclusion_retry`(寫入等待期間資料表的規則被改變;沒有寫入任何東西,請重送)。body 是固定訊息,絕不會指出資料列、日期或 scope 值。 | |
| 409 | 排除送審者(`exclude_requester`)之後,某個必要的審批 gate 沒有任何可核准者。送出會在任何 review process 出現之前就被拒絕;`gate_order` 指出該 gate。對於不管理每一張被引用資料表的 `authority: definition` command 呼叫者,只會回傳安全的 key,所以沒有 `gate_order`。 | |
| 409 | 這筆寫入需要排除送審者,但呼叫的主體沒有已驗證的人類身分(例如 service account),無法歸屬。不會暫存任何東西。 | |
| 404 | 這張資料表中沒有此資料列,或它在垃圾桶中(請先從垃圾桶還原)——或編輯層級為 `filtered` 時,資料列存在但被你的讀取篩選隱藏;這個 body 適用於管理此表或編輯層級為 `all`、`filtered` 的呼叫者。資料表不存在或已在垃圾桶時,編輯門檻會回 `404 CustomTable Not found`(chatroom 路由上,資料表不在路徑指定的聊天室中時也是)。 | |
| 404 | own/filtered 編輯者無法找到資料列,或資料列被可讀範圍隱藏。body 與一般資料列可見性檢查相同,使用 Record not found。 | |
| 404 | Department 或 company 路由:路徑 scope 之外的現行資料表。 | |
| 403 | 你的編輯層級為 own,資料列由他人建立且可讀取;不可讀的資料列改回 404 Record not found。 | |
| 403 | 你的編輯層級是 `filtered`,而資料列目前的內容或你要還原的版本落在你的編輯篩選之外——還原不能把資料列移出你可編輯的範圍。被你的讀取篩選隱藏的資料列則改回 `404 Record not found`。 | |
| 400 | 這筆資料列沒有此版本號的歷程。與讀取路由不同,還原時找不到目標版本回的是 400,而不是 404。 | |
| 400 | 有寫入規則否決還原後的資料列——`compare`、`check`、`require`、`no_overlap`、`exists`/`not_exists`、`count_limit` 或 `immutable_when` 會回 `400 Rule '<名稱或 id>' violated: …`——或某個被改動的 `user`、`social_client` 或 `principal` 欄位指向已刪除或不在公司內的對象(`400 Unknown or inaccessible user ids: [...]`,或 `… social_client ids`/`… chatroom ids`)。`transition` 與 `unique` 規則則回 409。 | |
| 409 | 目標版本已不符合資料表目前的欄位結構,沒有還原任何資料。每筆衝突的 `field` 是內部欄位鍵:`removed_column`(該版本含有之後被刪除的欄位——這種版本無法還原)、`missing_required_field`(之後新增了沒有預設值的必填欄位),或 `type_mismatch`(儲存的值已不被改型後的欄位型別接受——string→text 或 integer→float 可以正常還原——或 decimal 值已不符合欄位的精度或正負號,或必填的 decimal 欄位存著明確的 null;符合的 decimal 會依目前的 scale 重新序列化)。值規則造成的衝突另外回報(`invalid_value`)。 | |
| 409 | 目標版本通過欄位檢查,但有值違反目前結構的欄位規則——例如之後停用的 select 選項、現在必填的(非 decimal)欄位存著明確的 null,或文字超過調低後的 `max_length`。每筆衝突為 `type: "invalid_value"`、`field: null`,並由 `message` 以顯示名稱指出欄位。只有在沒有欄位衝突時才會做這項檢查,所以兩類衝突不會出現在同一個回應中;核准後重播還原時也會再檢查一次。 | |
| 409 | 資料表的 require_approval 規則命中這次還原——版本還原算作 `update` 事件,只要目前資料列或還原後的資料任一符合 `when` 就算命中——因此還原被暫存為 staged change、等待覆核;核准前現行資料列不會改變。 | |
| 409 | 這筆資料列已被另一個等待覆核的暫存變更鎖住;在該覆核結束前,不論這次還原是否會命中審批規則,資料列都不接受其他寫入。 | |
| 409 | `transition` 規則不允許這次還原造成的值變更(把狀態倒回去也算一次轉移)。`unique` 衝突同樣回 409,`detail` 為結構化物件。 | |
| 423 | 資料表目前被結構遷移鎖定。 | |
| 429 | 此表或此操作者的待覆核暫存變更已達上限(staged_cap_exceeded)。 | |
| 413 | 還原會寫入的資料列同時「超過上限」且「比目前更大」。把超大資料列還原成較小的版本仍然允許。 | |
目前的欄位 ACL 與 schema ceiling會過濾 record/table history、stored version 與 diff。受限 principal 看不到已移除欄位;未受欄位限制的讀者仍可能取得已移除的 stored field。這不會還原舊權限,也不會繞過目前 row authorization。
歷史 as-of 讀取 依目前權限取回時間點的儲存版本;不是 ACL 或計算值的時間旅行。