手冊首頁 / 租戶與組織 / 角色權限管理

角色權限管理(Role Management)

功能群:系統管理|三層 RBAC 模型與可見性規則先讀 功能群總覽 §2

事實基準:2026-07-05 從 FE src/views/role-manage/ + BE api/auth/routes/role_route.py + jedi-auth role_service / role_domain_service + routes.json / db_schema.json 掃出。

變更紀錄:2026-07-09 FR-047 已知坑修復 —— 角色能力變更對「當前 session 本人」即時生效(六項#1,重拉 /user/web-menu);編輯改名補重複檢查 + 撞名改 ConflictError(409)(R5,jedi-auth);ui_routes.name 加 UNIQUE(SCHEMA,DEV+STG);退役 notification.test capability → 權限矩陣「TEST」空欄消失(②-bis)

1. 功能描述

角色權限管理是全系統權限治理的樞紐頁:管理員在此建立 / 維護「角色」,並透過權限矩陣把角色綁定到能力點(capabilities),能力點再經 route_capabilities 決定使用者登入後看得到哪些選單、頁內哪些按鈕可用(機制見 _overview §2)。頁面分列表頁role-manage)與表單頁role-form,建立 / 編輯共用)兩條 route。

角色分兩種:系統預設角色tenant_id IS NULLis_admin=1,如 Administrator,全租戶共用)與租戶自訂角色(屬某租戶)。權限矩陣以「功能樹(ui_routes)× 動作欄(capabilities 的 action)」呈現,勾選結果就是該角色擁有的 capability id 集合。

角色速覽

角色 能做什麼
管理員(可見本選單者) 角色 CRUD + 權限矩陣設定
root 租戶管理員 額外可編輯系統角色、配置平台層(is_platform)能力
一般使用者 無此選單(ui_routes 可見性未命中)

1.1 功能總覽

