Commit ec4bf2b27d686b6100e0886ef2f2f193ae59f136
1 parent
f4449664
docs(module_usr): add module completion report
Showing
1 changed file
with
164 additions
and
0 deletions
docs/superpowers/module-reports/2026-04-30-module_usr.md
0 → 100644
| 1 | +--- | |
| 2 | +module_id: module_usr | |
| 3 | +date: 2026-04-30 | |
| 4 | +git_range: master..HEAD (31 commits) | |
| 5 | +--- | |
| 6 | + | |
| 7 | +# 模块完成报告 — module_usr 用户管理 | |
| 8 | + | |
| 9 | +## ① 模块信息 | |
| 10 | +- 模块 ID: module_usr | |
| 11 | +- 模块名: 用户管理 | |
| 12 | +- 开发区间: 31 commits,~4149 行新增 | |
| 13 | +- 分支: `module-module_usr` | |
| 14 | +- **里程碑**:USR-004 完成 stub 闭环——整个项目 SecurityConfig 收紧到 `登录接口外全部 authenticated()` | |
| 15 | + | |
| 16 | +## ② REQ 完成清单 | |
| 17 | + | |
| 18 | +- [x] REQ-USR-001 — 用户新增 | |
| 19 | + - spec: docs/superpowers/specs/2026-04-30-REQ-USR-001.md | |
| 20 | + - plan: docs/superpowers/plans/2026-04-30-REQ-USR-001.md | |
| 21 | + - review: docs/superpowers/reviews/2026-04-30-REQ-USR-001.md | |
| 22 | +- [x] REQ-USR-002 — 用户修改 | |
| 23 | + - spec/plan/review: 同名 2026-04-30-REQ-USR-002 三件套 | |
| 24 | +- [x] REQ-USR-003 — 用户查询 | |
| 25 | + - spec/plan/review: 同名 2026-04-30-REQ-USR-003 三件套 | |
| 26 | +- [x] REQ-USR-004 — 用户登录(含 Stub 闭环) | |
| 27 | + - spec/plan/review: 同名 2026-04-30-REQ-USR-004 三件套 | |
| 28 | + | |
| 29 | +## ③ 文件变更表 | |
| 30 | + | |
| 31 | +| 文件 | 操作 | 说明 | | |
| 32 | +|---|---|---| | |
| 33 | +| backend/src/main/java/com/xly/erp/module/usr/entity/User.java | 新建 | 17 字段 1:1 映射 tUser | | |
| 34 | +| backend/src/main/java/com/xly/erp/module/usr/entity/UserPermission.java | 新建 | 8 字段映射 tUserPermission | | |
| 35 | +| backend/src/main/java/com/xly/erp/module/usr/dto/CreateUserDTO.java | 新建 | USR-001 入参 | | |
| 36 | +| backend/src/main/java/com/xly/erp/module/usr/dto/UpdateUserDTO.java | 新建 | USR-002 入参(无 sPasswordHash) | | |
| 37 | +| backend/src/main/java/com/xly/erp/module/usr/dto/LoginDTO.java | 新建 | USR-004 登录入参 | | |
| 38 | +| backend/src/main/java/com/xly/erp/module/usr/vo/UserListVO.java | 新建 | USR-003 列表 VO(11 字段,含 LEFT JOIN tStaff) | | |
| 39 | +| backend/src/main/java/com/xly/erp/module/usr/vo/UserBriefVO.java | 新建 | USR-004 用户简表 | | |
| 40 | +| backend/src/main/java/com/xly/erp/module/usr/vo/LoginVO.java | 新建 | USR-004 登录响应 | | |
| 41 | +| backend/src/main/java/com/xly/erp/module/usr/mapper/UserMapper.java | 新建 + 多次扩展 | BaseMapper + 自定义查询 + 登录用方法 | | |
| 42 | +| backend/src/main/java/com/xly/erp/module/usr/mapper/UserPermissionMapper.java | 新建 + deleteByUserId | USR-001 + USR-002 | | |
| 43 | +| backend/src/main/java/com/xly/erp/module/usr/mapper/StaffMapper.java | 新建 | 最小 existsActiveById | | |
| 44 | +| backend/src/main/java/com/xly/erp/module/usr/mapper/PermissionCategoryMapper.java | 新建 | 批量校验 countActiveByIds | | |
| 45 | +| backend/src/main/resources/mapper/usr/UserMapper.xml | 新建 | USR-003 动态 SQL(pageWithFilter / countWithFilter) | | |
| 46 | +| backend/src/main/java/com/xly/erp/module/usr/security/LoginAttemptStore.java | 新建 | USR-004 内存失败计数 + 锁定 | | |
| 47 | +| backend/src/main/java/com/xly/erp/module/usr/service/UserService.java | 新建 + 4 次扩展 | create/update/list/login | | |
| 48 | +| backend/src/main/java/com/xly/erp/module/usr/service/impl/UserServiceImpl.java | 新建 + 4 次扩展 | 全部业务逻辑 | | |
| 49 | +| backend/src/main/java/com/xly/erp/module/usr/controller/UserController.java | 新建 | POST/PUT/GET /api/usr/users | | |
| 50 | +| backend/src/main/java/com/xly/erp/module/usr/controller/AuthController.java | 新建 | POST /api/usr/auth/login | | |
| 51 | +| backend/src/main/java/com/xly/erp/common/config/PasswordEncoderConfig.java | 新建 | BCryptPasswordEncoder bean(独立于 SecurityConfig,避免 NONE 上下文丢失) | | |
| 52 | +| backend/src/main/java/com/xly/erp/common/security/JwtAuthenticationEntryPoint.java | 新建 | USR-004 未认证返回 code=20001 | | |
| 53 | +| backend/src/main/java/com/xly/erp/common/security/SecurityConfig.java | 修改 | USR-001 加 /api/usr/** permitAll → USR-004 收紧到仅 /api/usr/auth/login permitAll + entryPoint | | |
| 54 | +| backend/src/main/java/com/xly/erp/common/security/JwtUtil.java | 修改 | 加 signRefresh + 通用 sign(userNo, ttl) | | |
| 55 | +| backend/src/main/java/com/xly/erp/module/mod/service/impl/ModuleServiceImpl.java | 修改 | USR-004 移除 stub.getStubUserNo() fallback | | |
| 56 | +| backend/src/test/java/com/xly/erp/module/usr/**/* (5 文件) | 新建 | UserMapperIT(7) / StaffMapperIT(1) / PermissionCategoryMapperIT(1) / UserServiceImplTest(35) / UserControllerIT(27) / LoginAttemptStoreTest(5) / AuthControllerIT(5) | | |
| 57 | +| backend/src/test/java/com/xly/erp/module/mod/controller/ModuleControllerIT.java | 修改 | USR-004 闭环:4 处 stub IT 期望从 200 改 20001 | | |
| 58 | +| backend/src/test/java/com/xly/erp/common/security/JwtUtilTest.java | 修改 | 加 signRefresh 验证 | | |
| 59 | +| docs/superpowers/specs|plans|reviews/2026-04-30-REQ-USR-{001..004}.md | 新建 | 12 份文档 | | |
| 60 | +| docs/superpowers/module-reports/module_usr-test-gate.md | 新建 | 本模块 test-gate 证据 | | |
| 61 | +| docs/08-模块任务管理.md | 修改 | 4 个 REQ checkbox 勾上 | | |
| 62 | + | |
| 63 | +## ④ 数据库使用表 | |
| 64 | + | |
| 65 | +- 读:`tUser` / `tStaff` / `tPermissionCategory`(各 REQ 的存在性校验 / JOIN 显示) | |
| 66 | +- 写: | |
| 67 | + - `tUser`:INSERT (USR-001) / UPDATE 可编辑列 (USR-002) / UPDATE tLastLoginDate (USR-004) | |
| 68 | + - `tUserPermission`:INSERT (USR-001) / DELETE+INSERT 重建 (USR-002) | |
| 69 | + | |
| 70 | +## ⑤ 测试结果 | |
| 71 | + | |
| 72 | +- `scripts/test.sh` 最终:**GREEN** | |
| 73 | +- 通过: 149 / 失败: 0 / 跳过: 0(前端段因 frontend/ 未初始化而 skip) | |
| 74 | +- 详见: docs/superpowers/module-reports/module_usr-test-gate.md | |
| 75 | +- 测试分布: | |
| 76 | + - SmokeTest: 1 | |
| 77 | + - 全局基础设施: GlobalExceptionHandlerTest 4 / JwtUtilTest 4 / JwtAuthenticationFilterTest 3 | |
| 78 | + - MOD 模块: ModuleMapperIT 5 / ModuleServiceImplTest 25 / ModuleControllerIT 26 | |
| 79 | + - USR 模块: UserMapperIT 7 / StaffMapperIT 1 / PermissionCategoryMapperIT 1 / LoginAttemptStoreTest 5 / UserServiceImplTest 35 / UserControllerIT 27 / AuthControllerIT 5 | |
| 80 | + | |
| 81 | +## ⑥ 本模块新增 Migration | |
| 82 | + | |
| 83 | +—(无 schema 改动;本模块 4 张表均在 V1 就位) | |
| 84 | + | |
| 85 | +## ⑦ 跨模块改动清单(软规则 S2) | |
| 86 | + | |
| 87 | +**1 处跨模块改动**(USR-004 stub 闭环必需,spec 已声明): | |
| 88 | + | |
| 89 | +- `backend/src/main/java/com/xly/erp/module/mod/service/impl/ModuleServiceImpl.java:create()/delete()` — 移除 `stub.getStubUserNo()` fallback | |
| 90 | +- `backend/src/test/java/com/xly/erp/module/mod/controller/ModuleControllerIT.java` — 4 处 `*WithoutJwt_permitAllStub_*` 用例改名为 `*WithoutJwt_returns20001`,期望 200 → 20001 | |
| 91 | +- `backend/src/test/java/com/xly/erp/module/mod/service/ModuleServiceImplTest.java` — 2 处 sCreatedBy 期望从 "STUB_ADMIN" 改为 null | |
| 92 | + | |
| 93 | +**原因 / 影响评估**: | |
| 94 | +- 原因:USR-004 是模块循环最后一个 REQ,按 docs/02 § 二 顺序正好在收尾。spec 把 stub 闭环作为 Phase B 纳入本 REQ;项目首次具备真正的 JWT 鉴权能力,必须把 MOD 模块 stub-friendly 的测试期望同步收紧 | |
| 95 | +- 影响评估:MOD 模块业务逻辑未变(仅 fallback 一行被删,行为等价于"sCreatedBy 必须由 SecurityContextHelper 提供"——authenticated 守卫保证非 null);MOD 模块的 IT 测试在改写后行为更接近生产实际(无 token 必拒),增强了回归质量 | |
| 96 | + | |
| 97 | +## ⑧ 偏离 spec 清单 | |
| 98 | + | |
| 99 | +- **REQ-USR-001 & spec § 实现范围 #3**:spec 写 BCryptPasswordEncoder bean 在 SecurityConfig 注册,实际移到独立 `PasswordEncoderConfig.java`。原因:SecurityConfig `@ConditionalOnWebApplication(SERVLET)` 在 webEnvironment=NONE 的 mapperIT 上下文不加载。良性设计修正——密码编码器应是领域基础设施而非 Web 安全基础设施。 | |
| 100 | +- **REQ-USR-002 & spec/plan § "controller 先 trim"**:实际实现 trim 在 service。功能等价;spec 文字与实现微差。 | |
| 101 | +- **REQ-USR-003 & plan § 文件变更清单**:未创建 `UserListQuery` DTO,5 参直接传 service。简化合理。 | |
| 102 | +- **REQ-USR-002 错误码 40022**:docs/05 § USR-002 错误码列表未列 40022;本实现复用 USR-001 已建立的语义(同字段两个接口错误码一致更优)。 | |
| 103 | +- **REQ-USR-004 LoginDTO.version `@NotBlank`**:spec § 输入说"仅记录, 不参与校验",实际加了 @NotBlank。微差。 | |
| 104 | + | |
| 105 | +## ⑨ AI reviewer 报告汇总 | |
| 106 | + | |
| 107 | +- REQ-USR-001: round 1 — approve | |
| 108 | +- REQ-USR-002: round 1 — approve | |
| 109 | +- REQ-USR-003: round 1 — approve | |
| 110 | +- REQ-USR-004: round 1 — approve(含 Phase B stub 闭环) | |
| 111 | + | |
| 112 | +4/4 round 1 一次性通过;4 份 review 共约 28 条 nice-to-have,无 must-fix。 | |
| 113 | + | |
| 114 | +## ⑩ 已知问题 | |
| 115 | + | |
| 116 | +整合自 4 份 review 的非阻塞 nice-to-have,按主题分组: | |
| 117 | + | |
| 118 | +**架构遗留(建议下一模块开始前 chore commit 一次性收口)** | |
| 119 | +1. `ModuleServiceImpl` / `UserServiceImpl` 移除 stub fallback 后 `private final StubSecurityProperties stub` 字段已无引用(但构造器仍注入);按 surgical-changes 原则建议删字段 + 构造器参数 + 测试 setUp | |
| 120 | +2. `JwtAuthenticationFilter` 仍带 `@Component`,与 SecurityConfig `addFilterBefore` 重叠注册;可改 @Bean + FilterRegistrationBean disable | |
| 121 | +3. `JwtUtil` 暴露两个 public 构造器;`JwtUtil(String secret)` 实质 test-only | |
| 122 | +4. 业务方法 (create/update/delete/listTree/login 5 处) 缺行内 `// REQ-USR-XXX` 锚点 | |
| 123 | +5. entity `Module` 类名与 `java.lang.Module` 冲突 | |
| 124 | +6. `application-dev.yml` 缺失(docs/09 § 二 列出) | |
| 125 | + | |
| 126 | +**测试覆盖增强(非阻塞)** | |
| 127 | +7. `LoginAttemptStoreTest.lockExpiresAfterDuration` 未驱动同 userName 跨过 lockExpireAt 验证 records.remove 自动清除 | |
| 128 | +8. PUT-stub-regression IT 只断单列 unchanged,建议同时断 sCreatedBy / tCreateDate | |
| 129 | +9. USR-001/002 permissionCategoryIds 重复 id 假阴性(IN 隐式去重,建议 service `distinct`) | |
| 130 | +10. USR-003 响应 records 缺直接 `has("sPasswordHash") == false` 断言 | |
| 131 | +11. USR-003 ORDER BY iIncrement DESC / tLastLoginDate JSON ISO 格式无显式断言 | |
| 132 | +12. `tCreateDate` / `sBrandsId` / `sSubsidiaryId` 在 update / delete IT 端未端到端断言保留 | |
| 133 | +13. `iParentId` 指向 `bDeleted=1` 旧记录是否回 40021 未单独验证 | |
| 134 | +14. AuthControllerIT 字段级负例(仅缺 sUserName)未单独覆盖 | |
| 135 | + | |
| 136 | +**配置 / 校验** | |
| 137 | +15. application.yml `${JWT_SECRET}` 缺 fail-fast 默认值 | |
| 138 | +16. GlobalExceptionHandler `handleAny(Exception)` 把 4xx 框架异常转 50000 | |
| 139 | +17. DTO `iParentId` / `iSortOrder` 缺 `@PositiveOrZero` / `@Min` 约束 | |
| 140 | +18. `LoginDTO.version` `@NotBlank` 与 spec "仅记录" 不一致 | |
| 141 | + | |
| 142 | +**信息泄漏** | |
| 143 | +19. UserListVO 设计上不暴露敏感字段,但 IT 缺 regression-locking 断言 | |
| 144 | + | |
| 145 | +## ⑪ 下一模块预览 | |
| 146 | + | |
| 147 | +**项目所有 REQ 已完成**:docs/02 § 二 共 8 个 REQ(MOD 4 + USR 4),全部 review approve 完毕。 | |
| 148 | + | |
| 149 | +USR 模块合并到 master 后,整个项目处于: | |
| 150 | +- 后端工程:149 用例全绿 | |
| 151 | +- 鉴权:仅 `POST /api/usr/auth/login` 公开,其余 `authenticated()` | |
| 152 | +- 数据库:tUser / tStaff / tPermissionCategory / tUserPermission / tModule 全部就位 | |
| 153 | + | |
| 154 | +**后续工作(不属于本期 REQ 范围,建议作为新 epic)**: | |
| 155 | +- 引入 frontend/(React + Vite) | |
| 156 | +- 引入 Redis 替换 LoginAttemptStore 内存实现 | |
| 157 | +- jacoco 覆盖率 | |
| 158 | +- application-dev.yml + dev profile | |
| 159 | +- `ModuleEntity` 重命名(Module 与 java.lang.Module 冲突) | |
| 160 | +- 4 处行内 `// REQ-XXX` 锚点补齐 | |
| 161 | + | |
| 162 | +## ⑫ MR 链接 | |
| 163 | + | |
| 164 | +待 mr-create 填入。 | ... | ... |