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.
5.0 KiB
5.0 KiB
| status |
|---|
| accepted |
联系人图谱后端契约(表/端点/校验链/版本锁,contact-graph 票 03)
Context
customer-contact-graph effort 票 03(spec §2/§3/§4):A4-4-2 客户详情 §6.4 联系人图谱落地 crm-customer 后端。spec 冻结的最大反转 D6「只有手动边,没有自动边」作废了票面早期的自动生成引擎/系统边 tombstone 假设;实现以 spec 为准。核心语义:等级双值模型(D1/D2,字典档位=初始值、level_source 区分字典跟随/手工锁定)、全量快照单事务保存(D4)、公司边派生不落库(D8)、图谱版本号乐观锁(D9)。
Considered Options
- 版本行主键:A(spec 草案 customer_id 作 PK)vs B(选中):id 雪花 PK +
uk_graph_customer唯一索引——域内BaseEntity雪花主键零例外(JPA@Id+ MPASSIGN_ID全表一致),customer_id PK 需要为单表破例;唯一索引等价保证单客户单版本行。 - 校验链顺序:A(边校验 67019 先行,实现初稿)vs B(选中):等级调整约束 67020 先于边校验——「撤级但快照仍留边」场景在 A 下被「边端点未定级」67019 抢先拦截,而用户真正需要的是「撤级前须先取消全部连线」这一可行动提示(修订⑦终态口径)。
- 无环检测:A(DFS 显式环检测)vs B(选中):免检——单父约束(67020)+「parentLevel > childLevel 严格递减」边约束(67019)联立后,环 v1>v2>…>v1 数学上矛盾,无需 DFS。
Decision
- 错误码顺延(执行拍板):spec 草案号位 67017 已被战略协议
CODE_AGREEMENT_INVALID(返工票 12-F5)占用,图谱三码顺延:67018 版本冲突(save 乐观锁不符,提示刷新重试)/ 67019 边非法(自连、快照内重复、未定级端点、等级倒挂、等级越界 1–10、端点越界、快照不完整)/ 67020 结构校验(单父违反 + 等级调整约束修订⑦)。 - 两张新表 + 一列:
customer_contact_edge(手动边,uk_edge_pair(customer_id,parent_id,child_id)唯一 +idx_edge_customer,无软删语义=快照表,物理 DELETE + 全量重插)与customer_contact_graph(版本行,id PK +uk_graph_customer);customer_contact加level_source tinyint not null default 1(1=字典跟随 / 2=手工锁定,D2)。 - 端点两个(ADR-0017 纪律:flat 动词、查询参数传 id、隐式表单绑定,嵌套行走 indexed 绑定
nodes[0].contactId):GET /api/customer/contact/graph/detail?customerId=(懒建版本行 version=0 + 全量节点 phoneMasked 脱敏 + 当前边集,悬空边防御过滤)与POST /api/customer/contact/graph/save(全量快照单事务,返回新版本号)。权限继承所属客户(无独立 ACL,SELF 范围他人客户 67002 防探测)。 - save 校验链(顺序为语义一部分):① 客户可见性(67002)→ ② 快照完整性(nodes 恰好覆盖客户联系人集 + 等级越界,67019)→ ③ 等级调整约束(67020):调级节点终态不得有上级边;只有下级连线的新等级须严格高于最高下级;撤级须无任何边;首定级(原 null → X)豁免——先定级后连线是正常流程 → ④ 边校验(67019)+ 单父(67020)→ ⑤ 版本 CAS → ⑥ level 批写 + level_source 维护 → ⑦ 边全量替换。
- 版本 CAS 用显式 SQL(
UPDATE … SET version=version+1 WHERE customer_id=? AND version=?),不用 MP@Version插件——ContactGraphVersionWriter组件收编(ensureRow 懒建 + DuplicateKeyException 并发兜底 / bumpVersion / casBump / removeEdgesOfContact),对称CustomerOplogWriter家族。 - 撤级 null 显式 set:level 批写用
LambdaUpdateWrapper显式.set(jobTitleLevel, null)——MPupdateById的 NOT_NULL 默认策略会跳过 null 字段(先例CustomerOwnershipWriter,同坑第二例)。 - 联系人生命周期联动(D9):
CustomerContactServiceImpl.create后 bumpVersion;delete前级联物理清边(physicalDeleteByContact)+ bumpVersion。
Consequences
CustomerH2Schema16→18 张表(edge/graph DDL +customer_contact.level_source列),两处既有测试构造器随动(CustomerContactServiceImpl加第 4 参);新集成测试CustomerContactGraphIntegrationTest12 例锁语义(detail 懒建/脱敏/越权、save 成功/撤级/幂等/空边集、67018/67019 六变体/快照不完整/67020 单父/等级调整约束三态/增删联动)。- reveal 明文端点与查看埋点表不在本票(spec 划入票 04);公司边不入库(D8,前端按 level==10 派生)。
mvn -pl crm-customer -am test全绿(198 例);起服 HTTP 冒烟归票 07 E2E 套件(单测已等价覆盖校验链)。- 决策来源:customer-contact-graph 票 01 spec 冻结 D1–D9 + 票 03 执行拍板(错误码顺延/主键形态/校验顺序/首定级豁免——后三项由集成测试红转绿驱动,语义回写本 ADR)。