# SCRM：区分客户身份、跟进关系与来源事实

本文依据 2026 年 10 月本地检出的 `scrm-server`、`scrm-pc` 及其当前实现文档整理，提炼已采用的设计决策。它不是企微接口手册，也不证明任何生产环境任务正在运行。这里的分层源自多渠道线索、多人跟进、回调和 AI 分析的实际复杂度；单渠道小项目不必预建全部模型。

## 技术选择

后端使用 Java 17、Spring Boot 3、MyBatis-Plus 和 MySQL；Redis、RabbitMQ、Quartz 分别服务现有缓存／协调、异步消息和定时任务。管理前端使用 Vue 3、Vite、Pinia、Element Plus。这是 SCRM 项目事实；公司新项目按[四仓技术基线](../../engineering/scaffolds/technology-selections.md)起步，不从本案例追加 RabbitMQ、Quartz 或 AI 模块。

## 三种主键回答三种问题

项目把“同一个人”“某负责人下的一条客户关系”和“一次渠道进入事件”分开：

| 概念 | 回答的问题 | 不应混用为 |
| --- | --- | --- |
| `identityId` | 多个平台或关系记录是否归于同一人？ | 某次渠道回调的幂等键。 |
| `eId` | 当前要操作哪条跟进关系？ | 这个人的全局身份。 |
| `source fact` | 客户从哪个入口、何时进入，留下了什么来源事实？ | 客户或跟进关系本身。 |

`seed` 是客户关系的一个阶段，而非另一套客户主表。来源事件的去重键用于判断“同一次事件是否重来”，不能据此判断“两条事件是否同一个人”。把这些语义写清后，撞单、重新激活、补挂来源和多负责人冲突才有稳定的归属。新项目只有在确有多来源、多负责人或身份合并时才需要这组模型；否则一个清楚的客户实体可能足够。

## 多渠道入口收敛到同一业务操作

仓库中，小红书回调和抖音拉取分别保存原始来源记录，再映射到统一的线索上下文，经同一摄入操作解析身份、选择或创建客户关系、写入来源事实。回放也复用摄入路径。渠道差异留在入口映射和原始记录，客户归并规则不在每个渠道复制一遍。

这种做法的价值不是“多一层抽象”，而是改动身份归并规则时只需找到一个所有者。Agent 接入新渠道时，应先找现有摄入契约，确认去重键、原始事实和失败重放，再决定是否新增适配入口。

## 先提交业务事实，再处理外部动作

企微关系落库是回调主链路的成功边界。身份重算、来源补挂和提醒等后置动作在事务提交后触发，避免数据库回滚时外部消息却已经发出。代价是短暂的最终一致性，因此失败必须能被诊断、重试或补偿，不能把“主记录已写入”误报为“所有副作用已完成”。

AI 销售链路进一步把模型分析、业务结果入库、报表写入和链接通知拆成不同操作。报表只读取已采用的分析结果；发布表格不顺带调用模型或发送通知，定时通知也不隐式补分析。这样的界限让重试的影响可预期，并避免一次“发链接”意外产生模型费用或覆盖数据。

## 给 Agent 一个受控的业务入口

项目的 Agent 接入以文档发现能力，但使用独立授权凭证；只读是默认范围，分析和报表发布分别授权。动作带幂等请求标识，返回“已派发”只表示受理，Agent 仍需查询业务终态。它不开放任意 SQL、任意字段更新或生产发布入口。

可借鉴的是把能力、权限、费用／副作用和完成状态写成清晰契约。若新产品尚无外部 Agent 调用方，不需提前建设这套授权与任务体系。

## 核对入口

本篇主要核对 `scrm-server/docs/CONTEXT.md`、`docs/adr/0001-客户身份与关系模型.md`、`0002-事务提交后执行外部副作用.md`、`docs/features/customer/统一平台线索摄入与来源事实模型.md`、`docs/features/ai-sales/direct-model-analysis.md`、`report-publication.md` 和 `docs/features/agent-api/README.md`，并查阅对应服务代码。目标项目的当前实现、运行环境与授权要求始终优先于本篇案例。
