You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

6.2 KiB

01 · 客户三 workspace 查询口径收敛(boardSummary 漂移修复 + 守恒断言)

  • Status: resolved
  • Type: task
  • 来源: /improve-codebase-architecture 2026-09-06 报告候选 #1(.scratch/architecture-review-20260906-102629.html),grilling 五决策已全部拍板

背景(缺陷事实)

CustomerMapper 的 workspace 公共 WHERE(内置视图 × 公共筛选 × groupColumn)手写了 4 份pageWorkspace 的 overview / mine+pool 两分支各一份 + boardSummary 的两分支。其中 boardSummary 的两份已漂移——相对 pageWorkspace 静默缺少 3 个条件:

  • FOLLOW_UP_DUE(待跟进视图 EXISTS)
  • industryCode
  • provinceCode

后果:同一参数下看板列头汇总数 ≠ boardCards(走 pageWorkspace)计数;javadoc 却声称「完全一致」。无测试覆盖该一致性(返工票 03 只测了 pool 拒绝)。CustomerWorkspacePageParam 为列表与看板共用基类,三个漂移参数在前端请求看板端点的路径上完全可达。

拍板决策(grilling 定案,不再重议)

  1. 漂移 3 条件按 bug 修:以 pageWorkspace 完整条件为准,boardSummary 补齐。唯一保留的有意差异 = saved-view 条件(票 10 明文「看板不接自定义视图」;savedViewConditions 为 null 时共享片段天然不拼,无需特判)。
  2. 载体 = 注解 SQL + static final String 常量编译期拼接:公共片段(c. 列前缀 + q. 参数名,四处上下文无关)提为接口常量,各语句 @Select("""…""" + COMMON_WHERE + """…""") 拼接。不引 XML mapper——全工程零 XML mapper 先例,且 H2 测试手工 MybatisConfiguration.addMapper() 自举不解析 XML(会 Invalid bound statement),爆炸半径大于收益。理由写进类 javadoc。
  3. 守恒断言 = 现有测试类加 4 用例CustomerWorkspaceOwnershipIntegrationTest 内,造数后同一参数 Σ boardSummary.cnt == pageWorkspace.total。4 用例 = 基础集 + viewType=FOLLOW_UP_DUE + industryCode + provinceCode 各一。不做全矩阵。
  4. /api/customer/page 不动:查实它是「客户管理」页面端点(e2e defs_a4.py 有消费、API-SUMMARY 独立行登记),与三 workspace 不是双轨。
  5. 范围 = R1 最小票:只动 CustomerMapper(两条 SQL、四处公共块)+ CustomerWorkspaceOwnershipIntegrationTest(4 用例)。不碰 service / controller / param / bruno——无契约变化。其余 5 条语句(selectSimilar×2 / selectByCreditCode / selectMaxCustomerNo / searchForOpportunity)各自单份无重复,不动。

做法

  1. CustomerMapper 内提公共 WHERE 常量(内置视图 ifs + 公共筛选 ifs + groupColumn ifs + saved-view foreach 按现有结构整合),pageWorkspace 两分支与 boardSummary 两分支改为常量拼接。
  2. boardSummary 补齐 3 个漂移条件(含两分支)。注意 overview 分支的 FOLLOW_UP_DUE EXISTS 在 boardSummary 现状里完全缺失,mine/pool 分支同理。
  3. 类 javadoc「两处同步」警示改写为「公共片段在 XXX 常量,新增筛选同步加进常量」;补一段载体决策理由(为何不用 XML mapper——见拍板 2)。
  4. CustomerWorkspaceOwnershipIntegrationTest 加 4 个守恒用例(口径见拍板 3;overview + mine 两 workspace 至少各覆盖一次)。
  5. crm-customer/CONTEXT.md 在「客户总览」词条(或邻近)补一句:「看板 summary/cards 与列表同口径(同一份列表数据三种渲染),守恒由集成测试断言」。

验收

  • mvn test -pl crm-customer 绿(既有 135+ 用例不回归 + 新增 4 用例);
  • 修复前先写守恒用例跑一次确认能红(证明用例真覆盖漂移),再修 SQL 转绿;
  • CustomerMapper 内公共 WHERE 字面只出现一份;
  • BOM 扫描通过(新增 Java 文件无 EF BB BF)。

Answer

红 → 绿两段式完成,验收 4 条全部满足。

红灯证据(先写测试坐实漂移)

4 守恒用例先行(assertBoardListConservation:同参数下 Σ boardSummary.cnt == page.total),改造 SQL 前跑 CustomerWorkspaceOwnershipIntegrationTest

  • 21 跑 3 红 0 回归conservation_followUpDue / conservation_industry / conservation_province 三用例红,expected: 1L but was: 2L——看板把未命中筛选的客户也计入,3 条件漂移坐实;
  • conservation_base(无筛选路径)绿——证明断言机制本身无误,红是漂移不是断言写错;
  • 既有 17 用例全绿。

修复内容

CustomerMapper.java(306 行重写,净减 ~120 行):

  • MINE_POOL_DATASET(mine 白名单 / pool 部门折算 <choose>)+ WORKSPACE_COMMON_FILTERS(归档排除 + 5 内置视图 + 7 列筛选 + 3 groupValue + saved-view foreach)两个接口常量;
  • pageWorkspace / boardSummary 四处公共 WHERE 全部改为 """ + 常量 + """ 编译期拼接——公共 WHERE 字面全工程只此一份;
  • boardSummary 两分支补齐 FOLLOW_UP_DUE EXISTS / industryCode / provinceCode 三条件(saved-view 保留不拼,票 10 有意差异);
  • 类 javadoc + 两语句 javadoc 改写:载体决策理由(拒 XML mapper 的两个事实)、「新增筛选同步加进常量」警示、D-15 同口径 + 守恒断言说明。

CustomerWorkspaceOwnershipIntegrationTest.java(+60 行):4 守恒用例 + helper,overview / mine 两 workspace 均覆盖。

crm-customer/CONTEXT.md:「客户总览」词条补「看板 summary/cards 与列表同口径(对称商机 D-15;公共 WHERE 在 CustomerMapper 常量单一事实源,守恒由集成测试断言)」。

绿灯证据

mvn -pl crm-customer -am test(2026-09-06):14 个测试类 164 跑 0 失败 0 错误 0 跳过

  • CustomerWorkspaceOwnershipIntegrationTest:21 跑全绿(4 守恒用例转绿 + 17 旧用例零回归);
  • CustomerWorkspaceSavedViewIntegrationTest:8 跑全绿(saved-view foreach 路径未受常量拼接影响)。

收尾核验

  • BOM 扫描:全工程 716 个 .java(排除 target)clean;
  • 环境注记:本地仓库 crm-rule 快照过旧,mvn -pl crm-customer test 不带 -am 会编译失败(与本次改动无关),验收命令须带 -am

Comments