做销售管理最头疼的不是业绩完不成而是你根本不知道客户到底在谁手上、聊到哪一步了。去年我带团队复盘时发现客户信息散落在Excel、微信聊天记录、纸质便签甚至个别销售的脑子里离职交接直接丢单撞单扯皮全靠吵。当时我下定决心自己动手做一个内部CRM这就是DeskcommCRM的由来。这个系统从需求梳理到上线用了不到两个月解决的核心问题就三个客户资产归公司、跟进过程可追溯、销售动作有提醒。如果你也在纠结要不要自研、或者想优化团队的客户管理流程这篇文章里的踩坑记录和设计方案应该能帮你少走不少弯路。1. 项目定位与整体思路拆解1.1 为什么不做现成CRM而选择自研市面上的CRM产品很多从通用大厂到垂直行业功能动辄几百个。但真正用过的人都知道80%的功能是摆设剩下20%想用的又和你的业务对不上。我当时的判断标准是三条第一团队规模三十人以内通用CRM的复杂权限模型反而拖慢录入速度第二销售流程高度固定询价、报价、合同、回款这条链路很清晰不需要自由流第三预算有限订阅费加上定制开发费一年下来够我请一个初级开发了。自研的本质不是做一套比商业软件更强的系统而是做一套和业务咬合得刚刚好的工具。我把需求收敛成三个词好录、好查、好提醒。销售在手机上30秒录完一条跟进主管随时能看下属的客户池分布系统自动提醒三天没跟进的客户。能做到这三点CRM就已经成功了一大半。1.2 技术选型与架构落地技术栈选的是Spring Boot加Vue数据库用MySQL部署用Docker扛一台2核4G的云服务器。为什么这么选团队里最熟的就是这套学习成本低出了问题能有人接得上。Spring Boot生态成熟权限框架直接用Spring Security加JWT前端用Vue加Element Plus表格、表单、弹窗这些组件开箱即用开发速度非常快。架构上我没搞微服务一个单体应用加一个MySQL实例高峰期再顶也就几十个并发微服务的复杂度在这个量级纯粹是给自己找麻烦。缓存用了Redis主要存登录token和验证码热点数据像客户列表这种实测下来MySQL加索引已经够快没必要再加一层缓存增加一致性维护成本。Docker部署这块有个经验镜像打小了启动速度快很多。我用的基础镜像是eclipse-temurin的JRE版本配合分层构建整个镜像不到200MB滚动升级基本秒级完成。服务器上用docker-compose管理把MySQL、Redis、后端、前端四个容器编排在一起日志统一打到宿主机目录排查问题方便很多。1.3 需求边界怎么圈MVP版本怎么定自研项目最大的风险不是做不出来是需求无限膨胀。销售说想要日历视图主管说想要业绩看板老板说想要BI报表全加进来这项目能拖一年。我做需求池的时候用了四象限法横轴是使用频率纵轴是业务价值只做高频高价值的低频高价值的排到二期高频低价值的能不做就不做低频低价值的直接砍。MVP版本只做了六个模块客户管理、联系人管理、跟进记录、商机管理、待办提醒、数据看板。客户管理是核心中的核心一切功能围绕客户数据展开。权限这块MVP版本先不做细粒度控制只区分两个角色销售和管理员。销售只看得到自己的客户管理员看全部。字段级权限、离职转交、公海池这些后来证明是刚需的功能都在上线后两周内紧急补上了。功能模块MVP版本二期追加优先级判断逻辑客户管理核心字段增删改查、搜索批量导入导出、回收站高频高价值先做基础跟进记录新增、列表、关联客户图片上传、语音转文字先保证文本记录闭环待办提醒简单时间轮询企业微信推送、短信先站内信再考虑触达权限控制数据级简单隔离字段级、部门级、审批流MVP用最少代码兜住底线数据看板按销售维度统计客户数、跟进度漏斗分析、趋势图先解决有没有再谈准不准2. 客户数据模型与生命周期管理2.1 三张核心表的结构设计客户管理系统的底层是数据模型数据模型设计得好不好直接决定后端改起来痛不痛苦。我设计了三张核心表客户表、联系人表、跟进记录表。客户表存公司维度的信息联系人表存公司里的具体人跟进记录表存每一次销售和客户交互的内容。客户表字段我精简到最实用客户名称、行业、规模、来源渠道、负责人ID、客户状态、下次跟进时间、创建时间、更新时间。这里有个容易忽略的点客户名称没有做唯一索引。但是我后悔了后来撞单问题频发就是因为同名客户被建了多条。正确做法是客户名称加唯一索引必要时再加一个信用代码或者统一社会信用代码字段做业务唯一键。联系人表的核心字段是姓名、电话、微信、职位、客户ID。电话这个字段必须做唯一约束因为一个联系人可能被多个销售录入不做去重就会产生重复骚扰客户的情况。我的做法是在导入和手动录入时就实时检索如果电话已存在且归属不同客户直接提示冲突让销售自己决定是关联还是新建。跟进记录表更关键字段包括所属客户ID、跟进人ID、跟进方式、跟进内容、下次跟进时间、创建时间。这条表设计了一个后置写优化跟进内容用TEXT类型索引只建在客户ID和创建时间上。为什么不给下次跟进时间建索引因为扫描时间范围的数据用创建时间索引就够了多建一个索引反而拖慢插入速度。2.2 客户状态机与公海池机制客户状态我定义了五个线索、跟进中、已签约、已流失、公海。线索是刚进来的新客户跟进中是正在沟通的已签约是成交客户已流失是暂时没戏的公海是公共客户池。状态流转规则是线索和公海的客户可以被销售认领跟进中的客户3天没动作自动打回公海已签约客户进入合同流程不走公海逻辑。公海池机制是CRM的标配它的核心价值是激活沉睡客户。客户被分到一个销售名下后如果这个销售连续30天没有跟进动作系统自动把客户放回公海其他销售可以认领。这样一来躺在别人列表里睡大觉的客户就会不断流动总有人觉得自己能搞定实际测试下来公海池启动后第二个月的签到率提升了15%。实现公海池的定时任务我用了Spring的Scheduled注解每天凌晨两点跑一次。SQL核心逻辑就是找出那些当前时间减去下次跟进时间大于30天且状态不是已签约的客户批量改成公海状态并清空负责人。这里有个细节批量更新前要先记录日志否则后面发现误迁还要手动回滚。UPDATE customer SET owner_id NULL, status public_pool, updated_at NOW() WHERE status IN (lead, following) AND next_follow_up_time DATE_SUB(NOW(), INTERVAL 30 DAY)2.3 数据唯一性与质量治理数据质量是CRM的大问题垃圾进垃圾出后面做任何数据分析都是白搭。我在系统里做了三层校验前端表单必填校验、后端业务校验、数据库约束。前端校验简单手机号格式、必填项提醒后端校验做业务逻辑比如手机号是否已存在、客户名称不能重复数据库约束是最后一道防线唯一索引直接兜底。Excel导入是个容易踩坑的重灾区。销售手上的历史客户数据基本都躺在Excel里导入功能是上线当天被要求最多的功能。我做了模板制先下载固定格式的Excel模板销售把数据填好再上传。上传过程用EasyExcel流式读取每读一行就做一次手机号去重重复的行直接写在导入错误报告里方便销售对照修改。最让我抓狂的一次是销售导入了一批手机号有300多个号码是虚拟运营商号段正则校验死活过不了。后来我调研了一下虚拟运营商号段虽然有特定前缀但定期会出新号段硬编码列表根本维护不过来。最后方案是只做基础校验11位、1开头不做号段白名单丢失的准确率用来换取可用性这个妥协在实际使用中完全够用。3. 核心功能模块的实操实现3.1 权限模型从简单隔离到真实可用的步步升级MVP阶段我天真地以为只需要区分销售和管理员代码写了个简单的拦截器根据角色判断能不能看全部数据。上线第二周问题就来了销售A离职他的客户怎么转给销售B新招了两个销售主管想看自己团队的数据但看不到别的组这时候才意识到权限模型要在数据层面做好准备。我升级成了RBAC加数据范围的组合方案。角色表定义角色名称权限表定义能操作的按钮和接口角色权限关联表把两者关联。数据范围的实现则是在客户查询SQL里动态加条件销售只看owner_id等于自己的主管看department_id等于自己部门的管理员看全部。这里的关键是租户ID和部门ID要建立树形结构主管要能看所有子部门的客户。字段级权限是基于角色的比如普通销售看不到客户的利润估算字段只有管理角色能看。实现方案是在后端定义字段可见性配置查询客户详情时动态过滤字段。这个功能比预想的复杂因为前端表单的Vue组件绑定也要跟着动态渲染后来我用一个指令封装了这个逻辑根据权限配置自动隐藏或禁用。3.2 待办提醒功能的实现与调优待办提醒这块我优先做了站内消息因为最简单也不依赖外部服务。每当销售新建跟进记录时系统会计算下次跟进时间当天的待办里就会生成一条记录。每天早上9点定时任务扫描当天的待办生成未处理的提醒。如果不做站内信这个功能的价值会大打折扣因为销售不会主动打开系统看待办。站内提醒的存储结构是消息表加消息接收人关联表字段包括消息类型、关联业务ID、接收人ID、是否已读。消息类型我分三种跟进提醒、客户分配通知、公海回收预警。公海回收预警是个很有用的小功能客户即将过期前3天提醒销售赶紧跟进比到期直接回收更人性化也减少了客户被误回收的抱怨。技术实现上我碰到过一个性能问题定时任务扫全量客户表的next_follow_up_time时数据到两万条后查询延迟明显。优化方案是直接用MySQL的事件调度器建一个专门的reminder表在写跟进记录时就把需要提醒的数据预生成进去定时任务只扫描reminder表。这样把大表扫描变成了小表扫描性能立刻提升了几十倍。CREATE EVENT IF NOT EXISTS generate_reminder ON SCHEDULE EVERY 1 HOUR DO INSERT INTO reminder(user_id, customer_id, remind_time, remind_type) SELECT owner_id, id, next_follow_up_time, FOLLOW_UP FROM customer WHERE next_follow_up_time IS NOT NULL AND next_follow_up_time BETWEEN NOW() AND DATE_ADD(NOW(), INTERVAL 24 HOUR) AND owner_id IS NOT NULL ON DUPLICATE KEY UPDATE remind_time VALUES(remind_time);3.3 数据看板的统计口径怎么定数据看板是团队开会最需要的功能也是最容易做得好看但没用的功能。我第一版就是简单统计客户总数、今日新增、本周跟进次数结果发现月底对账的时候销售和主管对不上数。问题出在统计口径上客户总数按什么状态算已流失的算不算公海里的算不算用创建时间还是更新时间作为分界点最后还是拉上团队一起开了个会把看板指标重新定义了一遍。客户总数只算状态是线索、跟进中、已签约的已流失和公海单独展示跟进次数按跟进记录的创建时间聚合删除的记录不算签约金额按合同表的签约日期统计而不是客户表。指标口径定义好之后所有页面的统计逻辑都统一了一套底层查询接口再也不出现同一天两个地方数字不一样的情况。看板的数据查询直接用SQL聚合不需要引入独立的BI系统。我给每个图表接口写了一个独立的查询方法和缓存策略热门维度比如按销售统计客户数的结果缓存5分钟。缓存时间不宜太长否则销售会以为系统坏了我踩过坑第一次设了30分钟缓存结果销售换了一个客户状态后看板半小时不变被群里问了好几次。4. 自动化流程与团队协作机制的落地4.1 销售自动分配与撞单规避自动分配是我整个系统里性价比最高的一个功能。线索从获客渠道进来后不用人工指派系统按规则自动分配给销售。规则是按销售当前客户数最少优先分配或者按固定轮询顺序分配。我采用的是结合方式周一到周五轮询周六日不自动分配等销售周一统一认领。撞单规避有两个层面录入时撞单和跟进中撞单。录入时撞单靠客户名称和手机号唯一索引兜底前端提交时实时请求接口校验客户已存在就直接弹窗提示让销售选择关联或新开。跟进中撞单主要靠状态锁定客户一旦被某销售认领其他销售只能查看不能编辑和新增跟进只能提交抢单申请给管理员审核。抢单申请我做成一个简单的审批单管理员的待办里会直接看到同意后客户负责人直接变更变更记录留在客户的操作日志里。这个日志很重要后期如果销售有争议直接拉日志看是谁、什么时候、做了什么操作比吵半天有用得多。日志记录字段包括操作人、操作时间、操作内容、操作前状态、操作后状态攒下来的操作日志也为后面做行为分析提供了基础。4.2 审批流与客户转交的规则设计审批流我做了三个客户转交审批、公海认领审批、合同金额折扣审批。MVP阶段只处理前两个合同折扣审批因为涉及财务流程二期才加上。客户转交审批的逻辑是销售A想把某个客户转给销售BA发起转交申请B确认接收管理员审批通过后系统自动完成客户负责人变更。这个流程看起来简单实现时发现有个坑转交过程中客户状态要保持不变但要锁定编辑权限防止A和B在审批期间同时操作。我加了一个转交中标志位客户表增加了一个lock_flag字段转交申请提交后置为1审批通过或驳回后置为0。虽然管理员审批一般几分钟内完成但有了这个锁机制协同冲突问题再也没出现过。公海认领这个流程我设计了两轮确认。销售在公海里看中一个客户后先发起认领请求系统先判断这个客户是否处于可认领状态再判断该销售当前名下客户数是否达到上限。我设的是一个销售最多活跃客户100个超过就不能认领新客户防止销售光占地不干活。到了上限之后系统会提示先去跟进自己的存量客户。这个限制看着简单实际对提升跟进率起到了立竿见影的作用。4.3 客户画像与自动标签的简单落地自动标签是二期功能里我觉得值得做的。最初销售在录入客户时会手动打标签比如已报价有意向暂缓。后期发现打标签这件事很主观同样的客户在A销售那里标着有意向在B销售那里可能标暂缓。我后来做了一套简单的规则引擎根据跟进记录和行为自动为客户打标签。规则引擎的实现比我想象的简单本质是一组条件判断。比如客户在7天内被跟进3次以上且状态为跟进中系统自动打上高活跃标签超过60天没有下一步动作的客户打上已沉睡标签。自动标签的结果同步更新到客户表的tag字段里前端客户列表支持按标签筛选销售在列表页一眼就能看出哪些客户该优先跟进。标签系统的核心价值不是给客户贴标签而是给销售的下一步动作提供决策依据。每天早上的待办提醒里我会增加一句建议你有12个高活跃客户建议今天优先跟进。这句话用Java的模板字符串拼接就行但销售反馈说这个提醒比冷冰冰的你有12个待办让他们的转化率更高。5. 部署上线与常见问题排查5.1 开发环境搭建和持续部署的踩坑记录开发环境的搭建不是难点真正的坑在部署和运维。我先说持续部署的流程本地Git提交Webhook触发服务器上的部署脚本脚本拉取代码、打包镜像、重新启动容器。这套流程我用了大概三天才稳定下来。第一天的教训是直接把后端服务停了再打包导致期间前端请求全部超时后来改成先构建新镜像再切换容器实现零停机升级。数据库变更又是一个独立流程。因为系统已经在跑真实数据不能随便改表结构所有表结构变更都要写成Flyway脚本部署时脚本自动执行。这个习惯是上线前一周才养成的原因是当时需求着急直接在测试库手工加了一个字段结果生产库忘了加线上当天就报错了。从那以后任何结构变更一律走Flyway生产、测试环境保持一致这条规则雷打不动。日志收集我也踩过坑。刚开始是让每个服务自己写日志文件排查问题时要把所有服务日志捞一遍特别浪费时间。后来用logback统一JSON格式输出每个请求带上traceId按天切割日志文件直接在日志目录下grep traceId就能串起一次请求经过了哪些环节。这套日志体系建好后排查线上问题的效率提高了一个量级。5.2 让我印象最深的5个线上问题上线第一周我就碰到了5个印象很深的问题这里整理成一个速查表如果你也在做自研CRM大概率也会遇到。问题现象根本原因解决方案客户列表加载慢列表页SQL缺少索引在owner_id、status、updated_at上建复合索引查询时间从3秒降到0.2秒导入Excel时系统OOM一次性把全部数据读入内存改成EasyExcel的流式读取每500条批量写一次数据库定时任务重复执行集群部署后多个节点同时跑加分布式锁用MySQL行锁实现抢到锁的节点才执行任务销售收到重复提醒消息表缺少业务唯一键增加unique key(user_id, customer_id, remind_type, remind_date)公海回收误伤了新客户逻辑判断用了创建时间而不是下次跟进时间修正SQL条件只回收超过30天无跟进的客户每个问题处理完我都写了一个复盘文档现在回过头来看这个文档成了团队最珍贵的知识库。新来的同事遇到类似问题直接查复盘不用再从头摸索一遍。5.3 数据备份和容灾机制要做到什么程度小团队自研系统最容易忽略的就是备份总觉得数据丢了也影响不多实则客户数据是核心资产丢一次就可能让你失去团队信任。我做了两层备份数据库每天凌晨全量备份到服务器本机再同步一份到对象存储另外开启MySQL的binlog保留7天支持恢复到任意时间点。恢复演练这件事我建议至少自己执行一次。我第一次演练恢复流程时才发现备份脚本只备份了数据库Redis缓存数据丢了导致所有登录用户需要重新登录不过这个影响可控。后来我把恢复流程写成了标准文档包括恢复数据库、刷新缓存、验证数据完整性三个步骤。容灾方面不可能跟大厂比我做到了能接受的RPO和RTORPO一天最多少一天的数据RTO两小时2小时内恢复服务。这个标准对三十人团队来说完全够用不能为了容灾增加过高的运维复杂度否则小团队根本吃不消。6. 上线后的运营心得与长期迭代思路6.1 让团队真正用起来的三个关键动作CRM系统最怕的是做出来没人用。我总结出三个关键动作第一个上线第一天就强制录入。我把客户录入纳入销售日报的必填项不录入当天日报不能提交。这个动作很粗暴但建立了数据基础没有数据任何功能都是空中楼阁。第二个每周一开数据复盘会。会上不看感觉只看系统里的数字按客户数是销售排名按跟进次数看积极性按公海回收量看大家都在忙什么。会上会被点名的压力会让销售认真对待录入这件事坚持一个月录入习惯就养成了。第三个是快速响应反馈。销售提的改进意见只要是合理的我尽量在两周内排上开发计划。有一次销售说在手机上录跟进内容还要打开电脑太麻烦了我花了三天适配了移动端页面简化了表单从此移动端录入率从20%提升到了50%。让使用者感到系统在跟着他们的需求成长他们才会愿意贡献更多数据。6.2 后续迭代方向从管理工具到决策辅助DeskcommCRM后续的迭代方向我想了很久核心是围绕销售做减法和加法。减法是指减少冗余操作比如语音转文字录入跟进、快捷填写模板、自动匹配联系人这些能减少输入成本的功能优先做加法是指增加决策辅助比如客户成交概率预测、跟进频率建议、最佳联系时间段分析这些数据能力能帮销售把时间花在刀刃上。但我不建议在初期就上AI和大数据原因很简单数据量不够。至少跑半年攒够几万条跟进记录和商机记录然后用一些基础统计模型做分析才有意义。我计划先做客户评分模型用简单的逻辑回归输入特征包括客户行业、来源渠道、跟进次数、平均响应时间输出0到100分的成交概率评分超过80分的客户排在列表最前面。另一个值得做的方向是移动端能力加强。现在的销售都是手机不离手微信是主要沟通工具如果能把CRM和企业微信打通让销售在微信聊天界面直接看到客户历史和待办那体验和价值会提升一个很大的台阶。我已经在调研企业微信的接口这是接下来最重要的一块拼图。6.3 我最后悔没在项目初期就做对的三件事写到这里我想坦白几个当初没做对的决策算是给后来人的预警。第一件是没有从第一天就做Flyway数据库版本管理导致上线前频繁手工改库、结构混乱。这个成本让我后面花了接近一周的时间来补齐。如果一开始就引入后面根本不会有手工改库的机会。第二件是没有提前设计字段级的操作日志。MVP版本的客户编辑没有记录操作历史等到销售员因为撞单问题吵到我这里来我只能靠客户表本身的updated_at去推测说服力非常弱。后来补了日志功能但前三个月的操作痕迹已经永远丢失了。第三件是导入功能没有做统一的校验规则文件。Excel模板改了一次字段后校验规则散落在前后端多处代码里改一个地方漏一个地方连续两个版本导入报错。现在我把所有校验规则统一到一个配置文件里前后端和导入导出的校验全部引用同一份规则定义数据一致性终于不再是个问题。这三件事的共同点都是基础工程不性感但很重要。做项目的时候人容易优先做看得见的功能把看不见的工程约束放后面等到数据量上来、团队多起来这些欠下的工程债会让你连本带利还回去。DeskcommCRM这个项目走到今天功能不算多但稳定可靠这几个字就是靠这些基础的地方撑起来的。