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.

124 lines
12 KiB

9 hours ago
# contact-graph effort E2E 报告(终稿)
> created: 2026-09-10(票 09 聚合)
> 范围:`.scratch/customer-contact-graph/` 全 effort(票 01–08)动态实测终态聚合;静态契约见 [spec.md](spec.md)(冻结版)。
> 环境:本地 8080(Spring Boot 单体)+ MySQL 8.129.84.155 crm + 修订⑧版 demo(`prototype/prototype-contact-graph.html`)。
> 两把动态量尺:**票 07 E2E API 套件**(e2e-graph.py,58 checks)+ **票 08 UI 冒烟**(demo_smoke_graph.py,40 步)。
## 一、执行摘要
| 量尺 | 结果 | 证据 |
|---|---|---|
| E2E API 套件 | **58 checks = 57 ✅ + 1 ⚠**(D-G1),21.6s,两轮幂等 | [e2e-graph-checks.json](e2e-graph-checks.json) / [e2e-graph-specimens.json](e2e-graph-specimens.json)(17 specimens) |
| UI Playwright 冒烟 | **40/40 全 PASS,两轮幂等**,console/page error = 0,网络层 27 条 /api/** 全 GET/POST 零 PUT/DELETE | [demo_smoke_graph-results.json](demo_smoke_graph-results.json) + shots-demo/ 13 截图 |
| 端点静态覆盖 | **SCAN 17/17 缺 0**(12 新端点 + tree/enabled-list/contact page/oplog/archive 5 联动既有端点) | e2e-graph-checks.json SCAN 节 |
| 单测底座 | crm-dict 64/64(票 02)/ 图谱 12/12(票 03)/ crm-customer 209(票 04)→ 218(票 05) | 各票 resolve 记录 |
| 阻断 | **0**(无 ❌,无未收敛缺陷) | — |
**结论:spec 全条款落地(13 ✅ + 1 ⚠ 记录性),唯一缺陷 D-G1 为 P2 语义缺口,不阻断验收。**
## 二、对照 spec 逐条三档结论
### 决策全景(§一 D1–D12 / T1–T2)
| # | 决策 | 结论 | 实测证据 |
|---|---|---|---|
| D1 | 等级双值模型 | ✅ | G-01 quickAdd 字典联动:董事长→level 10 / 市场经理→6 / 市场专员→3 / other_job→null(level_source=1);G-03 手工定级 level_source=2 |
| D2 | 职务变更来源区分 | ✅ | G-03 双分支:字典跟随重算(董事长/高层管理/10/level_source=1)+ 手工锁定不动(职务改市场专员 level 保持 8/level_source=2);两者均 bump 图谱版本 |
| D3 | 三档制 10/6/3 | ✅ | G-00 档位值集全等:chairman/shareholder=10,*_manager=6,*_specialist/bid_officer=3,other_job=None |
| D4 | 保存才入库 | ✅ | G-02 save 建边回读/空 edges=清空/恢复;demo 编辑态 pending→三弹窗(继续编辑/放弃/保存)→DB 边取证 |
| D5 | 布局零坐标 | ✅ | GraphDTO 无坐标字段;demo 拖卡行内位移后重进布局仍纯由 level 推导 |
| D6 | 只有手动边(修订⑧核心反转) | ✅ | e2e 全程无自动边;demo 修订⑧后拖线建边/×删边/重进持久(committed=1→0);无 rebuild 触发路径 |
| D7 | 公司边=level 10 自动挂 | ✅ | demo company 节点唯一且固定布局位(x:1080,y:184);detail 出参无公司边(派生) |
| D8 | 公司边派生视图不可删 | ✅ | demo 公司边无 ×;摘线=降级路径可达(未定级栏停卡实测) |
| D9 | 图谱版本乐观锁 | ✅ | G-02 旧版本保存 67018;G-05 双 session 同版本→S 先存→S2 旧版本 67018;quickAdd/batchEdit/导入成功均实测 bump |
| D10 | 明文埋点独立表 | ✅ | G-03 DB reveal_log 取证(operator_id/name/ip/op_time 齐全);demo 脱敏点击明文+logs=1 |
| D11 | 导入独立表镜像 | ✅ | G-04 三段式全链(预检→确认→轮询终态→failures clip500→DB 执行面 8 行账实相符) |
| D12 | contact_source 四项 | ✅ | G-00 enabled-list 4 项(组会/组局/转介绍/其他)——**W-01 销号复验通过**(见 §五) |
| T1 | 错误码段 67xxx | ✅ | 实现 67018–67024(spec 草案 67017–67023 因 67017 已被战略协议占用整体顺延一位——spec §五预留「号位实现期可顺延微调」);六连错误码逐个断言(67019×5/67020/67018×2/67021/67022/67023/67024) |
| T2 | 规模上限预案 | ⚠ 记录性 | 预案为记录性不提前实现;spec 预告的「票 08 500 节点 mock 压测」未列入票 08 票面 6 条、未执行——读端点结构(nodes 数组)与 demo 绝对定位渲染形态已验证可承载,500 节点量级压测留联调(不阻断) |
### 端点契约(§三)
**全部 12 个新端点按 ADR-0017 纪律落地并实测通过**(SCAN 17/17;形态 = flat 动词 + 查询参数传 id + 隐式表单绑定/indexed 嵌套行;零 @PathVariable/PUT/DELETE/@RequestBody——网络层 27 条请求全部 GET/POST 为 UI 层佐证)。字典组零新端点(tree/enabled-list 复用)✅。契约细节与 specimens 逐字段吻合(同名 specimens 已反哺 Bruno 文档示例值,见 §六)。
### 校验规则(§四 6 条)
✅ 单父违反 67020 / 两点一条边 + 快照内重复 67019 / 等级倒挂·自连·未定级端点·幽灵端点 67019×5 / 撤级须无边(NodeInput 契约)/ level∈{null,1..10}+越界联系人 67019 / save 单事务原子性(batchEdit 侧原子批实测:任一行失败零落库 + failedRows 定位 idx)。
### demo 修订⑧(§七)
✅ 票 06 回写四条(砍自动生成边/公司边派生化无 ×/无否决 tombstone/level 来源标记体现)全部在 demo 实测面得到覆盖(票 06 59 步 + 票 08 40 步)。
## 三、缺陷台账(D-xx)
| # | 严重度 | 现象 | 根因 | 处置 |
|---|---|---|---|---|
| D-G1 | P2 | batchEdit「空串=清空」手机号不可达:空串提交后 DB 电话不变 | Spring MVC 表单绑定(StringEditor allowEmpty)把空串转 null,后端收到恒为 null(=不改);Param 注释声称「空串=清空」与绑定行为矛盾(ContactBatchEditParam.phone 注释 vs Service isBlank→null 分支) | **记档不排查**(缺陷验证模式)。前端替代路径已可用:先 reveal 取明文再提明文即改号;清空手机号场景本期无 UI 入口。候选修法:后端换绑定策略(如 sentinel 值)或契约改为「不支持清空」——留待联调口径拍板 |
历史缺陷引用:客户导入 D-04/D-05(customer-e2e 台账)的镜像预防已在票 05 Analyzer 前移吸收(NOT NULL 无默认列必填校验 + fail_reason clip500 实测 ✅)。
## 四、覆盖对账(spec 条款 × 量尺)
| spec 面 | 票 07 API 套件 | 票 08 UI 冒烟 | 单测 |
|---|---|---|---|
| 图谱读写/乐观锁/六类非法边 | G-01/G-02/G-05(24 checks) | 编辑器闭环 12 步(拖卡/拖线/保存/重进/删边/重置/三弹窗) | 票 03 12 例 |
| 列表侧增强(reveal/quickAdd/batchEdit/export) | G-03(17 checks) | 列表侧 8 步 + quickAdd 三态 3 步 | 票 04 增补 11 例 |
| 导入三段式 | G-04(10 checks) | 导入 6 步(模板/预检/确认/轮询/失败明细/DB 账实) | 票 05 增补 |
| 字典前置(D3/D12) | G-00(4 checks) | 打开步字典加载 | 票 02 64 例 |
| oplog 链路 | G-06(2 checks) | 保存 toast「已记录关系变更日志」 | — |
| 清扫幂等 | TEARDOWN 3 checks(sweep=0) | teardown 首跑清 3 组/二跑清 1 组 = 无残留 | — |
**双量尺交叉互补**:API 套件管语义/错误码/并发/DB 真值;UI 冒烟管交互态机/渲染/网络纪律。两边无重复用例、无覆盖空洞。
## 五、W-01 销号记录
| 节点 | 动作 |
|---|---|
| 2026-09-04 挂账 | customer-e2e effort:`dict_group` 24 组无 contact_source,联系人创建不校验 source 回显原值,前端下拉将无数据源(report-core.md F-06 / e2e-report.md 观察点 W-01 维持挂账) |
| 2026-09-10 拍板 | 本 effort spec 冻结:D12 = contact_source 四项含其他(group_meeting/group_activity/referral/other),与 customer_contact.source 列注释口径一致——**W-01 销号口径入 spec** |
| 2026-09-10 落地 | 票 02 字典前置:crm-dict 种子 contact_source 4 项 + job_title 两级树 5+9(ADR-0036),crm-dict 64/64 全绿 |
| 2026-09-10 复验 | 票 07 G-00:`GET /api/dict/item/enabled-list?groupCode=contact_source` 实测 4 项 code/名/序全符 ✅——**W-01 正式销号**(e2e-graph-checks.json G-00 第 4 项) |
## 六、API-SUMMARY 增量核对(零漂移)
`.scratch/customer-module/API-SUMMARY.md` 增量登记(本次票 09 完成):
1. **§1 错误码总表**:补 67018–67024 七行,语义与 `CustomerConstants` 注释逐字一致(含 spec 草案号位顺延说明)。
2. **§2.7b 新节**:联系人图谱/页签增强/联系人导入 12 端点(三 Controller 分组),method+URL 与源码 `@*Mapping` 一致(与 bruno-sync verify 脚本同源对账)。
3. 核对结论:**零漂移**——URL/方法/错误码/入参形态四要素与实现、specimens 实测、Bruno 文档三处一致。
## 七、Bruno 文档同步(票 09 第①件)
- **新增 12 个 .bru**(全部走 bruno-sync generated 通道,tag=页面归属):
- `A4 客户管理/客户详情/联系人图谱/`:图谱全量读、图谱整体保存
- `A4 客户管理/客户详情/联系人/`:电话明文查看、快速添加联系人、页内批量编辑、联系人导出
- `A4 客户管理/客户详情/联系人导入/`:上传导入文件并预校验、确认执行导入、任务结果、失败明细与重复明细、最近导入记录、下载导入模板
- **示例值 = 票 07 specimens 实测真值**(9 端点 JSON 逐字段真值;export/template 非信封二进制流文字说明);请求/响应表、错误码节按源码注解 + CustomerConstants 初稿生成
- **verify 对账 12/12 PASS**(docs 首行钥匙 vs 源码钥匙集,零缺零余)
- 票面预估 11 端点 vs 源码实际 12(导入组含 `/page` 共 6 端点)——以源码为准(结构听源码)
- 目录归属按源码 tag 落 `客户详情/` 子目录(票面原述「联系人页签相关目录」的口径以源码 tag 为准——图谱/增强/导入发生在 A4-4-2 客户详情页联系人区,与「A4 客户管理/联系人」独立菜单旧端点分属不同目录,页面归属语义正确)
- **git 不操作**:文档仓变更留工作区,由用户 `git diff` 审查后自行提交
## 八、残留终态与移交
### 测试数据残留
- **零残留**:e2e 正门 archive 2 客户 + DB 兜底清扫 7 表(contact/graph/edge/reveal_log/import_task/fail/oplog);demo teardown 二跑仅清当轮 1 组 = 幂等收敛;套件可重复重跑。
- effort 工作件留存(`.scratch/customer-contact-graph/`):`_smoke-contacts.xlsx` / `_import-graph*.xlsx`(套件输入件,重跑可再生)+ `_diag-import.xlsx`(诊断残留,删除失败待手动清)+ `bruno-out/`(12 .bru 工作区副本 + _deploy/_verify 脚本,已同步至文档仓,可删)。
### 发版与验收移交(票 09 第③件)
1. `mvn clean package` → crm-app jar 上传测试环境 → `deploy/restart.sh` → 探针复验(新端点可达:graph/detail / reveal / import/template)。
2. 移交用户亲手验收清单(按修订⑧口径):
- 图谱:**只有手动边**(无自动生成/否决机制)——拖线建边、×删边、整体保存、重进持久、版本冲突提示刷新
- 编辑器全套:拖卡定级/撤级(右侧栏)、公司边派生不可删(摘线=降级)
- 脱敏明文 + 日志:列表/图谱电话脱敏,点击明文(reveal_log 埋点),日志面板关系变更记录
- 页内编辑:行内改姓名/职务(D2 联动提示)/关键联系人,保存全部,撤销单行
- 快速添加:多行、前端查重「确认知悉」、部分成功失败行保留重提
- 导入三段式:模板下载 → 上传预检(坏行明细)→ 确认执行 → 结果页 + 失败明细
- 字典下拉:职务两级级联(档位联动)、来源四项
3. 已知观察项随移交:D-G1(清空手机号语义)、T2 500 节点压测未执行、preference pool board 白名单特判未实现(customer-e2e-r2 遗留,本域未触碰)。
**destination 达成:票 09 三件全清,Map 收官。**