req_id: REQ-USR-002 date: 2026-04-30
spec_ref: docs/superpowers/specs/2026-04-30-REQ-USR-002.md
REQ-USR-002 用户修改 Implementation Plan
Execution: Parent skill
feature-tddexecutes this plan task-by-task.
Goal: 在 USR-001 已建工程基础上增量实现 PUT /api/usr/users/{id}:更新可编辑字段 + 重建权限组(删旧 + 插新);保留 sPasswordHash / sCreatedBy / 标准列。
Architecture: 复用 UserService / UserServiceImpl / UserController / 全部 mappers;新增 UpdateUserDTO、UserService#update、UserPermissionMapper#deleteByUserId。SecurityConfig 已对 /api/usr/** permitAll,无需改。
Tech Stack: 沿用(Spring Boot 3.3.5 / MyBatis-Plus / JJWT)。
Schema 改动
无(仅 UPDATE / DELETE / INSERT)。
文件变更清单
新增
backend/src/main/java/com/xly/erp/module/usr/dto/UpdateUserDTO.java
修改
-
backend/src/main/java/com/xly/erp/module/usr/mapper/UserPermissionMapper.java— 追加deleteByUserId(Integer) -
backend/src/main/java/com/xly/erp/module/usr/service/UserService.java— 追加Integer update(Integer id, UpdateUserDTO dto) -
backend/src/main/java/com/xly/erp/module/usr/service/impl/UserServiceImpl.java— 实现 update(含 5 类校验 + UPDATE + DELETE + INSERT × N) -
backend/src/main/java/com/xly/erp/module/usr/controller/UserController.java— 追加 PUT 端点 -
backend/src/test/java/com/xly/erp/module/usr/service/UserServiceImplTest.java— 追加 10 单测 -
backend/src/test/java/com/xly/erp/module/usr/mapper/UserMapperIT.java— 追加 1 用例(deleteByUserId) -
backend/src/test/java/com/xly/erp/module/usr/controller/UserControllerIT.java— 追加 10 IT
任务步骤
Task 1: UserPermissionMapper#deleteByUserId + IT
Files:
- Modify:
backend/src/main/java/com/xly/erp/module/usr/mapper/UserPermissionMapper.java - Modify:
backend/src/test/java/com/xly/erp/module/usr/mapper/UserMapperIT.java
API shape:
@Delete("DELETE FROM tUserPermission WHERE iUserId = #{userId}")int deleteByUserId(@Param("userId") Integer userId)-
Step 1: 写失败测试
userPermissionMapper#deleteByUserId_removesAllRowsForGivenUser- 准备:插 user1 + user2;user1 关联 cat1+cat2,user2 关联 cat1
- 调
deleteByUserId(user1.id)→ 返回 2,user1 行数 = 0;user2 行数 = 1(不受影响)
Step 2: 实现 mapper 方法
Step 3: 子会话验证 PASS:
mvn -B test -Dtest=UserMapperITStep 4: Commit:
feat(usr): mapper#deleteByUserId for permission rebuild REQ-USR-002
Task 2: UpdateUserDTO + UserService.update 主流程(合法 + 目标存在性 + bShowPerm null→false)
Files:
- Create:
backend/src/main/java/com/xly/erp/module/usr/dto/UpdateUserDTO.java - Modify:
backend/src/main/java/com/xly/erp/module/usr/service/UserService.java - Modify:
backend/src/main/java/com/xly/erp/module/usr/service/impl/UserServiceImpl.java - Modify:
backend/src/test/java/com/xly/erp/module/usr/service/UserServiceImplTest.java
API shape:
-
UpdateUserDTO字段(与 CreateUserDTO 平行,去掉permissionCategoryIds之外字段语义不变;剔除sPasswordHash,仍包含permissionCategoryIds用于重建权限组) UserService#update(Integer id, UpdateUserDTO dto) : Integer-
实现:
-
selectById(id)→ null 或 bDeleted=true → 40400 - 枚举校验 sUserType / sLanguage(同 create)→ 40001
- iStaffId 校验(同 create)→ 40022
- permissionCategoryIds 校验(仅当非空 list;null/空 list 跳过校验直接清空)→ 40023
- 构造 entity 仅 set iIncrement + 6 个可编辑字段(其余 null);
bCanModifyDocsnull → false -
userMapper.updateById(entity)try/catch DuplicateKeyException → 40020 userPermissionMapper.deleteByUserId(id)- 若 permissionCategoryIds 非空:for-loop 插 UserPermission
-
-
Step 1: 追加 4 单测
updateWithValidDto_invokesUpdateById_andRebuildsPermissionsupdateWithTargetNotFound_throws40400updateWithTargetAlreadyDeleted_throws40400updateWithBCanModifyDocsNull_setsFalseInEntity
Step 2: 实现 DTO + service 主流程
Step 3: 子会话验证 PASS:
mvn -B test -Dtest=UserServiceImplTest(期望 8+4=12)Step 4: Commit:
feat(usr): user update dto + service happy path REQ-USR-002
Task 3: Service 异常分支补全(枚举 / staff / permission / 唯一冲突 / 清空权限)
Files:
- Modify:
backend/src/main/java/com/xly/erp/module/usr/service/impl/UserServiceImpl.java - Modify:
backend/src/test/java/com/xly/erp/module/usr/service/UserServiceImplTest.java
API shape: 不变
- Step 1: 追加 6 单测
updateWithInvalidUserType_throws40001updateWithInvalidLanguage_throws40001updateWithStaffNotFound_throws40022updateWithSomeInvalidPermissionIds_throws40023updateWithDuplicateUserNo_throws40020-
updateWithEmptyPermissionIds_clearsExisting— permissionCategoryIds=null;deleteByUserId 调一次、insert 永不调
- Step 2: 实现校验分支
- Step 3: 子会话验证 PASS:
mvn -B test -Dtest=UserServiceImplTest(期望 12+6=18) - Step 4: Commit:
feat(usr): user update error branches REQ-USR-002
Task 4: Controller PUT + IT(10 用例)+ 全量回归
Files:
- Modify:
backend/src/main/java/com/xly/erp/module/usr/controller/UserController.java - Modify:
backend/src/test/java/com/xly/erp/module/usr/controller/UserControllerIT.java
API shape:
@PutMapping("/users/{id}") public Result<Map<String,Object>> update(@PathVariable Integer id, @Valid @RequestBody UpdateUserDTO dto)返回
Result.ok(Map.of("iIncrement", userService.update(id, dto)))Step 1: 追加 10 IT(参 spec 验收清单)
Step 2: 实现 controller PUT
Step 3: 子会话跑全量回归:
mvn -B test(期望 89 + 1+10+10=20 = 109+ 用例全绿)Step 4: Commit:
test(usr): user update integration coverage REQ-USR-002
提交计划
| commit | 覆盖 |
|---|---|
feat(usr): mapper#deleteByUserId for permission rebuild REQ-USR-002 |
Task 1 |
feat(usr): user update dto + service happy path REQ-USR-002 |
Task 2 |
feat(usr): user update error branches REQ-USR-002 |
Task 3 |
test(usr): user update integration coverage REQ-USR-002 |
Task 4 |