# Handoff — 线索模块 grill-with-docs(G1–G5 批量操作 + 视图统计)实现收官 生成时间:2026-08-14 18:01 仓库:`D:/code/crm-backend-matt`(多模块 Maven monorepo) 分支:见 `git status`(工作区未提交,尚未 commit/push) ## 一句话现状 grill-with-docs 会话已**全流程闭环**:决策 grill → ADR-0023(accepted) → 拆 5 张 ticket(10–14) → 逐张实现+测试闭环。**ticket 10–14 全部 resolved**,代码未提交。剩下的是**人工 review + 提交**(本会话按铁律不做 git 操作)。 ## 别重复读的既有产物(按路径引用,勿抄写) - **决策全景 / 逐页比对结论**:`.scratch/clue-module/map.md` → `## Decisions so far`(ticket 10–14 一行一条)+ `## 逐页比对(ticket 14 收口)`(原型 15 页 vs 已实现接口的对照表 + G1–G5 闭环结论)。 - **ADR**:`docs/adr/0023-lead-batch-operations-and-view-stats.md`(D1–D5 决策;status: accepted)。注意 `docs/adr/0022-...read-write-separation...` 是**别人**的读写分离重构 ADR,非本会话产出。 - **Ticket 底稿 + Answer**:`.scratch/clue-module/issues/10-..` ~ `14-..md`,每张 `## Answer` 已写明交付内容与验收结果。 - **PRD**:`.scratch/clue-module/线索业务-PRD.md` §13(v1.2,B1–B9 决策)。 - **领域语言**:`crm-lead/CONTEXT.md`、`crm-rule/CONTEXT.md`(含批量/统计新术语)。 - **生成的 API 文档**:独立 docs 仓 `D:/code/crm-api-docs`(bruno collection),本会话新增 32 个 `.bru`(4 个 tag 文件夹:`线索管理`/`线索规则-公海池配置`/`线索规则-行政区划`/`列偏好`)。**该仓也未提交**。 ## 已完成(ticket 10–14) 代码文件见 `git status`(下方"工作区注意")。要点: - **10** crm-base `BatchResult`(total/successCount/failCount/`List failures`),仿 `PageResult` 风格。 - **11** crm-lead 6 个 `-batch` 端点 + `LeadBatchFailReason`(8 值,回指 65xxx) + `LeadBatchFailItem`;impl 用 `@Lazy self` + 私有 `runBatch(List, Consumer)`,逐条 CAS、非原子、部分成功。 - **12** `LeadPageParam.status`→`statusIn(List)`;`LeadStatsDTO` + `POST /api/lead/stats`;抽 `buildViewWrapper()` 使统计口径=列表口径+@DataScope。 - **13** crm-rule `POST /api/rule/pool/delete-batch`(D5 方案 A:crm-rule 自建 `PoolBatchFailReason`/`PoolBatchFailItem`,复用 crm-base `BatchResult`,避 crm-rule→crm-lead 反向依赖)。 - **14** bruno-sync `sourceRoots` 扩容 + 生成 32 个 `.bru` + 原型 15 页逐页比对;**G1–G5 全闭环,G6/G7/G8 维持 Out of scope**(线索导入/池导入/池导出——原型有按钮≠本期交付)。 ## 铁律 / 陷阱(下个 agent 必读) 1. **`.java` 必须 UTF-8 无 BOM**(见 `AGENTS.md`)。写/改后跑 BOM 扫描:`head -c 3 file | od -An -tx1`(期望非 `efbbbf`)。docs 仓的 `.bru` 不受此约束(那个仓的既有文件本就带 BOM)。 2. **grep 前须 `export LC_ALL=C.UTF-8`**。 3. **依赖方向单向**:crm-lead→crm-rule;crm-rule **禁止**依赖 crm-lead(否则 cycle,D5 因此选方案 A)。 4. **别 `git checkout` 整文件**:工作区含**别人**的读写分离重构(ADR-0022)——`crm-lead/.../history/`、`.../query/`、`.../state/`、`LeadViewType.java`、`TransitionCmd.java`、`LeadTransitionImpl.java`、`LeadConstants.java`、相关测试——**非本会话产出,勿动勿清**。 5. **crm-auth 测试发现失败**(预存在,与本工作无关):`mvn -pl crm-auth test` → junit-jupiter discovery / SurefireBooterForkException(forked-JVM 环境问题)。这会污染 `-am` 链式测试。**工作区跑测试的姿势**:先 `mvn -pl -am install -DskipTests -q`,再 `mvn -pl test`(只跑目标模块)。 6. **`edit` 多改一组原子**:任一 `oldText` 匹配失败则整组回滚。 7. **`mvn -pl X -am test -Dtest=...`** 会对 `-am` 依赖模块也套同一 `-Dtest` 导致 "No tests matching";加 `-Dsurefire.failIfNoSpecifiedTests=false`。 ## 验收状态 - `mvn -q compile`(全模块)通过;全 `*.java` 无 BOM。 - 各 ticket 单测:`BatchResultTest` 4/4、`LeadBatchServiceTest` 5/5、`LeadServiceImplTest` 44/44、`LeadViewQueryImplTest` 6/6、`LeadPoolBatchDeleteTest` 4/4、`LeadPoolServiceImplTest` 15/15。 - **未做**:整仓 `mvn test` 汇总(受 crm-auth 环境问题阻塞,需用上面的 install-then-test 姿势);`git commit`;docs 仓提交。 ## 下一步(按优先级) 1. **人工 review 两个仓的 diff**:`D:/code/crm-backend-matt`(代码)+ `D:/code/crm-api-docs`(32 个新 `.bru`),确认后分别提交。**提交要把本会话代码与别人的 ADR-0022 重构分开**(工作区混杂,注意别一把 `git add .`)。 2. 若要整仓测试汇总:`mvn -pl crm-base,crm-lead,crm-rule,crm-preference -am install -DskipTests -q` 后逐模块 `mvn -pl test`。 3. G6/G7/G8(导入导出)若未来要做,需**新开 ADR + ticket**,不在本会话范围。 4. crm-auth 测试发现失败值得**独立排查**(与本工作无关,但阻塞 CI 全量测试)。 ## Suggested skills - **`code-review`**:review 自固定点以来的改动(标准轴 + spec 轴),正好对接"人工 review 后提交"。起点可用本会话开始前的 commit 或 merge-base。 - **`tdd`**:若继续做 G6/G7/G8 或补测,走红-绿-重构。 - **`request-refactor-plan`** / **domain 相关**:如需把 ADR-0022 读写分离重构单独整理成可提交的原子 commit 序列。