JSONL IaC 概念
JSONL IaC 把一組彼此關聯的表格、欄位、規則、觸發器、檢視、授權、用戶端存取設定、資料列、組合式指令、逐室洞察選擇與免驗證公開讀取 token,寫成一份可版本控制的宣告。它適合管理「多個資源共同構成一個系統」的情境,不必把一連串命令的執行順序當成唯一真相。
IaC 是無條件可用的。Plan、apply、state 與 export 永遠開啟;沒有需要先啟用的 feature flag,舊有的「flag 關閉時回 400」回應也已經在所有 scope 上消失。CUSTOM_TABLE_IAC_MAX_BYTES、CUSTOM_TABLE_IAC_MAX_LINES、CUSTOM_TABLE_IAC_MAX_TABLES、CUSTOM_TABLE_IAC_MAX_RECORDS 與 CUSTOM_TABLE_IAC_SYNC_RECORD_LIMIT 仍然存在,但它們是容量調節參數,不是開關。
有一項輸入限制刻意不屬於它們:每個實體行的 JSON 巢狀深度上限是 128 層 [/{,由寫死在 parser 內的防護擋下,沒有任何環境變數可以調高或調低。深度是就整行測量的,包含行本身的外框 —— record line 最外層的 { 就是第 1 層 —— 字串字面值內的括號不計入。它同時是每行的第一道檢查,排在 JSON 解碼、header 唯一性規則與 record/line/table 各項 cap 之前,因此一個過深的行即使同時是壞掉的 JSON、或本來也會撞破某個 cap,回報的仍是巢狀中止:
line 3: excessively nested JSON structure (max depth 128)只有文件層級的位元組上限與 UTF-8 檢查比它更早執行。parse 階段其餘的錯誤目錄見錯誤階段。
為什麼使用 IaC
一般 API 呼叫描述「現在做一件事」;IaC 文件描述「最後應該長成什麼樣子」。穩定的 ref 讓規劃器在環境間解析同一套關係,而 plan 先把 live 狀態與宣告的差異攤開。這帶來三個實際好處:
- 可審查:JSONL 與 plan diff 都能進入變更審查,建立、更新、移動與刪除不再藏在腳本控制流程裡。
- 可重複:相同文件可套用到新的 chatroom scope;套用完成後再 plan,既有資源應收斂為
noop,資料列則為skip。 - 可組合:一份文件可以宣告多張表與跨表欄位,規則、檢視和授權再以 ref 指向它們。
注意: IaC 不會因為資源從文件消失就刪除它。刪除必須以
state: "absent"明確宣告,讓破壞性變更保持可見。
system 是狀態命名空間與自動標籤
第一行的 header.system 同時扮演兩個角色:
- 它是伺服器 IaC state 的命名空間。
ref只在這個 system 內代表穩定身分,plan/apply 會用它把宣告與 live resource 對上。 - 非空的 system 會成為受管理表格的 IaC 自動標籤,方便辨認資源由哪個宣告系統管理。
system 最長 100 個字元;空字串是合法值,但不會同步自動標籤。請為長期維護的系統選一個穩定名稱,不要把部署時間或環境產生的 ID 放進去。
JSONL 心智模型
JSONL(newline-delimited JSON)的規則很小,但很嚴格:
- Content-Type 使用
application/x-ndjson;每個非空白實體行只能是一個完整 JSON object。 header可省略;若提供,它必須是第一個非空白行且只能出現一次,版本目前固定為1。省略時 system 是空字串。- 空白行會忽略;
#註解不是 JSON,不能放進文件。 - 後續行依文件順序規劃。先宣告
table,再宣告使用該表的子資源;跨表欄位也應在目標表 ref 可解析後出現。 - 頂層未知欄位與各 kind 不接受的欄位都會被拒絕,而不是靜默忽略。
十二種 line kind 是 header、table、column、rule、trigger、view、grant、client_access、record、command、insight_selection 與 public_read。這也是 discriminated union 宣告它們的順序,而 custom_table_iac_state.resource_type 同樣新增了這三個值。
三種 scope 都提供經驗證的 GET .../tables/iac/contract authored-contract 路由:
/private/module/custom_tables/chatroom/{chatroom_id}/tables/iac/contract/private/module/custom_tables/department/{department_id}/tables/iac/contract/private/module/custom_tables/company/tables/iac/contract
其 IacDocumentContractResponse 包含 version、kinds、resource_types 與 line。Runtime 的 line 值是一條合法 header;更重要的 OpenAPI 用途,是讓 schema 帶出完整的 discriminated IacLine union——plan/apply 接收的是原始 JSONL bytes,無法自行讓 request model 出現在 OpenAPI。生成工具應讀 contract/OpenAPI schema,但 apply 前仍必須對 live state 執行 plan。
其中三種不遵循其他 kind 共用的 {table}.{ref} 形狀。command 屬於 scope 層級,使用 command:{ref};insight_selection 使用 insight.{chatroom uuid} 且完全沒有 spec;public_read 雖是資料表子資源,但與單例的 client_access 不同,同一張表可以有多個。
一個小型系統
下列每一行都是獨立 JSON object;contacts 與 email 是作者選定的穩定 ref,不是伺服器 ID。
{"kind":"header","version":1,"system":"crm","description":"Shared contact workflow"}
{"kind":"table","ref":"contacts","spec":{"name":"Contacts","description":"Managed by JSONL IaC","key":"email"}}
{"kind":"column","table":"contacts","ref":"email","spec":{"name":"Email","type":"text","required":true}}
{"kind":"view","table":"contacts","ref":"directory","spec":{"name":"Directory","is_shared":true,"config":{"columns":["email"]}}}
{"kind":"record","table":"contacts","data":{"email":"alex@example.com"},"on_drift":"skip"}Plan 會先解析這些 ref,再產生 create、adopt、move、update、noop、delete、orphaned、insert 或 skip action。這份文件只是 desired state;真正的 live 差異仍以伺服器 plan 為準。
接著閱讀
- 從標準編寫流程開始,把既有系統先 export,再進行修改。
- 從
header開始,用十二種 line kind 頁面逐欄核對 authored contract,而不是猜測 API response 欄位能否寫回。 - 只要要寫出指名人員、部門、聊天室或社群用戶的行,就先讀可攜身分 token。
- 在送出變更前理解 plan/apply、狀態模型與錯誤階段。
- 欄位與端點的完整契約請查閱 IaC API 參考。
完整部署還需要幾個 REST 呼叫:用 REST 補完 列出六項文件裝不了的設定,以及每一項之後由哪一邊擁有。
動手試試
把上面的五行貼到 IaC 工作台。先用本機驗證確認 JSONL 與 ref,再選擇一個測試 chatroom 執行唯讀 plan;不要在第一次看見 diff 前 apply。