Merged
Merge Request #1 · created by 朱子纯


feat(module_mod): 模块管理

模块完成报告

docs/superpowers/module-reports/2026-04-30-module_mod.md(本 MR 仓库内完整贴入下方)。



module_id: module_mod date: 2026-04-30

git_range: 642c5f9..b3817b0

模块完成报告 — module_mod 模块管理

① 模块信息

  • 模块 ID: module_mod
  • 模块名: 模块管理
  • 开发区间: 642c5f9..b3817b0(33 commits,4035 行新增)
  • 分支: module-module_mod
  • 起点:项目首个模块(首个 REQ 同时承担 Spring Boot 工程脚手架建立)

② REQ 完成清单

  • REQ-MOD-001 — 模块新增
    • spec: docs/superpowers/specs/2026-04-29-REQ-MOD-001.md
    • plan: docs/superpowers/plans/2026-04-29-REQ-MOD-001.md
    • review: docs/superpowers/reviews/2026-04-29-REQ-MOD-001.md
  • REQ-MOD-002 — 模块修改
    • spec: docs/superpowers/specs/2026-04-29-REQ-MOD-002.md
    • plan: docs/superpowers/plans/2026-04-29-REQ-MOD-002.md
    • review: docs/superpowers/reviews/2026-04-29-REQ-MOD-002.md
  • REQ-MOD-003 — 模块删除
    • spec: docs/superpowers/specs/2026-04-29-REQ-MOD-003.md
    • plan: docs/superpowers/plans/2026-04-29-REQ-MOD-003.md
    • review: docs/superpowers/reviews/2026-04-29-REQ-MOD-003.md
  • REQ-MOD-004 — 模块查询
    • spec: docs/superpowers/specs/2026-04-29-REQ-MOD-004.md
    • plan: docs/superpowers/plans/2026-04-29-REQ-MOD-004.md
    • review: docs/superpowers/reviews/2026-04-29-REQ-MOD-004.md

③ 文件变更表

