Skip to Content
操作流程管理服務帳號

管理服務帳號

誰: 部門管理者,針對自己目前所屬的部門,路徑為 /service-accounts…。公司管理者可透過鏡像路徑 /company/departments/{department_id}/service-accounts… 管理公司內任何存活部門(請求與回應相同;department_id 不存在、已刪除或屬於其他公司 → 404 Department not found)。部門成員無法列出或讀取服務帳號,服務帳號呼叫者會被拒絕。路徑相對於模組基底。{id} 是 UUID(其他值 → 422)。概念:服務帳號。

路由

路由Body成功no-store
POST /service-accounts無201 ServiceAccountView否
GET /service-accounts?limit=&cursor=—200 ServiceAccountListResponse否
GET /service-accounts/{id}—200 ServiceAccountDetail是
POST /service-accounts/{id}/credential/reset無200 ServiceAccountResetResponse是
DELETE /service-accounts/{id}—200 ServiceAccountDeleteResponse是
PUT /service-accounts/{id}/chatroomsServiceAccountChatroomsRequest200 ServiceAccountChatroomsResult是
GET /service-accounts/{id}/chatroom-candidates?limit=&cursor=&q=—200 ServiceAccountChatroomCandidates是

沒有綁定路由:綁定是 Worker 操作設定中的欄位(見下方「綁定到操作」)。這些路由沒有路由專屬的 413。

建立

POST /service-accounts → 201 { "id": "…", "company_id": "…", "department_id": "…", "username": "EdgeWorkerSA-20261008T123456Z", "nickname": "EdgeWorkerSA-20261008T123456Z", "email": "sa-…@service-account.invalid", "role_id": 0, "auth_source": "service_account", "is_service_account": true, "enabled": true, "is_verified": true, "created_at": "…" }
欄位限制
id、company_id、department_idUUID
username^EdgeWorkerSA-[0-9]{8}T[0-9]{6}Z(?:-(?:[2-9]|[1-9][0-9]))?$,≤ 32 個字元
nickname1–64 個字元(等於 username)
email^sa-[0-9a-f-]{36}@service-account\.invalid$,≤ 128 個字元
role_id / auth_source / is_service_account一律 0 / "service_account" / true
enabled、is_verified布林值(true)
created_at時間戳記

新帳號還無法登入:首次綁定時才會取得憑證。目前這個 UTC 秒的 99 個名稱都被占用 → 409 Service account name is unavailable;一秒後重試。

列出

GET /service-accounts?limit=100 → { "items": [ { …ServiceAccountView… } ], "next_cursor": "100" }

limit 1–100(預設 100)。cursor 是上一頁的 next_cursor:最多 7 位數的十進位位移量(否則為 422 驗證錯誤),≤ 1 000 000(否則 422 Invalid cursor)。依 created_at、再依 id 遞增排序;最後一頁的 next_cursor 為 null。列表只讀取資料庫。

讀取單一帳號

GET /service-accounts/{id} → { …ServiceAccountView fields…, "rooms": [ { "id": "…", "name": "Field ops", "department_id": "…", "department_name": "Support", "is_member": true } ], "rooms_truncated": false, "bound_operations": ["syncProfile"], "credential": { "present": true, "updated_at": "…" } }
  • rooms:帳號所屬的存活聊天室,最多 500 個,由舊到新;超過時 rooms_truncated: true。未命名聊天室的 name 為 "",department_name ≤ 32 個字元(未知時為 "")。
  • bound_operations:至多 64 個操作 id(已排序),其在線上 release 中的有效綁定為此帳號(自己的綁定或經由部門預設)。除非線上 release 支援服務帳號憑證,否則為 []。
  • credential:Worker 未部署時(沒有 Worker、不是 active/paused、沒有目前的 deployed 修訂版)為 null;線上 release 早於服務帳號支援,或 Worker 未持有此帳號的憑證時為 {"present": false, "updated_at": null};Worker 持有時為 {"present": true, "updated_at": …}(updated_at = Worker 儲存目前憑證的時間)。
  • 無法讀取 Worker 狀態時 → 503 Department Worker service-account credentials are unavailable、Department Worker operation settings are unavailable 或 Deployed department Worker contract is unavailable。

聊天室