# 功能 說明 位置 詳述
1 角色列表 分頁表列所有角色(名稱 / 租戶 / 狀態 / 使用人數 / 建立更新軌跡),可多欄排序 列表頁 DataTable §6.1
2 搜尋角色 依名稱關鍵字搜尋(Enter 觸發) 列表頁工具列
3 重設搜尋 清空搜尋條件 列表頁工具列
4 建立角色 導向表單頁(新增模式) 列表頁工具列 UC-ROLE-01
5 編輯角色 導向表單頁(編輯模式),可點列名稱或「編輯」鈕 列表頁每列 UC-ROLE-01
6 停用 / 啟用角色 切換 enable系統角色(is_admin=1)隱藏此鈕 列表頁每列 §6
7 刪除角色 軟刪除;系統角色隱藏此鈕 列表頁每列 §6
8 角色基本欄位 名稱*(≤50)/ 租戶(下拉)/ 描述(≤250)/ 狀態 表單頁上半 §6.2
9 權限矩陣 TreeTable:功能樹 × 動作欄,cell / 列 tri-state 勾選 表單頁下半 UC-ROLE-02
10 矩陣展開 / 收合 一鍵展開或收合功能樹全部節點 矩陣工具列
11 平台功能列隱藏 編輯非 root 租戶角色時,濾除 is_platform / 平台專屬功能列 表單頁矩陣 §4
12 儲存角色 送出基本欄位 + 勾選的 capability id 陣列(全量取代 表單頁 UC-ROLE-02

展開成 UC:UC-ROLE-01(建立 / 編輯角色主流程)、UC-ROLE-02(權限矩陣設定與儲存)。其餘為列表 CRUD 常規操作。

2. Use Case

角色速覽

角色 能做什麼
管理員(可見本選單者) 角色 CRUD + 權限矩陣設定
root 租戶管理員 額外可編輯系統角色、配置平台層(is_platform)能力
一般使用者 無此選單(ui_routes 可見性未命中)

視覺慣例:判斷框(黃菱形)= 分支條件;橙框 = 擋下 / 隱藏;綠橢圓 = 成功終點。

UC-ROLE-01 建立 / 編輯角色

項目 內容
角色 管理員
前置條件 具本頁可見性(role 相關能力);編輯系統角色需 root 租戶角色
產出後置 roles 新增 / 更新一列 + role_capabilities 全量改寫

UC-ROLE-02 權限矩陣設定與儲存

見下圖:表單載入時併行取動作欄(/capabilities/menu)與功能樹(/ui-routes),編輯模式再取現有角色能力回填 tri-state;儲存時送出全部勾選的 capability id(非差異)。

role_save start 進入角色權限管理列表 click 點「建立角色」或列上「編輯」 start->click form 角色表單載入 GET /capabilities/menu(動作欄) GET /ui-routes(功能列 + route_capabilities) 編輯時 GET /role/<uid>(帶現有 capabilities) click->form fill 填名稱 / 租戶 / 描述 / 狀態 權限矩陣勾選(樹狀功能 × 動作,tri-state) form->fill root 編輯中角色屬 root 租戶? fill->root strip 非 root:隱藏平台功能列 (is_platform 或 PLATFORM_ROUTE_URLS) root->strip save 按儲存 POST /role(新增)或 PUT /role/<uid>(編輯) body.capabilities = 勾選的 capability id 陣列(全量取代) root->save 是(顯示全部) strip->save ok 成功 → 回列表 save->ok
角色儲存流程:建立/編輯→載入矩陣→勾選→(非root隱藏平台列)→POST/PUT 全量取代 capabilities→回列表

3. 權限矩陣(操作 × FE 判定 × BE 強制)

操作 FE 判定 BE 強制 BE 檢查位置
進入本頁 ui_routes web-menu 可見性(role 能力) 無端點層強制(僅 @jwt_required api/auth/routes/role_route.py:24,36,55
建立角色 有建立按鈕即可 ⚠️ 僅 @jwt_required無角色 / 能力守門 role_route.py:65-71
編輯角色 同上 ⚠️ 僅 @jwt_required role_route.py:78-84
刪除角色 FE 對 is_admin=1 隱藏刪除鈕 ⚠️ 僅 @jwt_requiredBE 未擋系統角色 role_route.py:90-93
停用 / 啟用 FE 對 is_admin=1 隱藏此鈕 ⚠️ 僅 @jwt_requiredBE 未擋系統角色 role_route.py:101
配置平台能力 FE 對非 root 角色隱藏 is_platform 功能列 ⚠️ 前端過濾,BE 端點未再驗 RoleForm.vue stripPlatformRoutes();BE 無對應 guard

⚠️ 系統角色與平台能力的保護只在 FE:BE role 端點全部僅 @jwt_required(),jedi-auth role_service.add_role/update_role/delete_role 也無角色 / is_admin / 平台守門。直接打 API 可繞過 FE 隱藏、編輯或刪除系統角色、把平台能力配給一般租戶角色。收進 §12。與 _overview §5 一致(本群多頁共通模式)。

4. 狀態機與前置條件

角色本身狀態單純(enable 啟用 / 停用 + is_delete 軟刪除旗標),無複雜狀態機。本頁 gate:

條件 效果 出處
角色名稱在同租戶內重複 儲存失敗 AUTH_ROLE_NAME_DUPLICATE(AUTH_409004) jedi-auth role_domain_service.py:144-154verify_role_name_duplicate
is_admin=1(系統角色) FE 隱藏停/啟用 + 刪除鈕(僅前端) RoleManage.vue:198v-if="data.is_admin !== 1"
編輯角色非 root 租戶 權限矩陣濾除 is_platform / 平台專屬功能列 RoleForm.vue isPlatformRoute() / stripPlatformRoutes()
儲存 role_capabilities 全量取代(非差異更新) jedi-auth role_service.update_rolecapability_ids 整包傳 domain)

授權邊界(角色套用到哪個租戶 / 部門)不在本頁設定,而在使用者管理指派角色時透過 user_roles.scope / tenant_id / org_unit_id 決定(見 _overview §2)。

5. UI 設計

📸 實機截圖待補(亮色模式,另有專責 session)。目前以版面骨架圖示意。待補清單:列表頁(含系統角色列隱藏操作鈕)、表單頁權限矩陣 TreeTable(tri-state cell)、非 root 角色隱藏平台列狀態。

版面骨架(列表頁 DataTable + 表單頁基本欄位/權限矩陣 TreeTable,可點跳轉 UC):

角色列表頁:搜尋列 + 建立角色鈕(系統角色 is_admin=1 隱藏停用/刪除鈕) POST /api/1.0/roles(分頁)・PUT /role/status/<uid>・DELETE /role/<uid> 開啟:UC-ROLE-01 建立/編輯角色 角色 DataTable:名稱/租戶/狀態/使用人數/建立更新軌跡,可多欄排序 GET /api/1.0/role/<uid>(明細)・POST /api/1.0/role(建立)・PUT /api/1.0/role/<uid>(更新) 逐列「編輯」→ 開表單頁;系統角色隱藏停用/刪除鈕 → UC-ROLE-01(建立/編輯角色,點我開啟) 表單頁(建立/編輯共用) 基本欄位:名稱*/租戶(下拉)/描述/狀態 GET /api/1.0/tenants/menu(租戶下拉) 名稱重複 → AUTH_ROLE_NAME_DUPLICATE(同租戶內) 開啟:UC-ROLE-02 權限矩陣設定與儲存 權限矩陣 TreeTable:功能樹(ui_routes)× 動作欄(capabilities),cell/列 tri-state 勾選 GET /api/1.0/capabilities/menu(動作欄)・GET /api/1.0/ui-routes(功能樹) 展開/收合全部節點;非 root 租戶編輯隱藏 is_platform 平台列 儲存=送出全部勾選 capability id(全量取代,非差異) → UC-ROLE-02(權限矩陣設定與儲存,點我開啟) 開啟:§6 API 規格 儲存:POST /api/1.0/role(新增)/PUT /api/1.0/role/<uid>(更新,全量改寫 role_capabilities) → §6 API 規格(點我開啟) 彩色=主要互動/明細區塊,整塊可點擊跳轉本頁 §6 或對應 UC|灰=本頁結構|虛線框=表單頁範圍/dialog API 僅列代表性 2~3 條,完整規格見 §6
角色管理版面:列表頁 DataTable(可跳 UC-ROLE-01)+ 表單頁基本欄位+權限矩陣 TreeTable(可跳 UC-ROLE-02)+儲存(連 §6)

狀態呈現:矩陣 cell 三態 —— ☑ 全選(該功能該動作能力已給)/ ◪ 部分(列層級:子功能部分勾選)/ ☐ 未選; 表該功能無此動作能力(route_capabilities 沒這條)。

6. API 規格

6.1 Endpoint 總清單

分類 Method + Path 說明 詳述
列表 POST /api/1.0/roles 分頁查詢角色(body 帶 pager / sort / filters) §6.2
選單 GET /api/1.0/roles/menu 角色下拉(uid / name / tenant_id / description) Swagger
明細 GET /api/1.0/role/<uid> 單一角色(含 capabilities / tenant / users) §6.2
建立 POST /api/1.0/role 建立角色 + 綁能力 §6.2
更新 PUT /api/1.0/role/<uid>(亦有 POST /api/1.0/role/<uid> 更新角色 + 全量改寫能力 §6.2
刪除 DELETE /api/1.0/role/<uid> 軟刪除角色 Swagger
狀態 PUT /api/1.0/role/status/<uid> 切換啟用 / 停用(body status Swagger
動作欄 GET /api/1.0/capabilities/menu 權限矩陣的動作欄定義 Swagger
功能樹 GET /api/1.0/ui-routes 權限矩陣的功能列(含 route_capabilities / is_platform §6.3

endpoint 存在性對 routes.json 核實。列表用 POST /roles(body 分頁),非 GET(envelope 分頁慣例,見 CLAUDE.md api-patterns)。

6.2 角色建立 / 更新(request / response)

RequestRoleRequestapi/auth/serializers/role.py:4-11):

欄位 型別 說明
name string(必填) 角色名稱
description raw(必填) 描述
enable int 啟用 1 / 停用 0
is_admin int 系統角色旗標(預設 0)
tenant_id int(allow_none) 所屬租戶;null = 系統角色
capabilities list[int] 勾選的 capability id 陣列(全量取代)

ResponseRoleResponserole.py:26-52):

欄位 型別 說明
id int 角色主鍵
uid string 角色 UID
pid int 父角色 id
name string 角色名稱
description raw 描述
enable int 啟用 1 / 停用 0
is_admin int 系統角色旗標
is_delete int 軟刪旗標
tenant_id int 所屬租戶 id
tenant_uid string 所屬租戶 UID
tenant object Nested 租戶資訊
capabilities array Nested CapabilityResponse(角色能力集合)
users array 使用此角色的使用者
user_count int 使用人數
created_user string 建立者(含 created_user_name
created_at date 建立時間
updated_user string 更新者(含 updated_user_name
updated_at date 更新時間

BE 鏈路RoleRoute.post/putrole_route.py:65-86)→ jedi-auth RoleService.add_role / update_rolerole_service.py:54-83)→ role_domain_service.add_role/update_role(role_entity, capability_ids)。建立時先 verify_role_name_duplicate(name, tenant_id)capability_ids 整包傳 domain = 全量取代,非差異。

6.3 UI Routes(權限矩陣功能樹)

ResponseUiRouteResponseui_route.py:6-27):

欄位 型別 說明
uid string 功能列 UID
id int 功能列主鍵
pid int 父功能列 id
name string 功能名稱(i18n key)
url string 路由路徑
icon string 圖示
enable int 啟用 1 / 停用 0
description raw 描述
sort int 排序
capabilities_count int 能力數
is_platform bool 平台專屬功能列旗標
route_capabilities array 每項 {capability(Nested), requirement}
children array 子功能列(遞迴樹)

矩陣以此樹為列、以 capabilities/menu 為欄,交集看 route_capabilities

7. 前端檔案地圖

檔案 角色
compliance-manager-fe/src/views/role-manage/RoleManage.vue 列表頁(DataTable / 搜尋 / 建立 / 每列操作)
compliance-manager-fe/src/views/role-manage/RoleForm.vue 表單頁(基本欄位 + 權限矩陣 TreeTable + tri-state + 平台列過濾)
compliance-manager-fe/src/stores/menuStore.js fetchCapabilityMenu() / fetchUiRoutes() 供矩陣
compliance-manager-fe/src/stores/userStore.js 登入後 permissions(web-menu 結果)來源
compliance-manager-fe/src/utils/userUtil.js 把 permissions 樹攤平成 capability Set,供按鈕權限判定
compliance-manager-fe/src/config/api/api.js ROLES / ROLE / CAPABILITIES_MENU / UI_ROUTES / WEB_MENU 端點常數

8. 後端檔案地圖

鏈路 Route App Service 底層
角色列表(enrich 暱稱) api/auth/routes/role_route.py(RolesRoute) app/auth/service/role_app_service.pyget_roles_and_pager jedi-auth role_service
角色 CRUD / 狀態 role_route.py(RoleRoute / RoleStatusRoute) 直接委派(無主專案 app service 包裝) jedi-auth role_service.pyrole_domain_service.py → repo
功能樹 / 動作欄 api/auth/routes/ui_route_route.pycapability_route.py jedi-auth

DDD 提醒:角色 CRUD 的 route 直接注入 jedi-auth RoleService、無主專案 app service 層(列表頁才有 RoleAppService 做暱稱 enrich)。這是外部套件擁有 domain 的情形,大半 RBAC 邏輯在 jedi-auth 套件~/Projects/Jedicogy/module/jedi-python-package/jedi-auth/),改行為要分清邊界(CLAUDE.md 外部套件異動規範)。

