1. 项目背景与整体设计思路1.1 为什么叫 DeskcommCRM这个项目到底解决什么问题“DeskcommCRM”这个名字其实是两个关键词的拼合Desk 加 Comm合在一起就是“桌面沟通式客户管理”。一开始做这个项目的时候我并没有把它定义成一个标准的销售管理软件而是瞄准了一个更具体的场景——销售每天坐在电脑前翻客户、查聊天记录、记跟进、写日报这些动作散落在不同的系统里来回切换非常费劲。市面上的 CRM 产品不是不够强而是太重了重到一个小团队要花两周才能把字段配完重到销售宁可用 Excel 也不愿意打开系统。DeskcommCRM 的定位是“轻量但完整”它不追求大而全的功能堆叠而是把客户档案、跟进记录、销售阶段、日常沟通提醒这些东西统一到同一个工作台上让销售打开系统就能看到今天该干什么、哪个客户该跟进了、上一个销售跟客户聊到了哪个节点。换句话说它解决的核心问题是信息找人而不是人找信息。这个项目最适合谁参考一种是准备从零搭建业务系统的开发者和产品经理另一种是手里有二三十人销售团队、正在纠结要不要上大厂 CRM 的负责人。前者可以拿走整套设计和部分代码思路后者可以理解一套轻量级 CRM 应该具备哪些核心模块、哪些功能真的能提升效率哪些功能只是锦上添花。1.2 设计之前的三个核心思考在动手写第一行代码之前我把整个系统的设计围绕三个问题展开。第一谁在用这个系统的最终用户是销售代表和销售主管不是管理层。很多 CRM 做失败原因就是权限和报表设计优先满足了老板销售录入客户资料变成了一种变相的任务负担。所以 DeskcommCRM 的交互逻辑全部围绕“销售愿意用它”来设计录入字段少、跟进记录一键保存、待办事项自动生成。第二数据从哪里来销售手头最真实的客户数据来自微信聊天、电话记录、名片扫码和 Excel 表格。系统不能指望销售重新把客户信息敲一遍所以我在设计上留了批量导入模板和一套简单的去重规则甚至在后期加了快捷方式可以从聊天记录复制一段文字系统自动提取公司名、人名和电话。第三什么样的功能会被高频使用答案是查看客户资料、添加跟进记录、查看待办事项。这三个操作的频率远高于任何统计分析功能。所以整个界面布局把这三个功能放在最显眼的位置数据报表反而收在二级菜单里。这就是 DeskcommCRM 这个名称中“Desk”的体现——它是一个工作台不是档案柜。2. 核心功能拆解与关键模块设计2.1 客户档案360°视图怎么搭才不臃肿客户档案是 CRM 的基础但档案不等于字段越多越好。DeskcommCRM 里的客户档案分成三层基础信息、交互记录、业务标签。基础信息只保留公司名称、行业、规模、联系电话、地址、负责人全部字段加起来不到十个。我做了一个比较硬性的取舍如果某个字段超过 80% 的记录都没有值说明这个字段设计不合理直接砍掉。这可以避免“客户类型”“客户来源”等字段录入时选半天但后期根本没人看。交互记录则是一个时间线组件所有与此客户相关的电话、会议、聊天记录、邮件、跟进任务都按时间倒序平铺展示。这里有个细节时间线不仅要记录新建的数据还要记录系统自动产生的行为比如管理员修改了客户负责人这条操作也要出现在时间线上方便后续追溯。业务标签是后来才加的功能。客户数量多了之后纯靠分组管理不够灵活一个客户可能既属于“重点跟进”又属于“华东区域”多对多的标签系统比单一的分组更贴合实际。标签还有一个用途是给自动化流程当条件比如打上“已签约”标签后自动触发售后欢迎任务。2.2 销售流程与阶段漏斗不要把流程做成绊脚石销售阶段管理是 CRM 的招牌功能也是最容易做砸的功能。很多系统把阶段设计得特别复杂什么“初次接触”“需求挖掘”“方案报价”“商务谈判”“合同审核”“验收回款”整整八到十个阶段销售点起来都嫌麻烦。DeskcommCRM 里的默认销售流程只有五个阶段新客户、联系中、方案中、谈判中、赢单另加一个标注失败状态。五个阶段的好处是漏斗清晰管理者和销售都能一眼看出问题出在哪个环节。如果某个团队确实需要自定义流程系统也支持把阶段扩展成自己的流程允许每个阶段设置不同的赢单概率这样系统可以自动算出下一阶段的预期回款金额。阶段流转的实现比表面看起来多一层逻辑阶段变更必须记录时间和操作人并且可以在系统里设置“阶段逾期提醒”。比如某个客户停留在“联系中”超过七天没有更新系统自动把这条记录推送到负责人的待办里。这个功能看上去不起眼但实际上是把销售流程从“记录”变成“管理”的分水岭。2.3 跟进沟通模块Deskcomm 的灵魂所在“Comm”即沟通是整个系统里我最看重的一块。设计思路来源于一个实际观察销售每天很大一部分时间花在沟通上但沟通内容往往不会进入 CRM因为让销售边打电话边填表不现实。所以跟进模块做了一个折中方案跟进记录采用“极简录入”模式默认只有一个多行文本输入框和一个“保存”按钮不需要选择类型、不需要填下一步时间先在最快时间内把内容记下来。系统会自动提取正文里的关键词去匹配客户标签也会检测记录中是否包含“明天”“下午”“周五”这类时间词如果有自动生成一个提醒任务。打个比方这就像记账软件你不需要一开始就选分类先把账记下来系统后续帮你归类。很多销售愿意用这个功能是因为它真的降低了记录成本。至于更正式的周报、月报可以由这些碎片化的跟进记录自动汇总生成而不是让销售月底再去回忆这周干了什么。2.4 数据看板销售主管真正需要看什么数据看板做给两种人看销售自己看自己的业绩进度主管看团队的整体情况。两者不能混在一个页面里。销售个人的看板核心是四个数字本月新增客户数、本月跟进次数、本月新增商机金额、赢单率。主管的看板核心是团队维度的漏斗数据和每个人的转化率对比同时还有一个“流失预警”列表列出那些超过 15 天没有任何跟进动作的客户以及离开当前阶段超过设定时长的商机。做看板的时候有一个经验值得分享不要试图把所有指标都塞进首屏。我最初在主管看板上放了十二个指标卡片测试时发现根本没人认真看因为信息过载等于没有信息。后来砍到五个核心指标反而被团队频繁使用。数据分析的第一原则是克制不是炫技。3. 技术选型与实现细节3.1 技术栈为什么这么选DeskcommCRM 的技术栈选择遵循了一个原则够用、稳定、好招人、好交接。没有刻意追新。前端用的是 React Ant Design这套组合在国内团队里非常普及组件库自带的 Table、Form、DatePicker 等组件几乎就是为管理系统量身定做的能省掉大量重复的样式和交互开发。后端选择的是 Node.js 的 NestJS主要是看中它自带模块化架构和依赖注入代码结构比较规整小团队后期加功能不容易把项目写成大泥球。数据库用的 PostgreSQL没有用 MySQL原因是 PostgreSQL 对 JSON 字段的支持更好后续如果需要给客户档案加自定义字段不需要频繁改表结构。缓存用的 Redis主要服务两个场景登录会话和权限缓存。我当时没有选择更重的 Java Spring Boot 技术栈不是因为 Java 不好而是这个项目的定位是轻量级、快速迭代Node.js 的开发效率在小团队场景下更高。如果你的团队本身是 Java 背景完全可以用 Spring Boot 重写后端接口设计思路是通用的。3.2 数据库模型设计一张客户表是不够的第一次设计表结构时我犯了一个典型错误想用一张 customer 表装下所有客户信息。结果客户联系人、地址、标签全部挤在一起关联查询不方便数据冗余也很严重。后来重新拆成了五张核心表customer客户主体信息只存公司级字段。contact联系人表一个客户下可以挂多个联系人销售跟进时具体到人。deal商机表一笔交易的基本信息关联客户、金额、阶段。activity跟进活动表包括电话、走访、微信沟通等记录。task待办任务表销售需要执行的下一步动作。这五张表构成了整个系统的主干业务链。还有一个比较关键的设计是“软删除”。业务表都不直接物理删除数据而是通过 deleted_at 字段标记。CRM 是做数据沉淀的误删客户是销售最不能接受的事软删除加回收站机制管理员可以从回收站恢复被误删的客户。这个功能看起来没有技术含量但在实际使用中救过很多次命。3.3 权限设计谁能看什么必须一开始就想清楚权限设计是 CRM 系统里最容易被低估的部分。刚开始我只设计了两种角色管理员和普通销售。上线两周后主管提了一个需求他是销售主管但他只能看自己的客户和自己的团队成员的客户不应该看到其他团队的客户。这就引出了三层权限模型数据权限按归属人隔离普通销售只能看自己名下的客户主管能看到自己部门所有销售名下的客户管理员可以看全部。操作权限不同角色对客户的编辑权限不同普通销售的客户转移到其他销售时必须走审批。字段权限有些字段对普通销售隐藏比如客户的成本价、合同利润比例。技术实现上我在每个业务表里都加了 owner_id 和 team_id 两个字段。查询数据时根据当前登录用户的角色动态拼 SQL 过滤条件。这里有个性能优化的细节不要在每个查询里都去 JOIN 用户表查角色而是登录后把角色和权限列表缓存进 Redis查询时直接从缓存里取。4. 实操过程与核心环节实现4.1 从环境准备到项目跑起来如果你想把 DeskcommCRM 的思路复现出来第一步是把基础环境搭好。我建议本地开发环境用 Docker Compose 一把拉起 PostgreSQL 和 Redis避免在装数据库上浪费时间。我当时的 docker-compose.yml 里只写了两个服务加上一个 pgadmin 用来查看数据几分钟就能把依赖环境准备好。后端启动后先跑数据库迁移脚本把基础数据表建出来然后接一个初始化种子脚本自动创建一个管理员账号和一个演示销售账号。这个过程做完系统已经可以启动登录页了。前端开发服务器起来之后需要留意接口代理配置。我本地开发时前后端分开两个端口跑NestJS 默认跑在 3000React 开发服务器跑在 5173需要在 Vite 配置里把 /api 前缀的请求代理到 3000 端口不然每次请求都有跨域问题。4.2 销售流程配置先做一套可以用的模板系统跑起来之后第一个要配置的往往不是客户资料而是销售流程。很多人忽略这一点等到录入了客户以后才想起改流程这时候调整数据很麻烦。DeskcommCRM 的管理后台里流程配置界面的核心是几个选项流程名称、阶段列表、每个阶段是否允许修改金额、每个阶段的预计停留时长提醒阈值。我的建议是第一次上线先使用系统内置的五阶段模板强制团队用两周收集到真实的卡点之后再调整。两个原则一是流程阶段尽量少二是所有阶段加起来必须覆盖“从获取线索到最终赢单”的完整路径。配置完成之后一定要做一次流程穿越测试创建一个测试客户按照正常业务路径录入并推进阶段观察时间线、漏斗统计和任务提醒是否都正确触发。这一步不能省因为流程配置涉及的数据联动是整个系统里最多的。4.3 批量导入历史客户数据一个最容易翻车的环节上线 CRM 时最头疼的往往不是开发而是把销售手里的 Excel 客户数据导进系统。我在这个环节踩了不少坑最终沉淀出了一个相对靠谱的做法。第一步提供一份标准导入模板模板里只有必须字段客户名称、所属行业、联系人、联系电话、负责人邮箱。第二步写一个数据清洗脚本在导入前自动做这几件检查手机号格式是否合法、必填字段是否有空值、是否存在重复客户按公司名称精确匹配加相似度匹配。第三步清洗结果生成一份导入报告标出每一行的错误原因让销售可以按行修正后重新导入而不是导完才发现有一半数据有问题。清洗脚本里用到了简单的相似度算法比如编辑距离低于一定阈值的公司名会标为疑似重复。这一步非常值得做不然后期靠人工在系统里合并重复客户工作量大到你想放弃这个 CRM。4.4 核心流程打通从客户建档到赢单回款整个系统能不能真正被团队用起来关键就看三个核心流程是否顺畅。第一个流程是新增客户。销售录入一个客户名之后系统实时调用一个简单的名称查重接口如果发现相似客户弹出一个确认框让销售选择“归入已有客户”还是“新建客户”。这个细节能有效减少后续的数据清洗成本。第二个流程是跟进客户的闭环。销售在客户详情页填完跟进记录后系统判断是否有关联的待办任务如果有自动把任务状态更新为“已完成”。如果销售在记录里提到了“下次跟进”系统生成一个新的提醒任务并分配给当前负责人。这个闭环是真正让团队愿意每天打开系统的原因。第三个流程是赢单后自动触发下一阶段动作。商机阶段更新为“赢单”时系统自动把客户标记为“已成交”并生成一个成交时间点同时通知后续的服务人员接手。这个自动化节省了很多人工沟通成本。5. 常见问题与排查技巧实录5.1 客户数据重复怎么从源头控制系统上线三个月后数据重复问题开始突显。同一个客户被两个销售分别录入双方各跟各的主管看数据时看到两个一样的公司名金额统计也会翻倍。排查后发现根本原因不是查重接口没生效而是很多销售录完第一个客户后忘记第二个销售去搜索直接新建。针对这个情况我做了两个调整第一把新增客户时的查重从“建议”改成“强制”发现疑似重复时不能跳过第二后台增加一个“重复客户合并”工具管理员可以根据相似度分数批量合并合并时保留主记录的信息副记录跟进的记录全部挂到主记录下面。务必重视合并操作的逻辑因为合并错误可能导致该客户的历史跟进记录丢失销售会非常不满。5.2 权限越权普通销售看到了不该看的合同金额权限上线后出现过一次越权问题普通销售在商机详情页看到了合同金额的字段而按照规则这个字段只对主管开放。排查过程很典型——前端判断了一个字段值来隐藏金额列但接口返回的数据里并没有把金额字段过滤掉。也就是说前端只是藏了显示后端仍然把完整数据返回给了前端稍微懂点接口调试的人就能看到不该看的数据。修复方案是把字段权限下沉到接口层后端根据当前角色动态决定返回数据中是否包含敏感字段。前端隐藏只是体验问题后端过滤才是权限安全的核心。这是一个 CRM 系统很常见的安全误区。正确的做法是默认后端永不返回超出角色权限的数据而不是靠前端遮遮掩掩。5.3 数据量大之后列表查询越来越慢当客户量增长到几十万条关联商机也到了百万级别之后列表页的查询开始变慢最明显的卡点在主管视角的团队销售漏斗报表上。排查后发现几个原因第一列表查询在 COUNT 统计时走了全表扫描第二阶段漏斗的统计查询实时去聚合几十万条商机数据没有任何预聚合第三前端一次性请求了太多字段导致传输数据量过大。我这边的优化方式是给 deal 表的 status、owner_id、created_at 建立了联合索引彻底解决漏斗查询的排序和过滤问题。同时引入了一套简单的定时任务每天凌晨把每个团队、每个销售、每个阶段的统计数据预计算后写入一张统计汇总表页面上直接查这张表查询时间从秒级降到了毫秒级。如果不想每天跑定时任务也可以用 Redis 做结果缓存设置五分钟过期也能达到很好的效果。5.4 跟进记录时间线乱序和时区问题上线后有一个反馈很奇怪销售在下午四点录入的跟进记录在时间线上显示的是第二天凌晨零点。排查发现是时区问题。后端存储时间用了 UTC 标准时间前端展示没有做时区转换直接把 UTC 时间当本地时间显示导致国内下午的数据显示成了凌晨。修复方式后端统一用 UTC 存储前端在请求拦截器里统一对时间字段做本地时区转换。更稳妥的做法是后端接口直接返回时间戳前端用 dayjs 转换成本地时间。这里还要注意数据库连接字符串也必须带上时区参数否则 ORM 读取时间时可能又出现一次偏移。5.5 常见问题排查速查表现象可能原因快速排查方法导入 Excel 时部分行丢失模板中必填字段存在空值查看导入报告按错误类型筛出问题行新用户无法登录用户未被分配给任何角色检查用户角色关联表确认角色状态为启用销售阶段变更后漏斗数据没变统计查询走了缓存检查 Redis 缓存 key主动清理对应缓存管理员能看到全部但主管只能看到部分客户团队 id 与员工团队 id 不一致核对权限配置中团队关系树是否正确客户详情页打开很慢时间线查询数据量过大给 activity 表增加客户 id 和时间的联合索引6. 实操心得与后续扩展建议6.1 上线初期最容易踩的坑是“想一步到位”很多项目失败不是因为技术不行而是因为第一版就想把所有功能都做出来。我当时也差点把客户公海、商机预测、多币种报价这些功能全部塞进第一版幸好及时刹住了车。第一版上线时只做了客户档案、跟进记录、任务提醒和最简单的漏斗看板剩下全部放在二期。事实证明这个决策非常正确。团队真正用了两周之后提出的需求和我们最初预想的重合度不到一半比如他们更在意“客户标签能不能从跟进记录里自动提取”而不是我们原本计划的“客户公海自动分配”。先上了核心闭环再根据真实反馈迭代软件的投入回报比要高得多。6.2 从单一 CRM 延伸出去工作台化是趋势DeskcommCRM 这个项目跑通之后我最大的感受是客户管理系统最终会走向工作台化。未来的 CRM 不该只是为了管理客户而存在而应该成为销售日常工作的唯一入口——打开系统就能看到今天的日程、待跟进客户、团队动态、本周要交付的方案。你可以把 DeskcommCRM 的沟通模块升级成一个轻量级的内置聊天工具把客户沟通和内部协作放在同一个界面里这也是“Desk”这个概念的延伸。如果后续要继续扩展我建议优先做两个模块一个是基于跟进记录的自动周报生成减少销售的报告负担另一个是客户健康度评分模型根据近期的跟进频率、商机阶段停留时长、互动次数给客户打一个 0 到 100 的分值让销售优先处理高价值高风险的客户。6.3 最后分享一个实际使用中的小技巧我们自己团队用下来最有效的一个使用习惯是每天下班前花五分钟把当天所有跟进记录过一遍凡是明确了下一步动作的顺手在系统里创建一个带时间的待办任务。这个动作看上去很机械但它能保证销售第二天早上打开 DeskcommCRM 时不需要回忆和思考系统已经列好了应该先联系谁、要说什么事。这也是我认为做这类工作台型系统的核心哲学系统不应该只是记录过去更应该主动规划未来。DeskcommCRM 的真正价值不是把销售的历史信息存下来而是让每个销售每天早上都清楚地知道下一步该做什么。如果你也在做类似的业务系统建议把这个原则贯穿到每一个模块的设计里。