Commit 3c49b6623296c8158843bc77ceaa94ec30c11062

Authored by zichun
1 parent c9cbceaa

docs(review:REQ-USR-001:r1): approve

docs/superpowers/reviews/2026-06-01-REQ-USR-001.md 0 → 100644
  1 +# REQ-USR-001 增加用户 — AI 自审报告(review, round 1)
  2 +
  3 +> 阶段:后端(backend)。审查维度:通用代码审查(plan-alignment / quality / architecture / docs)。
  4 +> 上游 spec:`docs/superpowers/specs/2026-06-01-REQ-USR-001.md`
  5 +> API 契约:`docs/05-API接口契约.md` § REQ-USR-001
  6 +> Schema SSoT:`sql/migrations/V1__initial_schema.sql`(对齐 `docs/03`)
  7 +> 被审提交:`c9cbcea`(HEAD);本 REQ diff 自 `cc0c846` 起
  8 +> 审查时间:2026-06-01 CST
  9 +
  10 +---
  11 +
  12 +## 1. 裁决
  13 +
  14 +**verdict = approve**(issues = 空)。
  15 +
  16 +本轮引入的后端代码在四个标准维度上均无客观、可验证的 must-fix 缺陷;测试证据 24/24 全绿(见 verify 报告),工作树干净。
  17 +
  18 +---
  19 +
  20 +## 2. 维度核对
  21 +
  22 +### 2.1 plan-alignment(实现 ↔ spec / 契约)
  23 +
  24 +| 核对项 | 结论 |
  25 +|---|---|
  26 +| 端点 `POST /api/usr/users` | 一致(`UsrUserController` `@PostMapping("/users")` + `@RequestMapping("/api/usr")`) |
  27 +| DTO 字段与校验(spec § 2.1) | 一致:`sUserName` `@NotBlank+@Pattern(3-20)`、`sUserNo` `@Size(50)`、`sUserType` `@Pattern(普通用户\|超级管理员)`、`sLanguage` `@NotBlank+@Pattern`、`iCanModifyBill` `@Min/@Max 0/1`、`initialPassword/permissionIds` 可选 |
  28 +| 错误码 40001 / 40301 / 40901 / 0 | 一致(`ResultCode` 枚举;`GlobalExceptionHandler` 转 `Result`) |
  29 +| 业务规则 1-9(spec § 3) | 全部落地:用户名查重→40901、并发 DuplicateKey 兜底→40901、密码 BCrypt+禁明文、用户类型/语言枚举约束、职员/权限存在性→40001、权限去重批量授权、`iIsVoid=0` 新建即生效、审计字段、管理员前置→40301 |
  30 +| Schema 列 / 唯一索引 | 实体 `UsrUser` / `UsrUserPermission` 列映射与 V1 一致;`uk_usr_user_username` / `uk_usr_user_permission` 对齐 |
  31 +| 多租户列 `sBrandsId/sSubsidiaryId` | 由 DB 默认值 `1111111111` 兜底(spec § 2.1 系统生成字段),与 spec 设计一致 |
  32 +
  33 +### 2.2 quality(正确性 / 边界 / 错误处理 / 安全)
  34 +
  35 +- 用户名先查重再插入,且 `DuplicateKeyException` 兜底转 40901,并发安全(`UsrUserServiceImpl` 第 64-68 / 115-119 行)。
  36 +- 密码:`BCryptPasswordEncoder` 哈希;`UsrUser.sPassword` 标 `@JsonIgnore`;响应仅 `data.id`。AC6/AC7 端到端验证(`UsrUserCreateIT` 用 `passwordEncoder.matches("666666", hash)` 断言,响应体不含 "password"/"666666")。
  37 +- 关联职员 / 权限存在性校验在插入前完成,失败抛 40001 且无副作用(单测 `never().insert(...)` 断言)。
  38 +- `@Transactional(rollbackFor = Exception.class)` 覆盖 `usr_user` + `usr_user_permission` 多表写,AC2 端到端验证回滚。
  39 +- `iCanModifyBill` 在 Service 兜底为非空 `Integer` 后再做拆箱比较,无 NPE 风险。
  40 +- 全局兜底异常只记栈、对外返回 50000,不泄露内部细节。
  41 +
  42 +### 2.3 architecture(分层 / 集成 / 可扩展)
  43 +
  44 +- 分层正确:Controller 仅做 `@Valid` + 管理员前置 + 委派,不碰 Mapper;Service 持有 4 个 Mapper + Encoder。
  45 +- 包路径 `com.xly.erp.modules.usr.{controller,service,service.impl,mapper,entity,dto}` 与 spec § 4 一致;作用域限于 `modules/usr/**` + `common/**` 基础设施,未跨业务模块、未触 `frontend/`。
  46 +- 公共基础设施(`Result` / `ResultCode` / `BusinessException` / `GlobalExceptionHandler` / `BaseEntity` / `MybatisPlusConfig` / Security/JWT)一次性建好并预留后续 REQ 复用,合理。
  47 +
  48 +### 2.4 docs(注释 / 约定)
  49 +
  50 +- 各类 Javadoc 标注 REQ 追溯(`REQ-USR-001 Tn`)与 SSoT 引用,符合 CLAUDE.md 约定。
  51 +- commit 信息遵循 `<type>(<scope>): <subject> REQ-USR-001` 规范。
  52 +
  53 +---
  54 +
  55 +## 3. 非阻塞建议(口头,非 must-fix)
  56 +
  57 +1. `UsrUserServiceImpl.java:124-125`:`new LinkedHashSet<>(dedupedPermissionIds)` 包裹的列表在第 78-81 行已 `.distinct()` 去重,此处再次去重为冗余防御代码,可简化直接遍历 `dedupedPermissionIds`。无功能影响。
  58 +2. `UsrUserController.java:38-41`:管理员判定位于 `@Valid` 之后,故非管理员携带非法 body 时先返回 40001 而非 40301。这是对 spec § 3.9「先于业务校验」的合理解读(bean 校验属框架层,区别于 Service 业务规则),且 AC5 仅以合法 body 验证 40301,故不构成缺陷;若后续业务要求 40301 严格优先于 40001,可将权限判定前移至过滤器 / 拦截器层。
  59 +3. `application.yml` / `application-test.yml` 将 DB 凭据与 JWT 密钥作为 env 默认值内联。按项目约定其单一来源为 `config-vars.yaml` 经 env 注入,属既定模式(非纯硬编码),仅作安全提示。
  60 +
  61 +---
  62 +
  63 +## 4. 结论
  64 +
  65 +四维均无客观 must-fix 缺陷;测试 24/24 全绿、AC1-AC7 全覆盖;工作树干净。**判定 approve。**
... ...