Commit f318427ae399865e73e5d1b74daecc9e23a19550
1 parent
8a1b01bd
docs(review:REQ-USR-002:r1): approve
Showing
1 changed file
with
74 additions
and
0 deletions
docs/superpowers/reviews/2026-06-01-REQ-USR-002.md
0 → 100644
| 1 | +# REQ-USR-002 修改用户 — AI 自审报告(review, round 1) | ||
| 2 | + | ||
| 3 | +> 阶段:后端(backend)。spec:`docs/superpowers/specs/2026-06-01-REQ-USR-002.md`。 | ||
| 4 | +> 分支:`module-usr`;审查范围 = 本 REQ diff(`09db895..8a1b01b`)。 | ||
| 5 | +> 维度:通用后端代码审查(plan-alignment / 正确性 / 边界 / 错误处理 / 一致性 / 架构 / 文档)。 | ||
| 6 | + | ||
| 7 | +--- | ||
| 8 | + | ||
| 9 | +## 裁决 | ||
| 10 | + | ||
| 11 | +**verdict = approve**(issues = 空数组)。 | ||
| 12 | + | ||
| 13 | +实现与 spec / docs/05 契约 / docs/04 技术规范一致,8 条验收标准均有对应实现与测试覆盖,无客观可验证的 must-fix 缺陷。 | ||
| 14 | + | ||
| 15 | +--- | ||
| 16 | + | ||
| 17 | +## 1. 变更清单 | ||
| 18 | + | ||
| 19 | +| 文件 | 性质 | | ||
| 20 | +|---|---| | ||
| 21 | +| `backend/.../usr/dto/UpdateUserDTO.java` | 新增入参 DTO(匈牙利前缀 + `@JsonProperty` 锁键名 + Bean Validation) | | ||
| 22 | +| `backend/.../usr/service/UsrUserService.java` | 接口新增 `updateUser(Integer, UpdateUserDTO)` | | ||
| 23 | +| `backend/.../usr/service/impl/UsrUserServiceImpl.java` | 新增 `updateUser` 实现(存在性校验 / 部分更新 / 权限全量覆盖 / 单事务) | | ||
| 24 | +| `backend/.../usr/controller/UsrUserController.java` | 新增 `PUT /api/usr/users/{id}` + 管理员前置 | | ||
| 25 | +| `backend/.../usr/dto/UpdateUserDTOValidationTest.java` | DTO 校验单测(5) | | ||
| 26 | +| `backend/.../usr/service/UsrUserServiceImplTest.java` | Service 单测续写(T2 3 + T3 5) | | ||
| 27 | +| `backend/.../usr/controller/UsrUserControllerTest.java` | Controller 单测续写(4) | | ||
| 28 | +| `backend/.../usr/UsrUserUpdateIT.java` | 端到端验收回归(6,AC1/2/3/6/7/8) | | ||
| 29 | + | ||
| 30 | +无 SQL migration 变更(符合 D5:所需表均在 V1 建好);无跨模块改动。 | ||
| 31 | + | ||
| 32 | +--- | ||
| 33 | + | ||
| 34 | +## 2. plan-alignment(与 spec / 契约对照) | ||
| 35 | + | ||
| 36 | +- 端点 / 方法 / 路径与 `docs/05 § REQ-USR-002`(`PUT /api/usr/users/{id}`)一致;响应 `Result<{id}>`、`code=0` 一致。 | ||
| 37 | +- DTO 字段集与契约请求体逐项吻合:`sUserNo / iEmployeeId / sUserType / sLanguage / iCanModifyBill / iIsVoid / permissionIds`;不接收 `sUserName / sPassword / 审计列 / 租户列`(spec § 2.1 注)。 | ||
| 38 | +- 决策落实:D1(不碰密码)、D2(`iIsVoid` 承载禁用)、D3(可选列 null = 不更新)、D4(`permissionIds` 全量覆盖 / `[]` 清空 / null 不改)、D5(不新增 migration)、D6(管理员 = `超级管理员`)。 | ||
| 39 | +- 错误码:`40401`(不存在)/ `40001`(关联职员或权限元素不存在、枚举越界)/ `40301`(非管理员)/ `0`(成功)——与 spec § 6 一致。 | ||
| 40 | + | ||
| 41 | +## 3. 正确性 / 边界 / 错误处理 | ||
| 42 | + | ||
| 43 | +- 目标用户存在性校验置于所有写入之前,命中即 `40401` 且不落库(AC2)。 | ||
| 44 | +- 关联职员、权限元素存在性校验置于主记录更新前,非法即抛 `40001`,配合 `@Transactional(rollbackFor=Exception.class)` 整体回滚、无副作用(AC3)。 | ||
| 45 | +- 权限全量覆盖:先删该用户全部旧授权再按去重集合逐行插入;`[]` → 只删不插(清空);`null` → 不进入分支(不改);`distinct()` + `Objects::nonNull` 过滤去重去空(AC6)。 | ||
| 46 | +- 主记录部分更新:仅 set 主键 + 必填两列 + 非 null 可选列;密码 / `sUserName` / 审计列 / 租户列全不 set,依赖 MP `updateById` 默认 `NOT_NULL` 字段策略(已核对 `MybatisPlusConfig` 与 `application.yml` 无策略覆盖)从 SET 子句剔除,保持原值(AC1 / AC8)。 | ||
| 47 | +- 响应仅 `{id}`,`sPassword` 实体侧 `@JsonIgnore`,IT 断言响应体不含 `password` 子串(AC8)。 | ||
| 48 | + | ||
| 49 | +## 4. 架构 / 一致性 | ||
| 50 | + | ||
| 51 | +- 分层正确:Controller 仅 `@Valid` + 管理员前置 + 委派,未直接调 Mapper;业务在 Service;数据访问走 `LambdaQueryWrapper` / MP 内置(docs/04 § 1.2 / § 3.4)。 | ||
| 52 | +- 复用 REQ-USR-001 已建 controller / service / mapper / entity,未另起类,未跨 `modules/usr/**` 之外(spec § 4)。 | ||
| 53 | +- 统一响应 / 全局异常 / 错误码枚举沿用既有公共设施,风格一致。 | ||
| 54 | + | ||
| 55 | +## 5. 文档 | ||
| 56 | + | ||
| 57 | +- 类 / 方法 Javadoc 完整,含 `REQ-USR-002` 追溯标记与决策引用,符合项目注释约定。 | ||
| 58 | + | ||
| 59 | +--- | ||
| 60 | + | ||
| 61 | +## 6. 非阻塞建议(口头,非 must-fix) | ||
| 62 | + | ||
| 63 | +1. **路径参数非正整数口径**:spec § 2.1 / § 6 期望非正整数 `id` 返回 `40001`,当前 Controller 未加 `@Positive`,`0` / 负数 `id` 会落到 `selectById` 返回 null → `40401`。因 `0` / 负数主键实际不可能命中记录,行为安全(仍被拒绝、不产生数据污染),但与契约文字口径略有出入;后续可在 `@PathVariable` 加 `@Positive` 并开启 `@Validated` 使其归一为 `40001`。 | ||
| 64 | +2. **注释 tag 笔误**:`UsrUserController` 中管理员判定注释引用 `spec § 8 D2`,实际管理员口径决策为 `D6`(D2 是 `iIsVoid` 状态决策);纯注释问题,不影响行为。 | ||
| 65 | +3. **并发健壮性(理论)**:权限"先删后插"在高并发同一用户授权场景下存在间隙锁 / 死锁的理论可能;当前管理员低频写场景可接受,不构成缺陷。 | ||
| 66 | +4. **非整数 `iIsVoid` / `iCanModifyBill` 反序列化**:传入非数字会触发 Jackson `HttpMessageNotReadableException`,落到兜底 `Exception` 处理器返回 `50000` 而非 `40001`;此为既有全局行为(与 REQ-USR-001 一致),不在本 REQ 作用域单独修。 | ||
| 67 | + | ||
| 68 | +--- | ||
| 69 | + | ||
| 70 | +## 7. 测试与闸门 | ||
| 71 | + | ||
| 72 | +- verify 证据(`2026-06-01-REQ-USR-002-verify.md`):`mvn checkstyle:check` exit 0、`mvn test` 36 通过 / 0 失败,`BUILD SUCCESS`。 | ||
| 73 | +- 单测覆盖:DTO 校验、Service 存在性 / 部分更新 / 关联职员 / 权限全量覆盖(含去重、清空、不改)、Controller 管理员前置 / 路由 / 404 转译。 | ||
| 74 | +- IT 覆盖 AC1/2/3/6/7/8;AC4(禁用实时生效)/ AC5(角色变更实时生效)依赖 REQ-USR-004 / REQ-USR-003,本 REQ 以"落库层读回等价验证"覆盖,符合 spec § 7 边界说明。 |