帳號透過 TeamSync API 能讀寫的範圍,等同其部門中一位位於這些聊天室的 role-0 成員,所以聊天室成員資格就是它的資料存取權。PUT /service-accounts/{id}/chatrooms 接受 {"add": [...], "remove": [...]}(聊天室 UUID,各 ≤ 100 個,不可重疊,否則為 422 驗證錯誤,其 msg 含 add and remove must be disjoint),並逐一獨立處理每個聊天室:results 列出 chatroom_id 與 status(added、already_member、removed、not_member、not_found、forbidden;前四種另帶 department_id/department_name),member_room_count 是處理後帳號所屬的聊天室數。forbidden 表示你無法管理該聊天室:部門管理者可使用自己部門的聊天室與自己建立的聊天室,公司管理者可使用公司內任何聊天室。GET /service-accounts/{id}/chatroom-candidates 列出你能管理的聊天室並附上 is_member,分頁方式同列表(q ≤ 128 個字元,依名稱篩選)。這兩個路由是把服務帳號加入聊天室的唯一途徑。

綁定到操作

前提:Worker 的線上 release 以 builder 政策 department-worker-project-v2.9 或更新版本建置(重新上傳專案並部署一次;否則 409 service_account_credentials_require_supported_release),且部署環境的 HOST 是單純的 HTTPS origin(否則 503 api_base_unconfigured)。

先讀取目前的設定,再連同綁定送回。列表必須列出線上 manifest 的每個操作(422 operation_settings_incomplete)。每個操作的 access 請照原樣送回,因為 access: null 代表「繼承 Worker 全域政策」。完整規則:管理逐操作存取。

GET /worker/operation-settings → { "state": "reconciled", "version_id": "…", "revision": 4, "default_service_account_id": null, "default_service_account": null, "operations": [ { "operation_id": "health", "access": null, "service_account_id": null, … }, { "operation_id": "syncProfile", "access": null, "service_account_id": null, … } ] } PUT /worker/operation-settings { "base_revision": 4, "operations": [ { "operation_id": "health", "access": null }, { "operation_id": "syncProfile", "access": null, "service_account_id": "…" } ] } → …, "operations": [ …, { "operation_id": "syncProfile", "service_account_id": "…", "effective_service_account": { "id": "…", "username": "EdgeWorkerSA-20261008T123456Z", "source": "operation", "live": true }, … } ]
  • 每個操作的 service_account_id,以及供所有沒有自己綁定之操作使用的 default_service_account_id。省略欄位即保留目前的綁定;null 會清除它(操作改為繼承預設;預設被清除則不綁定任何帳號)。
  • 設定表變更之前,後端會為 Worker 尚未持有的每個綁定帳號交付憑證。任一交付失敗時,設定表不會變更:503 Department Worker service-account credentials are unavailable、409 service_account_limit_exceeded(每個 Worker 256 個憑證)、503 service_account_verifier_unavailable,或 503 worker_release_unavailable(請重試)。
  • 同樣的欄位也可放在 POST /worker/deployments 的 operation_settings 區塊,此時只有列出的操作會變更。之後的部署即使不帶此區塊,也會延續存續操作的綁定與預設。

端到端範例

  1. 提交並部署一個修訂版,讓線上 release 達到 builder 政策 v2.9 或更新版本(提交修訂版、部署與輪詢)。
  2. POST /service-accounts → 記下 id。
  3. PUT /service-accounts/{id}/chatrooms,加入該操作需要的聊天室。
  4. PUT /worker/operation-settings,把 syncProfile 綁定到 id(見上文)。GET /service-accounts/{id} 此時顯示 "credential": {"present": true, …} 與 "bound_operations": ["syncProfile"]。
  5. handler 以該帳號身分呼叫 TeamSync API:
export async function syncProfile({ teamsync }) { try { const res = await fetch(`${teamsync.apiBase}/private/user/me`, { headers: await teamsync.authHeaders(), }) return Response.json(await res.json(), { status: res.status }) } catch (error) { if (error?.name === "TeamSyncServiceAccountError") { return Response.json({ code: error.code }, { status: 503 }) } throw error } }

各 code 值(service_account_not_bound、operation_settings_pending、service_account_unavailable、service_account_sign_in_failed、service_account_rate_limited)的說明見服務帳號。Edge Workers 成員路由會拒絕該帳號的 token(403 Service accounts cannot invoke Edge Workers),管理者路由則回應 403 Insufficient permissions.,所以它無法呼叫或管理 Worker。

重設憑證

