自研CRM实践:从数据模型到权限控制与业务闭环设计

发布时间:2026/10/19 11:32:53

自研CRM实践:从数据模型到权限控制与业务闭环设计 1. 为什么我会动手写一个叫 DeskcommCRM 的自研 CRM先说清楚一个反直觉的事实我们不是没有用过现成的客户管理系统恰恰是因为被现成方案够用但不合用卡了很久才决定自己开发 DeskcommCRM。当时团队大概三十几个人销售、售前、实施、运营各管一摊市面上主流的 SaaS CRM 功能很全但全到让人无从下手。管理员要配几十个字段销售不愿意填管理层看报表又总觉得数据不真实最后系统沦为为了开会才打开的摆设。这个问题的本质不是软件不行而是我们缺一张真正贴合自己业务流程的数据结构。比如我们公司做的是企业服务类项目一个客户从咨询到签约中间要经过售前方案、试用、报价、商务谈判、合同审批多个环节每个环节都有独立的负责人和有效期。主流的通用 CRM 把一切都抽象成联系人商机活动这确实标准但我们真正需要的其实是服务请求和交付里程碑这类业务对象硬用标准模型去套要么妥协要么在系统里堆满自定义字段后迷失。自研 DeskcommCRM 前我们权衡过几个选项方案优点缺点我们的判断继续用现成 SaaS零开发成本、更新快字段和流程被平台锁死个性化定制贵不符合多业务线并存需求找外包定制功能量身定制沟通成本高、后期维护依赖外包长期迭代风险不可控购买可私有化的开源 CRM功能起点高二次开发依赖原框架设计改动深层逻辑难和团队现有技术栈耦合度差自研轻量级 CRM数据模型可控、迭代快需要投入人力团队有后端和前端能力选方案我当时的判断是不要指望一步做出完整 CRM而是先把最关键的业务闭环做通。DeskcommCRM 核心只解决四件事每个客户从线索到签约之间发生了什么所有与客户的沟通记录能不能按时间串成一条线每个销售手上的任务和提醒是否可控管理者能不能实时看到真实的漏斗数字而不是销售每周手工填的表格。这四个核心需求拆开看并不复杂组合在一起却需要仔细设计后续文章会逐步展开。2. DeskcommCRM 的数据模型设计实体划分、自定义字段与可见性控制2.1 为什么先做数据模型再做界面很多团队开发 CRM 时容易犯一个错误先画界面原型把页面做得漂漂亮亮再反过来补数据结构。这会导致一个非常典型的问题——同一个客户信息可能散落在三个表里因为三个页面分别用了不同的字段存储。DeskcommCRM 的第一版我花了整整一周时间只做数据模型设计代码一行没写。最终核心实体我们留了五个客户账户account、联系人contact、线索lead、销售机会opportunity、活动activity。外加两个辅助实体任务task和附件attachment。客户账户和联系人的区别我当初专门跟销售团队解释过客户账户指的是合同跟谁签联系人指的是日常跟谁聊。一个客户账户可以有多个联系人尤其是企业服务领域甲方可能有商务对接人、技术对接人、决策人三个角色。如果把这两者混在一个表里后面做合同、开票、业绩归属时都会混乱。2.2 自定义字段的设计方式现成 CRM 里自定义字段通常就是加一个字段但在 DeskcommCRM 里我用了字段定义表 字段值表的设计方式而不是直接改业务表结构。原因是业务表的字段是动态的如果每个租户或每个团队都能随意加字段ALTER TABLE 会制造大量数据库迁移冲突。实际实现是这样实体定义表entity_definition保存客户、联系人、线索等对象的基础元数据字段定义表field_definition保存每个对象的字段名、字段类型、是否必填、是否唯一、排序等信息字段值表field_value以 EAV 方式保存具体记录的自定义值。EAV 模式有个众所周知的问题查询效率低、关联复杂。为此我做了两层优化。第一核心高频查询字段比如客户名称、手机号、负责人仍然保留在主表的固定字段中只有真正需要灵活扩展的业务属性才放进 EAV。第二查询时先通过主表过滤出一个很小的记录集再一次性批量取出所有自定义字段值而不是逐条 JOIN。实践下来在十万级客户数据量内性能完全可接受。自定义字段在前端的表现是管理员在字段设置页面可以拖拽排序、设置分组业务人员填写表单时自动按配置渲染输入控件。这样一个多功能配置体系的复杂度可控而且不会因为业务变化频繁改数据库表。2.3 权限与可见性CRM 最容易被忽视的失控点权限设计是最值得花时间的部分。没有权限控制的 CRM 就是全员可查全库这在实际业务里会带来严重问题销售能看到别人的客户可能造成抢单管理者看不到具体项目细节又等于没有控制。DeskcommCRM 的权限分成三个维度功能权限能否查看客户、能否删除线索、能否导出数据数据权限本人数据、本部门数据、全部数据字段权限某些敏感字段如合同金额、客户联系方式是否对特定角色可见。数据权限我采用所有权 共享规则结合的方式。每个客户记录有一个 owner负责人字段正常情况下只有负责人能编辑其他同部门成员默认只读。管理者可以批量发起共享操作把某个客户共享给某个人或某个团队共享可以设置只读或可编辑还可以设置有效期或永久有效。这里有三个特别容易踩的坑跨团队客户冲突问题。两个团队都按各自维度录入了同一个客户最后合并时到底以谁为准。我们设计了客户查重规则在创建和编辑两个时机都触发提醒匹配规则包括精确公司名、公司名相似度、统一社会信用代码等但当匹配到可能是同一家客户时不强制阻止创建而是提示用户确认。强限制会干扰业务提示要比拦截友好得多。删除权限必须严格控制。人员离职或客户信息被误删恢复成本极高。DeskcommCRM 中所有业务记录的删除都是软删除数据表增加一个 is_deleted 字段界面上先进入回收站只有系统管理员才能在回收站中彻底清除。字段权限和导出权限要联动。授权时不仅要控制在页面上看到什么更重要的是能导出什么。我们把导出也视作一种权限导出内容默认剔除敏感字段需要额外申请。3. 技术选型与部署架构数据库冲突一年多换过一次才踏实3.1 前端和后端框架的选择逻辑技术选型的核心原则是团队能长期维护而不是用最新最潮。前端我们选了 Vue 3 TypeScript配合 Element Plus 做后台界面。选择理由很简单团队成员都写过 Vue 2迁到 Vue 3 的语法学习成本低Element Plus 的表单和表格组件完善能够快速搭出符合内部工具风格的后台系统。没有选 React 不是因为 React 不好而是没必要在内部项目里引入一套团队不熟悉的技术栈。后端最初用的是 Node.js Express MongoDB跑了几个月后发现问题不少。MongoDB 的文档模型在存 CRM 这种关联极强的数据时业务逻辑越写越别扭客户和联系人分开存联系方式的频繁更新沟通记录的时间线查询这些场景都需要跨集合聚合开发效率反而下降。后来我们做了一个大胆的重构数据库换成 PostgreSQLORM 换成 Prisma整个数据层全部重写。这次重构耗时三周上线后又稳定运行了很久团队一致认为这一步代价很值。PostgreSQL 在我们场景里的优势非常明显严格的事务保证不会出现部分更新失败的情况JSONB 字段可以兼顾 EAV 自定义字段的灵活性行级锁和并发控制比 MongoDB 成熟得多。3.2 服务端模块与实际部署拓扑服务端采用模块化单体架构而不是一开始就拆微服务。内部项目初期拆微服务只会增加运维成本单体应用把业务模块通过代码目录区分清楚等瓶颈真正出现再考虑拆分也不迟。主要模块包括认证模块JWT Refresh Token客户管理模块账户、联系人、线索业务协同模块商机、任务、活动、时间线消息模块站内通知、邮件通知、Webhook报表模块漏斗统计、员工业绩、客户活跃度系统管理模块角色权限、字段配置、操作日志。部署拓扑也比较简单一台云服务器跑 Docker Compose包含前端 Nginx 容器、后端服务容器、PostgreSQL 容器、Redis 容器、MinIO 对象存储容器。文件通过 MinIO 存储邮件通过 SMTP 外发备份通过定时任务将 PostgreSQL 和 MinIO 数据打包上传到另一个区域的存储服务。刚开始时在单机环境下跑后来用户量增加数据库连接数吃紧又把 PostgreSQL 单独拆到一台性能好的主机上。这个演进路径对中小团队很实用不用一开始就搞 Kubernetes成本低且可控。3.3 备份容灾和恢复演练这里必须给所有自建系统的团队提个醒备份不是拷贝一份数据库文件那么简单。我们遇到过最尴尬的一次事故是测试恢复脚本时发现备份文件是坏的——因为之前每天凌晨的备份任务一直在数据库正在写入时执行导致备份文件一致性有问题。换上 pg_dump 的逻辑备份后才解决这个问题。现在的备份策略每天凌晨 2 点用 pg_dump 导出全量数据保留最近 30 天每 6 小时做一次 WAL 归档最多可恢复到最近 5 分钟内的任意时间点对象存储中的附件文件每天同步到异地存储每月执行一次完整的恢复演练在一个全新的临时数据库里恢复备份然后验证用户登录、客户查询、报表统计几个核心流程。折腾完这一套之后团队对数据安全这四个字才真正有了概念。4. 线索、商机、时间线打通业务闭环的关键实现4.1 线索到客户的转正流程线索lead是 CRM 里最容易被轻视的实体。很多人觉得线索就是还没确认的信息所以随便记一下就好。但实际业务里线索来源渠道官网咨询、展会名片、朋友推荐、老客户转介绍直接决定了后续转化率和佣金计算这块数据不准确整个报表系统都建立在流沙上。DeskcommCRM 采用简单但清晰的状态机来管理线索新建信息录入未分配负责人已分配管理员把线索指派给销售跟进中销售开始联系已转正线索通过筛选转换成客户账户和联系人已关闭跟进后判断无效或暂时不需要。状态流转的每个动作都会生成一条活动记录后台能查到这条线索的完整历史。在转正这一步系统会先让用户选择是关联到已有客户还是创建新客户并且自动执行查重规则这样可以避免同一个客户在系统里被重复创建。前端涉及一个很细节的问题线索的跟进时间。企业服务类项目的跟进周期往往长达几个月销售常常需要了解每一条线索已经跟了多少天多久没有更新了。所以在列表页我们做了一个距上次跟进 X 天的动态列每天定时任务更新一次超过 7 天没跟进的线索会被系统自动标记为待激活管理员看板也能直接筛选出来。4.2 统一时间线的合并策略客户沟通记录的时间线看起来很简单——就是把电话、邮件、会议、拜访、聊天记录按时间倒序排。但真实开发中踩过的坑是一条线索转正后线索里已有的沟通记录要跟着带过去如果处理不好转正后客户详情页就是空的销售只能靠记忆补录体验非常差。解决思路是沟通记录不直接挂在客户账户或联系人下而是通过活动对象关联到多个实体。每个活动有 opts 字段记录该活动关联了哪些对象类型可以是 lead、account、contact、opportunity。转正时将线索下的活动同步关联到新创建的客户账户上不需要复制数据只复制关联关系。这样既能保持历史记录的完整性又避免了数据冗余。为了减少销售录入成本DeskcommCRM 做了一个快速记录功能在客户详情页有一个固定的输入框支持文本和语音输入输入后点击保存会弹出几个快速选项——是电话沟通、在线聊天、邮件收发、还是线下拜访选中一个类型即可。同时支持在正文里自动提取日期和金额预填到商机字段。4.3 任务、日历和提醒的联动机制CRM 如果不和任务系统联动本质上就是个高级通讯录。DeskcommCRM 中任何业务对象上都可以创建任务任务有负责人、截止时间、优先级、关联业务对象。要实现任务驱动业务不能只做待办列表关键设计是三个配套功能逾期任务自动升级超过截止时间 24 小时仍为未完成任务状态变为逾期系统自动给负责人发送站内信提醒超时 7 天自动通知管理员日程视图把负责人维度下所有任务和活动按日历呈现支持拖拽调整日期跟进提醒设置了提醒时间的任务系统会在指定时间向站内消息、邮件、企业微信机器人三端同时推送。这里有个理念值得同行参考提醒并不是越频繁越好频繁的弹窗提醒很快就会让人麻木。我们实践后设定成重要任务只提醒三次——截止前一天、截止当天上午九点、逾期第一天。三次之后仍未处理就升级给管理者不再骚扰执行人。5. 开发过程中踩过的几个坑不是每个坑都能靠搜索解决5.1 搜索功能一开始就做错了CRM 里客户搜索是最高频操作。我们最初使用 PostgreSQL 的 ILIKE 模糊匹配数据量少的时候没问题但规模上来后明显卡顿。后来启用了内置的全文搜索tsvector姓名和公司名搜索提升明显但搜索很多客户都叫某某科技有限公司这类字段时中文分词效果不理想。为了控制开发成本我们没有引入 Elasticsearch而是做了一个折中搜索框支持按不同维度精确过滤客户名称、联系人姓名、手机号、公司信用代码默认使用前缀匹配对于模糊记忆型搜索启用 PostgreSQL 全文检索。经过配置后查询速度从原来的 1.8 秒降到 200 毫秒以内办公场景完全够用。如果数据量再翻十倍大概率需要重启讨论引入专门搜索引擎但现阶段够用 可控才是优先目标。5.2 多人同时编辑同一条客户记录后保存的人不被覆盖团队刚上线时遇到一个真实事故两个销售同时编辑同一个客户A 修改了手机号B 修改了备注A 先保存B 后保存结果 A 的修改被覆盖了。客户信息就在一次普通操作中丢失完全没提示。解决方式借鉴了乐观锁的常见做法客户表加一个 version 字段每次保存时比较 version如果不匹配后端拒绝此次更新并返回错误。前端收到错误后弹窗提示该数据已被其他同事更新请刷新后重试并保留用户当前编辑内容让用户手动决定如何处理。要注意的是乐观锁不是银弹。CRM 里有一部分更新是系统自动做的比如最近跟进时间字段每天由定时任务更新这种高频低冲突的更新如果也用乐观锁会因为频繁冲突导致任务失败。解决办法是单独另建了一张统计表来存储这类派生数据不再跟客户主表走同一个版本控制。5.3 时间线消息过多时的性能滑坡客户沟通时间线是所有客户详情页的必看模块。刚开始时每次打开页面都把全部活动查出来后来项目上线两三个月某大客户的沟通记录突破了数千条页面加载时间明显变长。优化方案是分页加载 滚动加载。但是分了页也有问题内存中的滚动容器下拉加载会让人常常看不到最早的历史记录而且加载全部历史这个动作对用户并不友好反而不利于聚焦最近的沟通内容。改进后的设计默认只展示最近 30 条沟通记录页面上方提供一个时间筛选器可以按日期范围查看另有一个导出发给团队按钮一键导出到 Excel。这样既不缺数据也不会让页面卡死。5.4 集成企业微信通知时遇到的身份映射问题我们给 DeskcommCRM 增加企业微信应用通知时一开始想得很简单只要拿到用户的企业微信用户 ID调用 webhook 推送消息即可。实际实施时发现CRM 系统中的用户 ID 和企业微信中的用户 ID 并不是一一对应的尤其是存在同名、手机号不一致、离职交接等情况时消息很容易发错人或者发不出去。最终是在用户配置表里增加了一个外部账户绑定子表字段包括外部平台类型、外部用户 ID、绑定状态。用户需要在个人设置中主动绑定企业微信账号绑定流程是点击绑定按钮系统生成一个一次性验证码用户在企业微信里通过官方应用发送这个验证码后台接口校验通过后完成绑定。这个流程虽然多了一步操作但是能准确定位推送对象避免消息误推。6. 上线之后的真实效果、团队反馈与持续演进方向6.1 上线一年后我们看到了什么变化DeskcommCRM 上线试运行三个月后我们做了一次全员使用反馈调研样本 36 人几点数据很能说明问题销售人员录入客户信息的主动率从原来的 20% 上升到 85%管理层每周制作业务报表的时间从原来的一个下午缩短到一个小时客户跟进记录缺失率显著下降原因很简单系统把记录沟通变成了非常低成本的动作但与此同时录入得很随意变成了新问题——有人在沟通记录里只写聊了聊根本没有有效信息。坦白说工具解决不了管理问题。一个 CRM 再智能也不能替销售去理解客户意图。但好的 CRM 至少要做到让记录不讨厌让一线的销售认为记下来对我也方便而不是这是公司要求我做的一件事。6.2 运营维护成本与安全性控制自研系统的代价不能回避。基础设施成本其实很低一台数据库主机加一台应用主机每个月几百元就够用。真正高的是人力成本两个人负责开发维护日常要处理权限调整、字段配置、报表新需求、系统性能优化平均每周投入两天左右。从安全性角度看有几个经验值得记录操作日志记录要够细。我们对核心业务对象做了审计日志记录谁在什么时候改了什么字段的什么值。虽然初期觉得增加存储但真正遇到问题排查时作用极大定期检查闲置账号。员工离职后账号如果没及时禁用会留下安全隐患。后来我们做了一个90 天未登录自动提醒管理员的功能大幅度减少了漏禁的情况不要让普通员工有批量导出权限。客户数据是团队最核心的资产批量导出必须走管理员审批。6.3 下一步DeskcommCRM 还能怎么演进现在 DeskcommCRM 已经能稳定支撑日常业务但我们很清楚它还缺什么。最想做的是报表模块的智能化升级目前的漏斗统计还是基于静态 SQL 查询假如业绩数据能按行业、区域、团队、时间等维度自由拖拽分析就更好了这背后需要引入多维度的聚合数据模型。第二件事是移动端的体验优化。销售外勤场景比较多目前 Web 端在手机上勉强能用但拍照上传、语音备注、离线缓存这些体验还需要改。第三件事是开放 API 和外部集成包括对接财务系统的开票数据、对接项目管理系统中的交付里程碑减少跨系统手工搬运数据。这个一旦做好团队的生产效率还能上一个台阶。如果你也是在小团队里被现成 CRM 折磨过我建议不要急着看技术先把自己团队的客户流程和数据流完整画出来把谁是负责人、谁可以看、字段怎么变、记录怎么留痕这四个问题回答清楚。DeskcommCRM 能跑通不是代码能力有多强而是这几个问题我们在做之前就已经把答案想得很透彻。先想明白业务再动手写代码这条路走起来会顺很多。
延伸阅读

