卡片 CM-2514(FR-132 T-1.4)。唯讀盤點,不改程式、不改 DB。
api/system_config/routes/ 2 支(8)、api/notify_config/routes/ 1 支(1)、api/setup/routes/ 1 支(2)、api/support/routes/ 2 支(2)、api/version/routes/ 2 支(2)。api/user_auth_provider/ 只剩 __pycache__,route 已上移 jedi-iam。routing.py 凍結 URL 43 條)、jedi-system-core 2 支(11)、jedi-notification 1 支(1)、jedi-issue 1 支(1,label_route;同套件的 feedback_route 屬 T-1.5)、jedi-log(jedi_api_log.forwarding)1 支(3)、jedi-license-runtime 2 支(14)。讀的是 .venv/lib/python3.11/site-packages/ 內實際執行的版本。localhost:5432/guidant_ai_dev)。範圍內舊能力點 45 個(另 storage-config 4 個屬 T-1.3,本表只列被本範圍 route 用到的部分)。GET /system/config/<group>/<key>、GET /system/configs/<group>、GET /system/config/<uid> 三支只驗登入;service 層只多兩道(AI/Drive 鎖平台管理員、SMTP/LDAP/登入政策鎖總部),沒有任何 *.read。登入的一般使用者可以讀通知設定、議題整合設定、儲存設定(機密欄已遮罩)。寫入那側有按 GROUP 分流守門,讀這側沒有。system_config.* 不是純孤兒。 它是 GROUP 分流的 fallback(core/plugins/system_core.py:88-93):對照表沒登記的 group(DEV 有 GOOGLE_DRIVE_APP_CONFIG、WEB_IDEL_CONFIG;AI_QUOTA 另被專門擋掉)寫入時就要 system_config.update。Drive 應用程式設定頁(/system/drive-app-config)的儲存走的正是這條,選單卻綁 storage-config.*。只有 Administrator 角色持有 system_config.*,實務上靠平台管理員那道把關才沒出事。/license/tenants*、/license/upload、/license/lc/plans 9 支只疊平台管理員守門;license.read 只綁 /license/manage 選單。租戶自救 5 支只驗登入是刻意的防死鎖設計。user.create、LDAP 連線測試守 ldap-config.create、改租戶只守平台管理員(tenant.update 沒有 route 用)。GET /auth-providers/user/<user_uid> 只驗登入,service(jedi_iam/app/service/user_auth_provider_service.py:87)不呼叫同檔的 _assert_caller_can_manage,任何登入者帶別人 uid 就能看到對方綁了哪個 LDAP/AD 帳號。新增與刪除兩支有本人或 user.update 檢查。system 模組(基礎設施,皆不受授權照管制或屬原廠):
| 新資源 | read | create | update | delete | 獨立動詞 | 取代的舊名 |
|---|---|---|---|---|---|---|
system.smtp-config |
✓ | ✓ | ✓ | ✓ | — | smtp-config.* |
system.ldap-config |
✓ | ✓ | ✓ | ✓ | — | ldap-config.* |
system.notify-config |
✓ | ✓(新建) | ✓ | ✓(新建) | — | notify_config.read/update |
system.issue-integrate-config |
✓ | ✓ | ✓ | ✓ | — | issue-integrate-config.* |
system.security-policy |
✓ | ✓(新建) | ✓ | ✓(新建) | — | security-policy.read/update |
system.log-forwarding |
✓ | ✓(新建) | ✓ | ✓(新建) | — | log-forwarding.read/update |
system.system-config |
✓(新建) | ✓ | ✓ | ✓ | — | system_config.create/update/delete(保留,見定案 1) |
system.system-menu |
✓ | ✓ | ✓ | ✓ | — | system-menu.* |
system.storage-config |
✓ | ✓ | ✓ | ✓ | — | storage-config.*(只管儲存設定頁,見定案 2) |
| 授權照 | — | — | — | — | — | 移至 platform.license.*(見定案 4) |
iam 模組:
| 新資源 | read | create | update | delete | 獨立動詞 | 取代的舊名 |
|---|---|---|---|---|---|---|
iam.user |
✓ | ✓ | ✓ | ✓ | import(Excel 批次匯入) |
user.* |
iam.role |
✓ | ✓ | ✓ | ✓ | — | role.* |
iam.org-unit |
✓ | ✓ | ✓ | ✓ | — | department.* |
iam.tenant |
✓ | ✓ | ✓ | ✓ | — | tenant.* |
update,不開 send:沒有客戶會要「能改設定但不能測」。見定案 3。ai.ai-provider-config.*(新開,歸 ai 模組)、Drive 應用程式憑證歸 platform 層、支援頁歸 platform.support.*(見定案 2)。欄位:route 路徑 | HTTP | 程式位置 | 現有守門 | 新三段名 | 現有能力點 | 對應 UI | 可指派範圍層 | 備註。
守門縮寫:J=jwt_required/套件 auth_required;C(x)=require_capability("x")/套件 capability_required("x");G(action)=按 GROUP 分流的 assert_config_capability(group, action)(對照表 core/plugins/system_core.py:63-79:STORAGE_CONFIG→storage-config、SMTP→smtp-config、THIRD_PARTY_LOGIN→ldap-config、NOTIFY_CONFIG→notify_config〔create/delete 改判 update〕、ISSUE_INTEGRATE_CONFIG→issue-integrate-config、RUNTIME_CONFIG→security-policy、AI_PROVIDER_CONFIG→storage-config;其餘 group fallback system_config.*);PA=平台管理員(require_platform_admin);HQ=總部層級(SMTP/LDAP/登入政策的讀寫、log 轉發的寫)。路徑前綴一律 /api/1.0。
| route 路徑 | HTTP | 程式位置 | 現有守門 | 新三段名 | 現有能力點 | 對應 UI | 範圍層 | 備註 |
|---|---|---|---|---|---|---|---|---|
/system/config/<group>/<key> |
GET | api/system_config/routes/system_config_route.py:149 |
J;service:AI/Drive 鎖 PA、共用設定鎖 HQ、AI_QUOTA 拒絕 | system.<group 對應資源>.read |
無 | SmtpConfigForm、LdapConfigForm、NotifyConfigForm、IssueIntegrateConfigForm、StorageConfigForm、AI 服務設定(ClassificationProfileService)、Drive 設定(CloudIntegrationService) |
tenant | 缺 read 守門(先看這幾點第 1 條);修法是 route 補 G(read) |
| 同上 | PUT | system_config_route.py:160 |
J+G(update);service 同上 | system.<group 對應資源>.update |
依 group:smtp-config.update、ldap-config.update、notify_config.update、issue-integrate-config.update、storage-config.update、security-policy.update;Drive/未登記 group=system_config.update |
同上 | tenant | 四設定頁的儲存都打這條 |
| 同上 | DELETE | system_config_route.py:173 |
J+G(delete) | system.<group 對應資源>.delete |
依 group 的 .delete;NOTIFY_CONFIG 改判 notify_config.update |
無 UI 直接呼叫 | tenant | |
/system/configs/<group> |
GET | 套件 jedi_system_core/api/routes/system_config_route.py:39 |
J;service 同上 | system.<group 對應資源>.read |
無 | SmtpConfigManage |
tenant | 缺 read 守門 |
/system/config/<uid> |
GET | 套件 system_config_route.py:54 |
J;service 同上 | system.<group 對應資源>.read |
無 | SmtpConfigManage |
tenant | 缺 read 守門;group 由 uid 反查 |
| 同上 | PUT | 套件 system_config_route.py:64 |
J+G(update),group 由 uid 反查,查無退回 system_config.update(先 403 再 404,刻意) |
system.<group 對應資源>.update |
依 group | SmtpConfigManage |
tenant | |
| 同上 | DELETE | 套件 system_config_route.py:79 |
J+G(delete) | system.<group 對應資源>.delete |
依 group | SmtpConfigManage |
tenant | |
/system/config |
POST | 套件 system_config_route.py:98 |
J+G(create),group 取自 payload | system.<group 對應資源>.create |
依 group;NOTIFY_CONFIG 改判 notify_config.update |
SmtpConfigForm |
tenant |
system_config_route 只驗登入是指 handler 外層;寫入三支在 handler 內呼叫 G(...),讀取三支什麼都沒呼叫。套件與宿主兩支 system_config_route 的分工:套件管純 CRUD(新增、by-uid 讀改刪、by-group 列表),宿主管吃產品規則的(by-group/key 讀改刪、出廠快照還原、AI 模型下拉);兩邊都注入同一支宿主包過的 GuardedSystemConfigService(app/system_config/service/guarded_system_config_service.py)。
| route 路徑 | HTTP | 程式位置 | 現有守門 | 新三段名 | 現有能力點 | 對應 UI | 範圍層 | 備註 |
|---|---|---|---|---|---|---|---|---|
/mail/test |
POST | 套件 jedi_notification/api/routes/mail_route.py:20 |
J+C(smtp-config.update)(名稱取 rt.config.test_mail_capability,預設 jedi_notification/plugin/contract.py:38) |
system.smtp-config.update |
smtp-config.update |
SmtpConfigForm |
tenant | 測試信;改名時改套件預設值 |
/ldap/connect-test |
POST | 套件 jedi_iam/api/routes/ldap_route.py:17 |
J+C(ldap-config.create) | system.ldap-config.update |
ldap-config.create |
LdapConfigForm |
tenant | 動詞不符,定案 3 |
/notify-config/<channel>/test |
POST | api/notify_config/routes/notify_config_route.py:23 |
J+C(notify_config.update) | system.notify-config.update |
notify_config.update |
NotifyConfigForm |
tenant | 底線改連字號 |
/system/security-policy |
GET | api/system_config/routes/security_policy_route.py:51 |
J+C(security-policy.read) | system.security-policy.read |
security-policy.read |
SecurityPolicyForm |
tenant | 已守 |
| 同上 | PUT | security_policy_route.py:59 |
J+C(security-policy.update) | system.security-policy.update |
security-policy.update |
同上 | tenant | 已守;寫入另有 HQ |
/log-forwarding |
GET | 套件 jedi_api_log/forwarding/api/routes/log_forwarding_route.py:49 |
J+C(log-forwarding.read)(宿主 core/plugins/api_log.py:311 注入) |
system.log-forwarding.read |
log-forwarding.read |
LogForwardingForm |
tenant | 套件 route 本身無 decorator,守門由 ROUTE_TABLE 逐 method 宣告、宿主注入 |
| 同上 | PUT | log_forwarding_route.py:57 |
J+C(log-forwarding.update)+HQ(api_log.py:312) |
system.log-forwarding.update |
log-forwarding.update |
同上 | tenant | |
/log-forwarding/test |
POST | log_forwarding_route.py:73 |
同 PUT | system.log-forwarding.update |
log-forwarding.update |
同上 | tenant | 套件刻意掛寫入欄(會對外送封包) |
/system/config/ai-provider/model-options |
GET | system_config_route.py:100 |
J+G(read)=storage-config.read |
ai.ai-provider-config.read |
storage-config.read |
ClassificationProfileService、AutoClassifyBatch |
tenant | 輔助端點;定案 2 |
/system/config/storage/restore-default |
GET | system_config_route.py:119 |
J+G(read)=storage-config.read |
system.storage-config.read |
storage-config.read |
StorageConfigForm |
tenant | 只回 flag |
| 同上 | POST | system_config_route.py:127 |
J+G(update)=storage-config.update |
system.storage-config.update |
storage-config.update |
同上 | tenant | 恢復出廠儲存 |
/labels/menu/<scope> |
GET | 套件 jedi_issue/api/routes/label_route.py:14 |
J | 跟 platform.feedback.read(T-1.5) |
無 | SystemFeedbackForm、SystemFeedbackManage |
tenant | 輔助端點;回饋表單的下拉,不是 issue-integrate-config |
| route 路徑 | HTTP | 程式位置 | 現有守門 | 新三段名 | 現有能力點 | 對應 UI | 範圍層 | 備註 |
|---|---|---|---|---|---|---|---|---|
/system/menu/<group> |
GET | 套件 jedi_system_core/api/routes/system_menu_route.py:36 |
J | 豁免:全站字典 | 無 | menuStore、surveyStore、UserManage、DeviceManage、BulletinForm 等 10 處 |
— | 套件註明刻意不守(全站下拉資料來源) |
/system/menus |
POST | system_menu_route.py:53 |
J+PA | system.system-menu.read |
無(system-menu.read 沒有 route 用) |
SystemMenuManage(/system/system-menu-manage) |
tenant(僅 root) | 補 read 守門 |
/system/category-menu |
GET | system_menu_route.py:75 |
J+PA | system.system-menu.read |
無 | 同上 | tenant(僅 root) | 輔助端點 |
/system-menu |
POST | system_menu_route.py:94 |
J+C(system-menu.create)+PA | system.system-menu.create |
system-menu.create |
同上 | tenant(僅 root) | 名字取 rt.config.menu_*_capability,預設在 jedi_system_core/plugin/contract.py:55-57 |
/system-menu/<id> |
PUT | system_menu_route.py:114 |
J+C(system-menu.update)+PA | system.system-menu.update |
system-menu.update |
同上 | tenant(僅 root) | |
| 同上 | DELETE | system_menu_route.py:126 |
J+C(system-menu.delete)+PA | system.system-menu.delete |
system-menu.delete |
同上 | tenant(僅 root) |
套件 jedi_license_runtime/api/routing.py:43-57 的 ROUTE_TABLE 宣告兩級:admin=J+PA(宿主 core/plugins/license.py:325-327),login=只有 J(license.py:332,刻意)。
| route 路徑 | HTTP | 程式位置 | 現有守門 | 新三段名 | 現有能力點 | 對應 UI | 範圍層 | 備註 |
|---|---|---|---|---|---|---|---|---|
/license/status |
GET | jedi_license_runtime/api/routes/license_route.py:64 |
J(login 級) | 豁免:防死鎖 | 無 | LicenseStatus、licenseStore |
— | 租戶自救;FR-076 L2 確認不可升級 |
/license/activation/machine-code |
GET | license_route.py:87 |
J(login 級) | 豁免:防死鎖 | 無 | LicenseActivation |
— | 同上 |
/license/activation/upload |
POST | license_route.py:104 |
J(login 級) | 豁免:防死鎖 | 無 | LicenseActivation |
— | 同上 |
/license/activation/online |
POST | license_route.py:120 |
J(login 級) | 豁免:防死鎖 | 無 | LicenseActivation |
— | 同上 |
/license/upload |
POST | license_route.py:48 |
J+PA | platform.license.import |
無 | LicenseManage |
tenant(僅 root) | 定案 4 |
/license/tenants |
GET | license_admin_route.py:42 |
J+PA | platform.license.read(定案 4) |
無(license.read 只綁選單) |
LicenseManage(/license/manage) |
tenant(僅 root) | |
/license/tenants/<uid> |
GET | license_admin_route.py:50 |
J+PA | platform.license.read(定案 4) |
無 | 同上 | tenant(僅 root) | |
/license/tenants/<uid>/events |
GET | license_admin_route.py:58 |
J+PA | platform.license.read(定案 4) |
無 | 同上 | tenant(僅 root) | |
/license/lc/plans |
GET | license_admin_route.py:140 |
J+PA | platform.license.read(定案 4) |
無 | 同上 | tenant(僅 root) | 輔助端點(請照表單下拉) |
/license/tenants/<uid>/assign |
POST | license_admin_route.py:66 |
J+PA | platform.license.assign |
無 | 同上 | tenant(僅 root) | 指派/換發 |
/license/tenants/<uid>/lc-issue |
POST | license_admin_route.py:106 |
J+PA | platform.license.assign |
無 | 同上 | tenant(僅 root) | 向 License Center 請新照=發給租戶 |
/license/tenants/<uid>/lc-extend |
POST | license_admin_route.py:127 |
J+PA | platform.license.update |
無 | 同上 | tenant(僅 root) | 展延 |
/license/tenants/<uid>/lock |
POST | license_admin_route.py:80 |
J+PA | platform.license.update |
無 | 同上 | tenant(僅 root) | 停權 |
/license/tenants/<uid>/unlock |
POST | license_admin_route.py:93 |
J+PA | platform.license.update |
無 | 同上 | tenant(僅 root) | 解除停權 |
| route 路徑 | HTTP | 程式位置 | 現有守門 | 新三段名 | 現有能力點 | 對應 UI | 範圍層 | 備註 |
|---|---|---|---|---|---|---|---|---|
/support/recent-errors |
GET | api/support/routes/recent_error_route.py:35 |
J;service PA(app/support/service/recent_error_app_service.py:46) |
platform.support.read(定案 5) |
無 | SupportPage(/system/support) |
tenant(僅 root) | 選單卻綁 storage-config.* |
/support/diagnostic-bundle |
POST | api/support/routes/diagnostic_bundle_route.py:37 |
J;service PA(diag_bundle_export_service.py:75) |
platform.support.export(定案 5) |
無 | SupportPage |
tenant(僅 root) | 匯出診斷包 |
/version |
GET | api/version/routes/version_route.py:28 |
無 | 豁免:免登入 | 無 | 全站(關於頁) | — | |
/csp-report |
POST | api/version/routes/browser_report_route.py:25 |
無 | 豁免:免登入 | 無 | 瀏覽器自動送 | — | 只記 log |
/setup/status |
GET | api/setup/routes/setup_route.py:91 |
無;帶有效 setup token 才多回機器指紋 | 豁免:安裝精靈 | 無 | SetupService(views/setup) |
— | 見下方結論 |
/setup/provision |
POST | setup_route.py:113 |
setup token(_require_setup_token)+已開通即 409 |
豁免:安裝精靈 | 無 | 同上 | — | 見下方結論 |
| route 路徑 | HTTP | 程式位置 | 現有守門 | 新三段名 | 現有能力點 | 對應 UI | 範圍層 | 備註 |
|---|---|---|---|---|---|---|---|---|
/users/menu |
GET | 套件 jedi_iam/api/routes/user_route.py:67 |
J | 豁免:跨模組挑人下拉(定案 6) | 無 | menuStore.fetchUserMenu:ProjectCreateView、ProjectPlanningView、ModuleFramePartiesPanel、SspBasicSection、InformationSystemManage、ProjectParticipantsPanel 等 |
— | 只回名字 |
/users |
POST | user_route.py:80 |
J+C(user.read) | iam.user.read |
user.read |
UserManage(/auth/user-manage)、PartyLinkDialog |
tenant | |
/user |
POST | user_route.py:107 |
J+C(user.create) | iam.user.create |
user.create |
UserMTRBACForm |
tenant | payload 帶 user_roles(指派),見 A.3 欄位位置 |
/user/<uid> |
GET | user_route.py:129 |
J;handler 內:本人放行、他人要 user.read |
iam.user.read(本人豁免) |
user.read |
UserMTRBACForm、UserProfileForm |
tenant | 刻意不能改 decorator(本人 profile 也用) |
| 同上 | PUT | user_route.py:154 |
J+C(user.update) | iam.user.update |
user.update |
UserMTRBACForm |
tenant | 同 POST 帶 user_roles |
| 同上 | DELETE | user_route.py:172 |
J+C(user.delete) | iam.user.delete |
user.delete |
UserManage |
tenant | |
/user/change-status/<uid> |
POST | user_route.py:211 |
J+C(user.create) | iam.user.update |
user.create |
UserManage |
tenant | 動詞不符:停用/啟用是改狀態不是新增 |
/user/web-menu |
GET | user_route.py:186 |
J | 豁免:本人 | 無 | AppTopbar、Login、RoleForm 等 |
— | 回本人側邊選單+capabilities |
/user-profile/<uid> |
PUT | user_route.py:224 |
J;非本人 401 | 豁免:本人 | 無 | UserProfileForm |
— | 角色/租戶/部門不採信 payload;擋他人回 401 而非 403 |
/user-mfa-type |
PUT | user_route.py:278 |
J;只改本人 | 豁免:本人 | 無 | UserProfileForm |
— | |
/users/upload |
POST | user_import_route.py:27 |
J+C(user.create) | iam.user.import |
user.create |
UserManageUpload |
tenant | 解析 Excel |
/user/validate |
POST | user_import_route.py:41 |
J+C(user.create) | iam.user.import |
user.create |
同上 | tenant | |
/user/batch-upload |
POST | user_import_route.py:74 |
J+C(user.create) | iam.user.import |
user.create |
同上 | tenant | |
/user/download/sample |
GET | user_import_route.py:57 |
J+C(user.read) | iam.user.import |
user.read |
同上 | tenant | 範本下載跟匯入走 |
/auth-providers/user/<user_uid> |
GET | user_auth_provider_route.py:20 |
J | iam.user.read(本人豁免) |
無 | UserProfileForm |
tenant | 無本人檢查,缺口 2 |
/auth-provider |
POST | user_auth_provider_route.py:49 |
J;service:本人或 user.update(user_auth_provider_service.py:38-52) |
iam.user.update(本人豁免) |
user.update |
UserProfileForm |
tenant | 綁 LDAP/AD |
/auth-provider/<uid> |
DELETE | user_auth_provider_route.py:31 |
同上 | iam.user.update(本人豁免) |
user.update |
同上 | tenant | 解綁 |
| route 路徑 | HTTP | 程式位置 | 現有守門 | 新三段名 | 現有能力點 | 對應 UI | 範圍層 | 備註 |
|---|---|---|---|---|---|---|---|---|
/roles/menu |
GET | jedi_iam/api/routes/role_route.py:26 |
J+C(role.read) | iam.role.read |
role.read |
useTenantScopedMenus(UserMTRBACForm、UserManageUpload) |
tenant | 輔助端點;只有 user.create 沒 role.read 的人在使用者表單拿不到角色下拉 |
/roles |
POST | role_route.py:38 |
J+C(role.read) | iam.role.read |
role.read |
RoleManage(/auth/role-manage) |
tenant | |
/role |
POST | role_route.py:61 |
J+C(role.create) | iam.role.create |
role.create |
RoleForm |
tenant | payload capabilities:能力點 id 陣列 |
/role/<uid> |
GET | role_route.py:78 |
J+C(role.read) | iam.role.read |
role.read |
RoleForm |
tenant | |
| 同上 | PUT | role_route.py:88 |
J+C(role.update) | iam.role.update |
role.update |
RoleForm |
tenant | |
| 同上 | DELETE | role_route.py:101 |
J+C(role.delete) | iam.role.delete |
role.delete |
RoleManage |
tenant | |
/role/status/<uid> |
PUT | role_route.py:113 |
J+C(role.update) | iam.role.update |
role.update |
RoleManage |
tenant | |
/capabilities/menu |
GET | capability_route.py:13 |
J | iam.role.read |
無 | menuStore.fetchCapabilityMenu:RoleForm、UserMTRBACForm |
tenant | 輔助端點(角色矩陣欄位);定案 6 |
/ui-routes |
GET | ui_route_route.py:13 |
J | iam.role.read |
無 | menuStore.fetchUiRoutes:RoleForm |
tenant | 輔助端點(角色矩陣列);定案 6 |
| route 路徑 | HTTP | 程式位置 | 現有守門 | 新三段名 | 現有能力點 | 對應 UI | 範圍層 | 備註 |
|---|---|---|---|---|---|---|---|---|
/org-units/menu |
GET | jedi_iam/api/routes/org_unit_route.py:23 |
J | 豁免:跨模組挑部門下拉(定案 6) | 無 | OrgUnitManage、ModuleFramePartiesPanel、ProjectPlanningView、BulletinForm、EntityPickerDialog 等 |
— | |
/org-units |
POST | org_unit_route.py:36 |
J+C(department.read) | iam.org-unit.read |
department.read |
OrgUnitManage(/department/department-manage)、PartyLinkDialog |
org_unit | |
/org-unit |
POST | org_unit_route.py:61 |
J+C(department.create) | iam.org-unit.create |
department.create |
OrgUnitManage |
org_unit | |
/org-unit/<uid> |
GET | org_unit_route.py:77 |
J+C(department.read) | iam.org-unit.read |
department.read |
同上 | org_unit | |
| 同上 | PUT | org_unit_route.py:86 |
J+C(department.update) | iam.org-unit.update |
department.update |
同上 | org_unit | |
| 同上 | DELETE | org_unit_route.py:98 |
J+C(department.delete) | iam.org-unit.delete |
department.delete |
同上 | org_unit |
| route 路徑 | HTTP | 程式位置 | 現有守門 | 新三段名 | 現有能力點 | 對應 UI | 範圍層 | 備註 |
|---|---|---|---|---|---|---|---|---|
/tenants/menu |
GET | jedi_iam/api/routes/tenant_route.py:26 |
J | iam.tenant.read |
無 | menuStore.fetchTenantMenu:TenantManage、UserManage、RoleManage、OrgUnitManage |
tenant | 輔助端點;呼叫者全是管理頁,可跟 read |
/tenants |
POST | tenant_route.py:38 |
J+C(tenant.read) | iam.tenant.read |
tenant.read |
TenantManage(/tenant/tenant-manage)、AiUsageSummary |
tenant | |
/tenant |
POST | tenant_route.py:59 |
J+C(tenant.create);建 root 租戶另加 PA | iam.tenant.create |
tenant.create |
TenantManage |
tenant | |
/tenant/<uid> |
GET | tenant_route.py:93 |
J+C(tenant.read) | iam.tenant.read |
tenant.read |
同上 | tenant | |
| 同上 | PUT | tenant_route.py:103 |
J+PA | iam.tenant.update |
無(tenant.update 沒有 route 用) |
同上 | tenant | 定案 7 |
| 同上 | DELETE | tenant_route.py:115 |
J+C(tenant.delete) | iam.tenant.delete |
tenant.delete |
同上 | tenant | 禁刪自己所在租戶 |
| route 路徑 | HTTP | 程式位置 | 現有守門 | 豁免理由 |
|---|---|---|---|---|
/login |
POST | jedi_iam/api/routes/login_route.py:37 |
無 | 免登入:登入第一關 |
/refresh |
POST | login_route.py:86 |
refresh token | 免登入:換發 access token |
/logout |
POST | login_route.py:97 |
J | 本人 |
/otp-verify |
POST | otp_route.py:112 |
mfa_token |
免登入:登入第二關 |
/otp-resend |
POST | otp_route.py:147 |
mfa_token+節流 |
免登入:登入第二關 |
/otp-qrcode/<uid> |
GET | otp_route.py:76 |
簽章短期憑證,path uid 須等於發放者 | 免登入:<img> 帶不了 bearer |
/otp-qrcode-token |
GET | otp_route.py:67 |
J;只發給本人 | 本人 |
/totp-secret |
POST | otp_route.py:45 |
J;只取本人 | 本人 |
/totp-verify |
POST | otp_route.py:99 |
J;只驗本人 | 本人 |
/forget-password |
POST | change_password_route.py:47 |
無 | 免登入:忘記密碼 |
/user/change-pwd-req/<uid> |
GET | change_password_route.py:84 |
無;憑證即請求 uid,service 驗有效期 | 免登入:重設密碼信連結 |
/user/change-pwd-by-req |
POST | change_password_route.py:20 |
無;憑證即請求 uid | 免登入:重設密碼 |
/version、/csp-report、/setup/status、/setup/provision |
— | 見上表 | — | 免登入/安裝精靈 |
/license/status、/license/activation/*(3) |
— | 見上表 | J | 防死鎖:只驗登入是刻意 |
/user/web-menu、/user-profile/<uid>、/user-mfa-type |
— | 見上表 | J | 本人 |
/system/menu/<group> |
GET | 見上表 | J | 全站字典 |
登記為豁免,不是漏網。 依據:
api/setup/routes/setup_route.py:1-50):首次啟動時一個帳號都沒有,JWT 不可用;改以 install.sh 印在終端的一次性設定碼(X-Setup-Token)當身分證據;端點刻意只留兩支。POST /setup/provision 先過 _require_setup_token()(setup_route.py:62-76),service 第一步 _assert_not_initialized()(app/setup/service/setup_wizard_service.py:167、:302-313)——已開通回 409,DB 查不出狀態時也當已開通擋下。判據是 DB 內是否已有業務租戶使用者,不是記憶體旗標,重啟不失效。common/setup/setup_token.py:81-97,磁碟上沒有 token 檔一律 False,timing-safe 比對。GET /setup/status 分級:無 token 只回 is_initialized 與 deployment_mode(開站看畫面就知道的資訊),機器指紋要有效 token 才給(setup_route.py:100-104)。@require_license,並在 common/middleware/license_readonly_mw.py 的 _EXEMPT_PREFIXES 補了 /setup/(裝機當下必然無照)。新名:不開能力點,在能力點登記表記為「豁免:安裝精靈(setup token+已開通即封)」。
| 舊名 | 主表有 route 守它? | 新名 | 其他引用處 |
|---|---|---|---|
smtp-config.create/read/update/delete |
create/update/delete 經 G 分流;.update 另守 /mail/test;.read 無 |
system.smtp-config.* |
宣告在 jedi_notification/plugin/contract.py:28-33;綁 /system/smtp-config-manage;基礎設施豁免 |
ldap-config.create/read/update/delete |
.create 守 /ldap/connect-test;create/update/delete 經 G(THIRD_PARTY_LOGIN);.read 無 |
system.ldap-config.* |
宣告在 jedi_iam/plugin/contract.py:72-75;綁 /system/ldap-config;基礎設施豁免 |
notify_config.read |
無 | system.notify-config.read |
宣告在 core/host_capabilities.py:54;綁 /system/notify-config |
notify_config.update |
有:通知測試、G 分流(create/delete 也改判它) | system.notify-config.update |
core/host_capabilities.py:55;_ACTION_ALIAS(system_core.py:84)改名後要拿掉 |
security-policy.read/update |
有:專屬端點;update 另經 G(RUNTIME_CONFIG) | system.security-policy.* |
宣告在 jedi_iam/plugin/contract.py:76-82;綁 /system/security-policy;基礎設施豁免 |
log-forwarding.read/update |
有:三支轉發端點 | system.log-forwarding.* |
宣告在 jedi_api_log/forwarding/plugin/contract.py:33-35;宿主名在 core/plugins/api_log.py:311-312;基礎設施豁免 |
issue-integrate-config.create/read/update/delete |
create/update/delete 經 G;.read 無 |
system.issue-integrate-config.* |
宣告在 jedi_issue/plugin/contract.py:44-47(is_platform);綁 /system/issue-integrate-config |
system_config.create/update/delete |
經 G 的 fallback:未登記 group 的寫入(Drive 設定頁實際走這條) | system.system-config.*(定案 1) |
宣告在 scripts/init/04-seed-core.sql:198-200、scripts/sql/2026-07-07-fr048-phase4a-capability-seed.sql;不綁任何選單;只有 Administrator 持有 |
system-menu.create/update/delete |
有 | system.system-menu.* |
宣告在 jedi_system_core/plugin/contract.py:33-50 |
system-menu.read |
無(管理端讀取只守 PA) | system.system-menu.read |
綁 /system/system-menu-manage |
license.read |
無(管理端只守 PA) | platform.license.read(定案 4) |
宣告在 jedi_license_runtime/plugin/contract.py:25-27;綁 /license/manage |
user.create |
有:新增、改狀態(語意不符)、匯入三支 | iam.user.create/.import/.update |
宣告在 jedi_iam/plugin/contract.py:54-57;綁 /auth/user-manage |
user.read/update/delete |
有 | iam.user.* |
user.update 另在 service 層當綁定第三方身分的放行條件(user_auth_provider_service.py) |
role.create/read/update/delete |
有 | iam.role.* |
jedi_iam/plugin/contract.py:60-63;綁 /auth/role-manage |
department.create/read/update/delete |
有 | iam.org-unit.* |
jedi_iam/plugin/contract.py:68-71;綁 /department/department-manage |
tenant.create/read/delete |
有 | iam.tenant.* |
jedi_iam/plugin/contract.py:64-67;綁 /tenant/tenant-manage |
tenant.update |
無(PUT 只守 PA) | iam.tenant.update |
綁 /tenant/tenant-manage |
storage-config.*(4,T-1.3 範圍) |
本範圍:AI 模型下拉、出廠還原、G 分流(STORAGE_CONFIG、AI_PROVIDER_CONFIG) | 見定案 2:儲存頁 system.storage-config.*、AI 頁 ai.ai-provider-config.* |
綁 /system/storage-config、/system/ai-service-config、/system/drive-app-config、/system/support 四頁 |
smtp-config.read、ldap-config.read、notify_config.read、issue-integrate-config.read、system-menu.read、license.read、tenant.update,共 7 個。全部有綁選單、決定「選單看不看得到」,只是端點沒跟著守——前四個正是〈先看這幾點〉第 1 條的讀取缺口。卡上說的「system_config.* 三個都是孤兒」不成立:它們沒有綁選單,但寫入守門會 fallback 到它們。
TENANT_ADMIN_EXCLUDED_RESOURCE_TYPES)core/plugins/identity.py:89-95 列的五個裡,DEV 只有 workflow 還有能力點(workflow.create/read/update/delete,T-1.1 已定刪除);cruise-project、dashboard、resource、report 在 DEV 都沒有任何能力點。workflow 刪掉後這份清單可以清空。
POST /role、PUT /role/<uid> 的 request:capabilities: List[int]——能力點 id 陣列(jedi_iam/api/serializers/role.py:13)。改成三段式名或 pattern 時這裡的型別要變。capabilities: List[CapabilityResponse],每筆 id/name/description/resource_type/action/is_platform(role.py:43、capability.py)。GET /capabilities/menu:同 CapabilityResponse 陣列,角色矩陣的欄。GET /ui-routes:route 樹,每個節點帶 route_capabilities、capabilities_count(serializers/ui_route.py:23-26),角色矩陣的列。GET /user/web-menu:每個選單項帶 operations: List[str] 與 capabilities: List[Dict](serializers/user.py:136-142)。POST /user、PUT /user/<uid> 的 request:user_roles: List[{role_uid, tenant_id, org_unit_id, scope, is_default, start_at, end_at}](serializers/user_role.py:4-11)——這就是指派。UserProfileRequest 刻意不收它。第 1~4 條併入 T-4.6(CM-2542),在該卡編為第 6~8 條(第 3、4 兩條守錯動詞合成一條);第 5 條屬改名時順手修,由 A.2/A.4 帶走,不併。
GET /system/config/<group>/<key>(system_config_route.py:149)、套件 GET /system/configs/<group>、GET /system/config/<uid>。修法對稱寫入側:route 呼叫 assert_config_capability(group, "read")(by-uid 用 resolve_group_for_uid)。注意 /system/configs/<group> 是套件 route,要動 jedi-system-core。上線前確認出貨角色範本都帶了各設定頁的 read。get_user_auth_providers 補呼叫 _assert_caller_can_manage(user_uid)(jedi-iam 套件內)。/user/change-status/<uid> 從 user.create 改為 iam.user.update。/ldap/connect-test 從 ldap-config.create 改為 system.ldap-config.update。/system/menus、/system/category-menu 補 system.system-menu.read;license 管理端照定案 4 補 platform.license.*(平台管理員那道保留)。決策者 2026-10-06 逐條裁決。
system.system-config 保留並補 read;GOOGLE_DRIVE_APP_CONFIG 正式登記進 GROUP 對照表,Drive 設定頁不再靠 fallback。fallback 只當「未登記 group 的兜底」。理由:fallback 不能拿掉(未登記 group 要有最嚴的門),但原本 Drive 頁「選單綁 storage-config、儲存要 system_config」是兩套門鎖,靠平台管理員那道才沒出事。system.storage-config.*;AI 服務設定頁+AI 證據分類設定 → ai.ai-provider-config.*(新開,歸 T-1.5 定案的 ai 模組);Google Drive 應用程式憑證 → platform 層(原廠,具體資源名由 T-1.6 定);支援頁 → platform.support.*(T-1.5 已裁)。storage-config 歸屬爭議結論:system。理由:五頁鎖的層級不同(AI、Drive 鎖平台管理員,儲存不鎖),共用一顆能力點無法分別授權。update,不開 send。 理由:沒有客戶要「能改設定但不能測」;log 轉發套件也已刻意把測試掛在寫入欄。platform.license.*,不留 system。 動詞:read、assign(指派、向 LC 請新照)、update(停權、解除、展延)、import(上傳照檔),is_platform = true;後端平台管理員判定保留再加能力點,兩道都過。租戶自救 5 支維持只驗登入(防死鎖,不變)。理由:這是原廠對租戶的操作,放 system 會讓客戶以為自己能管授權。platform.support.read/.export,本卡只引用不重裁。/users/menu、/org-units/menu 豁免(跨模組挑人挑部門,只驗登入);/capabilities/menu、/ui-routes → iam.role.read;/tenants/menu → iam.tenant.read。/roles/menu 守 role.read 的副作用(只有 user.create 的人在使用者表單拿不到角色下拉)留 A.3 處理。iam.tenant.update,平台管理員那道保留(兩道都過);A.3 實作時先查清 service 是否會動 parent_id,再決定能否拿掉。iam.org-unit,不用 department。 決策者原話:「跟程式統一才不會亂掉,以前已經改版過」。連帶:舊名 department.* → iam.org-unit.*;畫面顯示名由前端 i18n 處理,A.5 帶走。沿革見 FR-132-LOG.md 與 git log。