DDD 实战(四):协同办公 IM 的领域全景
DDD 实战(四):协同办公 IM 的领域全景
推荐 BeWild 代充 Codex ,工作猛猛提效。
前面三篇讲了 DDD 的基本概念。这一篇开始进入完整案例:协同办公 IM 平台。
这里先说明边界:我们不讨论钉钉、飞书/Lark 内部真实架构,因为那不是公开事实。我们能做的是基于它们官网、开放平台文档和可观察产品能力,反推出一个中大型协同办公 IM 平台通常需要覆盖的业务域。
所以本文所有“领域划分”都是架构推导,不是对任何厂商内部实现的断言。
1. 为什么协同办公 IM 适合讲 DDD
协同办公 IM 看起来是聊天工具,但成熟产品早已不是单纯发消息。
从钉钉官网可以看到,它面向企业沟通、组织协作、业务流程、AI 办公和开放生态等场景。钉钉官网
飞书/Lark 也把即时沟通、日历、文档、审批、开放平台和智能协作组合在一起,强调一站式企业协作。飞书官网、Lark 官网
开放平台文档进一步暴露了很多业务能力边界。比如飞书开放平台文档中可以看到通讯录、IM 消息、群组、事件订阅、机器人等能力入口。飞书开放平台文档
钉钉开放平台也提供通讯录、身份、消息、机器人、事件订阅、审批等开放能力入口。钉钉开放平台文档
这些公开能力说明,协同办公 IM 至少不是一个“消息表 + 群表 + 用户表”能概括的系统。它更像一个企业协作操作系统,IM 只是最高频入口。
2. 领域地图:先看全景
如果从 DDD 角度建模,一个协同办公 IM 平台可以先拆成这些限界上下文:
| 限界上下文 | 主要职责 | 核心模型 | 不应该承担 |
|---|---|---|---|
| Identity & Access | 账号、登录、认证、设备、登录会话、安全策略 | Account、Credential、Device、LoginSession、AuthPolicy | 不管理企业部门和好友关系 |
| Tenant & Organization | 企业、部门、成员、组织角色、通讯录可见性 | Tenant、Department、Member、OrgRole、VisibilityRule | 不处理登录凭证和群成员治理 |
| Contact & Relationship | 好友、联系人、外部联系人、黑名单、关系权限 | ContactRelation、FriendRequest、ExternalContact、BlockRelation | 不保存组织主数据 |
| Group & Conversation | 群、群成员、会话、群治理、会话设置 | Group、GroupMember、Conversation、ConversationSetting | 不保存消息正文和搜索索引 |
| Messaging | 消息发送、消息状态、撤回、引用、转发、已读未读 | Message、MessageReceipt、RecallRecord、MessageCursor | 不管理组织架构和群治理规则 |
| Notification | 站内通知、离线推送、提醒、通知偏好 | Notification、PushSubscription、Reminder、NotifyPreference | 不作为业务事实源 |
| Workbench & Workflow | 工作台、应用入口、审批、表单、任务、公告 | WorkbenchLayout、AppShortcut、ApprovalInstance、Form、Task | 不承担消息投递主链路 |
| Open Platform | 应用、机器人、Webhook、事件订阅、API 凭证、配额 | App、Bot、WebhookSubscription、ApiCredential、ApiQuota | 不拥有内部业务数据 |
| Search | 联系人搜索、消息搜索、文档搜索、应用搜索 | SearchDocument、IndexTask、SearchPermission | 不反写业务事实 |
| Governance & Security | 审计、风控、水印、敏感词、合规、数据隔离 | AuditEvent、RiskRule、DlpPolicy、ComplianceReport | 不绕过业务域直接修改聚合 |
这张表不是最终答案,但它能帮助团队先建立讨论基线。
DDD 讨论最怕一开始就陷入“群表应该归哪个服务”“好友表应该放哪里”。更好的起点是先承认:这些概念背后有不同业务语言、不同变化节奏和不同一致性要求。
3. Identity & Access:账号不是组织成员
账号上下文处理的是“谁可以登录系统,以及以什么方式登录”。
它关心的是:
- 账号 ID。
- 手机号、邮箱、第三方身份。
- 密码、验证码、单点登录、OAuth。
- 设备绑定。
- 登录会话。
- 多端登录策略。
- 风险登录和安全策略。
组织成员上下文处理的是“某个账号在某个企业里是什么身份”。一个账号可以加入多个企业,可以在不同企业有不同部门、岗位、角色和可见性。
因此 Account 和 Member 不应该强行合并。
如果把账号和成员揉成一个 User,短期会很省事,但后面会遇到很多问题:
- 一个自然人加入多个企业时,字段归属不清。
- 组织字段变化会污染登录模型。
- 登录安全策略和组织权限策略互相耦合。
- 外部联系人、客户、临时协作者难以表达。
更稳妥的模型是:账号上下文拥有 Account,组织上下文拥有 Member。二者通过 account ID 或主体 ID 关联,但各自维护自己的业务规则。
4. Tenant & Organization:企业协作的地基
协同办公 IM 和普通社交 IM 的最大差异之一,是它以组织为中心。
组织上下文通常要管理:
- 租户和企业。
- 部门树。
- 成员。
- 岗位、角色和职级。
- 通讯录可见性。
- 成员生命周期:邀请、入职、转岗、离职、禁用。
- 组织字段脱敏和权限。
开放平台中的通讯录能力也能说明组织数据的重要性。飞书开放平台和钉钉开放平台都把用户、部门、通讯录作为开放能力的重要部分。飞书开放平台文档、钉钉查询用户详情
组织上下文是很多其他上下文的上游,但不应该变成所有模块的超级中心。
例如消息发送需要判断成员是否还有效,文档权限需要判断成员是否属于某部门,开放平台事件需要通知成员变更。但这些不意味着消息、文档、开放平台都直接读写组织表。
更合理的做法是:组织上下文维护事实源,其他上下文通过 API、事件或缓存快照消费组织事实。
5. Contact & Relationship:关系不只是账号字段
很多早期 IM 系统会把好友关系直接放进用户模块。简单产品可以这么做,但协同办公 IM 往往更复杂。
关系上下文可能需要表达:
- 好友申请。
- 好友关系。
- 外部联系人。
- 客户联系人。
- 拉黑关系。
- 联系人备注。
- 关系可见性。
- 组织内外的联系策略。
一旦关系有了独立生命周期,就应该从账号或组织上下文里独立出来。
关系上下文不拥有账号,也不拥有组织成员。它只拥有“关系事实”。它可以引用账号 ID、成员 ID、外部联系人 ID,但不能修改账号状态或组织身份。
这样做的收益是关系规则可以独立演进。比如未来新增“客户联系人”“跨企业好友”“临时会话”“合作伙伴联系人”,不会把账号上下文越改越重。
6. Group & Conversation:群、会话和消息不是一回事
协同办公 IM 中,“群聊”是最容易混淆的模型。
至少要区分三个概念:
- Group:群组本身,关注群资料、群成员、群主、管理员、入群规则、群公告、群治理。
- Conversation:会话入口,关注用户侧的聊天列表、置顶、免打扰、草稿、会话设置。
- Message:消息事实,关注发送、投递、撤回、已读、转发、引用、内容类型。
一个群可以对应一个群会话,但群不是会话,会话也不是消息容器。
如果把群、会话、消息都塞进一个 Messaging 模块,早期很快,但后期容易出现问题:
- 群治理规则和消息投递规则混在一起。
- 会话列表设置和群成员状态互相污染。
- 群成员变更频繁影响消息主链路。
- 大群消息扩散时,群聚合可能被错误放大。
更合理的方式是让群组上下文回答“这个群是什么,谁在里面,规则是什么”,让会话上下文回答“用户如何看到这个聊天入口”,让消息上下文回答“这条消息如何成为事实并被投递”。
7. Messaging:IM 的高频核心域
消息上下文通常是协同办公 IM 的核心域之一。
它关注的是:
- 消息 ID 和幂等。
- 消息内容类型。
- 消息发送状态。
- 撤回、编辑、引用、回复、转发。
- 已读未读。
- 多端同步游标。
- 离线补拉。
- 大群扇出。
- 加密消息和普通消息的差异。
飞书开放平台的 IM 消息 API 暴露了应用发送消息、消息内容、接收方类型等能力,可以作为公开能力观察入口。飞书发送消息 API
但公开 API 只能说明产品开放了哪些能力,不能说明内部如何建模。我们能推导的是:成熟 IM 平台必然要把“消息事实”和“由消息触发的派生动作”区分开。
消息发送主链路应该尽量短:
- 鉴权和基础校验。
- 会话和群组规则校验。
- 消息幂等写入。
- 产生
MessageSent领域事件。 - 返回发送结果。
通知、搜索、机器人、审计、AI 摘要不应该阻塞主链路。
8. Workbench、Workflow 与 Open Platform:IM 之外的协作能力
协同办公产品的复杂度,往往从“聊天”扩展到“工作发生在哪里”。
工作台和流程上下文可能包含:
- 应用入口。
- 审批。
- 表单。
- 公告。
- 任务。
- 日程。
- 低代码应用。
开放平台上下文可能包含:
- 企业自建应用。
- 第三方应用。
- 机器人。
- Webhook。
- 事件订阅。
- API 凭证。
- 权限范围。
- 配额和审计。
飞书开放平台和钉钉开放平台都把开放能力作为重要入口,这说明协同办公 IM 不只是用户之间的通信系统,也是企业应用生态的承载层。飞书开放平台文档、钉钉开放平台文档
这里的建模重点是:开放平台不应该拥有内部业务事实。它应该通过授权、API、事件订阅和防腐层访问内部上下文。
9. Search、Notification、Governance:跨域支撑能力
搜索、通知、安全治理这些能力经常被误放。
搜索不是业务事实源。消息、联系人、文档、应用才是事实源,搜索只是索引和查询视图。搜索索引可以延迟,可以重建,不能反写消息事实。
通知也不是业务事实源。通知由业务事件触发,比如成员加入、审批通过、消息发送、文档分享。通知上下文负责偏好、渠道、频控、推送状态,不应该决定业务动作是否成立。
治理和安全更特殊。审计、风控、敏感词、水印、合规策略会影响多个域,但它们也不应该绕过业务模型直接改数据。更好的做法是:
- 风控前置参与决策。
- 审计通过事件记录事实。
- DLP 和水印通过策略影响文档、消息和文件上下文。
- 合规报表消费审计和业务事件。
这类横向能力要特别小心。它们既重要,又容易侵入所有模块。DDD 的边界设计,就是为了让它们通过清晰接口协作,而不是到处打补丁。
10. 第一版领域地图应该如何落地
如果从零设计一个协同办公 IM,不建议一开始就拆十几个微服务。更务实的做法是:
第一阶段,先在代码里建立模块边界:
- identity
- organization
- relationship
- group
- messaging
- notification
- workflow
- openplatform
- search
- governance
第二阶段,找出高变化、高吞吐、高故障隔离要求的上下文,优先拆部署:
- messaging
- group
- openplatform
- search
- notification
第三阶段,再根据团队组织和业务增长拆更多服务。
领域地图不是服务拆分清单,而是讨论业务边界、数据所有权和演进方向的地图。
下一篇我们专门讨论最容易争议的边界:账号、组织、关系、群组和会话。