Skip to Content
快速開始範圍與掛載路徑

範圍與掛載路徑

每張自訂資料表都掛在一個組織範圍(scope)下。範圍同時決定 URL 的掛載形狀與第一層存取邊界;真正能否讀、寫或管理資料,仍由該端點的驗證 dependency 與資料表 ACL 一起判斷。共用 public multipart chunk leg 是下方說明的刻意例外:它以持有 session capability 為 gate,不使用 user auth。

三種掛載範圍

模組基底路徑約略路由數
自訂資料表 — 聊天室範圍/private/module/custom_tables/chatroom/{chatroom_id}104
自訂資料表 — 部門範圍/private/module/custom_tables/department/{department_id}112
自訂資料表 — 公司範圍/private/module/custom_tables/company111
Commands(company 路徑含 {company_id})…/{scopeWithId}/commands…10×3,另加只在聊天室範圍的 5 條 composer 路由
能力探索(路徑含 scope id)…/{scopeWithId}/core/capabilities1×3
Public-read tokens(不含 scope id)…/{scopeName}/tables/{table_id}/public-read-tokens…3×3
附件(掛載於三種範圍,不含 scope id)…/{scopeName}/tables/{table_id}/…(multipart blobs/* ×4,加上 records/{record_id}/attachments/{blob_id}/download)5×3
共用 multipart chunk leg/public/module/etl/multipart/chunk1

路由數量是各 prefix 下掛載的操作數,另有獨立列的路由家族不計入。數量為概數,會隨每次同步變動。

GET …/{scopeWithId}/core/capabilities 是唯讀的版本探索:它回答 ct.generic-core/1 契約(伺服器版本、支援的 command DSL 與 IaC 文件版本、capability 旗標、上限與 schema 摘要),不授予任何資料存取。它的門檻在 chatroom scope 是房間存取權(成員、房間所屬部門的管理者或公司管理者),在 department scope 是同一家公司,在 company scope 則要求路徑上的 company_id 等於呼叫者自己的公司,否則回 404 {"detail": "Company not found"}。它也是 third_party 或 specific_chatroom 整合 API key 唯一能到達的 Custom Tables 路由:third_party key 在三種 scope 都可以,specific_chatroom key 則限於它清單中的房間(其他房間回 403 Access to chatroom <id> is not allowed for this API key);其他每一條路由對這類 key 都回 405,但 Custom Tables 的 input、artifact 與 package 路由,以及工作日行事曆路由例外,它們回 403 Access denied, invalid scope(見驗證)。scope 為 work_calendar_read 的 key 則只能到達 company scope 的兩條工作日行事曆 GET 路由。

ETL tables 是另一個模組。本手冊只保留這條 public chunk 路徑,因為 Custom Table 附件上傳會重用它;不要把 /private/module/etl/… 或其他 public ETL 路由當成 Custom Tables。

功能矩陣:哪個 scope 有哪些 family

大多數 record、schema、view、tag、rule、trigger、IaC、import、bulk、history、trash、lifecycle、user-grant、client-permission 與 callback-token 的 path tail 都掛在三種 scope。客戶端不該自行猜測的例外如下:

FamilyChatroomDepartmentCompany
核心 table/record/schema/自動化 tails有有有
GET …/tables/shared有無無
Chatroom table 的 department-permissions/{department_id}有無無
Permission requests(列出、approve、reject)有無無
Department table 的 chatroom-permissions無有無
Department/company 的 department-permissions/{target_department_id}無有有
Table moderators無有有
Publish sessions無有有
PUT …/columns/{column_id} 別名無無有
Commands(company/{company_id}/commands)有有有
Command composer(…/commands/composer/*)有無無
成員探索 GET …/readable-tables無有無
能力探索 …/core/capabilities(路徑含 scope id)有有有
附件與 public-read tokens({scopeName},不含 id)有有有

授權不會改變擁有範圍的掛載:部門表被授權給聊天室後,record API 仍走 department/{department_id}。驗證 gate 與 union 契約見範圍、掛載與跨範圍存取。

組織上各自代表什麼

  • 聊天室(chatroom):資料表屬於一個聊天室,路徑必須帶 chatroom_id。適合由該聊天室成員共同操作的資料;入口權限通常從加入聊天室或聊天室管理權開始,再套用表級 ACL。
  • 部門(department):資料表屬於一個部門,路徑必須帶 department_id。適合部門層級的共同資料;部門存取與表級 ACL 是兩層不同的判斷。
  • 公司(company):資料表屬於目前使用者的公司。路徑本身不帶 company_id,但仍會驗證使用者的公司身分、管理權或表級權限。

選 scope 時先問「這份資料由哪個組織單位擁有」,不要只為了縮短 URL 而選 company。資料表建立後的分享需求,應交給 ACL 與 grants,而不是複製到另一個 scope。

各範圍的驗證風格速覽

下表用這份快速入門會碰到的端點說明命名規律;dependency 名稱是後端的授權門檻,不是要放進 token 的 OAuth scope。

範圍建立/列出資料表資料列讀寫詳細資料
聊天室ChatRoomAccessRequired/ChatRoomJoinedRequiredCustomTableReadRequired、CustomTableInsertRequired、CustomTableEditRequired資料表參考、資料列參考、權限與 ACL
部門DepartmentAccessRequiredCustomTableReadRequired、CustomTableInsertRequired、CustomTableEditRequired資料表參考、資料列參考、權限與 ACL
公司CompanyAccessRequiredCustomTableReadRequired、CustomTableInsertRequired、CustomTableEditRequired資料表參考、資料列參考、權限與 ACL

不同操作的門檻並不完全相同;例如建立欄位與執行診斷在每個 scope 都需要資料表 moderator 權限(只有 read 或 insert grant 並不會得到;backend PR #1748),讀取 trigger 設定同樣只限 moderator(backend PR #1752),而解析 links 在各 scope 之間不同。實作前請以每張 reference card 的 Auth 與 scope matrix 為準。

不帶 scope ID 的路由例外

警告:migration 查詢、全部五個附件路由與三個 public-read-token 路由只掛在固定、不含 ID 的 scope 名稱下。即使 scope 是 chatroom 或 department,也不能插入 chatroom_id 或 department_id。

Migration ID 在全域唯一,因此兩個查詢形狀是:

/private/module/custom_tables/{scopeName}/migrations/{migration_id}/status /private/module/custom_tables/{scopeName}/migrations/{migration_id}/diagnosis-results

status 查詢對每一種拒絕都回同一個 404 {"detail": "Migration not found"}——不存在的 id、垃圾桶中或屬於其他公司的資料表(company 路由上也包含不屬於 company scope 的表)、門檻拒絕,或對該表完全沒有任何權限——而且只有該表的 manager 與 moderator 看得到儲存的計數與錯誤文字。其他對該表有權限的讀取者,拿到的是 status、progress 與時間戳,error_message 為 null;當他們自己的資料列計數受限(row policy、只能看自己的列、只有 insert 權限)時,計數也是 null(backend PR #1751)。

診斷結果查詢會回傳資料表診斷中失敗資料列的原始內容,所以在每個 scope 都需要資料表 moderator 權限,沒有的話回 403;未知、尚未完成或已過期的報告——以及自後端 5.21.0 起其他公司的 migration id——回 404 {"detail": "Diagnosis results not found"}。

附件也使用 {scopeName};例如聊天室 multipart 初始化是:

/private/module/custom_tables/chatroom/tables/{table_id}/blobs/multipart/init

它不是 /chatroom/{chatroom_id}/tables/...。產生 URL 時,只有一般 scoped route 才展開成 chatroom/{chatroom_id}、department/{department_id} 或 company;migration、附件與 public-read token 則只替換成 chatroom、department 或 company。完整形狀請見 migration 參考與附件參考。

Multipart 的 chunk upload 本身既不是 private scope mount,也不是上述每個 scope 的五條附件 routes 之一:

POST /public/module/etl/multipart/chunk

這條 route 沒有 user-auth dependency。Private scoped init 會建立高熵、短期 session_id;持有此值就是上傳 chunks 的 capability,因此不能放進 log、analytics 或 URL。它的 multipart/form-data 欄位是 session_id、zero-based chunk_index、binary chunk,以及選填、針對原始 bytes 的小寫 SHA-256 chunk_hash。非最後 chunk 必須等於 chunk_size;最後 chunk 必須等於精確剩餘 bytes。Response 回 uploaded indexes/progress;errors 包含 index/size/hash 無效(400)、session 不存在/過期(404)、重複/衝突(409)、size refusal(413)與 storage/cache failure(503)。Status、complete、abort、掛到 record 與 download 仍是具有 user/table authorization 的 private scoped operations。

找到別人分享給你的表

有兩條 discovery 路由完全不帶 scope 路徑段——連 scope 名稱都沒有——因為呼叫者根本不知道是哪個部門或哪個房間分享給他:

/private/module/custom_tables/shared-with-me /private/module/custom_tables/tables/resolve?name=<精確名稱>

兩條都以 get_current_user 作為唯一閘門:沒有角色檢查、沒有 scope 成員資格 dependency,租戶邊界改由查詢內部逐列把關,而不是由路由把關。

tables.sharedWithMe 回答「有什麼是從我自己的 scope 之外送到我手上的」:per-user grant、我所屬部門的 grant、透過我所屬活房間的 internal chatroom grant,或分享給全部部門的部門表。垃圾桶中的表不會出現。每一筆都帶著放行的 sources 與我解析後的權限(can_read、can_insert、can_edit、is_manager,以及自 backend PR #1732 起的 visible_columns:呼叫者看得到的即時內部欄位 key,null 代表所有欄位、[] 代表沒有;GET …/permissions/me 帶有同一個欄位),而 limit 上限是 200——不是各 scope 表清單的 1000。它與那些清單互補、不是超集:自己部門的表、company scope 的表、所屬房間的表都被刻意排除,想要「我能碰到的全部」必須把兩者聯集。

tables.resolveByName 把精確名稱轉成 id,範圍同時涵蓋 company 與 department scope。name 參數是 1–64 個字元。比對是逐位元組的(utf8mb4_bin),而 per-company 的名稱唯一鍵同時涵蓋兩種 scope,因此最多只會有一張表命中;所有落空——不存在、讀不到、在垃圾桶、別家公司、chatroom scope——都是同一個 404 {"detail": "Table not found"}。用它取代逐環境硬寫 id,也用它補上 discovery 唯一補不了的缺口:角色低於 CAN_MANAGE_COMPANY 的人在 company scope 表上的 per-user grant,在任何清單上都找不到。

探索不等於管理。部門的一般成員透過 GET …/department/{department_id}/readable-tables 列出自己讀得到的部門資料表(backend PR #1751)。它只需要 tenant 門檻(DepartmentTenantRequired):別家公司或不存在的部門是 404 {"detail": "Department not found"}。回應是一般的資料表清單形狀,而它的 total 恰好就是呼叫者讀得到的資料表數量——manager 看得到每一張存活的表,一般成員只看得到 grant 與預設權限開給他的那些,而 200 絕不代表擁有管理權。它接受 skip、limit(1–1000,否則 422)與 tag_id(不存在或屬於別處的 tag 是 404 {"detail": "Tag not found in this scope"})。一般的部門表清單仍保留它的 manager 門檻,所以非 manager 在那裡仍然收到 403 {"detail": "Insufficient permissions for department-level access."};MCP 的 tables_list 工具套用的是同一個可讀過濾(見 Agent 工具箱)。

依 id 讀取資料表 metadata 也遵循同一條規則。同公司、且對某張表完全沒有任何權限的呼叫者——沒有 read、insert 或 edit 能力,也不是 moderator——從三種 scope 的詳情、/columns、/permissions/me、/rules、/triggers、/staged-changes 與 /migration/status 路由,以及 department 與 company scope 的 /moderators 路由(chatroom scope 沒有這條路由),得到的恰好就是該路由對「不存在的 id」的回答,404 {"detail": "CustomTable Not found"}(chatroom 的 /permissions/me 回的是 {"detail": "Table not found"});自後端 5.21.0 起,別家公司的資料表也得到同一個 404(過去維持門檻的 403;見其他公司的 id 回應與不存在相同);只有 insert 權限、只有 edit 權限,以及擔任 moderator 的呼叫者仍可存取——除了 /triggers:它另外要求資料表 moderator 權限,所以有權限但不是 moderator 的呼叫者在那裡得到 403(backend PR #1752)。POST …/links/resolve 對這樣的表同樣回 found: false,schema graph 也會把垃圾桶中的表排除。

chatroom 的資料表清單 GET …/chatroom/{chatroom_id}/tables 遵循同一條規則:它只列出呼叫者持有某種權限(read、edit、只有 insert 或 moderation,包含聊天室建立者與該聊天室所屬部門或公司的管理者)的資料表,total、分頁與 tag_id 都以這個集合計算,而 GET …/tables/shared 同樣會省略呼叫者完全沒有權限的資料表。

從任一回應取得 table_id 之後,改走該表擁有 scope 的 by-id 路由——兩個回應都不含 schema、settings 或資料列。

Last updated on