更多相关文章

2026/10/19 11:32:53

HAL库EXTI深度实战:中断配置、回调机制与低功耗唤醒避坑指南

前阵子接了个小项目,板子上一个按键要承担“唤醒”和“用户输入”两件事。我一开始没多想,直接在回调里做了十几条逻辑判断,还顺带写了一个Flash标志位,结果上电一测,中断触发之后系统莫名其妙复位了几次。后来冷静下来…

2026/10/19 11:32:53

非结构化数据调度实战:BatchWorks多模态同步链路搭建

1. 为什么说非结构化数据才是调度平台的终极试炼做数据开发的朋友应该都有这种感觉:聊起调度平台,大家第一反应永远是 Hive 表、Spark 任务、离线数仓、指标计算,仿佛调度系统生来就是为结构化表格准备的。但真实业务里,图片、视频…

2026/10/19 11:32:53

向量数据库全生命周期管理:从选型到监控的实战指南

做AI检索类应用的人应该都有过这种体验:demo阶段怎么测怎么爽,向量召回的结果又准又快,PPT上写“精准语义匹配”底气十足。结果数据量一上来、并发一上来,检索质量突然变得不可控了,延迟从几十毫秒飙到几百毫秒&#x…

2026/10/19 12:23:17

SIGTERM vs SIGKILL:Android自动化测试中如何优雅清理monkey进程