文件 操作 说明
backend/pom.xml 新建 Spring Boot 3.3.5 + MyBatis-Plus 3.5.9 + Flyway + jjwt 0.12.6
backend/.gitignore 新建 target / *.iml / .idea
backend/src/main/java/com/xly/erp/ErpApplication.java 新建 Spring Boot 启动类 + EnableConfigurationProperties
backend/src/main/java/com/xly/erp/common/config/MybatisPlusConfig.java 新建 @MapperScan
backend/src/main/java/com/xly/erp/common/config/TenantProperties.java 新建 erp.tenant.* 多租户字段
backend/src/main/java/com/xly/erp/common/config/StubSecurityProperties.java 新建 erp.security.stub-user-no / jwt-secret
backend/src/main/java/com/xly/erp/common/response/Result.java 新建 统一响应 {code,msg,data}
backend/src/main/java/com/xly/erp/common/exception/BizException.java 新建 业务异常
backend/src/main/java/com/xly/erp/common/exception/GlobalExceptionHandler.java 新建 @RestControllerAdvice 三类 handler
backend/src/main/java/com/xly/erp/common/security/JwtUtil.java 新建 HS256 sign/parse
backend/src/main/java/com/xly/erp/common/security/JwtAuthenticationFilter.java 新建 OncePerRequestFilter 解析 token
backend/src/main/java/com/xly/erp/common/security/SecurityConfig.java 新建 /api/mod/** permitAll(USR-004 stub)
backend/src/main/java/com/xly/erp/common/security/SecurityContextHelper.java 新建 currentUserNo 含 anonymous 识别
backend/src/main/java/com/xly/erp/module/mod/entity/Module.java 新建 tModule 1:1 PO(17 字段)
backend/src/main/java/com/xly/erp/module/mod/dto/CreateModuleDTO.java 新建 REQ-MOD-001 入参(Bean Validation)
backend/src/main/java/com/xly/erp/module/mod/dto/UpdateModuleDTO.java 新建 REQ-MOD-002 入参(剔除 sProcedureName)
backend/src/main/java/com/xly/erp/module/mod/vo/ModuleTreeVO.java 新建 REQ-MOD-004 出参(递归 children)
backend/src/main/java/com/xly/erp/module/mod/mapper/ModuleMapper.java 新建 BaseMapper + 4 个自定义 SELECT
backend/src/main/java/com/xly/erp/module/mod/service/ModuleService.java 新建 create/update/delete/listTree
backend/src/main/java/com/xly/erp/module/mod/service/impl/ModuleServiceImpl.java 新建 含枚举/父链/子模块/拼树 全部业务校验
backend/src/main/java/com/xly/erp/module/mod/controller/ModuleController.java 新建 POST/PUT/DELETE/GET /api/mod/modules
backend/src/main/resources/application.yml 新建 DB / Flyway / 端口 / erp.* 配置
backend/src/main/resources/application-test.yml 新建 test profile override
backend/src/main/resources/logback-spring.xml 新建 默认 console appender
backend/src/test/java/com/xly/erp/SmokeTest.java 新建 Spring 启动 + Flyway apply 验证
backend/src/test/java/com/xly/erp/common/exception/GlobalExceptionHandlerTest.java 新建 4 用例(standalone MockMvc)
backend/src/test/java/com/xly/erp/common/security/JwtUtilTest.java 新建 3 用例
backend/src/test/java/com/xly/erp/common/security/TestJwtHelper.java 新建 测试辅助签发 JWT
backend/src/test/java/com/xly/erp/common/security/JwtAuthenticationFilterTest.java 新建 3 用例(filter 三分支)
backend/src/test/java/com/xly/erp/module/mod/mapper/ModuleMapperIT.java 新建 5 用例(insert/parent/child queries)
backend/src/test/java/com/xly/erp/module/mod/service/ModuleServiceImplTest.java 新建 25 用例(create/update/delete/listTree)
backend/src/test/java/com/xly/erp/module/mod/controller/ModuleControllerIT.java 新建 26 用例(4 接口端到端 + JWT 路径)
docs/superpowers/specs/2026-04-29-REQ-MOD-{001,002,003,004}.md 新建 4 份功能规格
docs/superpowers/plans/2026-04-29-REQ-MOD-{001,002,003,004}.md 新建 4 份 TDD 计划
docs/superpowers/reviews/2026-04-29-REQ-MOD-{001,002,003,004}.md 新建 4 份 AI 自审报告
docs/superpowers/module-reports/module_mod-test-gate.md 新建 本模块 test-gate 证据
docs/08-模块任务管理.md 修改 4 个 REQ checkbox 勾上
scripts/setup-test-db.sh 修改 macOS Homebrew mysql-client 路径自动 prepend
scripts/test.sh 修改 frontend 段在 frontend/ 缺失时跳过

④ 数据库使用表

  • 读: tModule(REQ-MOD-001/002/003/004 均涉及)
  • 写: tModule
    • INSERT:REQ-MOD-001(新增)
    • UPDATE:REQ-MOD-002(更新可编辑字段,依赖 MyBatis-Plus FieldStrategy.NOT_NULL 跳过 null 不动 sProcedureName/sCreatedBy/标准列);REQ-MOD-003(软删除:bDeleted=1 + tDeletedDate + sDeletedBy

⑤ 测试结果

  • scripts/test.sh 最终:GREEN
  • 通过: 67 / 失败: 0 / 跳过: 0(前端段因 frontend/ 未初始化而 skip 不计入)
  • 覆盖率:未配置 jacoco,本期不报告(建议 USR 模块开始前在 pom 引入)
  • 详见: docs/superpowers/module-reports/module_mod-test-gate.md
  • 测试分布:
    • SmokeTest: 1
    • GlobalExceptionHandlerTest: 4
    • JwtUtilTest: 3
    • JwtAuthenticationFilterTest: 3
    • ModuleMapperIT: 5
    • ModuleServiceImplTest: 25
    • ModuleControllerIT: 26

⑥ 本模块新增 Migration

—(本模块无 schema 改动;tModule 表由 A4 阶段 V1__initial_schema.sql 已落地)

⑦ 跨模块改动清单(软规则 S2)

无跨模块改动。本模块所有源码改动均位于 backend/src/main/java/com/xly/erp/module/mod/** + backend/src/main/java/com/xly/erp/common/**(首 REQ 必要的全局基础设施:Result/Exception/Security/Config)+ backend/src/test/**common/ 下的类(Result / GlobalExceptionHandler / JwtAuthenticationFilter / SecurityConfig 等)属于"项目级共用脚手架",由首 REQ MOD-001 一次建立,后续模块复用,不视为 S2 跨模块。

⑧ 偏离 spec 清单

  • REQ-MOD-002:错误码段位与 docs/05 偏离——MOD-002 spec 选择复用 MOD-001 的 40010(显示类型枚举非法),而 docs/05 § REQ-MOD-002 错误码列表只列 40001/40021/40400。 (原因: 同字段在两个接口语义一致更优;spec § 业务规则 #2 已显式声明该决策,docs/05 后续可补一行)
  • REQ-MOD-002:spec 与 plan 写"controller 先 trim",实际实现 trim 在 service。 (原因: service 集中归一化更易测,行为等价;REQ-MOD-004 review 已指出,建议改 spec 文案对齐)
  • REQ-MOD-003:未实现 docs/05 § REQ-MOD-003 列出的 40902 外部引用拦截。 (原因: docs/03 当前 schema 中 tModule 无引用方表;spec § 业务规则 #3 + § 实现范围与边界抉择 #4 双处显式声明本期不实现,待引用方表落地后回填)
  • REQ-MOD-004:拼树策略不扩展祖先链——子节点命中而父节点未命中时,子节点直接挂为森林 root。 (原因: spec § 实现范围与边界抉择 #1 已声明,REQ 卡仅要求"以树形展示匹配结果",森林是合法树形;扩展祖先需二次查询或 CTE,复杂度收益不匹配本期需求)
  • REQ-MOD-004:LIKE 通配符 % / _ 不做转义。 (原因: spec § 边界与约束已声明,业务上不敏感;docs/05 未要求;后续可通过 replace("%","\\%") 收口)

⑨ AI reviewer 报告汇总

  • REQ-MOD-001: round 1 — approve(link: docs/superpowers/reviews/2026-04-29-REQ-MOD-001.md)
  • REQ-MOD-002: round 1 — approve(link: docs/superpowers/reviews/2026-04-29-REQ-MOD-002.md)
  • REQ-MOD-003: round 1 — approve(link: docs/superpowers/reviews/2026-04-29-REQ-MOD-003.md)
  • REQ-MOD-004: round 1 — approve(link: docs/superpowers/reviews/2026-04-29-REQ-MOD-004.md)

全部 round 1 一次性通过;4 份 review 共 25 条 nice-to-have,无 must-fix。

⑩ 已知问题

整合自 4 份 review 的非阻塞 nice-to-have,按主题分组:

鉴权 stub 收尾(USR-004 闭环时一次性处理)

  1. SecurityConfigrequestMatchers("/api/mod/**").permitAll() → 改为 authenticated()hasAuthority('SUPER_ADMIN')(按 docs/05 § 各 REQ 的 Permission 字段精细化)
  2. ModuleServiceImpl#createstub.getStubUserNo() 回退路径需移除(sCreatedBy 必须来自 JWT principal)
  3. 6 处 IT stub 用例(postWithoutJwt_* / putWithoutJwt_* / deleteWithoutJwt_* / getWithoutJwt_*)缺 // REQ-MOD-001 stub: see USR-004 follow-up 锚点;USR-004 上线时 grep 替换会漏

架构遗留

  1. backend/src/main/java/com/xly/erp/module/mod/entity/Module.java 类名 Modulejava.lang.Module(JPMS)冲突;建议未来重命名为 ModuleEntityTModule
  2. JwtAuthenticationFilter@Component 同时被 Spring Security addFilterBefore 与原生 servlet 注册重复登记(OncePerRequestFilter 防住执行,但作用域不清);建议 USR-004 时改为 @Bean + FilterRegistrationBean(setEnabled(false))
  3. JwtUtil 暴露两个 public 构造器,JwtUtil(String secret) 实质 test-only;可改 package-private + 注释

配置 / 校验

  1. application.yml${JWT_SECRET} 缺 fail-fast 默认值;建议改为 ${JWT_SECRET:?JWT_SECRET 必须从 .env.local 注入}
  2. application-dev.yml 缺失(docs/09 § 二 列出但未生成);下一个模块本机 dev 启动时需要
  3. GlobalExceptionHandler#handleAnyHttpMessageNotReadableException / HttpRequestMethodNotSupportedExceptioncode=50000(应当是 40001);建议增加专用 4xx handler
  4. DTO iParentId / iSortOrder@PositiveOrZero / @Min 约束
  5. ModuleServiceImpl#updateById / delete 的返回值(受影响行数)丢弃;并发场景下 affected=0 仍返回成功——可断言 affected==1 否则抛兜底异常

测试覆盖缺口(非阻塞)

  1. @Size 长度溢出(如 sProcedureName > 100 字符)路径仅在"缺必填"用例顺带覆盖,未独立断言
  2. iParentId 指向 bDeleted=1 旧记录是否回 40021 未单独验证
  3. 环检测 MAX_PARENT_DEPTH=50 超深路径仅有间接覆盖(未构造 50 层脏数据链)
  4. tCreateDate / sBrandsId / sSubsidiaryId 在 update / delete IT 端未端到端断言保留(service 单测已 captureArgument 验 entity 字段为 null + 依赖 NOT_NULL 策略)
  5. 业务方法行内 // REQ-MOD-XXX: 锚点缺失(4 处:create/update/delete/listTree);建议下个模块开始前一次性补齐
  6. ModuleMapperIT#selectActiveByKeyword_filtersAndOrders 第 108–110 行 namesByEmpty 局部变量构造后未被任何 assert 使用(dead code),建议清理

⑪ 下一模块预览

module_usr 用户管理(docs/02 § 二 顺序的 REQ 5–8)

  • REQ-USR-001 用户新增(依赖 tStaff / tPermissionCategory 作下拉数据源)
  • REQ-USR-002 用户修改
  • REQ-USR-003 用户查询(多条件 + 分页)
  • REQ-USR-004 用户登录(关键——完成后才能把 /api/mod/**/api/usr/** 的 stub permitAll 收紧为 hasAuthority('SUPER_ADMIN'),并移除 service 层 stub.getStubUserNo() 回退路径)

预期范围:backend/src/main/java/com/xly/erp/module/usr/** 全新模块树;tUser / tStaff / tPermissionCategory / tUserPermission schema 已在 V1 就位;JWT 签发由 USR-004 接管(覆写 MOD 期间手工签发的逻辑)。

USR 模块开工前的"扫尾建议":

  • 处理 § ⑩ #16(业务方法行内 REQ 锚点 4 处)
  • 处理 § ⑩ #8(生成 application-dev.yml 占位)
  • 处理 § ⑩ #17(删除 dead code)

这三项是低成本一次性收口,建议作为 module_usr 的 REQ-USR-001 开工前第一个 chore commit 完成;其余 § ⑩ 项均围绕 USR-004 / 后续模块自然解决。

⑫ MR 链接

待 mr-create 填入。


本地闸门证据

  • test.sh: green(subagent: a7d5818a97a7b5c66)

审核入口

  • 本 MR = 模块 module_mod 的唯一人工介入点
  • Approve + Merge 后,下次用户运行 /erp-workflow:coding-start 时入口会自动扫描到 GitLab API state=merged,探测默认分支后 git pull --ff-only 同步并推进下一模块

From module-module_mod into master

Merged by 朱子纯

1 participants