
1. 为什么我要自己搭一套DeskcommCRM团队从五个人涨到二十多个人的时候客户资料散落在每个人的微信收藏、Excel表格、甚至纸质笔记本里这个问题就彻底兜不住了。销售离职带走一批客户联系方式售后查不到三个月前的沟通记录市场部想知道某个客户到底买过什么产品得在群里三个人才能拼凑出全貌。市面上的SaaS版CRM按人头收费二十个人一年下来费用不低而且客户数据放在别人服务器上心里总是不踏实。DeskcommCRM这个开源项目是我在对比了七八个方案之后定下来的。它本身是一套客户关系管理系统支持联系人管理、销售漏斗、任务分配、邮件集成这些核心功能代码完全开放可以自己部署在自己的服务器上。说白了就是数据在自己手里功能自己说了算没有按人头收费这回事。我最终选择的部署方案是Docker Compose编排底层数据库用PostgreSQL缓存用Redis。这套组合的好处是环境隔离干净迁移方便备份简单而且社区资料丰富遇到问题容易找到答案。整篇文章我会从架构选型、环境准备、部署实操、参数调优、问题排查这几个维度把整个自建过程拆开来讲。如果你也是中小团队的技术负责人或者单纯想拥有一套完全属于自己的CRM系统这篇内容应该能帮你少走不少弯路。2. 整体架构设计与技术选型思路2.1 为什么是DeskcommCRM而不是其他方案选CRM这件事我前前后后折腾了将近一个月。最开始试过某知名SaaS产品功能确实全但免费版限制太多付费版按人头算下来一年要花不少钱。后来转向开源方案对比了EspoCRM、SuiteCRM、Odoo CRM和DeskcommCRM这几个主流选择。EspoCRM功能强大但界面偏传统团队里非技术背景的同事上手有门槛。SuiteCRM基于比较老的PHP框架二次开发成本高。Odoo CRM功能没得说但整个Odoo生态太重为了一个CRM装一整套ERP有点杀鸡用牛刀的感觉。DeskcommCRM吸引我的点在于代码结构清晰前端用了现代框架API设计规范而且社区活跃度不错遇到问题提issue基本一两天内有人回复。另一个关键考量是数据迁移的便利性。DeskcommCRM支持标准的CSV导入导出也提供了RESTful API这意味着以后如果想换系统数据不会成为人质。这一点在选型时特别重要很多团队被某个系统绑死就是因为数据导不出来。2.2 Docker Compose编排的取舍不用Docker直接装行不行当然行。但我不推荐。原因很简单DeskcommCRM依赖Node.js运行时、PostgreSQL数据库、Redis缓存可能还有Nginx做反向代理。如果直接装在宿主机上版本冲突、依赖缺失、升级困难这些问题会一个接一个冒出来。我见过太多团队因为服务器上同时跑了三四个不同项目Node版本互相打架最后谁也不敢动。Docker Compose的好处是把每个服务隔离在独立容器里版本锁定在镜像层面宿主机只需要装Docker和Docker Compose就行。升级的时候改一下镜像tag重新up一下回滚也方便。数据持久化通过volume挂载到宿主机容器删了数据还在。当然也有代价。Docker会带来额外的网络层开销磁盘占用也比裸装大一些。但对于团队规模在五十人以下的场景这点开销完全可以接受。而且现在云服务器配置都不差多花几百兆内存换来的运维便利性绝对值。2.3 PostgreSQL和Redis的角色分工PostgreSQL在这套架构里承担主数据库的角色存所有结构化数据用户信息、客户资料、销售机会、任务记录、沟通日志等等。选PostgreSQL而不是MySQL主要考虑几个点JSON字段支持更好全文检索能力更强并发写入性能更优而且DeskcommCRM官方对PostgreSQL的支持更完善。Redis主要负责缓存和会话管理。用户登录后的session存在Redis里这样多个应用实例可以共享会话状态。另外一些频繁查询但不常变的数据比如系统配置、权限列表也走Redis缓存减少PostgreSQL的查询压力。这两个服务的版本选择也有讲究。PostgreSQL我建议用15或16版本性能比12以前的版本有明显提升尤其是并行查询和逻辑复制方面。Redis用7.x版本稳定性经过大量生产环境验证。具体版本号在后面的部署环节会给出。3. 部署前的环境准备与依赖安装3.1 服务器配置建议与操作系统选择先说服务器配置。我实测下来二十人左右的团队2核4G的云服务器跑这套东西基本够用但建议至少给到4核8G因为PostgreSQL和Redis都是吃内存的主而且后续数据量涨上来之后查询缓存需要更多内存。磁盘方面系统盘40G起步数据盘根据你的客户数据量来定一般100G能用很久。操作系统我推荐Ubuntu 22.04 LTS或者Debian 12。这两个发行版的软件源比较新Docker官方支持也好。如果你用的是CentOS Stream或者Rocky Linux步骤大同小异主要是包管理命令从apt换成dnf。特别提一下银河麒麟高级服务器操作系统V10这是国产化环境里比较常见的它基于CentOS安装Docker的步骤和RHEL系一致但需要注意默认的防火墙规则可能更严格后面会讲到怎么处理。注意不建议用Windows Server作为宿主机。虽然Docker Desktop for Windows也能跑但文件挂载的性能损耗明显而且Windows的换行符和权限模型容易导致容器内脚本执行异常。如果实在只有Windows环境建议开个虚拟机装Linux。3.2 Docker与Docker Compose安装实操Ubuntu下的安装步骤我整理成了一套可以直接复制执行的命令。先更新包索引然后安装必要的依赖sudo apt update sudo apt install -y ca-certificates curl gnupg lsb-release接着添加Docker官方GPG密钥和软件源sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg echo deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null然后安装Docker Engine和Compose插件sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin装完之后验证一下docker --version docker compose version如果输出显示版本号说明安装成功。这里有个细节新版的Docker Compose是作为Docker插件存在的命令是docker compose而不是docker-compose。网上很多老教程还在用带横杠的写法那个是Python版本的Compose已经停止维护了不建议再用。安装完成后把当前用户加入docker组这样不用每次敲sudosudo usermod -aG docker $USER newgrp docker实操心得newgrp docker只对当前终端会话生效其他已经打开的终端需要重新登录才能生效。如果执行docker命令还是提示权限不足退出SSH重新连一次就好了。3.3 目录规划与数据持久化设计在开始写docker-compose.yml之前先规划好目录结构。我习惯把所有跟这个项目相关的东西放在/opt/deskcomm下面/opt/deskcomm/ ├── docker-compose.yml ├── .env ├── data/ │ ├── postgres/ │ └── redis/ ├── uploads/ └── backups/data/postgres用来挂载PostgreSQL的数据目录data/redis挂Redis的持久化文件uploads放用户上传的附件backups放定期备份的数据库dump文件。这样规划的好处是备份的时候直接打包整个/opt/deskcomm目录就行迁移的时候也是整体搬走不会漏东西。目录权限要注意。PostgreSQL容器内的进程以特定UID运行如果宿主机目录权限不对容器启动会报权限错误。简单粗暴的做法是先创建目录然后给宽松权限sudo mkdir -p /opt/deskcomm/{data/postgres,data/redis,uploads,backups} sudo chmod -R 755 /opt/deskcomm生产环境当然要更严格但初期跑通流程阶段先把权限放开等跑起来之后再根据日志里的权限报错逐步收紧。4. Docker Compose编排文件逐段拆解4.1 服务定义与镜像版本锁定完整的docker-compose.yml我放在下面然后逐段解释每个配置项的作用version: 3.8 services: postgres: image: postgres:16.2-alpine container_name: deskcomm-postgres restart: unless-stopped environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} PGDATA: /var/lib/postgresql/data/pgdata volumes: - ./data/postgres:/var/lib/postgresql/data ports: - 127.0.0.1:5432:5432 healthcheck: test: [CMD-SHELL, pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}] interval: 10s timeout: 5s retries: 5 redis: image: redis:7.2-alpine container_name: deskcomm-redis restart: unless-stopped command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD} volumes: - ./data/redis:/data ports: - 127.0.0.1:6379:6379 healthcheck: test: [CMD, redis-cli, -a, ${REDIS_PASSWORD}, ping] interval: 10s timeout: 5s retries: 5 app: image: deskcomm/crm:latest container_name: deskcomm-app restart: unless-stopped depends_on: postgres: condition: service_healthy redis: condition: service_healthy environment: DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}postgres:5432/${POSTGRES_DB} REDIS_URL: redis://:${REDIS_PASSWORD}redis:6379 NODE_ENV: production APP_URL: ${APP_URL} SECRET_KEY: ${SECRET_KEY} volumes: - ./uploads:/app/uploads ports: - 3000:3000镜像版本我全部用了具体的小版本号加alpine后缀。alpine镜像体积小攻击面也小适合生产环境。为什么不写latest因为latest是个移动靶今天拉到的和明天拉到的可能不是同一个东西出了问题很难排查。锁定版本号之后升级变成一个有意识的操作而不是某次重启后突然发现行为变了。4.2 环境变量管理与敏感信息隔离所有敏感信息都通过.env文件注入不写在docker-compose.yml里。这样做的好处是compose文件可以提交到Git仓库做版本管理而.env文件加入.gitignore不会泄露密码。.env文件内容大概长这样POSTGRES_DBdeskcomm POSTGRES_USERdeskcomm_user POSTGRES_PASSWORD换成你自己的强密码 REDIS_PASSWORD换成另一个强密码 APP_URLhttps://crm.yourdomain.com SECRET_KEY用openssl rand -hex 32生成的随机字符串SECRET_KEY的生成方法openssl rand -hex 32这个密钥用于加密会话token和敏感字段一旦泄露等于所有用户密码都可能被破解。所以千万不要用默认值也不要用简单字符串。注意.env文件里不要用引号包裹值除非值里面确实包含空格或特殊字符。Docker Compose对引号的处理和shell脚本不完全一样有时候引号会被当成值的一部分传进去导致连接失败。4.3 网络配置与端口暴露策略上面的compose文件里PostgreSQL和Redis的端口映射写的是127.0.0.1:5432:5432而不是5432:5432。这个区别很关键。前者只监听本机的回环地址外部机器连不上后者监听所有网卡相当于把数据库直接暴露在公网上。我见过太多因为数据库端口暴露被挖矿或者勒索的案例。Redis尤其危险默认无密码暴露在公网上几分钟就会被扫描到并植入恶意脚本。所以这两个服务的端口映射一定要限制在127.0.0.1只允许宿主机上的其他进程访问。应用服务的端口映射是3000:3000这个可以暴露因为前面通常还有一层Nginx做反向代理和SSL终止。如果你打算直接用IP加端口访问那3000端口暴露是必须的。但生产环境强烈建议上Nginx后面会讲配置方法。Docker Compose默认会创建一个bridge网络所有服务在同一个网络里可以通过服务名互相访问。比如app服务里配置的DATABASE_URL用的是postgres:5432这里的postgres就是服务名Docker的内置DNS会把它解析到对应容器的IP。这个机制比写死IP地址灵活得多容器重建后IP变了也不影响。5. 启动、初始化与首次配置5.1 拉取镜像与启动顺序控制配置文件准备好之后在/opt/deskcomm目录下执行docker compose pull docker compose up -dpull先把镜像拉下来up -d后台启动。因为有depends_on和healthcheck的配置Compose会等PostgreSQL和Redis都健康之后才启动app服务。这个顺序很重要如果app先起来而数据库还没准备好应用会报连接错误然后退出虽然restart: unless-stopped会让它不断重试但日志里会刷一堆错误看着心烦。启动完成后查看状态docker compose ps正常的话应该看到三个服务都是running状态postgres和redis显示healthy。如果app显示restarting多半是数据库连接配置有问题用docker compose logs app看具体报错。5.2 数据库初始化与迁移执行DeskcommCRM首次启动时需要初始化数据库表结构。具体方式取决于镜像的入口脚本设计常见的有两种一种是容器启动时自动执行迁移另一种是需要手动执行命令。如果是手动执行命令大概是这样docker compose exec app npm run migrate或者有些项目用的是docker compose exec app node scripts/init-db.js执行之前建议先确认数据库连接是通的docker compose exec postgres psql -U deskcomm_user -d deskcomm -c \l这条命令会列出所有数据库能看到deskcomm就说明连接正常。实操心得迁移脚本执行前一定要先备份。虽然首次部署时数据库是空的没什么可丢的但养成习惯很重要。后面每次升级版本之前先pg_dump一份出问题了可以快速回滚。5.3 创建管理员账号与基础配置数据库初始化完成后通过浏览器访问http://你的服务器IP:3000应该能看到DeskcommCRM的登录页面。首次访问通常会引导创建管理员账号填写邮箱、密码、公司名称这些信息。如果没看到引导页面可能需要通过命令行创建管理员docker compose exec app npm run create-admin -- --email adminyourcompany.com --password 你的密码创建完管理员账号后登录进去第一件事是改配置。在系统设置里找到这几个关键项站点URL填你最终对外访问的域名比如https://crm.yourdomain.com。这个影响邮件通知里的链接和API回调地址。时区改成Asia/Shanghai不然所有时间戳都是UTC看起来别扭。邮件SMTP配置好SMTP服务器这样任务分配、客户跟进提醒才能发出去邮件。默认语言如果团队都用中文改成简体中文。这些配置看起来琐碎但一开始就设对后面省很多事。特别是站点URL如果一开始填的是IP后面换了域名所有已经发出的邮件里的链接都会失效。6. 反向代理与HTTPS配置6.1 Nginx反向代理配置模板直接暴露3000端口用IP访问短期测试可以长期用肯定不行。一是没有HTTPS浏览器会提示不安全二是IP地址难记而且换服务器的时候所有客户端都要改配置。所以需要Nginx做反向代理绑定域名配上SSL证书。Nginx的配置我一般放在/etc/nginx/sites-available/deskcomm.confserver { listen 80; server_name crm.yourdomain.com; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name crm.yourdomain.com; ssl_certificate /etc/letsencrypt/live/crm.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/crm.yourdomain.com/privkey.pem; client_max_body_size 50M; location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; 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; proxy_read_timeout 300s; } }几个关键点解释一下。client_max_body_size 50M是允许上传的最大文件大小默认是1M客户传个产品手册就超了。proxy_read_timeout 300s是后端响应超时时间导出大量数据的时候可能需要几分钟设太短会504。Upgrade和Connection这两个header是为了支持WebSocketDeskcommCRM的实时通知功能依赖这个。6.2 SSL证书申请与自动续期SSL证书用Lets Encrypt的免费证书就行通过certbot申请sudo apt install -y certbot python3-certbot-nginx sudo certbot --nginx -d crm.yourdomain.comcertbot会自动修改Nginx配置把证书路径填好然后reload Nginx。申请过程中会要求填邮箱和同意条款按提示操作即可。证书有效期90天certbot会自动创建定时任务续期。验证自动续期是否配置成功sudo certbot renew --dry-run如果输出显示成功说明续期机制正常。我建议还是定期手动检查一下因为有时候Nginx配置改过之后certbot的验证可能会失败而自动续期的失败通知邮件容易被忽略。6.3 访问测试与常见网络问题配置完成后用浏览器访问https://crm.yourdomain.com应该能看到登录页面而且地址栏显示锁图标。如果打不开按这个顺序排查域名解析是否正确dig crm.yourdomain.com看返回的IP是不是你的服务器IP。服务器防火墙是否放行443端口sudo ufw status查看。Nginx是否正常运行sudo systemctl status nginx。Nginx配置是否有语法错误sudo nginx -t。后端服务是否在监听curl http://127.0.0.1:3000看有没有响应。这五步走下来九成以上的网络问题都能定位到。7. 数据备份与恢复策略7.1 PostgreSQL逻辑备份与定时任务数据是这套系统里最值钱的东西备份策略必须认真对待。PostgreSQL的逻辑备份用pg_dump命令如下docker compose exec -T postgres pg_dump -U deskcomm_user -d deskcomm -F c -f /tmp/deskcomm_$(date %Y%m%d).dump docker compose cp postgres:/tmp/deskcomm_$(date %Y%m%d).dump ./backups/-F c指定自定义格式压缩比高恢复时也灵活。-T是禁用伪终端分配在脚本里执行必须加不然会报错。把这两条命令写进crontab每天凌晨三点执行0 3 * * * cd /opt/deskcomm docker compose exec -T postgres pg_dump -U deskcomm_user -d deskcomm -F c ./backups/deskcomm_$(date \%Y\%m\%d).dump注意crontab里的%需要转义成\%这是crontab的语法要求不转义会被当成换行符。备份文件保留最近30天更早的自动删除find /opt/deskcomm/backups -name *.dump -mtime 30 -delete7.2 恢复演练与验证方法备份不做恢复演练等于没备份。我建议每个月至少做一次恢复测试在另一台机器或者本地虚拟机上操作。恢复的步骤# 先停掉应用避免写入冲突 docker compose stop app # 删除现有数据库并重建 docker compose exec postgres psql -U deskcomm_user -d postgres -c DROP DATABASE deskcomm; docker compose exec postgres psql -U deskcomm_user -d postgres -c CREATE DATABASE deskcomm; # 恢复备份 docker compose exec -T postgres pg_restore -U deskcomm_user -d deskcomm --clean --if-exists ./backups/deskcomm_20240101.dump # 重启应用 docker compose start app恢复完成后登录系统检查几个关键数据客户数量、最近的联系人记录、任务列表。如果这些都对得上说明备份是有效的。注意pg_restore的--clean参数会先删除已存在的对象再重建如果目标数据库里有数据会被清掉。恢复前务必确认目标数据库是空的或者可以被覆盖的。7.3 附件与上传文件的同步方案数据库备份只覆盖了结构化数据用户上传的附件在./uploads目录里需要单独备份。最简单的办法是用rsync同步到另一台机器或者对象存储rsync -avz --delete /opt/deskcomm/uploads/ backup-server:/backup/deskcomm/uploads/--delete参数会删除目标端多余的文件保持两边完全一致。如果担心误删可以去掉这个参数改成只追加不删除。如果团队有对象存储服务也可以配置DeskcommCRM直接把附件传到对象存储这样备份压力就转移到存储服务那边了。具体配置方法在系统的存储设置里填上Access Key和Secret就行。8. 性能调优与日常运维8.1 PostgreSQL参数调优实战默认的PostgreSQL配置是给最小化环境用的在4核8G的机器上明显偏保守。需要调整几个关键参数配置文件在./data/postgres/postgresql.conf或者通过docker compose exec postgres psql执行ALTER SYSTEM SET命令。我一般调整这几个参数默认值建议值作用shared_buffers128MB2GB数据库缓存池大小effective_cache_size4GB6GB优化器假设的可用缓存work_mem4MB16MB每个排序/哈希操作的内存maintenance_work_mem64MB512MB维护操作VACUUM等内存max_connections100200最大连接数shared_buffers一般设为系统内存的25%左右8G内存给2G比较合适。effective_cache_size设为系统内存的75%告诉优化器操作系统层面大概有多少缓存可用。work_mem调大可以加速复杂查询但设太高会导致内存溢出16MB是个比较安全的起点。改完参数需要重启PostgreSQL容器docker compose restart postgres8.2 Redis内存策略与持久化配置Redis在这套系统里主要做缓存数据丢了可以从PostgreSQL重建所以持久化要求没那么高。但为了避免重启后所有用户都要重新登录还是建议开启AOF持久化。上面的compose文件里已经加了--appendonly yes数据会写到./data/redis目录。内存策略方面设置一个上限避免Redis把服务器内存吃光docker compose exec redis redis-cli -a 你的密码 CONFIG SET maxmemory 512mb docker compose exec redis redis-cli -a 你的密码 CONFIG SET maxmemory-policy allkeys-lruallkeys-lru表示内存满了之后淘汰最近最少使用的key。对于缓存场景这个策略最合适。8.3 日志管理与磁盘空间监控Docker容器的日志默认存在/var/lib/docker/containers下面时间长了会占很多磁盘。在compose文件里给每个服务加上日志轮转配置logging: driver: json-file options: max-size: 10m max-file: 3这样每个容器最多保留30M日志超出自动轮转删除。磁盘空间监控用简单的shell脚本就行#!/bin/bash THRESHOLD80 USAGE$(df / | tail -1 | awk {print $5} | sed s/%//) if [ $USAGE -gt $THRESHOLD ]; then echo 磁盘使用率 ${USAGE}%超过阈值 | mail -s 磁盘告警 adminyourcompany.com fi放进crontab每小时执行一次磁盘快满的时候能提前收到通知。9. 常见问题排查与避坑指南9.1 容器启动失败排查流程容器起不来是最常见的问题排查思路按这个顺序走第一步看容器状态和退出码docker compose ps docker compose logs --tail50 服务名退出码137表示被OOM Killer杀了内存不够退出码1一般是配置错误或依赖缺失。第二步检查端口占用sudo lsof -i :3000 sudo lsof -i :5432如果端口被其他进程占了要么改映射端口要么停掉冲突的进程。第三步检查挂载目录权限ls -la /opt/deskcomm/data/postgres如果属主不是容器内进程的UIDPostgreSQL会拒绝启动。解决办法是chown -R 999:999PostgreSQL alpine镜像里postgres用户的UID通常是999。9.2 数据库连接超时与认证失败应用报connection refused或者authentication failed按这个表排查错误信息可能原因解决方法connection refused数据库没启动或端口不对检查postgres容器状态和端口映射password authentication failed密码错误核对.env文件和数据库实际密码database does not exist数据库名错误检查POSTGRES_DB变量too many connections连接数超限调大max_connections或检查连接池配置timeout expired网络不通或防火墙拦截检查容器网络和宿主机防火墙有一个容易忽略的点如果修改了.env文件里的密码但数据目录已经存在PostgreSQL不会自动更新密码。因为初始化只在数据目录为空时执行。这时候要么进数据库手动改密码要么删掉数据目录重新初始化数据会丢慎用。9.3 附件上传失败与存储权限用户上传附件报错九成是./uploads目录权限问题。容器内应用进程的UID和宿主机目录的UID不匹配导致写入被拒。解决方法sudo chown -R 1000:1000 /opt/deskcomm/uploads sudo chmod -R 775 /opt/deskcomm/uploads1000通常是容器内node用户的UID。如果不确定可以进容器看一下docker compose exec app id输出的uid就是需要设置的属主。另一个可能的原因是Nginx的client_max_body_size设太小大文件被Nginx拦截了根本到不了应用。这个在Nginx配置章节已经讲过改成50M或更大即可。9.4 升级版本时的注意事项升级DeskcommCRM版本之前必须做三件事备份数据库pg_dump一份存到安全的地方。阅读更新日志看有没有破坏性变更比如数据库schema改动、环境变量改名。在测试环境先跑一遍复制一份生产数据到测试环境执行升级流程确认没问题再上生产。升级操作本身很简单docker compose pull app docker compose up -d app docker compose exec app npm run migrate但顺序不能错。先拉新镜像再重建容器最后执行迁移。如果迁移失败用之前备份的数据恢复然后回滚镜像版本。实操心得升级前把当前运行的镜像tag记下来比如deskcomm/crm:2.3.1。万一新版本有问题把compose文件里的tag改回去重新up就能回滚。这比从备份恢复快得多。10. 团队协作功能配置与使用建议10.1 角色权限体系设计DeskcommCRM内置了几种角色管理员、销售经理、销售代表、只读用户。但实际团队里往往需要更细的权限控制比如售后团队只能看工单相关的客户不能看销售机会金额。我的做法是创建自定义角色按功能模块分配权限。在系统设置的角色管理里可以勾选每个角色能访问的模块和能执行的操作。建议遵循最小权限原则新入职的销售先给只读权限熟悉系统后再开放编辑权限。一个容易踩的坑是删除了某个角色但还有用户属于这个角色这些用户会变成无权限状态登录后什么都看不到。删除角色前先把相关用户转移到其他角色。10.2 销售漏斗与任务分配实践销售漏斗的配置直接影响到团队的工作效率。我建议按实际销售流程来定义阶段不要照搬默认模板。比如我们的流程是线索→初步接触→需求确认→方案报价→谈判→成交/丢单每个阶段设置明确的进入和退出条件。任务分配用自动规则能省很多事。比如新分配的线索自动创建跟进任务负责人是线索归属人截止时间是分配后24小时。这样销售一登录就能看到待办事项不会漏跟。注意自动规则不要设太多否则任务列表会爆炸销售反而不知道先做哪个。我一般只设三到五条最关键的规则其他的靠人工判断。10.3 数据导入与历史客户迁移从Excel或者其他CRM迁移数据用CSV导入功能最方便。但导入之前要做数据清洗去重、补全必填字段、统一格式。我见过直接导入导致系统里出现几千条重复客户的案例清理起来非常痛苦。导入的步骤下载CSV模板按模板整理数据。先导入10条测试数据确认字段映射正确。全量导入导入后抽查几条记录。如果导入出错利用系统的回滚功能撤销本次导入。DeskcommCRM的导入功能支持字段映射可以把CSV里的列对应到系统的字段。如果CSV里的字段名和系统字段名不一致在这里手动指定对应关系。10.4 邮件集成与通知配置邮件集成配好之后系统可以自动发送任务提醒、客户跟进提醒、密码重置邮件。SMTP配置在系统设置里填上邮件服务器地址、端口、用户名、密码。如果用的是企业邮箱通常需要生成一个应用专用密码而不是用登录密码。这个在邮箱的设置里找不同服务商叫法不一样有的叫“客户端授权码”有的叫“应用密码”。通知频率也要控制。如果每分配一个任务就发一封邮件销售很快会把通知邮件设为垃圾邮件。我建议只对高优先级的任务发邮件通知普通任务在系统内的通知中心显示就行。11. 我在这套系统上踩过的坑与最终体会这套DeskcommCRM从第一次部署到现在稳定运行了将近一年中间踩的坑不算少。最开始用latest标签结果某次自动拉取新版本后数据库schema不兼容应用直接起不来花了大半天从备份恢复。从那以后所有镜像都锁定具体版本号升级变成一个有计划的动作。还有一次是服务器磁盘满了PostgreSQL写入失败应用报了一堆错。排查发现是Docker日志没配轮转某个容器日志涨到了几十个G。加上日志轮转配置之后这个问题再没出现过。Redis的密码我一开始没设想着反正只监听127.0.0.1。后来有一次做安全扫描发现本机上的另一个服务被入侵后攻击者可以通过localhost访问Redis。虽然最终没造成损失但这件事提醒我内网不等于安全该设的密码一个都不能省。如果让我给准备自建DeskcommCRM的团队一个建议那就是先把备份和恢复流程跑通再开始录入真实数据。数据一旦进去迁移成本就高了而备份是唯一的后悔药。另外不要追求一次配置完美先跑起来然后在用的过程中逐步调优。很多参数只有在实际负载下才知道该怎么设纸上谈兵没用。