diff --git a/docs/superpowers/specs/2026-07-07-执行编辑删除权限口径-design.md b/docs/superpowers/specs/2026-07-07-执行编辑删除权限口径-design.md new file mode 100644 index 0000000..25cb092 --- /dev/null +++ b/docs/superpowers/specs/2026-07-07-执行编辑删除权限口径-design.md @@ -0,0 +1,79 @@ +# 执行编辑删除权限口径 - 设计 spec + +- 日期:2026-07-07 +- 范围:`rdms-project` 项目对象域下执行编辑、执行删除、执行删除预检 +- 状态:已与用户确认设计,待 review 后写实现 plan + +## 1. 背景 + +任务侧已经采用“业务身份命中直接放行,未命中再回落对象域权限码”的兼容口径。执行侧当前仍主要依赖 `@CheckObjectPermission(permission = project:execution:update/delete)`,导致执行负责人如果没有对象域权限码,可能无法编辑或删除自己负责的执行。 + +用户确认执行侧应采用类似任务侧的裁决方式:项目负责人、执行负责人可直接操作;管理员仍走对象域权限码兜底;项目创建者不作为天然放行身份。 + +## 2. 权限口径 + +执行编辑、执行删除、执行删除预检的后端最终放行条件: + +| 操作 | 业务身份直接放行 | 权限码兜底 | +|---|---|---| +| 编辑执行 | 项目负责人、执行负责人 | `project:execution:update` | +| 删除执行 | 项目负责人、执行负责人 | `project:execution:delete` | +| 删除预检 | 项目负责人、执行负责人 | `project:execution:delete` | + +不放行的身份: + +- 项目创建者:只作为审计来源,不代表当前管理责任。 +- 执行协办人:参与执行,不代表可管理执行主数据。 +- 普通项目成员:除非其对象域角色拥有对应权限码。 + +这里的“管理员”不是全局超级管理员短路,而是项目对象域内拥有对应权限码的管理员型角色。当前对象域写权限不引入超管无条件绕过。 + +## 3. 后端设计 + +执行侧新增一个私有授权方法,语义与任务侧 `requireTaskEditDeletePermission` 对齐,但参与身份更少: + +1. 加载项目与执行。 +2. 组装候选负责人:`project.managerUserId`、`execution.ownerId`。 +3. 调用 `ProjectObjectAuthorizationService.checkAnyOwnerOrProjectPermission(projectId, ownerUserIds, permission)`。 +4. 命中任一负责人直接返回;否则由 `ProjectObjectPermissionService.checkPermission` 校验对象域权限码。 + +为了让“执行负责人但无权限码”的用户能进入方法体,执行编辑、执行删除、执行删除预检方法上的 `@CheckObjectPermission(permission = ...)` 不能继续作为前置拦截;这些入口改由方法内部统一裁决。 + +保持不变: + +- 创建执行仍走 `project:execution:create`。 +- 换执行负责人仍走项目层管理权限,不给执行负责人天然放权。 +- 执行状态动作 `complete/cancel/pause/resume` 仍保持执行负责人独占,不纳入本次编辑/删除口径。 +- 删除的业务规则不变:已完成执行禁删,非 completed 状态允许删除;删除预检仍不能被无权限用户用于探测下挂任务数量。 + +## 4. 前端联调口径 + +前端按钮展示建议: + +- 编辑执行:`currentProject.managerUserId === currentUserId || execution.ownerId === currentUserId || hasPermission('project:execution:update')` +- 删除执行 / 删除预检:`currentProject.managerUserId === currentUserId || execution.ownerId === currentUserId || hasPermission('project:execution:delete')` + +后端仍是最终裁决。前端不需要识别项目创建者,也不需要把执行协办人作为执行编辑/删除按钮依据。 + +## 5. 测试与验证 + +优先补单测覆盖: + +- 项目负责人可编辑执行,无需 `project:execution:update`。 +- 执行负责人可编辑执行,无需 `project:execution:update`。 +- 普通成员无 `project:execution:update` 时编辑被拒。 +- 拥有 `project:execution:update` 的对象域角色可编辑执行。 +- 执行负责人可删除预检和删除执行,无需 `project:execution:delete`。 +- 普通成员无 `project:execution:delete` 时删除预检和删除均被拒。 + +静态检查: + +- 执行编辑、删除、删除预检不再由方法注解提前拦截权限码。 +- 权限裁决落在 service 层,仍属于项目对象域通道。 +- 不新增菜单、角色、权限码或数据库结构。 + +运行验证需用户同意后执行 Maven 测试命令。 + +## 6. 数据与 SQL + +本次是纯代码权限裁决调整,不涉及表结构、字典、菜单、角色或权限码种子变更。无需演示库 SQL 补丁。