如果你所在的公司曾经买过两套CRM都没能坚持用下来那你应该能理解我们决定自研DeskcommCRM时身边同事的表情。大多数CRM产品的出发点其实是管理者的报表需求而不是一线销售的工作效率。销售不愿意录数据主管天天催最后系统里只剩一堆过期的商机和没人看的跟进记录。DeskcommCRM这个名字拆开看其实就是两件事Desk桌面办公场景 Comm通信集成它不是一个传统意义上管客户信息的数据库而是一个把通话、邮件、企业微信消息和客户资料全部收拢到一个桌面操作台的客户关系管理平台。这篇文章我打算把整个项目的立项判断、技术选型、数据建模、通信集成的实现路径以及上线九个月之后踩到的真实问题都写清楚。如果你正在纠结自研CRM还是继续买现成的或者已经决定自研但不确定从哪里下手这篇文章应该能帮你省掉不少弯路。1. 从买了用不起来到自研DeskcommCRM立项时的三个判断1.1 市面CRM为什么落不了地先说我观察到的普遍现象。很多团队买完CRM之后热情期不超过三个月。原因是销售真正的工作流根本不在CRM里他们每天在微信上跟客户聊、用手机打电话、在邮箱里发报价然后每天下班前再花半小时把沟通记录翻译进系统。这种二次录入本质上是在给销售增加工作量而不是在帮他们干活所以录入率低是必然的。还有一层问题在管理层老板想看的是漏斗、预测、回款而销售在意的是这个客户上周说过什么上次报价是多少他到底有没有看过我的方案。这两个诉求如果被强行塞进同一个页面结果就是页面无比臃肿点一个按钮要跳转四次。DeskcommCRM立项前我们做了一轮内部调研发现一线销售和生产主管对好用的定义完全不同一个要少点几下鼠标一个要能看出谁在怠工而市面产品往往想同时讨好两边最后两边都不满意。1.2 立项时锁定的两个关键词Desk和Comm所以我们在产品定义阶段就把范围收敛只做两个核心词。Desk指的是坐席桌面销售、售前、客服每天大部分工作时间都在电脑前处理客户消息和跟进事项这个系统必须首先是一个高效的操作台而不是一个录入窗口。Comm则是指通信能力客户触点不应该是需要人工转录的内容而是应该自动流进系统成为数据资产。目标产品形态最后敲定为三栏式工作台左边是客户列表和筛选器中间是客户详情与时间线右边是通信面板可以一键拨号、回复邮件、查看企业微信聊天记录。所有跟这个客户有关的动静都集中在一个屏幕上销售不需要切换窗口系统就能把通话记录、往来邮件、消息记录自动归档到对应的客户名下。1.3 给项目划定的边界立项时我们也很清楚什么不做。不做复杂的审批流引擎不做多仓库多币种的ERP联动不做营销自动化的各种花哨邮件触达。那个阶段团队的精力只够服务一条核心链路客户进来、跟进记录沉淀、商机推进、成交转化。其他功能宁可后面再补也不在一期堆进去。这个边界划得非常重要因为自研项目最大的风险不是技术难而是范围失控。如果一开始就想着做一个全家桶大概率半年后还在写需求文档。2. 技术底座自研但不过度设计2.1 为什么不用现成开源CRM二开这个问题几乎每个听到自研的人都会问。我确实认真调研过几款开源方案包括老牌的SugarCRM社区版、EspoCRM以及用PHP写的SuiteCRM。最终放弃的原因很统一二开成本被严重低估。首先是数据模型改不动。开源CRM的数据库表结构是围绕标准销售流程设计的而我们想要的是客户联系人商机事件流这种以时间线为核心的模型改起来基本等于动根基。其次是升级冲突一旦改了核心表结构上游更新就再也合不回来了等于把自己锁死在一个旧版本上。更现实的问题是界面交互普遍陈旧现在的销售团队早就习惯了企微、飞书这类工具的交互体验旧式表单录入很难让他们接受。当然自研的前提是团队确实有后端和前端的完整能力如果团队连一个能独立扛起全栈的人都没有那还是老老实实买现成的没必要为了技术情怀给自己挖坑。2.2 技术栈与部署形态DeskcommCRM的后端我们用了Node.js TypeScript NestJS选它的核心原因有两个团队对这个技术栈最熟以及NestJS的模块化结构非常适合按业务域来划分代码比如客户模块、通信模块、统计模块各占一块互不干扰。数据库用的是PostgreSQL这是我认为最适合做业务系统的选择。它的事务能力、JSONB类型、行级安全性都能同时满足业务建模和后续权限扩展的需求。前端是React Electron的桌面应用壳配合自建的REST API和WebSocket通道。通信网关方面电话能力用FreeSWITCH接SIP中继软电话走WebRTC邮件走IMAP/SMTP协议栈企业微信走官方API和会话存档接口。部署上我们放在了公司自己的私有云环境没有用公有云SaaS化。原因是客户数据敏感性比较高公司内部要求所有业务数据必须落在自有基础设施上这也是很多中小型公司选择自研而不是采购SaaS的一个重要考量。2.3 一个关键取舍桌面端还是纯Web端浏览器确实省事但通话功能成了绕不过去的坎。浏览器里的WebRTC虽然也能打电话但在设备管理、录音文件获取、本地音频回环这些层面限制很多尤其当你还要对接实体话机或者复杂的音频外设时纯Web方案很难做到稳定。最终采用Electron桌面壳之后桌面端和Web端的差异就体现出来了本地SIP注册、音频设备枚举、录音文件直接落盘、来电时系统级弹窗提醒这些能力都变得很自然。下面是当时做的对比维度纯Web端Electron桌面端通话能力受浏览器限制需要额外服务转发本地SIP注册走WebRTC直连延迟更低设备管理无法精确控制音频输入输出设备可以枚举设备并记忆用户选择录音落盘需要服务器转存流程长本地录制后同步可靠性更高离线能力基本没有可以缓存客户列表弱网可用包体与内存轻量包体大内存占用高需做优化Electron的缺点也真实存在安装包动辄一两百兆内存占用比浏览器高不少。我们的缓解办法是把不需要常驻的模块改成懒加载并定期释放缓存实测下来中端办公电脑跑起来不算吃力。3. 数据底盘客户、联系人、商机的建模细节3.1 企业和联系人分开建模这是很多初创CRM最不重视的地方。早期我们打算一张客户表解决所有问题后来发现如果客户是公司你想记对接人、决策人、财务联系人一张表根本塞不下。最终拆成了两张主表customers客户企业和 contacts联系人联系人和客户是多对一的关系。这种拆分看起来简单实际好处极大。销售电话打进来时来电号码先查contacts表命中后直接定位到客户企业客户详情页和该联系人的历史沟通记录一次性都带出来。如果号码没有在联系人表里还可以通过这一企业下的其他联系人来帮助判断来电者身份比单表设计灵活很多。3.2 商机阶段不是简单的下拉框商机管理我们一开始也做成了下拉框但跑了两周发现一个问题销售选阶段非常随意主管根本看不出哪些商机真正在推进。后来把阶段字段升级成了有约束力的状态机模型定义如下阶段含义进入条件预期停留时间1-初步接触已建立联系创建商机5天2-需求确认已明确需求和预算有会议纪要或需求文档7天3-方案报价方案已发进入商务报价单已创建10天4-商务谈判价格和条款谈判中有二次报价记录14天5-赢单/输单闭环合同审批通过或明确放弃-每个阶段匹配了预期停留时间系统每天凌晨跑定时任务发现有商机在某个阶段停留超过预期天数就自动给负责人和主管推送一条提醒。这个机制上线之后商机变动的及时性明显提升因为销售自己也被系统盯着偷懒不推进会被领导看见。3.3 时间线模型所有客户接触记录的统一容器时间线是DeskcommCRM最核心的数据结构。我们设计了一张统一的events表所有跟客户的交互都往这里面写电话、邮件、企微消息、会议纪要、跟进笔记、报价记录都作为一条事件记录存在关联到对应的客户和联系人身上。这样做的好处是前端渲染简单客户详情页只要按时间倒序拉取events表就可以了不需要为每种业务类型单独写一套列表组件。搜索也方便全局搜索只要索引events表的content字段客户相关的历史消息全都能被检索出来。统计也好做按事件类型分组聚合就能得出沟通频次、响应时长这些管理指标。当然统一模型也有代价每种事件类型会有自己独特的字段比如电话有通话时长邮件有主题和附件工单有状态。解决办法是主表只存公共字段扩展字段放附属的JSONB列查询的时候按需解析。PostgreSQL的JSONB性能足够支撑这种用法不用过度纠结表结构。4. 通信集成DeskcommCRM的灵魂模块4.1 通信层抽象所有外部触点都收敛成会话记录如果DeskcommCRM只是一个客户资料库那它跟Excel没什么本质区别。通信集成才是让系统真正活起来的关键。我们的做法是抽象出一个统一的消息记录接口不管消息来自电话、邮件还是企业微信最终都归一化成同一种数据结构写入message_records表。这个接口大约长这样interface MessageRecord { id: string; customerId: string; contactId?: string; direction: inbound | outbound; channel: call | email | wechat; content: string; mediaUrl?: string[]; startedAt: Date; duration?: number; rawPayload?: Recordstring, unknown; }这个抽象非常重要。它让上层业务完全不需要关心消息来自哪个渠道通话记录、邮件、消息全部平等地出现在时间线上展示、搜索、统计都只需要处理一张表。新接一个渠道时只需要写一个适配器把外部数据翻译成MessageRecord结构剩下的功能全部复用。4.2 通话模块FreeSWITCH与来电弹屏的落地电话这块我们用了FreeSWITCH配合SIP中继前端通过SIP.js做WebRTC软电话。核心功能有三个点击拨号、来电弹屏、录音归档。点击拨号的逻辑是销售在客户页点击电话号码系统调FreeSWITCH的API发起外呼FreeSWITCH先呼坐席分机坐席接听后系统再呼客户号码这种模式叫做先呼坐席再呼客户好处是客户看不到坐席的真实手机号而且支持录音。来电弹屏的逻辑是来电接入FreeSWITCH后系统拿到主叫号码在contacts表里查这个号码对应的联系人和客户然后把客户信息直接推送到所有在线坐席的桌面端弹窗上。销售还没接电话就已经知道这个客户叫什么、上次聊到什么、有没有未处理的报价。这里有个很实在的坑SIP信令的超时时间设置。最开始我们用的是默认值60秒结果有些客户电话响了很久没人接系统里一直处于呼叫中状态坐席不知道要挂断还是继续等。后来把无应答超时改成了25秒同时加了音频提示体验才正常。4.3 邮件模块IMAP同步与自动关联邮件模块我们走的是IMAP协议。每个坐席登录系统时绑定自己的企业邮箱账号系统通过IMAP定时拉取收件箱新邮件。拉下来之后要做三件事去重、解析、关联客户。去重是个容易被忽视的坑。同一封邮件如果既有收件箱又进了某个文件夹IMAP的UID会不一样容易造成重复入库。我们后来加了一个规则用message-id received日期做唯一索引才彻底解决重复问题。关联客户的策略是反向匹配先提取发件人和收件人的邮箱地址去contacts表里查这些邮箱有没有绑定过联系人如果找到了就自动把邮件挂到该联系人名下。如果找不到就把邮件放进待分配池子销售看到后可以手动归属归属之后系统会记住这个外部邮箱发来的后续邮件自动进该客户的收件箱。发送邮件的部分相对简单我们做了一个模板库销售可以选一个模板然后自动带入客户称呼、公司名这些变量。不要小看模板功能它直接提升了报价邮件和跟进邮件的规范化程度。4.4 企业微信/企微消息记录把外部IM也收进来很多销售跟客户沟通都用企业微信这部分聊天记录如果进不了CRM系统的时间线就是残缺的。我们接入了企业微信的会话存档和外部联系人能力。特别注意这里不是爬聊天记录而是通过官方API在客户和员工都同意的前提下获取合规的会话内容。企微消息进系统后同样转换成MessageRecordchannel标记成wechat。为了减少噪音我们还设置了一个开关可以把某些闲聊群组排除在归档范围之外避免时间线被无关消息刷屏。4.5 统一收件箱的交互细节通信模块做好之后界面交互反而成了新的战场。所有渠道的消息汇入同一个收件箱之后我们设计了几个交互细节新消息在桌面端弹Toast提醒点击直达对应客户时间线消息按客户聚合而不是按渠道聚合同一个客户下的电话、邮件、消息全部混排在一起按时间排序已读未读状态全局统一处理过的消息自动标记为已读。这三个细节看起来简单但实际上决定了用户愿不愿意天天打开这个系统。5. 权限模型让一线安心用让管理层看得见5.1 三级客户池私有、团队共享、公海客户资源分配是销售团队最敏感的话题。我们当时把客户归属设计成了三级池子私有客户只有归属人可见可操作、团队共享客户同组成员可见但编辑和跟进需要权限、公海客户无归属人所有销售都可以认领。所有新线索进入系统后默认落在公海销售主动认领后变为私有。私有客户如果在30天内没有跟进记录则自动回到公海由其他同事认领。这个规则听起来会让销售紧张但实际跑起来之后反而提升了线索利用率沉睡的客户资源不再被个人私藏。还要注意公海回收和商机阶段的联动。如果一个私有客户名下存在处于方案报价阶段的活跃商机就不应该被回收否则容易引起冲突。我们的策略是有活跃商机的客户不参与自动回收需要主管手动移出。5.2 字段级权限与数据导出边界权限不能只靠谁的客户谁看这种粗粒度控制。客户资料里有些字段很敏感比如客户负责人的手机号、合同金额、备注中的个人信息。我们的方案是给字段打标记分为全员可见、仅本人和上级可见、仅管理员可见三种级别。前端根据当前登录用户的角色动态渲染字段后端接口同步做过滤前端隐藏字段只算第一层保险后端不下发数据才是真正的权限边界。数据导出权限也做了限制。普通销售只能导出自己名下客户的列表导出操作会生成审计日志记录操作人、时间、导出的数据范围和条数。我们遇到过销售把整个团队客户导出带走的情况所以导出权限必须从严。离职继承这块我们做了自动转移员工账号标记为离职后名下私有客户自动转移给部门主管主管可以再批量分配给指定接手人。这个功能看着不起眼但能省掉大量线下扯皮。6. 上线之后一组真实数据和几个要返工的设计6.1 用了九个月的数据反馈DeskcommCRM上线九个月最直观的变化是数据活起来了。团队成员30人左右每天平均产生600多条客户交互记录而以前手动录入的时候这个数字长期在50条以下。下面是整理的一些关键指标指标上线前手动录数据上线后系统自动采集人均每日录入跟进记录不到10条20条左右且多为自动同步客户联系响应时间邮件8小时以上2小时以内商机阶段更新及时性滞后2-3周当天数据完整率客户电话约70%95%以上这组数据说明一个事当记录不再依赖人工二次录入而是操作过程中自动产生数据质量自然而然就上来了。管理者想要的看得见其实是这么来的。6.2 三个做对了的地方复盘下来有三个决策我觉得是对的。第一个是把通信放在客户详情页旁边而不是单独一个模块销售不需要来回切换界面使用频率自然就上来了。第二个是所有沟通记录自动进时间线销售不再需要为写跟进记录这件事买单系统替他们完成了记录他们只需要偶尔补充备注。第三个是报表少而精我们没有做几十个维度的BI看板核心就保留了商机漏斗、团队活跃度、客户响应时长三个报表管理者真正盯着的也就这几个数。6.3 下一步计划返工的两个模块当然也有要返工的地方。第一是自定义字段能力实在太弱了客户资料里有些行业特定的字段当时是写死在代码里的结果每接一个行业就要发一次版本。现在已经在规划一套动态表单引擎让管理员可以在后台自己添加字段而不改代码。第二是移动端体验。DeskcommCRM目前只有桌面端销售外出拜访客户时只能用手机浏览器凑合看体验很差而且通话模块在移动端也不能用这个短板已经直接影响了外勤人员的接受度。如果当时能更早意识到移动端不是桌面端的缩小版而是另一个使用场景可能会把H5轻量版提前排进迭代计划。这也是我给所有准备自研CRM的团队一个最实在的建议别只盯着电脑前的场景销售真正签单的时刻往往是在客户现场。