创始人销售管道正确性:阶段事件、证据谓词与重开语义
CRM 看板只显示机会现在在哪一列,却隐藏并发拖动、迟到同步和误标成交。本文把阶段变化写成不可变事件,以版本化证据谓词和 CAS 接受转换,并让 Won、Lost 与 Reopen 保持可追溯。
本文要点
- 主题聚焦:AI、DevOps、独立开发
- 适合人群:独立开发者、全栈工程师、AI 应用开发者
- 核心价值:快速理解背景、实践路径、常见误区和工程建议
创始人把一个机会从“已演示”拖到“口头承诺”,销售助手又根据一封迟到邮件把它移回“已联系”;几分钟后财务 Webhook 把同一公司标成 Won。最终看板只有一个绿色格子,却无法说明谁依据什么接受了转换,也无法区分重复同步、纠正误操作和客户下一季度重新开启的新销售周期。用当前阶段字段直接计算预测,会把这些冲突一起压扁。
AI 付费意愿访谈验证问题、预算和承诺,开发者 Launch 留出实验测量营销增量。本篇从一个销售机会已经建立后开始,只保证阶段事实与转换证据正确;它不是获客归因账本,也不把一次销售状态当成产品需求真值。
用 stagePolicy.v1 定义证据,而不是颜色
发布不可变 sales.stagePolicy.v1,为每个稳定 stage ID 定义含义、允许前驱、必需证据谓词、最大证据年龄、概率显示规则、终态性质和授权角色。RFC 8174 的 MUST/SHOULD 关键词只有在规范明确采用时才具有约束含义;内部策略也要把“建议填写”与“缺失即拒绝”分开,不能靠 UI 星号猜测。
schema: sales.stagePolicy.v1
policy: founder-sales@9
stage: commercial-commitment
allowedFrom: [qualified, solution-validated]
requires:
- economicBuyerIdentified@2
- priceScopeAcknowledged@3
- decisionDateConfirmed@1
maxEvidenceAgeDays: 21
terminal: false
authorizedRoles: [account-owner, founder]
证据引用不可变 artifact:会议记录摘要、报价 digest、客户域名下确认、采购工单或付款 receipt,并保存采集主体、occurredAt、recordedAt、可见性和撤销状态。外部 CRM 通常把阶段、是否关闭和是否赢单呈现为当前字段,但供应商的数据模型不能替本公司的接受规则;同步器必须记录 connector 和字段 mapping generation。预测金额还要绑定币种、数量、周期和报价版本,不能只存一个会被编辑的数字。
当前阶段只是不可变事件的投影
每次命令生成 opportunityStageEvent.v1,包含 opportunityId、salesCycleId、event ID、expected sequence、from/to stage、policy digest、证据根、actor、occurredAt 和 recordedAt。CloudEvents 可作为交换信封,但其规范不保证业务顺序或恰好一次;消费者按 source 与 id 去重,同身份异文进入 IDENTITY_CONFLICT。事件驱动架构负责交付模式,本账本负责一次阶段事实。
机会流程可以是 DISCOVERED -> QUALIFIED -> SOLUTION_VALIDATED -> COMMERCIAL_COMMITMENT -> WON,也可从允许阶段进入 LOST。转换请求先是 PROPOSED,证据齐全变成 VALIDATED,并发版本不符为 STALE_COMMAND,冲突证据为 EVIDENCE_DISPUTED。唯一接受点是存储层在同一事务中以 CAS 匹配 current sequence 和 policy generation,追加事件、更新 projection 并写 outbox,返回 stageTransitionReceipt.v1;拖动动画、HTTP 200 或第三方 CRM 已更新都不算接受。
对外 API 可用 RFC 9110 的强 ETag 与 If-Match 把客户端看到的 projection version 带回,条件失败应返回冲突而不是覆盖。但 HTTP 条件请求只保护该资源版本,数据库仍须原子提交事件和投影。投影可随时从事件流重建并比较 digest;数据库 CDC可把已接受事件传播到分析系统,却不能从一条被覆盖的 current row 恢复丢失历史。
WON 和 LOST 是某个 salesCycleId 的终态,不允许普通拖动离开。若原事件事实错误,由有权限的人追加 stageCorrection.v1,绑定原 receipt、理由和双人审批,旧事件继续存在;若客户在三个月后重新采购,则创建新 cycle 并链接 prior outcome,不能重写旧成交日期。付款撤回、合同取消和交付失败是成交后的独立业务事件,不应把历史 Won 偷改成 Lost。
注入并发移动与迟到同步
演练同时让两名用户基于 sequence 17 移到不同阶段,重复投递 CRM Webhook,让离线客户端晚一天提交,交换 occurredAt 与 recordedAt 顺序,注入同 event ID 异文、证据在验证后撤销、stage policy 切换、币种 mapping 缺失、终态普通重开,以及 outbox 成功但 projection 更新失败。预期只有一个 CAS 获胜,原子事务不允许半条接受;未知 mapping 和冲突证据不得进入正式管道。
运营 CSV 导入可用于历史机会迁移,但每行必须先映射为 staging 候选,再按同一转换规则晋级,不能直接覆盖 current stage。门禁要求所有正式转换都有 policy digest、actor 和 evidence root,事件/投影 sequence 一致率 100%,重复事件产生的新转换为 0,同 identity 异文接受为 0,非法边和无证据终态接受为 0。重放全量事件所得 projection digest 必须 100% 匹配;99% 合法交互在 500 ms 内返回确定的 accepted/rejected/stale 结果,UNKNOWN 不计成功。
上线先从现有 CRM 读取变化并建立影子事件流,连续四周只比较 projection、漏斗数和 stage age;再让 10% 新建、非关键机会通过新写路径,旧 CRM 仍是展示回退。cohort 按 opportunity ID 稳定分配,不能让同一机会双主写。若投影分歧超过 0.1%、发现一次终态被普通覆盖或 outbox 缺口,关闭新命令入口并把读 alias 切回旧字段,同时继续捕获事件供修复。只有完成并发、纠错和新 cycle 重开演练,才逐步把预测查询切到事件投影。
Related