POST /service-accounts/{id}/credential/reset → { "delivery": "delivered" } # or not_deployed | unsupported_release | not_bound | failed

舊機密在每一種結果下都會失效;新機密不會顯示給任何人。delivered 表示 Worker 已持有新機密。not_deployed、unsupported_release 與 not_bound 表示沒有任何東西使用此帳號,舊機密僅被撤銷。failed 表示無法讀取 Worker 的憑證狀態,或交付失敗、結果不確定:舊機密照樣撤銷(只要曾嘗試交付新機密,新機密即已提交),綁定的操作可能登入失敗,直到你再次重設並得到 delivered。交付問題永遠不會以獨立的狀態碼出現。

409 {"code":"deployment_in_progress","message":"Another Worker settings mutation or deployment is in progress"} 只在部門的設定鎖被持有時出現:由操作設定寫入、部署暫存、另一個重設或服務帳號刪除持有(鎖的存活時間 600 秒)。只有線上 release 支援服務帳號憑證時,重設才會取得這個鎖;進行中部署的其餘階段不會擋住它。鎖儲存失敗時為 503 Operation-settings mutation lock is unavailable。

移除或替換可疑的 Worker 程式碼之後,請重設該 Worker 用過的每一個服務帳號;維運人員輪替 JWT_SECRET_KEY 之後也一樣。release 中的程式碼能觀察到它所用帳號的機密;被截取的機密在下一次重設或刪除前都有效。部署永遠不會輪替機密。

刪除

DELETE /service-accounts/{id} → { "deleted": true, "unbound_operations": ["syncProfile"] }

帳號立即停止運作:它的 JWT 無法再解析,成員資格與 refresh token 都被移除。第二次 DELETE → 404。即使移除 Worker 中的憑證副本失敗或鎖正被占用,回應仍是 200。

unbound_operations(≤ 64,已排序)列出有效綁定為此帳號的線上操作(沒有支援服務帳號的線上 release,或無法讀取其綁定時為 [])。它們的綁定不會被移除:在你重新綁定之前一律失敗即關閉(fail closed)。刪除前先查看詳細資料中的 bound_operations;刪除後,送出 PUT /worker/operation-settings,在 service_account_id(或 default_service_account_id)中指名另一個存活帳號,或送 null 改用預設。重新送出已刪除的 id → 422 service_account_not_found;省略該欄位則保留失效的綁定。

錯誤

狀態detail位置
400Cannot modify yourself.階層檢查(防禦性)
403Insufficient permissions.role 低於管理者門檻;服務帳號 token 在這些路由上得到此回應(role 0)
403Service accounts cannot invoke Edge Workers服務帳號 token 呼叫 Edge Workers 成員路由(例如 GET /worker、呼叫)
403A live manager identity is required執行操作的管理者已不存在
404Service account not found不存在、已刪除、他部門或一般使用者的 id
404Department not found公司鏡像路徑;建立期間部門被刪除
409Service account name is unavailable建立
409{"code":"deployment_in_progress", …}鎖被持有時的重設、操作設定寫入、部署暫存
409{"code":"service_account_credentials_require_supported_release", …}在 v2.9 之前的 release 上綁定;持有憑證時降版
409{"code":"service_account_limit_exceeded","message":"Worker service-account credential limit was reached"}綁定第 257 個帳號
409Service-account credential delivery is stale綁定交付衝突
422Invalid cursor(7 位數且大於 1 000 000 的 cursor);其他錯誤參數及重疊的 add/remove 得到驗證錯誤清單列表、候選聊天室、聊天室
422[{"loc": ["body", "default_service_account_id"], "msg": "service_account_id is not a live service account of this department", "type": "service_account_not_found"}],對操作則為同一筆內的 "loc": ["body", "operations", <i>, "service_account_id"]操作設定或部署的綁定欄位;每個出問題的欄位各一筆;<i> 是 operations 清單中從 0 起算的位置(部署時這些欄位在 operation_settings 底下,但 loc 維持如上)
503Department Worker service-account credentials are unavailable讀取詳細資料、綁定交付
503{"code":"api_base_unconfigured","message":"This deployment's HOST is not a bare HTTPS origin"}綁定
503{"code":"service_account_verifier_unavailable","message":"Service-account credentials cannot be verified by this deployment"}綁定(重設回報 failed)
503Operation-settings mutation lock is unavailable重設、綁定

detail 可能是字串或 {code, message} 物件。完整目錄:錯誤。

Last updated on