有段时间我经常要处理自动化测试设备的残留进程问题。跑完Monkey压测后,设备上偶尔会留下几个monkey进程,拖慢后续任务。一开始清理方式很粗暴,用kill -9硬杀。结果某次批量跑完测试后,新启动的任务频繁报端口冲突和日志目录被占用…

2026/10/19 12:23:17

MATLAB复杂网络攻击仿真:从BA网络生成到级联失效的完整实现

简介:这份MATLAB复杂网络攻击模拟源代码面向网络安全、复杂网络方向的学习者与研究人员,用于在MATLAB环境中复现网络攻击过程并分析其性能变化。包内共3个文件,包含1个m脚本、1个doc说明文档和1个txt文本,压缩包约37KB&#xff0c…

2026/10/19 12:23:17

电力系统6机30节点混合规划求解实战:建模、求解器与踩坑全记录

做电力系统优化调度的人,多半绕不开6机30节点这套经典测试系统。我去年在与这个系统规模相当的项目上正式接触混合规划求解时,最大的感触是:网上资料要么只讲数学原理,要么直接甩代码,中间那段“为什么这么建模、选哪个…

2026/10/19 12:23:17

拆解Iocomp源码包:工业控件绘制底细与二次开发实战

简介:这套完整源码属于 Iocomp Components v4.02 SP2,由 Iocomp 公司推出,面向工业自动化与工控界面开发人员,用于快速构建仪表、曲线、表头、实时数据显示等各类仿真控件,解决上位机界面组件选型与二次开发问题。资源…

