1. 从“随便用个CRM”到动手写DeskcommCRM:这中间发生了什么
1.1 市面上一堆CRM,为什么还是想自己折腾
先说说背景。我们是一个二十来人的销售型团队,业务是典型的B2B项目制销售,客户从线索到成交流转周期长,涉及售前、销售、实施多方协作。最早也跟风用过几款市面上的SaaS CRM,说实话,功能都很全,全到让我觉得焦虑——页面上一堆按钮我不知道什么时候能用上,但真正想按自己业务逻辑调整的时候,又发现处处是壁垒。
最让我难受的是三件事。第一,销售流程是跟着我们业务长的,我们会有“方案报价后客户搁置一个月又回来”的情况,标准的SaaS CRM里阶段一锁死,你想改就得靠自定义对象绕来绕去。第二,数据导出的颗粒度不够,做月度复盘的时候想拉一张“每个销售在某个阶段停留了多久”的表,后台折腾了半小时也没导明白。第三,千万别说自定义字段,改一次字段要提工单,等两个工作日,改完还影响所有终端的展示逻辑。
于是我们就开始评估自研CRM的可行性。团队里有人反对,理由是“CRM是成熟软件,造轮子不划算”。后来我们用了一个星期做了一次冷静评估:我们不打算做复杂的营销自动化,也不做多币种、多区域、复杂权限那种集团级功能,我们要的其实就是线索管理、客户信息沉淀、跟进记录、销售漏斗、提醒和基础的报表。这么一框,工作量其实可控。真正决定动手的那一瞬间,是我想起某次系统升级,所有自定义字段全部丢失恢复不了,客服给了句“抱歉给您带来不便”。那一刻我就明白了,数据和控制权必须握在自己手里,所以才有了DeskcommCRM这个项目。
1.2 DeskcommCRM到底定位成一款什么工具
DeskcommCRM不是想做成一款多全能的通用产品,恰恰相反,我们给自己定的原则是“只做销售管理链条上最能提高效率的40%”。刚开始规划的时候我们也列过一百多项需求,最后砍到只剩下四块核心:
- 客户与联系人管理:把客户、联系人、往来记录沉淀成结构化的数据,不再让客户信息散落在每个人的微信聊天记录和Excel表格里。
- 销售过程管理:从线索、跟进、报价、成交到回款,每个环节都有记录,阶段一目了然,管理层能看清在手的项目到底卡在哪一步。
- 提醒与日程:跟进计划、合同到期、回款日期自动提醒,减少“忘记跟进”这种低级失误。
- 数据报表:按销售、按产品线、按月份统计转化率和业绩,让复盘有据可依。
产品定位想清楚之后,技术选型就顺理成章了。后端用的Java Spring Boot,前端Vue,数据库MySQL,为了后续好扩展,还引入了Redis做缓存和分布式锁。可能有朋友会说这组合有点“老派”,但对我们这种小团队来说,稳定、资料多、招人容易才是第一位的。我们不追求新框架带来的技术快感,只追求这个系统能安安稳稳跑上几年。
2. 数据模型设计:客户、联系人、跟进记录这三张表怎么拆才不乱
2.1 客户主表和联系人子表的拆分逻辑
CRM系统里最容易设计错的就是客户和联系人。很多刚起步的团队会图省事,把客户名称、联系人姓名、电话、职位全塞进一张表里。看起来简单,实际跑三个月就会发现问题:一个客户公司里往往有四五个对接人,老板、采购、技术、财务各管一段,你要是一个客户一行,新增联系人就得重复录入一遍客户信息,后面统计“这个客户有几个人在跟我们对接”就变得无比痛苦。
DeskcommCRM用的是经典的“一客户多联系人”模型。客户主表存公司维度的信息,比如公司名称、行业、规模、来源渠道、所属销售、客户状态;联系人表存人维度的信息,比如姓名、职务、电话、微信、邮箱、是否关键决策人。两张表通过customer_id关联。这个设计的核心收益在于:销售跟进某个客户时,看到的是客户的完整画像,以及这家公司里我们跟几个人打过交道、谁说了算、谁只负责传递信息。
这里有一个实操细节值得展开说。我们在联系人表上加了一个is_primary字段,用来标记主联系人。为什么需要这个字段?因为后续做跟进提醒、合同审批、邮件推送的时候,系统需要知道默认把消息发给谁,如果每次都去联表查询再来判断,逻辑会复杂很多。设置了主联系人之后,所有默认动作都能直接取到值,代码简化不少。这个看似很小的设计决策,后来在报表统计“有效联系人数量”时也派上了用场。
2.2 跟进记录用追加大表还是分表存储
跟进记录是CRM里数据增长最快的表。每个销售每天打几十通电话、发几十条微信,每条都可能产生一条记录。一个二十人的销售团队跑一年,轻松产生几十万条跟进记录。
我们在设计时纠结过一个问题:跟进记录是单独一张大表,还是按客户维度拆分?单独一张大表的好处是逻辑简单,统一查询方便;坏处是单表数据量上来之后,按客户查询时索引压力会变大。分表的思路在这个阶段还不值得,因为MySQL单表几百万条数据在合理索引下其实完全扛得住。我们最后决定用单表,但做两个强制约定:
- 所有针对客户详情页的跟进记录查询,必须带上customer_id作为等值查询条件,走联合索引。
- 列表页不允许跨客户全局搜索跟进内容,如果需要全文检索,走Elasticsearch,而不是在MySQL里做模糊匹配。
跟进记录的结构也不复杂,核心字段包括:customer_id、contact_id、跟进类型(电话/微信/拜访/邮件)、跟进内容、下次跟进时间、创建人、创建时间。我们额外加了一个follow_up_date索引,这个后面在提醒模块里会用到。
2.3 自定义字段的JSON方案,够用且灵活
前面提到,SaaS CRM改字段要提工单,这在自研系统里绝对不能发生。我们采用的方案是给核心业务表预留一个ext_json字段,类型是JSON,允许用户在前端动态添加自定义字段,值就存进这个JSON里。
有人可能会质疑:JSON字段没法建索引,查询性能怎么办?这个质疑有道理,但我们的应对思路是:自定义字段只用于展示和筛选标签,不做复杂条件查询。销售如果真想按自定义字段做统计,可以用筛选功能先圈定一个较小的数据范围,再在这个范围内做二次筛选,实际体验下来完全够用。
另一个要注意的点是JSON字段的前端渲染。我们做了一个轻量的字段配置表,存每个自定义字段的显示名称、类型、所属对象,前端拿到配置后动态渲染表单。新增字段只往配置表里插一条记录,不需要改表结构、不需要发版,销售第二天就能用上。这个功能上线后,使用率远超我们预期,因为大家终于可以从“让IT帮个忙”变成“我自己就能加字段”了。
3. 功能模块落地:从线索到成交流转的完整链路
3.1 线索池、公海和回收规则的设计
有个概念我特别想展开讲讲,就是线索的公海与回收机制。做过销售管理的都知道,如果一个销售手里攥着大量线索却不跟进,这些资源就等于被浪费了。DeskcommCRM的线索模块设计成“先入池,后认领”的模式。
所有新线索进来统一进入线索池,销售可以在池子里看到线索的基础信息,但看不到详细的联系方式和完整的跟进历史。认领之后,线索才会完整开放。这里有个关键规则:认领后的线索如果连续N天没有跟进记录,系统自动回收进公海,供其他销售再次认领。N的取值我们早期设的是7天,后来发现不同行业的销售周期差异很大,改成按产品线配置,有3天的、有10天的、也有15天的。
这个机制落地后带来一个立竿见影的效果:线索认领率显著提升,销售不再把线索当成“先占个坑”,而是真的当成需要立刻转化的机会。技术上要注意的点是回收规则的执行,我们一开始是用定时任务每天凌晨扫一次,后来发现高频场景下延迟太长,改成了“跟进记录创建时触发检查+每日定时兜底”的双保险机制。这样既保证了实时性,又不会因为漏扫导致规则失效。
3.2 销售漏斗看板:阶段转换怎么算才准确
销售漏斗是管理层最关心的页面。DeskcommCRM的漏斗看板按机会(Opportunity)维度统计,每个机会有一个当前阶段,阶段包括:初步接触、需求确认、方案报价、商务谈判、赢单/输单。看板展示的是每个阶段的商机数量和金额总和。
这个看板看起来简单,真正做起来有个坑:阶段历史。如果只存机会的当前阶段,我们只能看到一张静态快照,无法分析“这个商机在报价阶段停留了多久”“哪个阶段的转化率最低”这些动态问题。我们的解决办法是增加一张opportunity_stage_log表,每当机会的阶段发生变化时,记录一条日志:机会ID、旧阶段、新阶段、操作人、操作时间。这张日志表就是把漏斗看板从“静态展示”升级成“动态分析”的关键。
基于阶段日志,我们能算出一组很有价值的指标:平均每个阶段停留天数、阶段间转化率、销售对不同阶段项目的推进速度。有一次我们发现“方案报价”到“商务谈判”的转化率只有三成,深入排查后发现是报价方案模板太弱,销售要花大量时间定制,进一步拖慢了报价节奏。这个结论要是没有阶段日志,根本没法定位。
看板的性能也要注意,因为每一次刷新都要聚合几十个销售的数据。我们的方案是预计算:每天凌晨跑一个定时任务,把当天的漏斗统计结果写入一张summary表,白天看板直接读summary表,查询时间从秒级降到毫秒级。销售数据实时性要求没那么高,延迟一天完全能接受,但体验上的提升是巨大的。
3.3 跟进提醒与日程联动
DeskcommCRM的提醒模块,逻辑上就一句话:跟进记录里带了一个“下次跟进时间”,到了时间系统就提醒对应销售。但这个逻辑落地时比想象中复杂。
首先是提醒渠道的选择。我们用过站内消息、邮件、企业微信机器人三种方式,最后发现效果最好的是企业微信机器人,因为销售每天都会看,站内消息上线半天没人点进去是常态。机器人消息的模板要注意,不要只是冷冰冰地写“您有客户需要跟进”,而是带上客户名称、最近一次跟进摘要、距离上次跟进天数,让销售在收到提醒的瞬间就能回忆起上下文,减少重新翻阅客户详情页的时间和心理成本。
其次是提醒的时间窗口。客户的下次跟进时间可能是凌晨两点填的,我们不能真的凌晨两点去轰炸销售。我们做了一个提醒时间归一化的处理:用户在填写“下次跟进时间”时,如果选择的是非工作时间,系统自动把提醒时间调整到下一个工作日的上午十点。这个细节不大,但实际使用中大家反馈特别好,因为不会再被不合理的提醒时间打扰。
还有一类提醒容易被忽略,就是合同到期和回款逾期。这类提醒和跟进提醒不一样,它不是以“人”为维度,而是以“事”为维度。我们把合同信息表单独拉出来,加了一个expire_reminder_sent标记,确保同一个合同到期只会提醒一次,不会因为定时任务的重复执行而给用户发三遍通知。
3.4 权限模型:按部门隔离还是按角色控制
权限设计是CRM系统里绕不开的硬骨头。DeskcommCRM的权限模型没有做得特别复杂,采用了“角色+数据范围”的组合方案。
角色层面分成三类:普通销售、销售主管、管理员。普通销售只能看自己的客户和自己的跟进记录;销售主管可以看本部门所有销售的数据,可以做跨销售的客户转移;管理员拥有全部权限,包括系统配置、字段管理、流程设置。
数据范围的控制在后端实现,不是在前端隐藏菜单栏。就是说,即使某个用户通过接口直接请求其他销售的客户数据,后端也会校验数据权限,返回403。这个看似基础的校验,很多系统做得并不好——以为菜单不显示就万事大吉,实际上接口层完全裸奔。我们的经验是,权限控制必须做在后端的数据库查询层面,用SQL层面强制加上数据范围条件,比如查询客户的SQL统一带上owner_department_id的过滤条件,从源头避免越权。
还有一个容易忽视的权限细节是操作日志。管理员做任何敏感操作,比如修改销售所属、删除客户、调整权限,系统都会记录操作日志。这既是安全审计的需要,也是防止内部纠纷时“死无对证”的保障。
4. 实操过程中的关键细节与性能优化:没有踩过坑,就不会理解的几个点
4.1 列表页越查越慢,根因在offset分页
客户列表页是使用频率最高的页面,每个销售一上班就先打开“我的客户”看一遍。系统上线初期列表页响应都在200毫秒以内,随着数据量增长到五十万级,列表页开始出现肉眼可见的卡顿,最慢的查询跑到五秒以上。
一开始我们按常规思路排查,加索引、优化SQL,但收效不大。后来用慢查询日志定位到一个典型的SQL模式:ORDER BY updated_at DESC LIMIT 20 OFFSET 200000。问题就出在这里,MySQL的offset分页在数据量大的时候,需要扫描并丢弃前20万条记录,才能拿到目标页的数据,这个开销随着页数增加会越来越大。
解决方案是改成“键集分页”(Keyset Pagination),也就是通过WHERE条件定位到上一页最后一条记录的updated_at和id,下一页只取比这个位置更早的数据。改造后的查询SQL变成:WHERE updated_at < '2024-06-01 10:00:00' OR (updated_at = '2024-06-01 10:00:00' AND id < 10086) ORDER BY updated_at DESC LIMIT 20。这个方案下,无论翻到多少页,查询耗时就锁定在几十毫秒级别。
这个改造给我们的启发是:不能想当然地把页面上看得见的“上一页/下一页”直接映射到SQL的offset/limit。数据量小的时候怎么查都无所谓,数据量大了以后,这种基础设计的差异会被放大到让人怀疑人生。
4.2 大批量导入客户数据,事务一包到底差点搞挂线上库
系统上线不久,销售团队想要把原来散落在Excel里的两千多条历史客户数据导入系统。我们第一版导入程序很粗暴:读Excel,循环逐条插入MySQL,每1000条提交一个事务。看起来挺合理,结果导入跑到一半,销售反馈说系统变得特别卡,其他页面虽然还能打开,但操作起来明显的延迟感。
一查才发现问题:批量导入大量占用数据库连接和写入锁,影响了业务表的正常读写。更危险的隐患是,如果导入过程中Excel里面有数据格式错误,整个事务回滚,前面导入的数据全部作废,得重新再来。
后来导入模块做了三件事重写。第一,改为异步任务,导入请求先落到任务表,后台线程池按批次执行,每批100条一个事务;第二,每条数据先做完整性校验,清洗格式错误的数据并生成错误报告,而不是一个错误就中断整个流程;第三,导入进程通过限流控制写入速率,每批次之间sleep 100毫秒,给其他业务查询让出资源。这套机制上线之后,导入两千条数据不会对线上业务产生任何可感知的影响,而且中途遇到脏数据不会影响其他normal的条目导出。
这里要特别提醒一点:任何批量操作都必须有“可观测性”,就是说要能让人看到当前进度到了百分之几、成功了多少、失败了多少、失败原因是什么。第一版导入程序就是什么都没显示,用户只有干等,也不知道会不会失败。重写后我们加了导入进度条,销售看着进度心里有底,体验完全不一样了。
4.3 搜索排序的排序稳定性:为什么按时间排序会出现“跳动”
搜索是CRM的另一个高频入口。销售想找出某个客户的联系方式,直接在搜索框输入客户名、联系人、手机号就能定位。突然有一天有销售反映:搜索结果第一页的排序一直在跳动,明明同一个词搜了两次,第一次在第三位的客户,第二次刷新跑到了第七位。
这个问题的根因很普通:搜索排序字段不是唯一的,排序字段相同的情况怎么办?我们当时的搜索SQL是ORDER BY score DESC,MAP个余弦相似度作为评分,问题是很多客户的评分一样,而MySQL在处理相同排序值时返回顺序是不确定的。数据量不大时这种不稳定不会暴露,一旦搜索返回的结果集比较大,就会出现“排序跳动”。
解决方案是在排序条件里加上一个唯一字段作为兜底:ORDER BY score DESC, id DESC。这样即使评分相同,也有一个完全确定的排序依据,搜索结果稳定不会跳。这个改动很小,但它反映出来的通用原则是:凡是用户能感觉到“结果不稳定”的地方,都要排查是否存在排序不唯一的问题——搜索结果、下拉选项、列表数据都一样。
4.4 与外部系统的对接:企业微信、钉钉、邮件同步的取舍
销售团队日常沟通主要靠企业微信。DeskcommCRM如果还要销售专门登录网页去录入信息,那使用率一定上不来。我们做了一个轻量集成:企业微信服务号推送给销售每日提醒、线索通知、合同预警,销售点消息卡片就能直接跳转到CRM网页端对应的详情页,免去了登录后还要找菜单的麻烦。
这个跳转背后是一个带token的深链,链接里带着客户ID或机会ID,前端路由解析后直接定位到具体的页面。做这一步的时候要注意链接的有效期和安全性,token必须设置合理的过期时间,防止链接泄露后被第三方盗用。我们用JWT作为token载体,额外加了一个expires_at字段控制有效期,过期后跳转到登录页面重新认证。
邮件同步这块我们做了个简单方案:每个客户在系统里分配一个专属的邮件接收地址,比如customer_10086@crm.example.com,销售把往来邮件CC到这个地址,系统通过IMAP协议拉取邮件并关联到对应客户。这个功能的取舍在于:我们不去做复杂的邮件客户端,只解决“邮件内容进入系统留痕”这个最核心的需求。实际效果还不错,特别是合同确认邮件和报价邮件,自动留存到客户详情页的附件区域,后续翻找历史记录非常方便。
5. 上线之后遇到的那些坑:三次典型故障排查实录
5.1 故障一:同一客户被两个销售同时编辑,后保存的把先保存的覆盖了
上线第二个月,有个销售主管反应:两个销售跟进同一个客户,A在上午修改了客户电话,B在下午把客户行业从“制造业”改成“医疗”保存,结果A改的电话记录丢了。听起来像是一个普通的并发覆盖问题,但内部原因比想象中更隐蔽。
我们当时的编辑逻辑是:前端打开详情页时读取整行数据存到内存;用户编辑后点保存,前端把整个对象的字段全部提交后端,后端执行一条UPDATE语句,把数据库里对应的字段全部更新成提交的值。如果A和B同时打开页面,他们看到的都是旧数据,各自修改自己关心的字段后提交,后来的提交就会覆盖先前的提交。
修复方案有两条路:一是字段级并发控制,保存时只提交修改过的字段;二是基于版本号的乐观锁,在客户表加一个version字段,更新时强制条件WHERE version = 旧版本号,如果更新影响行数为0,说明数据已经被其他人改过,这时候提示冲突并引导用户刷新页面查看最新数据再决定是否合并。我们选了乐观锁方案,因为实现简单且能覆盖大多数场景。这个坑告诉我们,任何更新操作都要想清楚并发场景,即便是内部系统,也不能默认用户都是串行操作。
5.2 故障二:跟进记录的时间统计全部不对,原来是时区埋的雷
有一段时间,销售反馈报表里的“今日新增跟进”数据总是偏少,新建的跟进明明显示是下午三点,日报里却归到了第二天。排查了很久,最后发现是后端服务与时区不一致导致的:服务器默认时区是UTC,数据库连接的时区参数没设置,导致TIMESTAMP类型的字段在写入和读取时发生了偏移,个别场景偏移了整整8小时。
这个问题的修复本身很简单:在数据库连接串里显式指定serverTimezone=Asia/Shanghai,应用启动参数里也强制指定时区。但这件事让我反思了很久,时区问题在开发环境很难发现,因为本机数据库一般配置正常,只有部署到云服务器上才会暴露。加上现在很多团队用Docker部署,镜像的基础时区默认就是UTC,更容易踩坑。建议所有涉及时间存储的项目,在初始化阶段就统一约定:所有时间字段统一存UTC时间戳,展示层再转换为用户本地时区,如果嫌麻烦,至少保证数据库连接、应用服务、容器镜像三层时区统一。
另外我们还埋了一个深雷:定时任务用的Cron表达式没有指定时区,导致每天0点跑的日报统计实际上在早上8点才执行,统计窗口错位,日报数据总是慢半天。这个也是时区问题的一个变种,提醒大家设置定时任务时一定要检查调度器默认用的时区。
5.3 故障三:Excel导出功能把线上库内存打满
销售主管有个习惯,每周要导一次全量数据做线下分析。我们的导出功能第一版是直接用JDBC查询所有符合条件的记录,加载到内存里,然后用EasyExcel写文件流。在数据量只有几万的时候没问题,有一次导出的数据量接近二十万,服务器内存直接被打满,服务崩溃了好几分钟。
修复方案做了两层优化。第一层,采用流式查询,让JDBC游标逐条读取、逐条写入输出流,而不是等所有数据都加载到内存再统一写;但仅仅这样还不够,因为一次导出二十万行数据,输出的Excel文件本身也有几十兆,网络传输和文件生成期间占用的资源依然很高。第二层,异步导出:导出请求提交后,后台任务生成文件到磁盘指定目录,生成完成后通过消息通知用户下载,同时给下载链接设置24小时有效期。这样用户不需要傻傻地盯着页面转圈,服务器也不需要为了一个请求长时间占用连接。
导出功能还有一个反直觉的经验:Excel单元格的数量会直接影响文件大小和生成速度。如果数据列太多又不合理设置列宽,Excel文件体积会异常膨胀,生成时间翻倍。我们在导出前会动态裁剪空列,并设置合理的列宽,效果立竿见影。
6. 如果让我再设计一次DeskcommCRM,我会在这些地方用不同的做法
6.1 一开始就引入软删除,而不是上线半年后补课
DeskcommCRM最初的客户表做的是物理删除,也就是说销售误删了一条客户记录,这条数据就永久没有了。后来销售误删了一个重要客户,幸好有数据库备份我们才救回来,但整个过程折腾了整整半天。后来我们花了大力气把所有业务表改造为支持软删除:增加deleted字段和deleted_at字段,所有查询默认过滤deleted=0,删除操作变成先软删后异步清理。
这个改造的工程量远比想象中大,因为所有关联查询、统计SQL都要带上过滤条件。现在回顾,这套机制应该在系统设计的第一天就建好,后期补课的代价太高。补充一点,软删除记录也不是永远保留,我们会在存储过程里定期把超过90天的软删除数据导出归档表,再做物理清理,确保业务表不会无限膨胀。
6.2 通用审批流未必比定制流程好用
最初我们也考虑过引入一份通用审批流引擎,比如基于Activity的工作流,想在合同审批、报价审批等场景里体现“复用性”。后来评估来评估去,发现就三个审批场景,提取公共流程的价值并不大,反而引入了一个重量级组件,部署复杂度、运维成本、学习曲线都上来了。
最终DeskcommCRM采用最“笨”的方案:每个审批场景单独建模,用一张审批记录表加一个状态字段就能完成。合同审批就是一条数据带一个pending/rejected/approved状态,审批人是固定的销售人员主管。这套方案唯一的缺点是不够灵活,但优点是简单到团队成员三天就能上手维护。后来系统稳定跑了一年多,审批模块的故障率是所有模块中最低的。这个经验在其他系统设计里同样适用:不要为了“架构弹性”提前引入当前用不上的复杂度。
6.3 报表模块要预留一点扩展空间
现在DeskcommCRM的报表模块只做了固定报表,也就是每个报表的SQL都是写死的,产品经理说加一个指标,研发就得改一段SQL再发一次版。后期其实有越来越多的临时分析需求,都是“就统计这一次”的那种,这块体验是不够好的。
如果重新来做,我会在设计初期就引入一个“自定义报表”的轻量模块:允许用户选定数据源(客户、机会、跟进记录)、选择时间范围、拉入维度和度量字段,系统自动生成透视表,再决定是否保存为固定报表。这个模块的复杂度比想象中低,因为底层就是一套由元数据驱动的动态查询。预留这样一个扩展接口,会大大减少后续的数据分析沟通成本。
7. 给也想自研CRM的团队的几条实在建议
第一,先想清楚边界。自研CRM最大的风险不是技术难度,而是需求蔓延。今天想加个营销自动化的画布,明天想对接财务系统的回款核销,半年之后发现自己其实在做一个跟SaaS厂商抢饭碗的东西。我们的经验是,每周需求评审会上反复问一句“这个功能不做会怎么样”,能砍就砍,保住核心价值比什么架构设计都重要。
第二,数据模型设计阶段多花时间。CRM系统的数据模型一旦跑起来,后面调整非常困难。特别是客户、联系人、机会这几张核心表的关系,以及自定义字段的外挂方案,宁可前期多讨论几天,也不要上了生产环境再折腾。
第三,权限模型的初始设计要留好扩展位。现在团队二十人,角色简单;万一哪天业务发展团队变两百人了,数据隔离的维度可能会从部门变成事业部,权限模型要从一开始就支持“用户-角色-数据范围”三层解耦,否则中期加一层数据隔离,改动量会非常痛苦。
第四,重视可观测性。不管是导入任务、定时任务、报表预计算还是异步导出,都要有日志和监控。系统出问题不可怕,可怕的是出了问题你不知道在哪、不知道进度、不知道结果。
第五,备份要制定到人。我们因为一次误删数据紧急恢复了数据库,后来把“每日备份+每周异地备份+每月恢复演练”写成了制度。数据安全不是靠代码保证的,是靠流程和纪律保证的。
DeskcommCRM至今已经运行了两年多,踩了无数的坑,也实实在在帮团队把客户信息从散落的Excel和聊天记录里收拢成了结构化的数据资产。每次看到销售在详情页里快速找到一条两年前的报价记录时,我都会觉得当初坚持自研不是一个冲动的决定。做一个够用、可控、能随着业务一起演进的内部工具,这本身就是一件很有成就感的事情。