CRM客户建模核心:字段契约、状态机与权限三维设计
简介本资源是一份完整的CRM客户管理模块软件需求说明书PRD面向企业数字化转型中的产品经理、系统分析师及CRM开发实施人员聚焦客户档案管理、交互历史追踪、销售漏斗分析等核心业务场景助力团队精准定义需求、对齐业务目标与技术实现。文档由蜂网供应链管理上海有限公司于2017年8月正式发布编写人为周旭丽全文共54页PDF结构严谨覆盖项目背景、目标顾客、平台政策、竞品分析、名词解释、业务用例、功能列表及基本流程等关键章节附有详细变更记录与版本控制说明。资源为单文件PDF格式大小3.11MB轻量易读适合作为CRM需求分析范本、行业方案参考或高校信管/电商专业教学案例。目前已有310人学习下载内容机密性标注清晰具备真实企业级交付文档的规范性与实操参考价值。1. 这份2017年的CRM PRD不是过时文档而是可复用的客户建模骨架很多人看到“V1.0-20170825”就直接划走觉得这是历史遗迹。但实际拆过蜂网这份《客户关系管理CRM_客户管理_软件需求说明书_V1.0》后会发现它没写一行代码却精准框定了CRM系统最硬核的客户数据结构、状态流转逻辑和权限边界——这些恰恰是今天搭建SaaS型CRM或私有化部署客户中台时最容易被跳过的底层基建。它不讲微服务怎么拆也不提React还是Vue而是用54页纸把“客户是谁、谁管客户、客户怎么变、数据怎么活”这四件事钉死在字段级、流程级和规则级。比如“上级客户”字段明确要求“不允许互为上下级”“工商注册”字段标注“系统判定”且“非空不可编辑”这种设计不是拍脑袋而是来自供应链场景下对集团客户、子公司、经销商三级架构的真实约束。适合正在从Excel手工管理转向系统化客户运营的中小团队也适合需要快速验证客户模型是否完备的ToB产品负责人——你不需要照搬它的UI截图但必须吃透它定义的37个客户关键数据项、5类预置查询方案、4种负责人变更路径以及那个被标注为“二期实现”却至今仍被多数CRM忽略的线索自动归集逻辑。2. 客户实体建模从37个字段到状态机驱动的生命周期管理2.1 字段设计背后的业务刚性约束蜂网PRD在3.1.3.1.2.3节列出了客户列表默认关键数据项共37个字段但真正决定系统健壮性的不是数量而是每个字段携带的业务契约。以“上级客户”为例它不仅是普通参照字段PRD明确要求“参照CRM客户上下级关系不允许互为上下级”。这意味着数据库设计时必须引入循环检测机制而非简单外键关联。再看“工商注册”字段类型为布尔值但取值来源标注为“系统判定”合法性说明为“非空不可编辑”。这暗示系统需集成国家企业信用信息公示系统API在客户录入公司名称和统一社会信用代码后自动调用接口校验并回填结果——这个字段本质是风控开关而非展示属性。提示很多团队在开发初期把“工商注册”设为手动勾选导致销售随意标记“已认证”后续审计时无法追溯真实性。蜂网的设计强制将校验环节前置把合规责任交给系统而非人。2.1.1 关键字段的可编辑性与来源映射表字段名类型可编辑性来源业务含义开发注意事项客户名称字符可编辑手工输入非空≤200字符前端需实时校验长度后端SQL加CHECK(LENGTH(name) 200)上级客户参照可编辑手工输入禁止A→B→A循环插入/更新时执行递归查询检测环路建议用闭包表Closure Table优化性能行业枚举可编辑数据字典从启用行业列表选择字典表需带is_enabled字段前端请求时过滤WHERE is_enabled 1成交状态枚举可编辑手工输入默认“未成交”选项含“已成交”状态变更需触发事件如发送通知、更新统计报表缓存最新活动记录时间日期时间不可编辑系统自动最后活动保存时的时间戳每次创建/更新联系人、商机、动态记录时同步更新客户主表该字段2.2 客户状态转换从静态枚举到动态审批流PRD在3.1.3.3.1节附有状态转换图虽未提供图形但文字描述清晰界定出客户生命周期的四个核心状态新建 → 待审核 → 已启用 → 已停用。更关键的是3.1.3.3.3节“审批流”要求“客户创建需经部门负责人审批超500万年采购额客户需升级至区域总监审批”。这揭示出状态机不是孤立存在而是与组织架构深度耦合。2.2.1 审批规则落地的两种实现方式方式一硬编码角色判断适用于组织稳定场景# Python伪代码根据客户预估年采购额动态路由审批人 def get_approver(customer): if customer.estimated_annual_purchase 5000000: return DepartmentManager.objects.get(dept_idcustomer.department_id) else: return RegionalDirector.objects.get(region_idcustomer.region_id) # 调用示例 approver get_approver(new_customer) ApprovalTask.objects.create( customer_idnew_customer.id, approver_idapprover.id, leveldepartment if new_customer.estimated_annual_purchase 5000000 else regional )参数说明estimated_annual_purchase字段在PRD中虽未列于关键数据项但在“业务规则”章节隐含要求——需在客户新增/编辑界面提供输入入口并作为审批路由依据。代码中level字段用于后续统计不同层级审批通过率。方式二配置化审批引擎推荐用于多变组织建立approval_rule表rule_idcondition_fieldcondition_valueoperatortarget_rolepriority1estimated_annual_purchase5000000GTregional_director102department_id101EQdepartment_manager5运行时解析规则-- PostgreSQL示例动态获取审批人 SELECT u.user_id, u.name FROM users u JOIN approval_rule ar ON u.role ar.target_role WHERE ar.condition_field estimated_annual_purchase AND new_customer.estimated_annual_purchase ar.condition_value ORDER BY ar.priority DESC LIMIT 1;逻辑说明当客户预估采购额超过500万优先匹配regional_director角色若未命中则降级匹配部门经理。这种方式避免修改代码即可调整审批策略符合PRD中“审批流需支持灵活配置”的隐含需求。2.3 权限控制基于“负责人部门组织”的三维校验PRD在3.1.3.3.4节强调“客户数据可见性遵循‘我负责的客户’、‘我参与的客户’、‘我关注的客户’三重维度”。这不是简单的RBAC基于角色的访问控制而是ABAC基于属性的访问控制雏形。具体到操作层面“更改负责人”按钮支持批量操作但删除操作必须弹出确认界面——这种差异源于权限粒度设计负责人变更属协作行为而删除是数据主权动作。2.3.1 查询方案背后的SQL生成逻辑PRD预置5类查询方案其SQL生成需动态拼接WHERE条件-- “七日未跟进客户”查询方案对应PRD 3.1.3.1.2.4节第5条 SELECT * FROM crm_customer c WHERE c.org_id :current_org_id -- 所属组织我所在组织基础过滤 AND c.last_activity_time NOW() - INTERVAL 7 days AND NOT EXISTS ( SELECT 1 FROM crm_activity a WHERE a.customer_id c.id AND a.created_at NOW() - INTERVAL 7 days );参数说明:current_org_id由当前登录用户会话注入确保租户隔离last_activity_time字段在PRD中定义为系统自动维护此处利用其减少子查询开销NOT EXISTS替代LEFT JOIN避免因活动记录为空导致客户重复。注意PRD要求“列表默认按创建时间倒序”但“七日未跟进”方案需按last_activity_time升序排列以便优先处理陈旧客户。前端应允许用户切换排序字段后端SQL需支持ORDER BY动态参数化。3. 客户操作闭环从新增、合并到导入导出的工程化实现3.1 新增客户的关键路径与防错设计PRD 3.1.3.1.2.8节的“客户-新增界面示意图”虽无图形但3.1.3.1.2.9按钮清单明确要求“新增界面需包含‘保存’、‘保存并新建’、‘取消’三按钮”。这暗示着用户高频操作路径——销售每天录入数十客户必须降低单次操作成本。“保存并新建”意味着表单提交后清空字段并保持焦点在客户名称输入框而非跳转回列表页。3.1.1 查重机制的双重校验实现PRD 3.1.4.2节“查重设置”仅一句话“支持按客户名称、电话、邮箱组合查重”。但实际落地需分层防御前端实时校验用户输入客户名称时AJAX请求/api/customers/check-duplicate?namexxxphoneyyy返回{exists: true, ids: [101,102]}提示“已存在同名客户ID:101,102”后端最终校验INSERT前执行原子性检查INSERT INTO crm_customer (name, phone, email, created_by, org_id) SELECT ABC公司, 13800138000, contactabc.com, 123, 456 WHERE NOT EXISTS ( SELECT 1 FROM crm_customer WHERE (name ABC公司 OR phone 13800138000 OR email contactabc.com) AND org_id 456 );逻辑说明WHERE NOT EXISTS确保插入前无冲突避免应用层与数据库层时间差导致的脏数据。org_id 456限定查重范围在本租户内符合PRD“客户所属组织我所在组织”的默认规则。3.2 客户合并的技术难点与数据血缘保留PRD 3.1.3.1.2.17节“客户-合并”功能看似简单实则涉及复杂的数据迁移。当合并客户A主与客户B从时需处理联系人、商机、合同等关联记录的customer_id外键更新动态记录如邮件、通话的归属转移合并操作本身需生成审计日志记录“客户B已合并至客户A”。3.2.1 合并操作的事务安全实现BEGIN TRANSACTION; -- 步骤1锁定被合并客户防止并发修改 SELECT * FROM crm_customer WHERE id 201 FOR UPDATE; -- 步骤2更新所有关联表外键 UPDATE crm_contact SET customer_id 101 WHERE customer_id 201; UPDATE crm_opportunity SET customer_id 101 WHERE customer_id 201; UPDATE crm_contract SET customer_id 101 WHERE customer_id 201; -- 步骤3标记原客户为已合并非物理删除 UPDATE crm_customer SET status merged, merged_to_id 101, updated_at NOW() WHERE id 201; -- 步骤4记录合并日志 INSERT INTO crm_merge_log (main_customer_id, merged_customer_id, operator_id, created_at) VALUES (101, 201, 123, NOW()); COMMIT;参数说明FOR UPDATE确保行锁避免其他事务同时合并同一客户merged_to_id字段在PRD中未明确定义但为满足“客户层级关系”3.1.3.1.2.25节和审计要求必须新增日志表crm_merge_log需单独建表便于后续分析合并频次与客户质量。3.3 导入导出模板驱动与增量同步的平衡PRD 3.1.3.1.2.27/28节要求“客户-导入/导出”但未指定格式。结合2017年企业实践Excel是事实标准。然而直接读取Excel易引发内存溢出单文件超10万行且字段映射错误难定位。3.3.1 分片导入与错误反馈机制# 后端接收导入请求curl示例 curl -X POST http://crm-api/v1/customers/import \ -H Authorization: Bearer token \ -F filecustomers_template.xlsx \ -F org_id456 \ -F batch_size500Python处理逻辑def import_customers(file_path, org_id, batch_size500): # 1. 读取Excel首行获取字段映射 headers pd.read_excel(file_path, nrows0).columns.tolist() # 2. 分块读取每500行一个批次 for chunk in pd.read_excel(file_path, chunksizebatch_size): # 3. 字段校验检查必填字段客户名称、负责人是否存在空值 errors [] for idx, row in chunk.iterrows(): if pd.isna(row[客户名称]): errors.append(f第{idx2}行客户名称不能为空) if pd.isna(row[负责人]): errors.append(f第{idx2}行负责人不能为空) if errors: raise ImportValidationError(errors) # 返回给前端具体行号错误 # 4. 批量插入使用ON CONFLICT DO NOTHING避免重复 insert_sql INSERT INTO crm_customer (name, phone, email, owner_id, org_id, created_by) VALUES %s ON CONFLICT (name, org_id) DO NOTHING; execute_values(cursor, insert_sql, chunk.values.tolist())逻辑说明execute_values是psycopg2的高效批量插入方法ON CONFLICT利用唯一索引UNIQUE INDEX ON crm_customer(name, org_id)自动去重避免先查后插的竞态错误反馈精确到Excel行号idx2因首行为标题符合PRD“导入失败需明确提示错误位置”的隐含要求。4. 查询方案实战用5个预置条件构建销售作战地图4.1 “我负责的客户”方案的权限穿透实现PRD 3.1.3.1.2.4节第2条“我负责的客户客户负责人我本人”表面是简单WHERE条件但需穿透组织架构。例如销售张三属于北京销售部但其负责客户可能跨华北区多个子公司——此时customer.owner_id current_user.id只是起点还需关联user_department和department_hierarchy表获取其管理范围。4.1.1 多级部门管辖的SQL展开-- 获取张三及其下属部门所有客户 WITH RECURSIVE dept_tree AS ( -- 锚点张三所在部门 SELECT id, parent_id, name FROM departments WHERE id ( SELECT dept_id FROM users WHERE id 123 ) UNION ALL -- 递归子部门 SELECT d.id, d.parent_id, d.name FROM departments d INNER JOIN dept_tree dt ON d.parent_id dt.id ) SELECT c.* FROM crm_customer c WHERE c.owner_id 123 -- 直接负责 OR c.department_id IN (SELECT id FROM dept_tree); -- 部门管辖参数说明current_user.id123为张三用户IDdept_tree递归CTE获取其部门及所有下级部门IDOR条件确保既包含张三直管客户也包含其团队管理的客户符合PRD“我负责的客户”业务语义。4.2 “七日未跟进客户”的预警自动化改造PRD将此列为预置查询方案但未提自动化。实际落地时可将其转化为定时任务每日凌晨扫描并推送预警# Celery定时任务每日0点执行 app.task def alert_inactive_customers(): # 查询七日未跟进客户复用PRD逻辑 customers Customer.objects.filter( org_idsettings.CURRENT_ORG_ID, last_activity_time__lttimezone.now() - timedelta(days7) ).select_related(owner).values( id, name, owner__name, owner__email ) # 按负责人分组发送邮件 from collections import defaultdict alerts defaultdict(list) for c in customers: alerts[c[owner__email]].append(c) for email, cust_list in alerts.items(): send_mail( subjectf【CRM预警】您有{len(cust_list)}个客户超7天未跟进, messagerender_to_string(inactive_alert.txt, {customers: cust_list}), from_emailcrmfengwang.com, recipient_list[email] )逻辑说明select_related(owner)减少N1查询render_to_string渲染模板邮件内容包含客户名称、最后活动时间、一键跟进链接settings.CURRENT_ORG_ID确保多租户隔离。此改造将PRD的静态查询方案升级为动态预警机制直击销售管理痛点。4.3 高级查询的字段扩展与性能保障PRD 3.1.3.1.2.5节要求“高级查询条件客户表字段包含自定义字段”。自定义字段通常以EAVEntity-Attribute-Value模式存储易引发性能问题。推荐采用JSONB字段PostgreSQL或动态列MySQL 5.7-- PostgreSQL JSONB方案 ALTER TABLE crm_customer ADD COLUMN custom_fields JSONB DEFAULT {}; -- 查询含自定义字段的客户如行业偏好IT SELECT * FROM crm_customer WHERE custom_fields {industry_preference: IT};参数说明为JSONB包含操作符支持Gin索引加速custom_fields字段存储销售自定义的标签、评分、来源渠道等避免EAV表JOIN导致的慢查询。此设计在PRD框架下平滑扩展无需修改主表结构。提示PRD未定义自定义字段但“业务类型”、“客户级别”等枚举字段已预留扩展空间。JSONB方案让销售团队可自主添加字段而IT团队只需维护索引符合PRD“支持灵活配置”的底层精神。本文还有配套的精品资源点击获取