2026/10/19 12:18:10

QT5结合OpenCV实现摄像头实时显示:从Mat到QImage的完整流程

简介:这套基于QT5与OpenCV的摄像头视频采集显示工程,面向需要在图形界面中实时调用USB或内置摄像头的QT开发者和计算机视觉入门者,能够快速解决从打开摄像头、逐帧读取到界面显示的完整链路问题。压缩包共9个文件、约21KB,包含QT …

2026/10/18 0:01:50

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/19 0:04:56

悟空开源无代码平台实战:从实体建模到应用设计避坑指南

简介:基于悟空开源无代码平台的多种应用设计源码,面向希望在不编写代码的情况下快速搭建CRM、HRM、财务系统、ERP、SRM等业务应用的企业与技术人员,通过拖放式界面和内置模板即可完成应用定制与部署。压缩包共697个文件,约10.74MB…

2026/10/19 0:04:56

基于.NET9的多租户权限系统:数据权限与动态API落地实践

简介:这份资源是一套面向 .NET 与 Vue 全栈开发者的中台权限管理系统,后端基于 .Net9,前端采用 Vue3 Element Plus,并配套 uniapp uviewui 移动端方案,实现前后端分离。系统覆盖多租户隔离、数据权限、动态 Api、任务…

2026/10/19 0:04:56

场地预约小程序毕设实战:SSM+微信小程序+MySQL数据库设计到避坑

简介:面向毕业设计场景的场地预约小程序完整项目,基于微信小程序SSMMySql技术栈开发,适合计算机相关专业学生作为选题参考、功能扩展或二次开发起点。系统实现场地类型管理、场地管理、预约管理、取消申请与押金退回等功能,分为管…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