适合小团队且保持简单的轻量级 CRM 架构
构建一个轻量级 CRM 架构,将 Contacts、Deals、Activities 和权限保持简单,同时支持可靠的报表和日常工作流。

这个 CRM 模式要解决的问题
小团队需要一个能快速回答日常问题的 CRM:我们在和谁沟通?我们要达成的交易是什么?上次发生了什么?下一步是什么?这就是轻量级 CRM 模式的真实目标。任何不支持这些问题的设计通常就是噪音。
小团队很少需要复杂的客户层级、成百上千的自定义对象或复杂的评分模型。他们需要的是明确的归属、简单的接触历史,以及大家能同样理解的销售管道。
“简单”会被自由文本和重复数据破坏。如果一个人把交易阶段写成 “Negotiation”,另一个人写成 “negotiating”,报表就变得靠猜。若把活动分在多张表里(电话、会议、笔记),你会得到多个日期字段而没有可靠的“最后接触”值。
这个模式坚持四个核心对象,覆盖大多数小团队的 CRM 需求,同时不演变成怪兽:
- Contacts(联系人,必要时还有 Organizations)作为你沟通的对象
- Deals(交易)作为你在管道中跟踪的机会
- Activities(活动)作为任务、会议、电话和笔记的统一日志
- Permissions(权限)作为谁能查看和编辑的实用规则
干净的报表意味着你可以可靠地看到本周按阶段的交易、阶段间的转换率、阶段的平均停留时间、每笔交易的最后活动,以及每位销售今天的未完成任务。即便团队从 3 人增长到 15 人,这些报表仍然要有意义。
如果你在像 AppMaster 这样无代码工具中构建内部 CRM,这种方法能保持数据库小巧,同时为仪表板和周会提供稳定的数据。
在保持轻量的同时不把自己限制住的原则
轻量级 CRM 模式的有效之处在于它能清楚回答一个问题:这个事实应该存放在哪里?如果同一个“真相”可以存两处,那就会被重复存储,报表会漂移。
选定少量的事实来源对象,让其他内容都指向它们。对大多数小团队来说,这意味着 Contacts、Organizations(可选)、Deals 和 Activities。当你需要更多细节时,新增一张表,而不是把含义塞进一个会变成杂物抽屉的文本字段。
几条规则能让模型既简单又灵活:
- 一条事实一个归属:电话号码属于 Contact,交易金额属于 Deal。
- 倾向显式表而非重载字段:阶段历史不是逗号分隔的字符串。
- 保持 ID 稳定,名称可编辑:公司会重命名,但不会改主键。
- 把 “状态” 和 “类型” 分开:一个任务既可以是 “open”,也可以是 “call”。
- 假设导入会很混乱:空白、重复和怪异格式是常态。
从第一天就为混乱数据做准备,添加几个枯燥但强大的字段:created_at、updated_at,以及核心表上的简单 external_id(或 import_source + import_key)。这给你一个在不产生重复记录的情况下重新导入数据的安全方式。
举个具体例子:你导入一张表格,“Acme Inc.” 在一半行写成 “ACME”。如果 Organization.name 可编辑且 Organization.id 稳定,你以后可以合并记录而不会破坏已有的交易和活动。
联系人和公司:最简单且可用的结构
轻量级 CRM 模式从一个决策开始:你只跟踪人,还是既跟踪人也跟踪公司?如果你的团队对企业销售,几乎总是需要同时有 Contact(个人)和 Organization(公司)。如果面向消费者,可以完全跳过 Organizations,把每条记录都当作联系人处理。
在 B2B 场景下,保持关系简单:每个联系属于一个主组织(可为空),一个组织可以有多个联系人。这覆盖了大多数小团队的工作流,而不会把你推入复杂的客户层级中。
保持必填字段最小化
把字段要求做得尽可能少是避免数据变糟的最快方式。一个合适的基线是:
- Contact:
id、姓名(或first_name+last_name)、created_at - Organization:
id、name、created_at
其他字段(职务、网站、地址、行业、来源)都可以设为可选。你可以以后添加规则,但把数据库填满像 “N/A” 这样占位符很难清理。
邮箱和电话:不那么苛刻的唯一性策略
把邮箱设为唯一看起来很诱人。对 B2C 或把 CRM 当做登录系统的场景,这种规则效果很好。但在小型 B2B 团队中,共享邮箱(sales@、info@)和被重复使用的电话号码很常见。硬性唯一性规则可能阻挡合法记录。
一个务实的折中方案:
- 只有当值存在时才强制唯一(并且只在适合你流程时这样做)。
- 允许重复,但在 UI 中发现匹配时显示软提示。
如果需要多个邮箱或电话号码,避免添加 email_2 或 phone_3 这类列。用单独的表(例如 ContactMethod,包含 type、value、is_primary)代替。报表保持清晰,模型自然可扩展。
示例:你的团队遇到 Pat,Pat 在季度中换了工作。有了 Contact 与 Organization 的关联,你可以把 Pat 移到新公司,保留旧的联系方式用于历史记录,并且报表仍然能按公司正确统计交易。
交易与管道:保持结构易读
交易是你预测的基本单位:一个有明确下一步的潜在购买。把交易记录保持精简,其他信息都用引用来关联。
从任何团队成员都能解释的字段开始:
- Deal name:一段在列表中能看懂的短标签
- Stage:引用一个管道阶段(不要手工输入)
- Value:预期金额(并为整个系统选择一种货币)
- Owner:负责推进的人
- Close date:一个对下一步的最佳预计关闭时间
对于关系,选择一个主要联系人作为交易的主联系人。这样报表更直接(例如按联系人统计收入、按细分计算赢单率)。如果有时需要更多人参与,增加 deal_contacts 表以便添加额外联系人,而不必把每笔交易一开始就做成复杂的多对多模型。多数小团队用 1 个主联系人加若干可选参与者就足够了。
阶段是 CRM 常出问题的地方。不要把阶段存为自由文本。把阶段存为参考数据,这样你可以后来重命名阶段而不破坏报表。一个最小的阶段表可以包括:
stage_idpipeline_idstage_namestage_orderis_closed(或分别标记 won 和 lost)
若你的团队规模小,除非你确实用不同流程管理线索,否则不要把记录拆成 “lead” 和 “deal”。一个简单规则是:当确实有值得跟踪的机会时,它就是一笔交易。在那之前,把它当作带有 “new” 或 “nurture” 状态的联系人即可。这让管道更可读,也避免半创建的交易污染数据。
示例:两人销售团队把 “Acme Renewal” 记录为 Sam 负责的一笔交易,阶段是 “Proposal Sent”,金额 12,000,预计下月关闭。主联系人是买方,另一个联系人作为财务审批人被添加。因为阶段名称和顺序固定,报表保持一致。
活动:任务、会议和笔记用同一种模型
小团队不需要为电话、邮件、会议和笔记分别建表。一张 Activity 表通常足够,这也让 CRM 更易用、报表更简单。
单一 Activity 表
对每一件发生的事(或应该发生的事)保存一条记录。给它一个简单的 type 字段,使用一小组固定值,例如:call、email、meeting、note、task。把列表保持短,这样大家每次都会选同样的词。
为避免混淆,使用明确的关联规则:
- 如果是关于某人(跟进电话、介绍邮件),关联到 Contact。
- 如果是为推动收入(定价电话、谈判会议),关联到 Deal。
- 如果确实同时涉及两者,则两个都关联,但在管道报表中以 Deal 为主关联。
实际中,Activity 可以有 contact_id(可空)和 deal_id(可空),再加上可选的 owner_id(谁负责)。
便于报表的时间字段
同时保留 due_at 和 completed_at。它们回答不同的问题:due_at 告诉你应该发生什么(计划与工作负载),completed_at 告诉你实际发生了什么(执行与周期时间)。
你可以不额外加状态字段:如果 completed_at 被设置,则视为已完成;否则视为未完成。这避免了额外状态值随着时间不同步的风险。
对于活动文本,保留一个可搜索字段,比如 summary 或 body。早期避免过度结构化笔记。例如:“与 Maya 通话:确认预算,周五发提案。”只有在真正觉得痛点时再添加专门字段。
所有权与可见性:保持务实
所有权是指谁负责下一步。在轻量级 CRM 模式中,通常在交易上有一个像 owner_user_id 的字段(联系人上也常有)。
“owner” 有两个常被混淆的含义:用户指派(具体某人)和团队指派(某个群体)。如果一开始就把一切都做成团队所有,你会失去关于“今天谁该行动”的清晰度。
一个对多数小团队适用的默认是:所有东西对大家可见,但每笔交易有且只有一个 owner。协作保持简单,也避免当有人需要替代同事时出现权限边界问题。
当你确实需要更严格的可见性时,把它做成一个单一开关,而不是复杂矩阵。例如,在交易和活动上加一个 visibility 字段,值为 public 或 private,其中 private 意味着 “仅 owner(和管理员)可见”。
只有当满足以下情形之一时,你才需要团队或区域级别的逻辑:
- 存在互相不该看见对方交易的独立小组。
- 你需要按团队报表且成员在团队间流动。
- 管理者需要访问其团队的数据,但不能访问全公司数据。
- 你把线索放到共享队列,等待销售认领。
所有权影响报表。如果你想要干净的“按人”报表,应当按交易当前的 owner_user_id 报表。如果你还想要“按团队”的汇总,添加 owner_team_id(或从 owner 的个人资料派生),但要明确哪一个是事实来源。
示例:两位销售共享一个收件箱。新交易开始时未分配,owner_user_id = null,owner_team_id = Sales。当 Alex 领取它,就设置 owner_user_id = Alex(团队仍为 Sales)。这样管道可读,团队总数也能正常统计。
权限设计:足够控制但不复杂
从简单的 RBAC 开始
把“谁(角色)”、“什么(资源)”和“能做什么(动作)”区分开最有用。这就是基于角色的访问控制(RBAC),随着团队增长它仍然易于理解。
把资源限制在核心对象附近:Contacts、Organizations、Deals、Activities,可能还包括 Pipelines(如果阶段可编辑)。在这些对象间定义一组小而一致的动作:view、create、edit、delete、export。
Export 值得单独区分。许多团队对查看权限宽松,但想限制批量数据导出。
从对象级权限开始是最容易的起点:“这个角色能否编辑交易?”对大多数小团队来说,这几个月足够用。记录级规则(按单条记录控制)是复杂度的来源,仅在真正需要时再加。
一个实用的第一步是单一所有权规则:每条记录有 owner_user_id,非管理员只能编辑自己拥有的记录。如果需要再加一层,添加 team_id 并允许团队内查看,同时把编辑权限限定为 owner。
真正需要时才加记录级规则
在这些场景下再加入记录级权限:
- 销售代表之间不能互相查看对方交易
- 支持团队可以查看交易但不能编辑
- 管理者可以查看所有并重新指派 owner
把审计需求做得轻量但实用。给每个主表加 created_at、created_by、updated_at、updated_by。若以后需要更深的历史,增加一个小的 audit_log 表:object type、record id、action、who、when、以及一个短 JSON 描述变更字段。
分步走:在一个周末内构建这个模式
把它当成一个小产品会最容易做对:先定义数据、用真实条目验证,然后再做界面。
第一天:确定数据模型
先在纸上或白板上画一个快速 ERD。表数量保持小,但要清楚关系:contact 可属 organization(可空),deal 属于某个 pipeline 并有 owner,activity 可以关联 contact 和/或 deal。
然后按顺序做基础工作:
- 定义对象和关系:contacts、organizations、deals、activities、users/roles,加上必要的小型查找表。
- 定义必填字段和默认值:让
created_at、owner_id和关键名称必填;如果使用金额,给阶段和货币设默认值。 - 定义枚举或查找表:把交易阶段和活动类型抽成表或枚举以保持报表一致。
- 为常用筛选添加索引:
owner_id、stage、due_at、created_at和日常按外键筛选的字段。 - 用 20 条真实记录测试:用真实的名字、日期和混乱的笔记看看哪里会出问题。
第二天:验证报表是否干净
在做表单之前,写下团队每周要问的 6-8 个问题。例如:“按负责人统计处于 Negotiation 的交易”、“逾期活动”、“本月新联系人”、“按月计算的已赢收入”。如果某个问题需要复杂连接或大量特例来回答,就现在修正模式。
一个简单的测试场景很有帮助:添加 3 个同公司联系人、2 笔不同阶段的交易,以及 6 条活动(一个电话、一个会议、两个任务、两个笔记)。检查你是否能在不猜测的情况下回答谁负责、下一步是什么,以及上周发生了什么。
数据稳定后再做 UI 和自动化。你会跑得更快,也不必为了让报表匹配现实而频繁重写历史。
导致报表混乱的常见错误
报表混乱通常始于那些看起来今天更快但代价更高的“速成修补”。当数据有清晰的形状并且团队遵循少量规则时,轻量级 CRM 模式最管用。
一个常见陷阱是把一切强行塞进一个 “customer” 表。听起来简单,但你会无法回答诸如 “有多少笔交易关联到同一家公司?” 或 “哪个人跳槽了?” 这类问题。把人(contacts)和公司(organizations)分开并建立连接。
另一个报表杀手是让交易阶段成为自由文本。如果一个人输入 “Negotiation”,另一个人输入 “negotiating”,你的管道图表已经错了。使用固定的阶段列表(或阶段表),让每笔交易都指向同一套值。
避免把多个值打包到一个字段里。逗号分隔的邮箱或电话号码会让搜索、去重和导出变痛苦。如果确实需要多个值,就把它们作为多行存储(例如在子表中每条记录一个邮箱)。
活动会在日期不清晰时变得混乱。单个 “date” 字段无法区分任务是上周到期还是上周完成。把这些概念分开,这样你就能正确报表逾期工作和已完成工作。
这是一个“为将来的你省心”的快速清单:
- 把 contacts 和 organizations 分开并链接
- 使用阶段 ID,而不是手工输入的阶段名称
- 每个字段只存一个值;需要多个值就用子表
- 保持
due_at和completed_at为独立字段 - 从简单角色开始;只有在看到真实工作流后再加记录级规则
示例:如果团队把通话记录作为笔记并通过编辑同一字段来标记“已完成”,你就无法统计跟进用了多久。把字段分开后,这类报表会变得直接可得。
在确定模式前的快速检查清单
在你构建界面、自动化和仪表板前,做一次快速的报表与规则检查。轻量级 CRM 模式之所以能保持轻量,是因为你能在不靠自定义补丁或一次性字段的情况下回答常见问题。
用真实样本数据(即使只有 20 个联系人和 10 笔交易也够)跑一遍这些检查。如果卡住,通常意味着缺少字段、选择项不一致或关系太松散。
五项检查能捕捉大多数问题
- 报表基础:你能否按阶段、按负责人和按关闭月份分组交易,而不用猜哪个日期字段?
- 工作管理:你能否在一份报表里拉出 “按负责人分的逾期活动”,且逾期以单一的到期日和明确的完成状态为准?
- 联系人与公司:联系人能否在没有组织的情况下存在,并且能在以后链接组织而不破坏历史(邮箱、笔记、交易参与)?
- 一致性:阶段和活动类型是否来自固定清单,避免出现 “Follow up”、“Follow-up” 和 “Followup” 这类三种不同值?
- 安全性:你能否限制谁可以删除记录或导出列表,同时不阻碍诸如把交易移到下一阶段这类正常更新?
如果这五项都能回答 “是”,你就处在一个不错的位置。如果不能,就在模式还小的时候修正它。
一个实用建议:把阶段和活动类型在一个地方定义(表或枚举),并在各处重用,这样每个界面和流程都用同样的值。
一个现实的小团队示例与后续步骤
一个 5 人的代理机构是轻量级 CRM 模式的好测试对象。团队忙碌、线索来源多样、没人愿意花时间照看数据。想象一个团队:1 名管理员、2 名销售、1 名运营负责人和 1 名只读成员(创始人,只看数据)。
一条新的入站请求到来(表单或邮件):“需要网站刷新,预算 15k,周期 6 周。” 规则很简单:创建一个组织(如果是公司)和一个联系人(该人),然后创建一笔关联该组织的交易,并把该联系人设为该交易的主联系人。
为加快速度,他们使用一个小的接收清单:
- 如果域名或公司名称与现有组织匹配,重用它。
- 如果该人的邮箱存在,重用该联系人。
- 对于真正有购买意向的情况,总是创建交易。
- 把原始信息放在交易描述中。
- 把来源(referral、form、outbound)作为单一字段保存。
活动防止错过电话,因为每个下一步都变成了一个带日期并有负责人的人做的事项。当销售做了发现电话,他们记录一条类型为 meeting 的活动,并立即添加下一条活动:两天后的电话。如果运营需要细节来估算工作量,他们就在同一笔交易上创建一个 task 类型的活动,这样这些事项都出现在一个地方。
角色设置保持务实:管理员可以编辑所有内容并管理设置,销售可以创建和更新联系人、交易及其活动,运营可以更新交付相关字段和活动,只读用户只能查看管道和报表而无法修改数据。
如果你想快速把这做成可用的内部工具,AppMaster (appmaster.io) 是一个直接的选项:你可以在它的 Data Designer(PostgreSQL)中建模,在 Business Process 编辑器中添加工作流规则,构建一个简单的线索收件箱和交易页面,然后在准备好与团队共享时部署到 AppMaster Cloud 或你自己的云。
常见问题
从四个核心对象开始:Contacts(人),Organizations(可选,公司),Deals(机会),以及 Activities(统一的操作日志)。如果团队的日常问题都能映射到这些对象上,你就能保持高效并且报表不会失真。
如果你是 B2B 并且需要按公司做报表,或一个客户下有多个联系人,就需要 Organizations 表。对于 B2C 或者只面向个人的场景,可以省略 Organizations,把所有记录都作为 Contacts。
不要把阶段做成自由文本,因为拼写和命名会漂移,最终破坏仪表盘。使用固定清单(阶段表),在每个交易上存储阶段 ID,这样你可以之后重命名阶段而不影响历史数据。
把必填字段保持在最小集合:对于 Contacts 和 Organizations,要求 id、名称和 created_at 即可;对于 Deals,要有阶段、负责人(owner)、金额和预计关闭日期等核心字段。可选字段可以留到以后,否则会填出很多 “N/A” 式的占位符。
不要盲目阻止重复,除非你确定流程允许。实用的默认做法是允许重复,但在发现相似邮箱或电话时在 UI 中提示,并在核心表上添加 external_id(或 import_key/import_source)以便重复导入时不产生额外记录。
使用一张 Activity 表,并用一个小的固定 type 集合(call、email、meeting、note、task)。这样“最后接触时间”、逾期工作和活动历史都能统一查询,因为它们使用同样的时间戳和结构。
同时保存 due_at 和 completed_at,因为它们回答不同的问题:due_at 用于计划和逾期报表,completed_at 用于执行情况和周期时间分析;把两者合并会让报表不可靠。
默认每笔交易关联一个主要联系人,这样报表更清晰,界面也更简单。如果偶尔需要更多参与者,可以增加 deal_contacts 关联表,用来作为附加参与者,而不是一开始就把每笔交易做成复杂的多对多模型。
一个实用默认是:所有内容对团队可见,但每笔交易只有一个负责的 owner。这样协作容易,而且当需要隐私时,用一个简单的 visibility 字段(例如 public / private)来控制,而不是从一开始就设计复杂的权限矩阵。
先做表建模,然后用真实样本数据测试再做界面。如果你不能方便地回答常见问题(比如按阶段的交易、逾期活动、每笔交易的最后接触),说明模式需要在小规模时修正。


