前阵子整理客户资料翻到一份两年前的报价Excel文件名后缀是“最终版(4).xlsx”我盯着那串后缀看了很久。客户早就换了负责人报价也改了三轮但所有历史记录仍旧躺在不同文件夹、不同人的聊天记录和各自邮箱里。那段时间我在对比各种免费CRM软件也查过不少自建方案最后花了一周多搭了一套自己的客户关系管理系统起名叫DeskcommCRM。这篇文章就是把这套系统的完整思路、技术选型、部署过程和踩过的坑原原本本写下来。这套系统能做的事情很直接打开浏览器登进页面能看到客户列表、联系人、商机阶段、跟进记录和团队数据看板员工通过邀请链接加入每个销售默认只能看到自己名下和共享给自己的数据管理员拥有全部权限。数据全部存在自己的服务器上只要服务器不关机页面就一直在。它适合跟我一样厌倦了Excel满天飞、又不想把核心客户数据放在第三方免费平台里的个人创业者、小团队销售组织也适合想搞明白“自建一套CRM到底要做什么”的技术型业务负责人。1. 先聊聊DeskcommCRM到底想解决什么问题1.1 一句话理解这个项目DeskcommCRM的名字是我自己拼的Desk代表桌面办公场景Comm是Communication的缩写组合起来就是“桌面沟通型客户管理系统”。说白了它是一套面向销售和售后场景的轻量级CRM核心目标是把客户资料、跟进过程、商机推进和人员协作全部收敛到一个Web系统里替代到处散落的Excel、微信聊天记录和纸质笔记本。我不打算把它做成Salesforce那种庞然大物那对个人和小团队来说太重了。DeskcommCRM要解决的痛点非常具体一是客户信息不集中换台电脑就找不到历史记录二是跟进过程不透明今天聊了什么、下一步约什么时候全靠记忆三是权责不清晰三个人同时跟进一个客户撞单了才知道四是数据归属不明确人走了客户资料也跟着走了。这些恰好是免费CRM和自建私人系统最容易踩坑的地方。1.2 为什么越来越多人想要“永久在线”的CRM“永久在线”这个词听起来很玄其实指的就是系统部署在一台长期运行的云服务器上通过域名访问随时打开浏览器都能用。不是装在自己电脑里的软件不依赖某个人是否开机也不用担心笔记本带回家以后办公室同事就查不到数据。我研究免费CRM方案时发现一个很现实的问题很多宣称免费的CRM要么限制联系人数量要么把高级功能藏起来要么要求数据必须存在对方平台上。免费额度用着用着就不够用了数据迁移又麻烦。而自建系统的优势在于一次性投入硬件和域名成本后续没有按人头收费的订阅费数据也牢牢掌握在自己手里。你不需要IT团队只需要会基本的Linux命令和一点耐心就能把一个稳定运行的CRM网站跑起来。DeskcommCRM就是朝着“长期、稳定、数据可控”这个方向设计的。2. 技术选型与数据模型设计2.1 技术栈到底怎么选这是很多人问我的第一个问题。做CRM没必要追求最新最炫的框架关键是稳定、可维护、资料多。我最终选定的组合是前端用Vue3加Element Plus后端用Node.js的NestJS数据库用PostgreSQL部署用Docker加Nginx。下面说说每个选择的理由。前端选Vue3是因为团队里有人熟模板语法对后端转前端的开发者很友好Element Plus的表格、表单、弹窗组件非常齐全做管理后台效率极高。后端选NestJS是因为它有完整的模块化结构和依赖注入权限控制、参数校验、数据库操作这些CRM必须的能力都有现成方案。数据库用PostgreSQL是因为它原生支持JSONB字段、数组类型和全文检索客户标签、自定义字段这种灵活数据存起来比MySQL舒服得多。部署层用Docker统一打包换服务器只要一条命令拉起来配合Nginx做反向代理和HTTPS证书管理。这套组合对服务器要求不高2核4G的云服务器足够支撑几十人规模的小团队日常使用。如果你完全不会Node.js换成Python的FastAPI或者PHP的Laravel也完全可以核心逻辑是相通的技术栈不是CRM成败的关键搞清楚业务模型才是。2.2 核心数据模型设计CRM这个领域再怎么折腾核心逃不出几个实体用户、客户、联系人、商机、跟进记录。我在设计DeskcommCRM表结构时没有画复杂的ER图而是先用一句话说清楚每张表的责任再往里填字段。用户表存员工账号、姓名、角色、状态和密码哈希。客户表存公司名称、行业、来源渠道、标签、归属销售和统一社会信用代码这类基础信息。联系人表跟客户表是多对一关系一个客户公司可以有多个联系人每个联系人记录姓名、电话、微信、邮箱和职务。商机表存跟进的销售机会标题、金额、阶段、预计成交日期、赢单率。跟进记录表是CRM里最重要的表记录每一次跟客户交互的时间、方式和内容同时关联客户、联系人和商机。为什么要拆这么细而不是一张表全装下因为业务上它们是一对多或多对多的关系。一个客户有多个联系人和多笔商机一条商机有多次跟进记录。如果塞进一张表里会出现大量重复数据后续统计归因会非常痛苦。拆表以后看板统计、筛选导出、权限隔离都容易实现。这里也提醒一句设计表结构时一定要想清楚“每个销售看到哪些数据”这个问题最早期我就是在客户表上加了一个owner_id字段所有列表查询都强制带上后面才没出现数据越权的事故。2.3 为什么我选择自托管而不是直接租一套SaaS对比免费CRM和自建私人网站最核心的区别有三个数据所有权、定制能力和长期成本。免费CRM的数据放在服务商的数据中心哪天平台调整产品线数据导出和迁移不一定顺畅。自建系统虽然初期要花时间搭服务器和部署环境但数据库文件在自己手里随时可以全量备份甚至可以导出成通用格式迁移到其他系统。定制能力方面SaaS产品给到的是固定功能字段、流程、权限模型都是别人设计好的你只能适应它。DeskcommCRM这类自建系统表单要加一个字段、列表要改一个按钮都能直接改代码业务和系统是真正对齐的。长期成本上SaaS按年付费小团队一个人一年几百到上千元几年下来也是一笔不小的开销自建系统的成本主要是一次性的时间投入和每月几十块的服务器费用。如果你对技术不熟悉我依然建议先用成熟SaaS后面会专门聊这个问题。3. 部署上线全流程实操3.1 准备一台长期运行的服务器“永久在线”的第一步是有一台不会“睡觉”的服务器。我选了一台2核4G的云服务器操作系统用的Ubuntu Server 22.04 LTS。选它没别的原因社区资料多遇到问题搜一下就有答案而且Docker支持很完善。新服务器到手第一件事不是急着装环境而是先做安全加固。我用SSH登录后做了三件事更新系统软件源创建一个带sudo权限的普通用户代替root登录把SSH的密码登录关掉换成密钥登录。这三步看起来繁琐但能省掉后面一大堆被暴力破解的麻烦。做完之后检查防火墙把22端口、80端口、443端口放开其他端口一律关闭。很多新手容易在这里栽跟头觉得端口开得越多越方便。实际上数据库端口、应用调试端口只需要在服务器内部访问完全没必要暴露到公网。我在部署过程中就遇到过有人扫数据库端口的情况被盯上以后修改密码和限制IP来源真的很折腾。所以我的习惯是凡是面向用户的功能只留80和443两个入口其余全部内部网络通信。3.2 用Docker把数据库和后端跑起来我强烈建议用Docker来做部署哪怕你之前没用过花半天时间学一下基础命令也值得。Docker的好处是环境隔离本地跑起来什么样服务器上就是什么样不会出现“在我电脑上明明没问题的”这种鬼话。先写一个docker-compose.yml把PostgreSQL和NestJS应用的容器配置好。数据库指定版本号比如postgres:16-alpine不要用latest否则某天拉取镜像时版本变化可能引发兼容问题。应用容器构建时把环境变量通过.env文件传入包括数据库连接串、JWT密钥和管理员初始密码。数据库的数据目录挂载到宿主机这样容器删了重建数据也不会丢。启动命令很简单docker compose up -d第一次运行会自动拉镜像等一两分钟以后用docker compose ps看容器状态。这里我踩过一个坑数据库容器启动需要时间应用容器如果启动太早会因为连不上数据库而退出。后来我在应用启动脚本里加了重试逻辑连续尝试连接数据库三十次每次间隔两秒等数据库就绪了再继续初始化表结构。解决这个问题以后部署成功率明显提升重启也不会手忙脚乱了。3.3 配置域名和HTTPS证书系统跑起来以后直接用公网IP加端口也能访问但这样既不美观也不安全。我买了一个域名把A记录解析到服务器IP然后用Nginx做反向代理。为什么必须做HTTPS因为员工登录系统要输密码如果走明文HTTP密码在网络上传输等于裸奔任何一个中间设备都能看到。有了SSL证书以后浏览器地址栏会出现小锁标识用户也放心。证书我用的是Lets Encrypt免费证书配合certbot自动续期。Nginx配置里核心是两段一段把80端口请求重定向到443一段监听443并代理到本地的应用服务端口。写一个简要的server块server { listen 443 ssl; server_name crm.example.com; ssl_certificate /etc/letsencrypt/live/crm.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/crm.example.com/privkey.pem; location / { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }配好以后把certbot的续期任务加到crontab里证书到期前会自动续签。这个小步骤千万不要漏我有一次忽略续期结果员工第二天打开系统看到证书过期的红色警告那场面挺尴尬的。3.4 创建管理员账号与员工邀请系统部署完成后第一步是初始化管理员账号。我在项目里做了一个启动种子脚本第一次运行时自动创建管理员用户默认账号是admin密码通过环境变量注入。管理员登录后台以后第一件事是修改初始密码这个必须写进操作规范里否则等于给系统留后门。员工接入系统我做的是邀请制而不是管理员直接创号。具体流程是管理员在“员工管理”页面点击添加成员输入姓名和邮箱选择角色管理员、销售、只读系统生成一条带令牌的邀请链接。这条链接默认24小时内有效管理员把链接发给员工员工打开后设置自己的登录密码账号就算激活了。这个流程参考了飞鱼CRM等成熟产品的邀请员工方式好处很明显。第一员工初始密码是自己设置的不需要管理员通过线下渠道告知避免密码明文流传。第二邀请链接有有效期过期就作废防止链接被转发滥用。第三员工激活以后系统自动给他的客户数据初始化空看板从第一天起就知道自己负责哪些客户。权限上销售角色只能看到自己和共享给自己的客户管理员能看到全部数据。4. 数据安全与日常运维4.1 自动备份方案对于CRM系统来说数据就是公司的资产客户联系方式、报价记录、合同金额一旦丢失很难挽回。所以备份是整个运维里最重要的一环没有之一。我设计了一个三层备份策略。第一层数据库每天凌晨自动执行pg_dump全量备份保留最近14天的备份文件。第二层关键文件比如上传的合同、附件同步到另一个对象存储桶减少单点故障风险。第三层每周手动把一份备份文件下载到本地硬盘做离线容灾。有人说第三层太笨了但真到服务器出现不可恢复故障的那天你会感谢自己做了这个动作。备份脚本很简单核心就是一条docker exec加pg_dump命令再用find命令清理过期文件。写好了丢进crontab每天凌晨三点执行。#!/bin/bash DB_CONTAINERdeskcomm-db DB_USERdeskcomm DB_NAMEdeskcomm BACKUP_DIR/data/backups TIMESTAMP$(date %Y%m%d_%H%M%S) docker exec $DB_CONTAINER pg_dump -U $DB_USER $DB_NAME $BACKUP_DIR/db_$TIMESTAMP.sql find $BACKUP_DIR -name *.sql -mtime 14 -delete备份脚本写完一定要做一次恢复演练。我试过很多次刚备份完的文件在测试库里恢复成功了才算真备份否则备份文件是坏的都不知道。这个坑我印象太深了第一次写备份脚本时备份文件看起来是完整的实际恢复时发现少了临时表空间关联的数据排查了半天。4.2 日常巡检清单系统上线以后不能一劳永逸我每周固定花几分钟做一次巡检检查范围不多但每一件都关系到系统稳定。第一看磁盘空间CRM的业务数据增长虽然不快但日志文件和数据库备份会慢慢占满磁盘。第二看容器和进程状态docker compose ps确认所有服务都是runningsystemd管理的Nginx也正常。第三看HTTPS证书有效期虽然certbot自动续期但偶尔会因为网络等原因续签失败浏览器端会提前报警。第四看登录日志管理员登录、失败尝试、用户激活事件都要扫一眼发现异常就早点处理。我习惯把巡检内容写成一个备忘录每次照着逐项打勾。不要相信自己的记忆力忙起来很容易跳过某项到时候出问题只能从日志里倒推是哪天开始异常的。4.3 高频故障排查技巧整理几个我实际遇到过的故障和排查思路希望能帮你少走弯路。页面打不开先看Nginx的error.log如果出现502 Bad Gateway多半是后端应用挂了或者端口不对。这时候用命令看下应用容器的状态和日志docker logs确认有没有报错堆栈。如果是数据库连接失败导致应用退出检查数据库容器是否正常以及数据库连接串里的密码有没有被环境变量覆盖。系统变慢优先看数据库慢查询日志。PostgreSQL默认不开启慢查询可以临时打开把执行时间超过100毫秒的SQL拉出来看。我在DeskcommCRM里遇到过列表页加载特别慢的情况后来发现是客户表缺少索引所有查询都在做全表扫描。加上owner_id和updated_at的联合索引后查询时间从几百毫秒降到了几十毫秒。这里说句实话索引不是越多越好每个索引都会拖慢写入速度只给高频查询的字段建索引就够了。忘记管理员密码这种事大概率会发生在放假回来以后。处理办法是直接进数据库更新密码字段把新密码先用同样的哈希算法处理好再写进去。虽然操作不算复杂但我建议在系统里加一个“通过邮箱找回密码”的流程否则每次都得手动改数据库太原始了。5. 免费CRM与自建系统到底怎么选5.1 两套方案的横向对比结合前面这些经验我把免费CRM和自建私人网站的区别整理成一张表方便你做选择。对比维度免费CRMSaaS自建CRM自托管数据所有权数据存在服务商平台数据存在自己服务器初始成本零门槛注册即用需要服务器和域名费用长期成本用户数多了以后大概率收费主要是维护人力费用固定定制能力依赖平台开放能力完全可定制灵活度高维护门槛平台方负责需要自己打补丁、做备份数据安全看厂商安全水平取决于自己的运维水平上手速度几分钟完成至少半天到一周这张表不是要证明谁一定更好而是想说明两条路的成本结构完全不同。免费CRM省下了初期搭建的时间但把数据控制权和长期费用交给了别人。自建系统前期投入明显换来的是长期可控和灵活扩展。5.2 什么情况适合自建如果你的团队有以下特征自建系统值得考虑。第一客户数据比较敏感不希望经过第三方平台。第二业务流程特殊标准CRM满足不了需要自定义字段、状态和审批逻辑。第三你有一定技术能力或者团队里有兼职运维愿意花时间维护。第四长期使用按几年算下来自建的成本明显低于SaaS订阅费。我有一位做外贸的朋友他们的客户跟进流程跟常规销售差别很大需要记录每个柜子的出货进度和验货报告。市面上的CRM要么不支持要么要买高价定制包。我帮他用类似DeskcommCRM的思路搭了一套按他的流程改了字段和状态看板用下来非常顺手。这就是自建系统最大的价值所在系统跟着业务走而不是业务去适应系统。5.3 什么情况别折腾老老实实用成熟产品自建系统很香但它不适用于所有人。如果你属于以下情况我真心建议直接用成熟产品。第一团队里没有一个人懂技术服务器出了故障只会重启那系统稳定性就无从谈起。第二需要iOS和Android原生App自建系统做移动端开发和上架成本非常高。第三业务要求快速上线今天就要用没时间等搭建调试。第四你的客户管理需求非常标准没有奇怪的流程那么成熟产品的通用功能完全够用。很多免费CRM服务商都提供不错的免费额度几十个联系人以内的小规模使用体验其实挺好。等团队规模和个人需求明确上来了再考虑迁移到自建系统也不迟。反过来说一开始就硬着头皮自建搞不定运维数据丢失以后比用SaaS更惨。6. 上线半年后的经验与扩展计划6.1 从Excel迁移到DeskcommCRM的笨办法系统搭好以后最头疼的一步不是部署而是把旧数据搬进来。我这里说的不是技术难题是数据清洗的脏活累活。老Excel里同一个客户的名称写着“某某科技有限公司”“某某科技公司”“某某科技”三种电话格式也不统一还有大量重复记录。我的做法是分三步。第一步把Excel导出成CSV用脚本清洗统一字段格式去重合并相同客户。第二步然后按“客户-联系人-商机-跟进记录”的顺序分批导入先用客户表再导入联系人。第三步导入后随机抽检几十条记录核对字段对应关系是否正确重点确认电话号码和邮箱的准确性。这个过程中我意识到以后所有数据都要从源头规范化录入否则几个月后又要重新清洗一遍。6.2 后续可以加的模块DeskcommCRM目前覆盖了客户、联系人、商机和跟进记录接下来我想加几个实用性很强的模块。一个是工单模块把售后问题和销售线索分开管理客户报修不再靠微信聊天记录。一个是合同管理模块记录每个商机最终关联的合同、回款节点和开票状态。还有一个是消息通知模块当商机阶段变更或跟进任务到期时主动给负责人发站内信和邮件提醒。另外有不少朋友问我能不能接入企业微信消息推送这样手机也能及时收到提醒。这个方案我放在下一阶段规划里思路是在后端加一个消息队列把通知事件发出去再由一个独立的worker推送到企业微信群机器人。这样CRM本身不依赖任何IM也能让用户在日常办公工具里感知到系统动态。如果让我回到最开始第一件要做的事不是写代码而是先把客户字段定义清楚。我前期改过好几版客户字段数据在里面迁来迁去浪费了很多时间。但正是因为踩过这些坑DeskcommCRM现在才这么合手也希望我的这些经历能让你少走点弯路。
企业数字化 ERP 产品动态
相关推荐
微信外卖小程序源码实战:Java前后端架构与订单状态机 简介:这是一套基于Java语言开发的完整版微信外卖小程序系统,包含前后端源码及数据库脚本,面向需要快速搭建外卖平台的开发者、商家,以及学习Java全栈与小程序开发的学员。系统覆盖商家管理、骑手派单、用户下单、订单跟踪等核心流… · 2026/9/25 11:59:51
Manus平替:多智能协作框架OWL安装与使用「喂饭教程」——TaoToken统一Key接入配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 11:59:51
SSM+JSP社会保险管理系统实战部署与改造指南 简介:这是一套基于SSM框架与JSP技术实现的社会保险管理系统毕业设计级源码,面向计算机专业本科生、Java初学者及课程设计实践者,解决社保业务中参保档案、缴费审核、待遇发放、多维查询等核心管理场景的系统化开发需求。资源包共24.47MB&… · 2026/9/25 11:59:51
用 Claude Code 开发游戏阵容推荐脚本:TaoToken 统一 Key 配置与调试实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 15:22:19
5 步本地跑通 AI 小说生成:AI_NovelGenerator 部署与配置教程 5 步本地跑通 AI 小说生成:AI_NovelGenerator 部署与配置教程 【免费下载链接】AI_NovelGenerator 使用ai生成多章节的长篇小说,自动衔接上下文、伏笔 项目地址: https://gitcode.com/GitHub_Trending/ai/AI_NovelGenerator
AI_NovelGenerator 是… · 2026/9/25 15:21:48
Ox Alpha 模型免费开放:开发者如何用 TaoToken 统一 Key 快速接入 Agent 工作流 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 15:21:48
Ubuntu 22.04 NVIDIA驱动安装深度指南:避坑、签名与GDM3修复 1. 这不是“装个驱动”那么简单:为什么Ubuntu 22.04上NVIDIA驱动安装总让人抓狂在Ubuntu 22.04上装NVIDIA驱动,表面看只是敲几行命令的事,但实际操作中,90%的人会在重启后面对黑屏、登录循环、nvidia-smi报错“Failed to initiali… · 2026/9/25 15:21:42
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37