简介:《客户关系管理CRM-客户管理-PRD-V1.0》是一份面向产品经理、需求分析师、CRM实施人员及开发测试团队的软件需求说明书,聚焦客户档案、联系人跟踪、销售漏斗、市场营销自动化与客户服务等模块的规范化设计,可用于理解CRM项目从需求来源到功能落地的完整思路。文档共54页,按项目介绍、方案概述、业务流程、业务用例、功能列表和基本流程等章节展开,并涉及平台政策、竞品分析、名词解释、系统用例与角色用例,便于读者对照梳理功能边界和业务建模线索。资源包内含1个PDF文件,大小约3.11MB,单文件结构便于检索、传阅和评审参考。目前已有318人学习,产品、研发与测试人员可从中获取需求组织方式、模块拆解方法及文档变更管理思路。
1. 一份 2017 年的客户管理 PRD,今天照着做会不会翻车
上周有个做企业服务的朋友拿来一份 2017 年 8 月定稿的客户关系管理 CRM 客户管理模块 PRD,问我能不能直接照着开工。我的判断是:里面关于客户主数据、角色权限、状态流转的定义,八成今天还用得上;但如果照着它的页面结构直接建表,后面大概率要返工。原因不复杂——那一代客户管理 PRD 普遍把「客户」当成一张静态档案表来设计,字段堆在同一个页面里,权限靠人配,状态靠手改;而今天的业务对一个客户的要求是带生命周期、带归属变更、带跟进轨迹的活对象。这份文档真正值钱的部分不在页面长什么样,而在它把哪些字段定义成唯一、把哪些动作定义成不可逆。下面我按自己落地这类 PRD 的顺序,把它拆成能开发、能验收、能排错的六块内容,中间穿插几条血泪经验。
2. 先划边界:客户管理里谁是主数据,谁只是附属
动手建表之前,先把「客户」这个词的边界划清楚,这一步偷懒,后面每一层都要还债。客户管理里最容易混淆的是三个对象:客户、联系人、线索。客户是主数据,一个客户在企业视角下应当是唯一的;联系人是客户的附属,一个客户可以有多个联系人,联系人离职了客户还在;线索是未经验证的原始信息,可以重复、可以脏、可以来自任何渠道。三者混在一张表里,最典型的后果是列表页搜「某公司」出来七八条记录,销售各自跟进,老板看到的业绩数字永远对不上。
我一般会用一句话把边界钉在 PRD 的首页上:客户是唯一实体,线索是客户的候选池,联系人是客户的挂件。这句话决定了后面所有唯一性校验、权限范围、合并逻辑怎么写。
2.1 客户主数据字段:进主表的和进从表的分开算
一份 2017 年的客户管理 PRD,字段清单通常密密麻麻写两三页,但真正决定系统好不好用的是「哪些字段进主表」。我的划分标准只有一条:会被高频筛选、排序、做权限判断或者做唯一性校验的字段,进主表;其余全部进从表或扩展表。按这个标准,客户主表保留的字段大致如下。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| customer_id | bigint | 是 | 主键,自增或雪花 |
| customer_no | varchar(32) | 是 | 对外客户编号,业务生成,唯一 |
| customer_name | varchar(200) | 是 | 客户全称 |
| customer_type | tinyint | 是 | 1 企业 / 2 个人 |
| social_credit_code | varchar(32) | 否 | 企业统一社会信用代码 |
| mobile | varchar(20) | 否 | 个人客户手机号 |
| industry | varchar(64) | 否 | 所属行业,字典值 |
| level | tinyint | 是 | 客户等级,默认 3 级 |
| source | varchar(64) | 是 | 来源渠道,字典值 |
| owner_id | bigint | 是 | 归属销售 |
| dept_id | bigint | 是 | 归属部门,随归属人冗余 |
| region_code | varchar(16) | 否 | 所属区域 |
| status | tinyint | 是 | 生命周期状态,见第 4 章 |
| in_pool | tinyint | 是 | 是否在公海,0 否 1 是 |
| last_follow_time | datetime | 否 | 最后跟进时间,冗余字段 |
| next_follow_time | datetime | 否 | 下次跟进时间 |
| version | int | 是 | 乐观锁版本号 |
| created_at / updated_at | datetime | 是 | 创建与更新时间 |
| is_deleted | tinyint | 是 | 软删除标记 |
这张表里有两个字段值得单独说。一个是dept_id,它其实可以从归属人反查组织树得到,但我仍然冗余存一份,原因是数据权限过滤是列表页最高频的查询条件,每次 join 组织表会让分页查询变慢,而组织调整是低频动作,归属人换部门时同步刷一次dept_id就够了。另一个是last_follow_time,它由跟进记录写入时同步更新,列表页默认排序、公海回收规则都依赖它,属于典型的用写放大换读性能。
至于从表,联系人、地址、开票信息、银行账号、附件、自定义扩展字段,一律拆出去。自定义扩展字段尤其要注意,2017 年的 PRD 喜欢在客户表上预留ext1到ext20,这种设计三年内一定失控,常见做法是单独建一张crm_customer_ext,用field_key、field_value的纵表结构存,或者干脆用 JSON 字段,但 JSON 字段不要拿来做筛选条件。
唯一性约束是这一节最容易被跳过的地方。企业客户按名称去重会误杀同名不同主体的情况,我一般用customer_name + social_credit_code做联合唯一索引,信用代码为空时降级为「名称 + 归属部门」做软校验,只在新建时提示不阻断。个人客户直接按mobile做唯一,手机号是个人客户最强的识别项。
2.2 角色与数据权限:销售只能看自己的客户,这句话要拆成矩阵
PRD 里写「销售只能看自己负责的客户」只有一行字,落到实现上是一张二维矩阵:角色决定能做什么操作,数据范围决定能看到哪些行。这两件事必须分开设计,否则后面加一个「区域经理」角色就要改一遍代码。
| 角色 | 数据范围 | 查看 | 编辑 | 转移 | 删除 | 导出 |
|---|---|---|---|---|---|---|
| 销售 | 本人 | 是 | 是 | 否 | 否 | 否 |
| 销售主管 | 本团队 | 是 | 是 | 是 | 否 | 是 |
| 区域经理 | 本部门及下级 | 是 | 是 | 是 | 是 | 是 |
| 客服 | 本人 + 指派 | 是 | 仅跟进记录 | 否 | 否 | 否 |
| 运营 | 全部(只读) | 是 | 否 | 否 | 否 | 是 |
| 管理员 | 全部 | 是 | 是 | 是 | 是 | 是 |
数据范围的实现,我一般用「范围类型 + 范围值」两个字段挂在角色上,范围类型取本人、本团队、本部门及下级、指定部门、全部五档,查询时翻译成一段where条件拼进列表 SQL。不要用「给每个用户配一条可见客户 ID 列表」的做法,客户量过万之后这张关联表会变成灾难,而且人员变动时同步逻辑极难写对。
这里有个细节:数据权限必须在服务端拼进查询条件,不能只靠前端隐藏按钮。我见过一个项目,列表接口做了权限过滤,详情接口忘了做,结果销售改一下 URL 里的 ID 就能看到别人的客户,这种问题在验收阶段基本发现不了,只能靠代码评审兜。
2.3 线索、客户、商机三段式:转化时的唯一性怎么保证
客户管理的主线是「线索 → 客户 → 商机」,三段各自的职责要写死:线索负责承载未验证信息,可以重复、可以批量导入、可以来自表单和展会名单;客户负责承载已验证的、要长期经营的实体;商机负责承载一次具体的成交机会。一个客户可以有多个商机,一个线索最多转成一个客户。
转化动作是这条链上最容易出问题的一环。我一般会把转化做成一个显式接口,而不是让用户在客户列表里手工新建,因为转化时要处理三件事:查重、合并、留痕。查重按企业名称和信用代码双条件模糊匹配,命中已有客户时不是直接拦截,而是弹出一个选择框,让操作人选「关联到已有客户」或「仍然新建」,选择结果写进线索的转化日志。合并的动作要谨慎,两个客户合并意味着联系人、跟进记录、商机、合同全部要改挂,这个动作我一般只开放给主管角色,并且要求填写合并原因。
还有一条经验:线索表上要留converted_customer_id和converted_at两个字段,转化后线索不删除,只打标记。否则半年后有人问「这条线索到底转没转」,你只能去翻操作日志,那就成了黑匣子。
3. 把 PRD 拆成可开发的功能清单与页面流
PRD 是给人看的,功能清单是给开发和测试看的。这两者之间的差距,主要差在参数上:PRD 写「客户列表支持按条件筛选」,功能清单要写清楚筛哪些条件、默认值是什么、多选怎么拼、空值算不算命中。这一章按客户管理最核心的三个页面——列表页、详情页、表单页——把参数一条条摊开。
3.1 客户列表页的筛选、排序与分页参数
列表页是销售每天打开次数最多的页面,它的默认行为直接决定用户觉得这个系统「顺不顺手」。我一般会定这几条:默认按最后跟进时间倒序,默认每页 20 条,默认只查「跟进中」和「待分配」两种状态,已成交和流失的客户要主动切标签才看得到。
筛选参数清单如下,开发时直接照这张表实现。
| 参数 | 类型 | 默认值 | 匹配方式 | 备注 |
|---|---|---|---|---|
| keyword | string | 空 | 名称/编号/手机号模糊 | 长度限制 50,前后空格 trim |
| status | array | 跟进中、待分配 | 精确 in | 多选 |
| level | array | 空 | 精确 in | 多选 |
| owner_id | array | 空 | 精确 in | 受数据权限二次约束 |
| dept_id | array | 空 | 含下级则用树查询 | 与组织树联动 |
| source | array | 空 | 精确 in | 字典值 |
| tag_ids | array | 空 | 交集匹配 | 多标签取同时命中 |
| created_range | date range | 空 | 闭区间 | 跨度不超过 365 天 |
| last_follow_range | date range | 空 | 闭区间 | 同上 |
| page | int | 1 | — | 上限 10000 |
| page_size | int | 20 | — | 上限 100 |
几个参数背后的取舍值得说清楚。关键词搜索不要对customer_name做%关键词%的全模糊,客户量到几十万之后这个查询会拖垮整个列表,常见做法是用前缀匹配关键词%走索引,或者单独维护一张搜索引擎的索引表,关键词走搜索服务,其余条件走数据库。标签多选用交集而不是并集,是因为销售筛标签的真实意图通常是「既是重点客户又属于制造业」,并集会把结果撑得没法看。
排序字段只开放三个:最后跟进时间、创建时间、客户等级。不要开放任意字段排序,否则前端传个没建索引的字段进来,一次排序就是一次全表扫描。
分页用 limit offset 在深翻页时会变慢,客户量大的系统我一般加一条约束:超过 100 页的翻页强制要求用户先加筛选条件,或者改用「上一页 / 下一页」的游标分页,游标用last_follow_time + customer_id组合。
3.2 客户详情页的 360 视图分区
详情页的核心诉求是「一眼看完这个客户的全部信息」,但全部信息往往意味着十几个模块、上百个字段,首屏一次性加载完会让打开速度很难看。我的做法是分 tab 懒加载,首屏只加载基础信息加最近 5 条跟进记录,其余 tab 点开时再请求。
| 分区 | 内容 | 加载时机 | 数据来源 |
|---|---|---|---|
| 基础信息 | 名称、等级、归属、状态、来源、标签 | 首屏 | 客户主表 |
| 联系人 | 姓名、职务、手机、是否关键人 | 首屏折叠 | 联系人表 |
| 跟进记录 | 时间轴,按时间倒序 | 首屏 5 条,滚动加载 | 跟进记录表 |
| 商机 | 商机名称、阶段、金额、预计成交日 | 点击 tab | 商机表 |
| 合同订单 | 合同编号、金额、回款状态 | 点击 tab | 合同表 |
| 附件 | 文件名、大小、上传人 | 点击 tab | 附件表 |
| 变更日志 | 归属变更、状态变更、字段修改 | 点击 tab | 日志表 |
基础信息区顶部要放三个东西:客户状态标签、归属人、下次跟进时间。前两个是判断「这个客户现在归谁、处于什么阶段」,第三个是销售自己的行动提醒,这三个信息放在一起,用户扫一眼就知道下一步该干什么。跟进记录的时间轴要支持按类型筛选(电话、拜访、邮件、微信),但不要在时间轴上做分页器,滚动加载加「加载更多」按钮的体验更贴近真实使用。
详情页还有一个容易漏的点:所有 tab 的数据请求都要带一次权限校验,尤其是通过 URL 直接访问详情页的场景。
3.3 新建与编辑表单的校验规则表
表单校验是客户管理里翻车最集中的地方,因为这里的规则最多、最琐碎,而且每一条都直接对应用户的一次挫败感。我一般把校验分成三类:阻断型(不通过不能提交)、提示型(可以提交但给警告)、异步型(需要请求后端判断)。
| 字段 | 规则 | 类型 | 提示文案方向 |
|---|---|---|---|
| customer_name | 必填,2~200 字符,去首尾空格 | 阻断 | 请填写客户全称 |
| customer_type | 必选,默认企业 | 阻断 | — |
| social_credit_code | 18 位,字母数字,企业类型必填 | 阻断 | 信用代码格式不正确 |
| mobile | 11 位手机号正则,个人类型必填 | 阻断 | 请填写正确的手机号 |
| level | 必选,默认 3 | 阻断 | — |
| owner_id | 必选,只能是当前用户或其下级 | 阻断 | 无权将客户分配给该人员 |
| customer_name + 信用代码 | 联合查重 | 异步 | 已存在同名客户,是否继续 |
| 富文本备注 | 长度 2000,过滤脚本标签 | 阻断 | 备注最多 2000 字 |
异步查重要做防抖,输入停顿 500 毫秒再请求,且只在新建时触发,编辑时不重复校验自己。手机号正则不要写得过分严格,170、171、162 这些号段要放进来,我见过一个项目的正则漏了虚商号段,导致一批客户建不进去,排查了半天才发现是前端正则的问题。
编辑表单还要处理并发:两个人同时打开同一个客户,A 先改了归属人,B 后提交把归属人改回去了。解决办法是在提交时带上version,服务端update ... where version = ?,影响行数为 0 就返回「数据已被他人修改,请刷新后重试」。这条规则写进 PRD 只需要一行,但不写就一定会在上线后被投诉。
4. 数据模型与状态机:客户生命周期怎么落表
页面是皮,数据模型是骨。客户管理这类系统的数据模型并不复杂,难点在于「一个客户的一生」要在几张表里被完整记录:谁创建的、归谁、被谁改过归属、跟进了几次、什么时候被回收进公海。这一章给出我常用的五张核心表和一套状态机,可以直接对照着建。
4.1 五张表撑起客户管理:主表、联系人、跟进、日志、标签
| 表名 | 作用 | 关键字段 | 索引建议 |
|---|---|---|---|
| crm_customer | 客户主表 | 见 2.1 字段清单 | 唯一索引 (customer_no),联合索引 (owner_id, status),索引 (last_follow_time) |
| crm_contact | 联系人 | customer_id、name、title、mobile、is_key | 索引 (customer_id),唯一索引 (customer_id, mobile) |
| crm_follow_up | 跟进记录 | customer_id、type、content、next_follow_time、creator_id | 索引 (customer_id, created_at desc) |
| crm_owner_log | 归属变更日志 | customer_id、from_owner、to_owner、reason、operator_id | 索引 (customer_id, created_at) |
| crm_customer_tag | 客户标签关联 | customer_id、tag_id | 联合主键 (customer_id, tag_id) |
索引这块说两个坑。crm_follow_up的索引必须带created_at desc,因为详情页时间轴永远是按时间倒序取,只建customer_id单列索引会导致每次都要回表排序。crm_customer的(owner_id, status)联合索引顺序不能反,列表页最高频的查询就是「某人的跟进中客户」,把status放前面选择性太低,索引基本失效。
跟进记录表要不要冗余客户名称?我一般冗余一份customer_name快照,因为销售看跟进列表时希望直接看到客户名,不冗余就要 join,而客户改名是低频动作,快照过期可以接受。
4.2 客户状态机的六个状态与流转条件
状态字段最忌讳「谁都能改」。我一般把状态设计成只能通过动作接口变更,每个动作对应一条明确的流转规则,前端不提供「直接改状态」的下拉框。
| 当前状态 | 触发动作 | 目标状态 | 前置条件 | 可操作角色 |
|---|---|---|---|---|
| 待分配 | 领取 | 跟进中 | 客户在公海,且当前用户有领取额度 | 销售 |
| 待分配 | 指派 | 跟进中 | 指定归属人存在且在职 | 主管及以上 |
| 跟进中 | 成交 | 已成交 | 至少关联一个已赢单商机 | 销售及主管 |
| 跟进中 | 暂缓 | 暂缓 | 填写暂缓原因与唤醒日期 | 销售及主管 |
| 跟进中 | 公海回收 | 待分配 | 超过 N 天无跟进记录,N 可配 | 系统 |
| 暂缓 | 唤醒 | 跟进中 | 到达唤醒日期或手动唤醒 | 销售及主管 |
| 已成交 | 流失 | 流失 | 填写流失原因 | 主管及以上 |
| 任意 | 合并 | 被合并 | 目标客户存在且未删除 | 主管及以上 |
这张表里有两个设计决策值得展开。第一,「成交」不提供手动按钮给销售自由点,必须挂在商机上,原因是成交状态直接关联业绩统计,如果允许空手点成交,财务口径一定对不上。第二,「公海回收」是系统动作,不占用人工操作权限,但要在日志里留一条系统记录,方便销售事后申诉。
状态和公海是两套概念:状态描述客户的生命周期阶段,公海描述归属关系。一个客户可以处于「跟进中」但被标记为待回收,这两个字段不要合并成一个。
4.3 跟进记录与归属变更:留痕要留到能复盘的程度
跟进记录的字段不多,但每一条都要有用:类型(电话/拜访/邮件/其他)、内容(富文本,限 2000 字)、下次跟进时间、附件、创建人、创建时间。防重复提交用「同一客户 30 秒内相同内容不重复写入」的规则,比前端按钮置灰更可靠,因为网络慢的时候用户会连点。
归属变更日志要记五个要素:谁操作的、什么时候、从谁转到谁、变更原因、是单条还是批量。批量的场景在人员离职交接时特别常见,一次转几百个客户,如果日志只记一条「批量转移」,事后根本没法复盘哪个客户被转到了哪里,所以批量操作要拆成 N 条明细写。
公海回收规则我一般做成可配置的:超过 N 天未跟进自动回收、回收前 M 天给销售发提醒、每人最多持有 X 个客户。这三个参数在 PRD 里要写默认值,比如 N=30、M=3、X=200,并且明确说明「参数由管理员在后台修改,修改后次日生效」。规则一旦写死,业务侧调整一次就要发一次版,这是很多人踩过的坑。
5. 避坑与排查:客户管理 PRD 落地最容易翻车的五个地方
前面讲的是怎么把 PRD 变成能跑的系统,这一章讲的是上线之后一定会遇到的事。下面五条都是我在实际项目里撞过的,按「现象 → 原因 → 解决」记下来,照着排查能省不少时间。
5.1 数据层的三个坑:重复客户、脏手机号、删不干净
现象一:同一家公司在系统里出现三到五条记录,销售各跟各的,老板看到的客户总数虚高。原因不是查重没做,而是查重做在了前端,导入、接口、手工新建三条入口里只有手工新建走了查重。解决:把查重下沉到服务层,所有写入口统一走一个createCustomer方法,方法内部先按「名称 + 信用代码」查一次,命中就返回已有 ID 并提示关联;批量导入走单独的导入处理器,导入前先跑一遍全量比对,把疑似重复的行标黄让运营人工确认。
现象二:客户列表里手机号格式五花八门,带空格、带横杠、带 +86,按手机号搜不到人。原因是输入时没做归一化,前端校验只管提交,不管存储。解决:入库前统一清洗,去掉空格和横杠,去掉 +86 前缀,只保留 11 位数字;历史数据用一次性脚本刷一遍,刷之前先导出备份,脚本按「清洗后是否与其他记录冲突」分两批处理,冲突的进人工队列。
现象三:客户被删除后,跟进记录、商机、合同还在,详情页点进去一片空白但数据仍在库里。原因是用了物理删除,且没有处理关联表。解决:客户表统一软删除,is_deleted置 1,所有查询默认带is_deleted = 0;关联表不删,靠客户的软删除标记在查询时过滤。这条规则要写进开发规范,不能靠每个人自觉。
5.2 流程与权限的两个坑:公海误伤、导出泄数据
现象四:销售休了三天假回来,名下十几个客户被系统自动收进公海,客户直接投诉。原因是回收规则只看「最后跟进时间」,没有考虑请假、出差这些状态。解决:回收前加一道校验,归属人在请假状态或者在出差审批单有效期内的,跳过回收并记录一条「豁免」日志;同时把回收动作从「直接改归属」改成「先进入待回收池,24 小时后执行」,给销售留一个后悔药窗口。
现象五:一次导出操作把全公司的客户名单导了出去,导出的还是带手机号的完整表格。原因是导出接口复用了列表查询,只校验了「登录」,没校验「数据范围」。解决:导出走独立接口,独立权限点,导出前二次校验数据范围,导出字段做白名单(手机号中间四位打码),单次导出上限 5000 条,超过上限要求分批并记录导出日志。导出日志要记谁、什么时候、导了哪些条件、多少条,这条日志在出问题时是唯一的追溯依据。
这五条里,有三条的共同点都是「校验只做在一个入口」。客户管理这类系统入口多、角色多、批量操作多,任何一条规则如果只在前端或者只在某一个接口里实现,早晚会被绕过去。
6. 验收与迭代:怎么判断这份 PRD 真的落地了
PRD 写完不算落地,功能上线也不算落地,真正的验收标准是「运营能自己配、销售能自己用、出问题能自己查」。我一般会在上线前跑一张验收表,每一项都要有明确的判定标准和验证方法,测试同学照着点,产品同学照着签字。
| 验收项 | 判定标准 | 验证方法 |
|---|---|---|
| 客户唯一性 | 同名同信用代码无法重复创建 | 手工新建两次,第二次提示关联 |
| 数据权限 | 销售 A 无法通过 URL 访问销售 B 的客户 | 换 ID 直接请求详情接口,返回 403 |
| 状态流转 | 所有状态变更只能在动作接口中发生 | 直接改库状态后,页面刷新应被日志纠正 |
| 公海回收 | N 天未跟进客户进入待回收池 | 造一条 31 天前的数据,跑定时任务 |
| 跟进留痕 | 每次归属变更产生一条明细日志 | 批量转移 10 个客户,日志应有 10 条 |
| 导出打码 | 导出文件手机号中间四位为星号 | 导出一份,打开检查 |
| 并发编辑 | 两人同时编辑,后提交者收到冲突提示 | 两个浏览器同时打开同一客户提交 |
这张表里我最看重「数据权限」和「状态流转」两项,因为这两项出问题不会报错,只会悄悄错,等到发现的时候数据已经乱了。验收之外,还有一件我每次都会做的事:在上线后第一周,每天拉一次操作日志,看有没有人反复执行同一个失败动作。比如某个销售一天内连续 20 次点「领取」都失败,大概率是领取额度或者公海规则配错了,这比等用户来投诉快得多。
迭代节奏上,客户管理模块我建议按「字段 → 流程 → 报表」的顺序推进,先把字段和唯一性做扎实,再做状态机和公海规则,最后才是统计报表。反过来做,报表口径一变就要回头改数据模型,返工量是前者的好几倍。
我自己在这类项目上养成的习惯是:每加一个字段,先问一句「它会不会被用来筛选或者做权限判断」,会,就进主表并建索引;不会,就进扩展表。这个习惯帮我躲过了很多次「列表页越用越慢」的投诉。希望帮到你。
本文还有配套的精品资源,点击获取