事實盤點,不下判斷。分支
fix/v1.8.0-bugs。所有 route 前綴/api/1.0。assert_project_manager定義於common/util/participant_guard.py(route 提示的common.authz.project尚未遷入,現況仍common.util.participant_guard)。
重要脈絡:api/participant/__init__.py 內多個 resource 已被註解停用(FR-038 DEAD-V1,2026-06-18,FE 無 caller)。停用者標「路由已註解」。仍掛載的 live 寫入端點:/task-assignees/batch(POST)、/task-assignee(POST/PUT/DELETE)、/project-participant(POST/PUT/DELETE)、/project-control-participant(POST/PUT/DELETE)、/control-group-participant(POST/PUT/DELETE)。
| Route path | Method | Route file:line | @jwt_required? | 呼叫的 service method | 現況守門 | 備註 |
|---|---|---|---|---|---|---|
| /api/1.0/task-assignees | POST | api/participant/routes/task_assignee_route.py:49 | 是 | TaskAssigneeService.get_task_assignees |
僅 JWT | POST 實為分頁查詢(讀) |
| /api/1.0/task-assignees/batch | POST | api/participant/routes/task_assignee_route.py:24 | 是 | TaskAssigneeService.batch_add_task_assignees |
僅 JWT | 寫入端點但 service 為 FR-038 2A 死碼 stub,直接 return [](app/participant/service/task_assignee_service.py:173-188),無守門也無實際寫入 |
| /api/1.0/task-assignee | POST | api/participant/routes/task_assignee_route.py:65 | 是 | TaskAssigneeService.add_task_assignee |
已有: assert_project_manager @ app/participant/service/task_assignee_service.py:142 |
role level: project manager,以 control_id scope(enforce_role 預設 True) |
| /api/1.0/task-assignee | PUT | api/participant/routes/task_assignee_route.py:80 | 是 | TaskAssigneeService.update_task_assignee |
已有: assert_project_manager @ app/participant/service/task_assignee_service.py:212 |
role level: project manager,control_id scope |
| /api/1.0/task-assignee | DELETE | api/participant/routes/task_assignee_route.py:103 | 是 | TaskAssigneeService.delete_task_assignee |
已有: assert_project_manager @ app/participant/service/task_assignee_service.py:249 |
role level: project manager,control_id scope |
| /api/1.0/project-participants | POST | api/participant/routes/project_participant_route.py:61 | 是 | ProjectParticipantService.get_project_participants |
僅 JWT | POST 實為分頁查詢(讀) |
| /api/1.0/project-participant | POST | api/participant/routes/project_participant_route.py:78 | 是 | ProjectParticipantService.add_project_participant |
已有: assert_project_manager @ app/participant/service/project_participant_service.py:83 |
role level: project manager(無 group/control scope) |
| /api/1.0/project-participant | PUT | api/participant/routes/project_participant_route.py:95 | 是 | ProjectParticipantService.update_project_participant |
已有: assert_project_manager @ app/participant/service/project_participant_service.py:125 |
role level: project manager |
| /api/1.0/project-participant | DELETE | api/participant/routes/project_participant_route.py:109 | 是 | ProjectParticipantService.delete_project_participant |
已有: assert_project_manager @ app/participant/service/project_participant_service.py:144 |
role level: project manager |
| /api/1.0/project-control-participants | POST | api/participant/routes/project_control_participant_route.py:59 | 是 | ProjectControlParticipantService.get_control_participants_with_inherits[_by_uid] |
僅 JWT | POST 實為分頁查詢(讀) |
| /api/1.0/project-control-participant | POST | api/participant/routes/project_control_participant_route.py:89 | 是 | ProjectControlParticipantService.add_project_control_participant |
已有: assert_project_manager @ app/participant/service/project_control_participant_service.py:66 |
role level: project manager,scope=group_id+control_id |
| /api/1.0/project-control-participant | PUT | api/participant/routes/project_control_participant_route.py:114 | 是 | ProjectControlParticipantService.update_project_control_participant |
已有: assert_project_manager @ app/participant/service/project_control_participant_service.py:110 |
role level: project manager,scope=group_id+control_id |
| /api/1.0/project-control-participant | DELETE | api/participant/routes/project_control_participant_route.py:139 | 是 | ProjectControlParticipantService.delete_project_control_participant |
已有: assert_project_manager @ app/participant/service/project_control_participant_service.py:143 |
role level: project manager,scope=group_id+control_id |
| /api/1.0/control-group-participant | POST | api/participant/routes/control_group_participant_route.py:78 | 是 | ControlGroupParticipantService.add_control_group_participant |
已有: assert_project_manager @ app/participant/service/control_group_participant_service.py:87 |
role level: project manager,scope=group_id |
| /api/1.0/control-group-participant | PUT | api/participant/routes/control_group_participant_route.py:101 | 是 | ControlGroupParticipantService.update_control_group_participant |
已有: assert_project_manager @ app/participant/service/control_group_participant_service.py:126 |
role level: project manager,scope=group_id |
| /api/1.0/control-group-participant | DELETE | api/participant/routes/control_group_participant_route.py:124 | 是 | ControlGroupParticipantService.delete_control_group_participant |
已有: assert_project_manager @ app/participant/service/control_group_participant_service.py:156 |
role level: project manager,scope=group_id |
| (control-group-participants) | POST | api/participant/routes/control_group_participant_route.py:51 | 是 | ControlGroupParticipantService.get_control_group_participants_with_inherits[_by_uid] |
僅 JWT | POST 實為分頁查詢(讀);路由已註解(init.py:64) |
| (control-group-participants/menu) | GET | api/participant/routes/control_group_participant_route.py:27 | 是 | ControlGroupParticipantService.get_control_group_participant_menu[_by_uid] |
僅 JWT | 讀取 menu;路由已註解(init.py:65) |
| (process-participant) | POST | api/participant/routes/process_participant_route.py:57 | 是 | ProcessParticipantService.add_process_participant |
已有: assert_project_manager @ app/participant/service/process_participant_service.py:65 |
role level: project manager,control_id=process_id;路由已註解(init.py:50) |
| (process-participant) | PUT | api/participant/routes/process_participant_route.py:70 | 是 | ProcessParticipantService.update_process_participant |
已有: assert_project_manager(經 _assert_manager_for_process)@ app/participant/service/process_participant_service.py:90→57 |
role level: project manager,反解 record.project_id;路由已註解 |
| (process-participant) | DELETE | api/participant/routes/process_participant_route.py:86 | 是 | ProcessParticipantService.delete_process_participant |
已有: assert_project_manager(經 _assert_manager_for_process)@ app/participant/service/process_participant_service.py:111→57 |
role level: project manager;路由已註解 |
| (process-participants) | POST | api/participant/routes/process_participant_route.py:40 | 是 | ProcessParticipantService.get_process_participants_with_inherits |
僅 JWT | POST 實為分頁查詢(讀);路由已註解(init.py:48) |
| (process-participants/menu) | GET | api/participant/routes/process_participant_route.py:25 | 是 | ProcessParticipantService.get_process_participant_menus |
僅 JWT | 讀取 menu;路由已註解(init.py:49) |
| (project-group-participant) | POST | api/participant/routes/project_group_participant_route.py:78 | 是 | ProjectGroupParticipantService.add_project_group_participant |
僅 JWT | 無 assert_project_manager(service 全檔無守門,app/participant/service/project_group_participant_service.py:67-92);路由已註解(init.py:72) |
| (project-group-participant) | PUT | api/participant/routes/project_group_participant_route.py:101 | 是 | ProjectGroupParticipantService.update_project_group_participant |
僅 JWT | 無 assert_project_manager(同上 service:95-119);路由已註解 |
| (project-group-participant) | DELETE | api/participant/routes/project_group_participant_route.py:124 | 是 | ProjectGroupParticipantService.delete_project_group_participant |
僅 JWT | 無 assert_project_manager(同上 service:122-136);路由已註解 |
| (project-group-participants) | POST | api/participant/routes/project_group_participant_route.py:51 | 是 | ProjectGroupParticipantService.get_project_group_participants_with_inherits[_by_uid] |
僅 JWT | POST 實為分頁查詢(讀);路由已註解(init.py:70) |
| (project-group-participants/menu) | GET | api/participant/routes/project_group_participant_route.py:27 | 是 | ProjectGroupParticipantService.get_project_group_participant_menu[_by_uid] |
僅 JWT | 讀取 menu;路由已註解(init.py:71) |
| /api/1.0/project-participants/menu | GET | api/participant/routes/project_participant_route.py:25 | 是 | ProjectParticipantService.get_project_participant_menus[_by_uid] |
僅 JWT | 讀取 menu(live) |
| (project-participant/permission/<project_id>) | GET | api/participant/routes/project_participant_route.py:45 | 是 | ProjectParticipantService.get_project_participants_permissions |
僅 JWT | 讀取;路由已註解(init.py:43) |
| /api/1.0/project-control-participants/menu | GET | api/participant/routes/project_control_participant_route.py:28 | 是 | ProjectControlParticipantService.get_control_participant_menu[_by_uid] |
僅 JWT | 讀取 menu(live) |
| (enums/participant-roles) | GET | api/participant/routes/participant_enum_route.py:19 | 是 | 無(直接 enum dump) | 僅 JWT | 靜態 enum;路由已註解(init.py:76) |
重要脈絡:FR-039 File Agent registry。程式碼註解多處寫「需 admin」(EnrollToken / Revoke / Rebind 等),但追進 service 層後,所有 FE 端點皆無任何 admin / role / is_admin 守門——僅 @jwt_required()。控制面端點(/agents/register、/agents/heartbeat)刻意無 JWT(agent→cloud,走 token+mTLS,非 user JWT)。agent_enrollment_service.py:186 的 ForbiddenError 是 agent status=revoked 的業務拒絕,非授權守門。
| Route path | Method | Route file:line | @jwt_required? | 呼叫的 service method | 現況守門 | 備註 |
|---|---|---|---|---|---|---|
| /api/1.0/remote-agents | GET | api/remote_agent/routes/remote_agent_route.py:34 | 是 | RemoteAgentService.list_enabled_agents |
僅 JWT | 下拉清單(讀) |
| /api/1.0/remote-agents | POST | api/remote_agent/routes/remote_agent_route.py:47 | 是 | RemoteAgentService.create_agent |
僅 JWT | 寫入;registry 新增,無 admin 守門 |
| /api/1.0/remote-agents/all | GET | api/remote_agent/routes/remote_agent_route.py:88 | 是 | RemoteAgentService.list_all_agents |
僅 JWT | 管理頁列表(讀,含停用) |
| /api/1.0/remote-agents/health-check | POST | api/remote_agent/routes/remote_agent_route.py:61 | 是 | RemoteAgentService.check_health |
僅 JWT | 雲端打 agent /health;POST 但非寫 DB、非分頁查詢(動作型) |
| /api/1.0/remote-agents/<uid>/reconcile | POST | api/remote_agent/routes/remote_agent_route.py:74 | 是 | RemoteAgentService.reconcile |
僅 JWT | 對帳動作(讀取/比對),無 admin 守門 |
| /api/1.0/remote-agents/<uid> | GET | api/remote_agent/routes/remote_agent_route.py:102 | 是 | RemoteAgentService.get_agent |
僅 JWT | 單筆 detail(讀) |
| /api/1.0/remote-agents/<uid> | PUT | api/remote_agent/routes/remote_agent_route.py:115 | 是 | RemoteAgentService.update_agent |
僅 JWT | 寫入(含啟用/停用),無 admin 守門 |
| /api/1.0/remote-agents/<uid> | DELETE | api/remote_agent/routes/remote_agent_route.py:128 | 是 | RemoteAgentService.delete_agent |
僅 JWT | 寫入(刪除),無 admin 守門 |
| /api/1.0/agents/register | POST | api/remote_agent/routes/remote_agent_route.py:143 | 否 | AgentEnrollmentService.register |
無 JWT | FR-039 控制面,agent→cloud,刻意不擋(token+TLS bootstrap) |
| /api/1.0/agents/heartbeat | POST | api/remote_agent/routes/remote_agent_route.py:155 | 否 | AgentEnrollmentService.heartbeat |
無 JWT | FR-039 控制面,agent→cloud,刻意不擋(mTLS);service:186 對 revoked agent 拋 ForbiddenError(業務拒絕非授權) |
| /api/1.0/agents/enroll-token | GET | api/remote_agent/routes/remote_agent_route.py:168 | 是 | AgentEnrollTokenService.get_current |
僅 JWT | 讀 token 摘要;註解稱「需 admin」但 service 無 admin 守門 |
| /api/1.0/agents/enroll-token | POST | api/remote_agent/routes/remote_agent_route.py:178 | 是 | AgentEnrollTokenService.generate |
僅 JWT | 敏感 GET/寫:產生註冊 token(明文僅此次回);註解稱「需 admin」但 service 無 admin 守門 |
| /api/1.0/agents/enroll-token/revoke | POST | api/remote_agent/routes/remote_agent_route.py:193 | 是 | AgentEnrollTokenService.revoke |
僅 JWT | 停用全 tenant token;註解稱「需 admin」但 service 無 admin 守門 |
| /api/1.0/remote-agents/<uid>/revoke | POST | api/remote_agent/routes/remote_agent_route.py:206 | 是 | RemoteAgentService.revoke_agent |
僅 JWT | 撤銷 agent;註解稱「需 admin」但 service 無 admin 守門 |
| /api/1.0/remote-agents/<uid>/unrevoke | POST | api/remote_agent/routes/remote_agent_route.py:220 | 是 | RemoteAgentService.unrevoke_agent |
僅 JWT | 解除撤銷;註解稱「需 admin」但 service 無 admin 守門 |
| /api/1.0/remote-agents/<uid>/rebind | POST | api/remote_agent/routes/remote_agent_route.py:235 | 是 | RemoteAgentService.rebind_agent |
僅 JWT | 重新綁定設備指紋;註解稱「需 admin」但 service 無 admin 守門 |