9. DB

9.1 資料表總清單

讀寫 說明 詳述
public.roles 讀 / 角色本體 §9.3
public.role_capabilities 讀 / 寫(全量取代) 角色 ↔︎ 能力關聯 §9.3
public.capabilities 能力點(動作欄來源) _overview §6
public.ui_routes 功能樹(矩陣列) _overview §6
public.route_capabilities 路由 ↔︎ 能力(矩陣交集 + ALL/ANY) _overview §6
public.tenants 租戶下拉 _overview §6
public.user_roles 讀(user_count 統計角色使用人數 _overview §6

9.2 ER 圖

角色相關表關係見 _overview §2 RBAC 模型圖§6 核心資料模型圖(本頁寫入集中在 roles + role_capabilities)。

9.3 核心表欄位卡

public.roles(來源 db_schema.json):id / uid / pid(父角色) / name / description / enable(1啟用 0停用) / is_admin(1系統角色) / is_delete(1軟刪) / tenant_id(NULL=系統預設) / created_user / created_at / updated_user / updated_at

public.role_capabilities:複合 PK (role_id, capability_id),無其他欄位;儲存角色時先刪後插 = 全量取代該角色的 capability 集合。

10. 頁面邏輯與資料對應

表單載入時序

role_load_seq mount RoleForm onMounted cap menuStore.fetchCapabilityMenu() GET /capabilities/menu → 動作欄定義 mount->cap route menuStore.fetchUiRoutes() GET /ui-routes → 功能樹 + route_capabilities + is_platform cap->route edit 編輯模式? route->edit role GET /role/<uid> → 現有 role.capabilities(id 陣列) edit->role merge 矩陣建置:功能列 × 動作欄 以現有 capabilities 勾選 tri-state (非 root 角色濾除平台列) edit->merge 否(新增,全空) role->merge ready 矩陣就緒可編輯 merge->ready
角色表單載入:onMounted→取動作欄→取功能樹→編輯模式取現有能力→矩陣 tri-state 回填→就緒
畫面元素 FE state API 欄位
名稱 / 描述 / 狀態 / 租戶 currRole.name/description/enable/tenant_id RoleRequest 同名欄位
矩陣勾選 cell 勾選集合 → capabilities: number[] RoleRequest.capabilities(id 陣列)
功能列 tri-state 由該列子 capability 勾選數計算(all / some / none) 前端計算,非 API 欄位
平台列顯隱 isEditingRootTenantRole + isPlatformRoute() UiRouteResponse.is_platform

儲存流程:勾選集合序列化成 capabilities id 陣列 → POST /role(新增)或 PUT /role/<uid>(編輯)→ BE 全量改寫 role_capabilities → 回列表。

錯誤對應:名稱重複 → AUTH_ROLE_NAME_DUPLICATE(AUTH_409004;⚠️ 實際 raise 的是 NotFound→HTTP 404,與 409 語意不符,見 §12);角色不存在 → AUTH_ROLE_NOT_FOUND(AUTH_404003)。

11. 背景行為與外部依賴

類型 內容
通知
Job / 排程
Socket 無(角色變更不即時推播;改動當前使用者本人的角色時 FE 會重拉 /user/web-menu 即時反映,改動他人在對方另一 session 仍需重登 / 重取 web-menu 才反映)
jedi-* 套件 jedi-auth 擁有 role / capability / ui_route 的 service / domain / repo / ORM;主專案只有 route + 列表 enrich app service
系統參數

權限變更生效時機(2026-07-09 部分即時化,六項#1):改動當前 session 本人持有的角色能力後,RoleForm 存檔即重拉 /user/web-menu 更新 userStore.permissions,側邊選單(AppMenu 已改 computed)與 hasCap 即時反映、不需重登。改動他人的角色,對方在另一 session 仍需重登 / 重取 web-menu(即時需 socket,依「別過度」未做)。此為 §12 坑 4。

12. 邊界情況與已知坑

  1. 系統角色 / 平台能力保護只在 FE:BE role 端點全僅 @jwt_required()、jedi-auth service 無 is_admin / 平台守門;直接打 API 可編輯 / 刪除系統角色、把 is_platform 能力配給一般租戶角色。本 spec 只記錄不修
  2. role_capabilities 全量取代:儲存送整包 capability id 陣列,BE 先刪後插;漏帶已有能力 = 該能力被移除。FE 務必回填完整現有集合再送。
  3. 編輯改名的重複檢查與錯誤型別已修(2026-07-08 FR-047 R5,jedi-auth):原本 verify_role_name_duplicate 只在新增路徑呼叫、update_role 內對應檢查被註解掉(改既有角色名稱撞他人不被擋);且撞名 raise NotFound(404) 卻配碼 AUTH_409004(型別 / 碼不符)。已在 update_role 接回 dup-check(帶 tenant_id + exclude_uid 排除自身,解「跨租戶誤判」與「自己撞自己」兩顆雷)、撞名改 ConflictError(409)(碼 AUTH_409004 不變、FE i18n 不受影響);新增走同一支 verify、一改兩邊都對。
  4. 權限變更對本人已即時、對他人仍不即時(2026-07-09 六項#1):改動當前 session 本人持有的角色能力後 FE 重拉 web-menu 即時反映;改動他人在對方另一 session 仍需重登 / 重取 /user/web-menu(§11)。
  5. ui_routes.name 已加 UNIQUE(2026-07-08 FR-047 SCHEMA,DEV+STG 已套、POC 待部署):功能樹依賴 name 當 i18n key,原無 DB 約束、重名會顯示錯亂;已加 uq_ui_routes_name UNIQUE(name)2026-07-08-add-unique-ui-routes-name.sql),root 已封(_overview §7 坑 3)。
  6. 跨環境 id 漂移:矩陣勾選存的是 capability id,DEV/STG/POC 的 capability id 不一致——搬角色設定不能直接複製 id(_overview §7 坑 4)。
  7. read 設 ALL 的陷阱:某功能 read 未給時該選單完全不可見(即使給了 write 能力),矩陣只勾 write 不勾 read 會讓使用者看不到頁(_overview §2.1)。

13. 開發與驗證

  • 跑起來:BE python main_socketio.py(port 8000);FE compliance-manager-fe npm dev。
  • 測試帳號:管理員帳號見 memory reference_dev_login / .env(憑證不寫入本文件)。編輯系統角色需 root 租戶角色。
  • 導航路徑:登入 → 側選單「系統管理」→「角色權限管理」(/auth/role-manage)。
  • 前置資料capabilities / ui_routes / route_capabilities 需已由 migration 灌入(新功能納權限走 _overview §2 SOP)。
  • 相關 FR / 文件:權限系統設計說明書 docs/system-design/permission/;納權限 SOP memory reference_permission_system_sop