# 模块完成报告 — USR 用户管理(backend) > 生成时间:2026-06-01 CST > 模块 id:usr|阶段:后端(backend)|功能分支:`module-usr`(自默认分支 `master` 分叉) > 本报告为标准化 12 节模块完成报告,供 milestone 标记前置。摘要级(不引入 diff 正文)。 --- ## ① 模块概述 - **模块名称**:USR 用户管理(`com.xly.erp.modules.usr`)。 - **业务范围**:企业内部管理系统的用户账号全生命周期与登录认证,覆盖用户新增、修改、分页查询、登录认证 4 个后端 REQ。 - **依赖**:无(docs/08 § 二 标注「依赖: 无」),为整个 ERP 的基础模块。 - **路径作用域**:`backend/src/main/java/com/xly/erp/modules/usr/**` + 公共基础设施 `com/xly/erp/common/**`(统一响应 / 异常 / 安全 / JWT / BaseEntity,本模块首次落地,供后续模块复用)。 - **本阶段产出范围**:controller / service / repository(mapper) / DTO / VO / 校验 / REST 契约实现;不触 `frontend/`(UI 推迟到前端阶段);本模块未新增 SQL migration(复用 A4 生成的 `V1__initial_schema.sql`)。 --- ## ② 需求覆盖(REQ 清单 + spec 摘要) 本模块 4 个 REQ 全部完成并在 `docs/08-模块任务管理.md` § 二 勾选为 `[x]`: | REQ | 标题 | 端点 | spec 摘要 | |---|---|---|---| | REQ-USR-001 | 增加用户 | `POST /api/usr/users` | 管理员新建用户:用户名 3-20 位唯一、密码 BCrypt(默认 `666666`)、用户类型 / 语言枚举约束、可选关联职员 + 权限组授权(多对多);多表写入事务化;新建即生效(`iIsVoid=0`)。错误码 0/40001/40301/40901。 | | REQ-USR-002 | 修改用户 | `PUT /api/usr/users/{id}` | 管理员改用户基础信息(用户号 / 关联职员 / 用户类型 / 语言 / 单据修改权限 / 作废标志 / 权限组);`sUserName` 与 `sPassword` 不可改;权限组**全量覆盖**语义;可选字段 null = 不更新(保守不清空)。错误码 0/40001/40301/40401。 | | REQ-USR-003 | 查询用户 | `GET /api/usr/users` | 任意已认证用户的只读单条件分页查询(8 个查询字段 × 3 种匹配方式);跨表 LEFT JOIN `usr_employee` 取员工名 / 部门;文本模糊(LIKE 转义)/ 枚举 / 布尔 / 日期精确匹配;分页参数非法 → `42201`,数据越界返回最后一页;密码绝不返回。错误码 0/40001/42201(+401 未认证)。 | | REQ-USR-004 | 登录用户 | `POST /api/usr/login`(+ 配套 `GET /api/usr/companies`) | 用户名 + 密码 + 版本(companyId) 认证:BCrypt 比对 → 签发带 exp 的无状态 JWT + 更新 `tLastLoginDate`;防账号枚举(不存在/密码错误同码同提示);禁用账号 `40302`;进程内登录限流 `42901`(默认 5 次/300 秒)。配套补齐只读公司列表端点支撑登录页「版本」下拉。错误码 0/40001/40101/40302/42901(+401)。 | > spec 全文:`docs/superpowers/specs/2026-06-01-REQ-USR-00{1,2,3,4}.md`。各 spec § 8 已逐条登记自主决策(见本报告 § ⑩)。 --- ## ③ 文件变更摘要(git diff --stat,master...HEAD) - **提交数**:53 个 commit(`git log master..HEAD --oneline`)。 - **变更规模**:85 个文件,+8280 / -5 行。 - **新增生产代码**(`backend/src/main/java/com/xly/erp/`,A=新增): - 公共基础设施 `common/`:`base/BaseEntity`、`config/{MybatisPlusConfig,SecurityConfig}`、`exception/{BusinessException,GlobalExceptionHandler}`、`response/{Result,ResultCode,PageResult}`、`security/{JwtUtil,JwtAuthenticationFilter,SecurityUtil}`、`ErpApplication`。 - USR 模块 `modules/usr/`:controller(`UsrUserController`、`UsrAuthController`)、service(`UsrUserService(+Impl)`、`UsrAuthService(+Impl)`)、mapper(`UsrUser/UsrCompany/UsrEmployee/UsrPermission/UsrUserPermission` Mapper)、entity(`UsrUser/UsrCompany/UsrEmployee/UsrPermission/UsrUserPermission`)、dto(`CreateUserDTO/UpdateUserDTO/UserQueryDTO/UserQueryCondition/LoginDTO`)、vo(`UserVO/LoginVO/CompanyOptionVO`)。 - 资源:`application.yml`、`application-test.yml`、`mapper/usr/UsrUserMapper.xml`(跨表分页查询)。 - 构建:`backend/pom.xml`(Spring Boot + MyBatis-Plus + Flyway 10.10.0 + JWT,`java.version=17`)、`backend/checkstyle.xml`。 - **新增测试代码**(`backend/src/test/java/`):25 个测试类(详见 § ⑤)。 - **流程 / 文档**:`scripts/test.mjs`(M,新增 `ensureJava17()`)、`docs/08-模块任务管理.md`(M,4 个 REQ 勾选)、`docs/superpowers/{specs,plans,reviews}/2026-06-01-REQ-USR-00{1..4}*.md`(A)、`docs/superpowers/module-reports/usr-test-gate-r1.md`(A)。 - **migration**:无新增(见 § ⑥)。 - **跨模块**:无(见 § ⑦)。 --- ## ④ 读写的数据表 本模块涉及 5 张表,全部由 `sql/migrations/V1__initial_schema.sql` 建好(A4 阶段从 docs/03 翻译),本模块**未做 schema 变更**: | 表 | 操作 | 涉及 REQ | 说明 | |---|---|---|---| | `usr_user` | 读 + 写 | 001(写) / 002(写) / 003(读) / 004(读+写 `tLastLoginDate`) | 用户主表,主键 `iIncrement`,唯一索引 `uk_usr_user_username`。 | | `usr_user_permission` | 写 | 001(批量插入) / 002(全量覆盖) | 用户-权限多对多关联表,唯一索引 `uk_usr_user_permission(iUserId,iPermissionId)`。 | | `usr_employee` | 读 | 001/002(存在性校验) / 003(LEFT JOIN 取员工名/部门) | 职员表;与 `usr_user` 外键 `fk_usr_user_employee` ON DELETE SET NULL。 | | `usr_permission` | 读 | 001/002(权限 id 存在性校验) | 权限组表。 | | `usr_company` | 读 | 004(版本下拉 + companyId 存在性校验) | 公司/版本支撑表,与 `usr_user` 无外键(仅登录时选择)。 | > 严格遵循 docs/04 § 3.4:仅经 Mapper 访问;查询不 SELECT `sPassword`;VO 不含密码列;SQL 参数化防注入,LIKE 通配符转义。 --- ## ⑤ 测试与质量闸(test-gate) **flake 判定:无 flake。** test-gate attempt 序列仅 `r1`,且 r1 = **GREEN**(首跑即绿)。 > 说明:历史上曾在 JDK25 默认工具链下有 5 次 RED 记录(旧 r1–r5),其根因为 Mockito/Byte Buddy 不支持 JDK25 的 class file 版本(69),导致 `UsrAuthServiceImplTest` 对 `JwtUtil` 整片 `Mockito cannot mock` 报 error(终态 88 跑 / 9 error)。该批旧证据因属过期工具链问题已在 commit `282a524` 移除,并非当前 attempt 序列的一部分;工具链修复在 `dbc3454`(`scripts/test.mjs` 新增 `ensureJava17()`,把后端测试 JVM 的 `JAVA_HOME` 固定到 Java 17)。本模块当前 attempt 序列从修复后重新起算,r1 首跑即绿,故不构成「red→green flake」。 **本次 r1 证据**(`docs/superpowers/module-reports/usr-test-gate-r1.md`): - 执行命令:`node scripts/test.mjs`(内部 `ensureJava17()` → `/opt/homebrew/Cellar/openjdk@17/17.0.19/.../Home`)。 - 工具链确认:Spring Boot 测试日志 `Starting ErpApplicationTests using Java 17.0.19`;Maven 3.9.15 / Java 17.0.19。 - 5 级闸门:1/5 setup-db ✅、2/5 build(`mvn -q -B -DskipTests package`) ✅、3/5 lint(`mvn -q -B checkstyle:check`) ✅、4/5 unit+integration(`mvn -q -B test`) ✅、5/5 e2e(后端无 e2e,skip)✅。 - 退出码 0,终态 `[test.mjs] GREEN`。 - **测试统计(surefire-reports 汇总)**:`Tests run: 125, Failures: 0, Errors: 0, Skipped: 0`(25 个测试类)。曾整片报错的 `UsrAuthServiceImplTest`(含 `JwtUtil` mock)本次 9/9 全绿,证明根因消除。 **测试类清单(25)**: - 公共:`ErpApplicationTests`、`SecurityConfigTest`、`GlobalExceptionHandlerTest`、`ResultTest`、`ResultCodeLoginTest`、`PageResultTest`、`JwtUtilTest`。 - DTO 校验:`CreateUserDTOValidationTest`、`UpdateUserDTOValidationTest`、`UserQueryDTOValidationTest`、`LoginDTOValidationTest`。 - VO 序列化:`UserVOJsonTest`、`LoginVOJsonTest`、`CompanyOptionVOJsonTest`。 - Mapper:`UsrUserMapperPageTest`、`UsrCompanyMapperTest`。 - Service 单测:`UsrUserServiceImplTest`(24)、`UsrAuthServiceImplTest`(9)。 - Controller 单测:`UsrUserControllerTest`(11)、`UsrAuthControllerTest`(6)。 - 端到端 IT:`UsrUserCreateIT`(5)、`UsrUserUpdateIT`(6)、`UsrUserQueryIT`(13)、`UsrLoginIT`(12)、`AuthLoginConfigIT`(1)。 --- ## ⑥ 数据库 migration **本模块未新增 migration。** - `git diff --name-only --diff-filter=A master...HEAD -- 'sql/migrations/V*.sql'` 结果为空。 - 现有唯一 migration `sql/migrations/V1__initial_schema.sql` 由 A4 阶段 `db-init` 从 `docs/03-数据库设计文档.md`(schema SSoT)翻译生成,第一行:`-- Flyway migration V1 — initial schema for 小羚羊`。 - 4 个 REQ 的 spec § 8 均明确决策「复用 V1,无 schema 变更」(4 张依赖表 `usr_user/usr_employee/usr_permission/usr_user_permission/usr_company` 结构与 docs/03 一致)。REQ-USR-004 仅对 `usr_user.tLastLoginDate` 做 UPDATE(DML 非 DDL)。 - Flyway 依赖已在 `pom.xml` 声明(`flyway-core` + `flyway-mysql` 10.10.0),schema 由 Spring Boot / 测试启动时自动 apply(符合 CLAUDE.md Schema 演化规约)。 --- ## ⑦ 跨模块改动 **无跨模块改动。** - `docs/superpowers/module-reports/usr-cross-module.md` 不存在(cross-module-log 未生成 = 本模块未触碰非当前模块的业务代码)。 - 本模块新增的 `common/**` 公共基础设施(统一响应 / 异常 / 安全 / JWT / BaseEntity)属全局基础层首次落地,非「改动其他业务模块」,不计入跨模块改动。 --- ## ⑧ 与规范 / 契约的偏离 **实现层无偏离**——4 个 REQ 的实现端点、请求/响应字段、错误码、分层、命名、统一响应、异常处理、事务、安全均与 docs/04 技术规范及 docs/05 API 契约一致(详见各 review 报告四维核对结论)。 仅记录 2 项**对 docs/05 契约的反向同步建议**(实现期已落地为代码,建议择机补入契约 SSoT,非阻塞、非违规): 1. **新增端点 `GET /api/usr/companies`**(REQ-USR-004 spec § 8 D1):docs/05 仅定义 `POST /api/usr/login`,未单列公司列表端点。为使登录链路自洽(前端需先取 companyId),后端补齐该只读放行端点。建议补入 docs/05 § REQ-USR-004。 2. **新增限流错误码 `42901`**(REQ-USR-004 spec § 8 D7):docs/05 未列该码,系为落地卡片「连续失败锁定/限流」要求引入。建议补入 docs/05 错误码段。 > 以上两项均已在 spec § 8 显式登记为「建议反向同步(非本 stage 强制)」,review 亦标为非阻塞建议。其余无任何偏离。 --- ## ⑨ 评审与验证记录 每个 REQ 均有 round-1 review(裁决 approve)+ verify(证据验证)报告,路径 `docs/superpowers/reviews/2026-06-01-REQ-USR-00{1..4}{,-verify}.md`: | REQ | review 裁决 | 关键核对结论 | |---|---|---| | REQ-USR-001 | **approve**(issues=[]) | 四维(plan-alignment / quality / architecture / docs)无 must-fix;用户名查重 + DuplicateKey 兜底并发安全;密码 BCrypt + `@JsonIgnore` 不外泄;多表写事务回滚验证;24/24 测试绿。 | | REQ-USR-002 | **approve** | 全量覆盖授权、null=不更新语义、`sUserName/sPassword` 不可改、审计字段只读均落地;权限差量覆盖与禁用实时生效端到端验证。 | | REQ-USR-003 | **approve** | 单条件 8 字段 × 3 匹配、跨表 LEFT JOIN、LIKE 转义防注入、参数非法 `42201` / 数据越界返回最后一页、密码不返回均验证。 | | REQ-USR-004 | **approve** | 认证判定顺序(限流→查用户→验密码→判禁用→校 companyId→签发+更新时间)与 spec § 8 D3 一致;防账号枚举(同码同提示);JWT 含 exp;进程内限流 `42901`;安全放行 `/api/usr/companies`。 | - 各 review 均附非阻塞口头建议(如限流计数与事务非原子、契约反向同步、冗余去重代码简化),无任何 must-fix。 - verify 报告确认各 REQ 在通过工具链下测试全绿、验收标准(AC)逐条覆盖。 - 模块级 test-gate(本报告 § ⑤)在锁定 JDK17 下 125/125 全绿,作为合并默认分支前的硬闸。 --- ## ⑩ 自主决策汇总(decisions) 本报告渲染过程中的自主决策见文末 `decisions[]`(test-gate 重跑判定、flake 归类等)。各 REQ 实现期的自主决策已在对应 spec § 8 逐条登记,要点汇总: - **语言取值锁定**:`sLanguage` ∈ {中文,英文,繁体},不取 docs/03 带审阅占位的默认值(REQ-001 D1)。 - **管理员判定口径**:以 `sUserType=超级管理员` 视为有写权限(无独立角色表)(REQ-001 D2 / 002 D6)。 - **修改语义**:可选字段 null = 不更新(保守不清空);权限组全量覆盖(REQ-002 D3/D4)。 - **查询边界**:单条件查询;参数非法 `42201` vs 数据越界返回最后一页二分;LIKE 通配符转义(REQ-003 D1/D2/D3)。 - **登录链路自洽**:补 `GET /api/usr/companies` 端点;进程内限流 `42901`(5 次/300 秒);先验密码再判禁用防枚举;JWT 默认 2 小时(REQ-004 D1/D3/D7/D10)。 - **migration**:4 个 REQ 全部复用 V1,无新增(REQ-001~004 各 Dn)。 --- ## ⑪ 已知限制 / 后续事项 1. **登录限流为进程内 MVP**:当前按 `sUserName` 在进程内存计数(默认 5 次失败 / 锁定 300 秒),分布式部署下不共享、不随 `@Transactional` 回滚(极小窗口)。技术栈虽列 Redis 但当前无连接配置,留待后续平滑替换为 Redis 原子计数(REQ-004 spec § 8 D7、review 非阻塞建议)。 2. **契约反向同步待补**:`GET /api/usr/companies` 端点与 `42901` 错误码建议补入 `docs/05-API接口契约.md`(见 § ⑧)。 3. **多租户列兜底**:`sBrandsId/sSubsidiaryId` 由 DB 默认值 `1111111111` 兜底,未引入运行时多租户上下文解析(按 spec 设计,当前阶段足够)。 4. **冗余防御代码**:`UsrUserServiceImpl` 权限去重存在一处可简化的二次去重(review 口头建议,无功能影响)。 5. **前端未实现**:FE-01~FE-04(登录页 / 主页框架 / 用户列表 / 用户单据)属前端阶段,docs/08 § 三 待办,不在本后端模块范围。 --- ## ⑫ 结论 USR 用户管理后端模块 4 个 REQ(增 / 改 / 查 / 登录)全部实现并 approve,模块级硬测试闸在锁定 JDK17 工具链下 **125/125 全绿(r1,无 flake)**,工作树干净,无新增 migration、无跨模块改动、实现层无偏离(仅 2 项非阻塞契约反向同步建议)。满足里程碑 `milestone/usr` 标记的全部前置条件。 > 证据:`docs/superpowers/module-reports/usr-test-gate-r1.md`(GREEN)。