[{"data":1,"prerenderedAt":760},["ShallowReactive",2],{"blog-ddd-im-domain-map":3},{"id":4,"title":5,"body":6,"category":744,"date":745,"description":731,"extension":746,"meta":747,"navigation":748,"path":749,"seo":750,"series":751,"seriesOrder":752,"stem":753,"tags":754,"__hash__":759},"blog\u002Fblog\u002Fddd-im-domain-map.md","DDD 实战（四）：协同办公 IM 的领域全景",{"type":7,"value":8,"toc":730},"minimark",[9,13,28,31,34,37,42,45,53,67,75,83,86,90,93,259,262,265,269,272,275,300,303,306,314,328,331,335,338,341,364,375,378,381,384,388,391,394,420,423,426,429,433,436,439,450,453,456,470,473,477,480,483,512,520,523,526,548,551,555,558,561,584,587,613,622,625,629,632,635,638,641,655,658,662,665,668,700,703,715,718,721,724],[10,11,5],"h1",{"id":12},"ddd-实战四协同办公-im-的领域全景",[14,15,16],"blockquote",{},[17,18,19,20,27],"p",{},"推荐 ",[21,22,26],"a",{"href":23,"rel":24},"https:\u002F\u002Fbewild.ai?code=BYZDOTME",[25],"nofollow","BeWild"," 代充 Codex ，工作猛猛提效。",[17,29,30],{},"前面三篇讲了 DDD 的基本概念。这一篇开始进入完整案例：协同办公 IM 平台。",[17,32,33],{},"这里先说明边界：我们不讨论钉钉、飞书\u002FLark 内部真实架构，因为那不是公开事实。我们能做的是基于它们官网、开放平台文档和可观察产品能力，反推出一个中大型协同办公 IM 平台通常需要覆盖的业务域。",[17,35,36],{},"所以本文所有“领域划分”都是架构推导，不是对任何厂商内部实现的断言。",[38,39,41],"h2",{"id":40},"_1-为什么协同办公-im-适合讲-ddd","1. 为什么协同办公 IM 适合讲 DDD",[17,43,44],{},"协同办公 IM 看起来是聊天工具，但成熟产品早已不是单纯发消息。",[17,46,47,48],{},"从钉钉官网可以看到，它面向企业沟通、组织协作、业务流程、AI 办公和开放生态等场景。",[21,49,52],{"href":50,"rel":51},"https:\u002F\u002Fwww.dingtalk.com\u002F",[25],"钉钉官网",[17,54,55,56,61,62],{},"飞书\u002FLark 也把即时沟通、日历、文档、审批、开放平台和智能协作组合在一起，强调一站式企业协作。",[21,57,60],{"href":58,"rel":59},"https:\u002F\u002Fwww.feishu.cn\u002F",[25],"飞书官网","、",[21,63,66],{"href":64,"rel":65},"https:\u002F\u002Fwww.larksuite.com\u002Fen_sg\u002F",[25],"Lark 官网",[17,68,69,70],{},"开放平台文档进一步暴露了很多业务能力边界。比如飞书开放平台文档中可以看到通讯录、IM 消息、群组、事件订阅、机器人等能力入口。",[21,71,74],{"href":72,"rel":73},"https:\u002F\u002Fopen.feishu.cn\u002Fdocument\u002Fhome\u002Findex",[25],"飞书开放平台文档",[17,76,77,78],{},"钉钉开放平台也提供通讯录、身份、消息、机器人、事件订阅、审批等开放能力入口。",[21,79,82],{"href":80,"rel":81},"https:\u002F\u002Fopen.dingtalk.com\u002Fdocument\u002F",[25],"钉钉开放平台文档",[17,84,85],{},"这些公开能力说明，协同办公 IM 至少不是一个“消息表 + 群表 + 用户表”能概括的系统。它更像一个企业协作操作系统，IM 只是最高频入口。",[38,87,89],{"id":88},"_2-领域地图先看全景","2. 领域地图：先看全景",[17,91,92],{},"如果从 DDD 角度建模，一个协同办公 IM 平台可以先拆成这些限界上下文：",[94,95,96,115],"table",{},[97,98,99],"thead",{},[100,101,102,106,109,112],"tr",{},[103,104,105],"th",{},"限界上下文",[103,107,108],{},"主要职责",[103,110,111],{},"核心模型",[103,113,114],{},"不应该承担",[116,117,118,133,147,161,175,189,203,217,231,245],"tbody",{},[100,119,120,124,127,130],{},[121,122,123],"td",{},"Identity & Access",[121,125,126],{},"账号、登录、认证、设备、登录会话、安全策略",[121,128,129],{},"Account、Credential、Device、LoginSession、AuthPolicy",[121,131,132],{},"不管理企业部门和好友关系",[100,134,135,138,141,144],{},[121,136,137],{},"Tenant & Organization",[121,139,140],{},"企业、部门、成员、组织角色、通讯录可见性",[121,142,143],{},"Tenant、Department、Member、OrgRole、VisibilityRule",[121,145,146],{},"不处理登录凭证和群成员治理",[100,148,149,152,155,158],{},[121,150,151],{},"Contact & Relationship",[121,153,154],{},"好友、联系人、外部联系人、黑名单、关系权限",[121,156,157],{},"ContactRelation、FriendRequest、ExternalContact、BlockRelation",[121,159,160],{},"不保存组织主数据",[100,162,163,166,169,172],{},[121,164,165],{},"Group & Conversation",[121,167,168],{},"群、群成员、会话、群治理、会话设置",[121,170,171],{},"Group、GroupMember、Conversation、ConversationSetting",[121,173,174],{},"不保存消息正文和搜索索引",[100,176,177,180,183,186],{},[121,178,179],{},"Messaging",[121,181,182],{},"消息发送、消息状态、撤回、引用、转发、已读未读",[121,184,185],{},"Message、MessageReceipt、RecallRecord、MessageCursor",[121,187,188],{},"不管理组织架构和群治理规则",[100,190,191,194,197,200],{},[121,192,193],{},"Notification",[121,195,196],{},"站内通知、离线推送、提醒、通知偏好",[121,198,199],{},"Notification、PushSubscription、Reminder、NotifyPreference",[121,201,202],{},"不作为业务事实源",[100,204,205,208,211,214],{},[121,206,207],{},"Workbench & Workflow",[121,209,210],{},"工作台、应用入口、审批、表单、任务、公告",[121,212,213],{},"WorkbenchLayout、AppShortcut、ApprovalInstance、Form、Task",[121,215,216],{},"不承担消息投递主链路",[100,218,219,222,225,228],{},[121,220,221],{},"Open Platform",[121,223,224],{},"应用、机器人、Webhook、事件订阅、API 凭证、配额",[121,226,227],{},"App、Bot、WebhookSubscription、ApiCredential、ApiQuota",[121,229,230],{},"不拥有内部业务数据",[100,232,233,236,239,242],{},[121,234,235],{},"Search",[121,237,238],{},"联系人搜索、消息搜索、文档搜索、应用搜索",[121,240,241],{},"SearchDocument、IndexTask、SearchPermission",[121,243,244],{},"不反写业务事实",[100,246,247,250,253,256],{},[121,248,249],{},"Governance & Security",[121,251,252],{},"审计、风控、水印、敏感词、合规、数据隔离",[121,254,255],{},"AuditEvent、RiskRule、DlpPolicy、ComplianceReport",[121,257,258],{},"不绕过业务域直接修改聚合",[17,260,261],{},"这张表不是最终答案，但它能帮助团队先建立讨论基线。",[17,263,264],{},"DDD 讨论最怕一开始就陷入“群表应该归哪个服务”“好友表应该放哪里”。更好的起点是先承认：这些概念背后有不同业务语言、不同变化节奏和不同一致性要求。",[38,266,268],{"id":267},"_3-identity-access账号不是组织成员","3. Identity & Access：账号不是组织成员",[17,270,271],{},"账号上下文处理的是“谁可以登录系统，以及以什么方式登录”。",[17,273,274],{},"它关心的是：",[276,277,278,282,285,288,291,294,297],"ul",{},[279,280,281],"li",{},"账号 ID。",[279,283,284],{},"手机号、邮箱、第三方身份。",[279,286,287],{},"密码、验证码、单点登录、OAuth。",[279,289,290],{},"设备绑定。",[279,292,293],{},"登录会话。",[279,295,296],{},"多端登录策略。",[279,298,299],{},"风险登录和安全策略。",[17,301,302],{},"组织成员上下文处理的是“某个账号在某个企业里是什么身份”。一个账号可以加入多个企业，可以在不同企业有不同部门、岗位、角色和可见性。",[17,304,305],{},"因此 Account 和 Member 不应该强行合并。",[17,307,308,309,313],{},"如果把账号和成员揉成一个 ",[310,311,312],"code",{},"User","，短期会很省事，但后面会遇到很多问题：",[276,315,316,319,322,325],{},[279,317,318],{},"一个自然人加入多个企业时，字段归属不清。",[279,320,321],{},"组织字段变化会污染登录模型。",[279,323,324],{},"登录安全策略和组织权限策略互相耦合。",[279,326,327],{},"外部联系人、客户、临时协作者难以表达。",[17,329,330],{},"更稳妥的模型是：账号上下文拥有 Account，组织上下文拥有 Member。二者通过 account ID 或主体 ID 关联，但各自维护自己的业务规则。",[38,332,334],{"id":333},"_4-tenant-organization企业协作的地基","4. Tenant & Organization：企业协作的地基",[17,336,337],{},"协同办公 IM 和普通社交 IM 的最大差异之一，是它以组织为中心。",[17,339,340],{},"组织上下文通常要管理：",[276,342,343,346,349,352,355,358,361],{},[279,344,345],{},"租户和企业。",[279,347,348],{},"部门树。",[279,350,351],{},"成员。",[279,353,354],{},"岗位、角色和职级。",[279,356,357],{},"通讯录可见性。",[279,359,360],{},"成员生命周期：邀请、入职、转岗、离职、禁用。",[279,362,363],{},"组织字段脱敏和权限。",[17,365,366,367,61,370],{},"开放平台中的通讯录能力也能说明组织数据的重要性。飞书开放平台和钉钉开放平台都把用户、部门、通讯录作为开放能力的重要部分。",[21,368,74],{"href":72,"rel":369},[25],[21,371,374],{"href":372,"rel":373},"https:\u002F\u002Fopen.dingtalk.com\u002Fdocument\u002Forgapp\u002Fquery-user-details",[25],"钉钉查询用户详情",[17,376,377],{},"组织上下文是很多其他上下文的上游，但不应该变成所有模块的超级中心。",[17,379,380],{},"例如消息发送需要判断成员是否还有效，文档权限需要判断成员是否属于某部门，开放平台事件需要通知成员变更。但这些不意味着消息、文档、开放平台都直接读写组织表。",[17,382,383],{},"更合理的做法是：组织上下文维护事实源，其他上下文通过 API、事件或缓存快照消费组织事实。",[38,385,387],{"id":386},"_5-contact-relationship关系不只是账号字段","5. Contact & Relationship：关系不只是账号字段",[17,389,390],{},"很多早期 IM 系统会把好友关系直接放进用户模块。简单产品可以这么做，但协同办公 IM 往往更复杂。",[17,392,393],{},"关系上下文可能需要表达：",[276,395,396,399,402,405,408,411,414,417],{},[279,397,398],{},"好友申请。",[279,400,401],{},"好友关系。",[279,403,404],{},"外部联系人。",[279,406,407],{},"客户联系人。",[279,409,410],{},"拉黑关系。",[279,412,413],{},"联系人备注。",[279,415,416],{},"关系可见性。",[279,418,419],{},"组织内外的联系策略。",[17,421,422],{},"一旦关系有了独立生命周期，就应该从账号或组织上下文里独立出来。",[17,424,425],{},"关系上下文不拥有账号，也不拥有组织成员。它只拥有“关系事实”。它可以引用账号 ID、成员 ID、外部联系人 ID，但不能修改账号状态或组织身份。",[17,427,428],{},"这样做的收益是关系规则可以独立演进。比如未来新增“客户联系人”“跨企业好友”“临时会话”“合作伙伴联系人”，不会把账号上下文越改越重。",[38,430,432],{"id":431},"_6-group-conversation群会话和消息不是一回事","6. Group & Conversation：群、会话和消息不是一回事",[17,434,435],{},"协同办公 IM 中，“群聊”是最容易混淆的模型。",[17,437,438],{},"至少要区分三个概念：",[276,440,441,444,447],{},[279,442,443],{},"Group：群组本身，关注群资料、群成员、群主、管理员、入群规则、群公告、群治理。",[279,445,446],{},"Conversation：会话入口，关注用户侧的聊天列表、置顶、免打扰、草稿、会话设置。",[279,448,449],{},"Message：消息事实，关注发送、投递、撤回、已读、转发、引用、内容类型。",[17,451,452],{},"一个群可以对应一个群会话，但群不是会话，会话也不是消息容器。",[17,454,455],{},"如果把群、会话、消息都塞进一个 Messaging 模块，早期很快，但后期容易出现问题：",[276,457,458,461,464,467],{},[279,459,460],{},"群治理规则和消息投递规则混在一起。",[279,462,463],{},"会话列表设置和群成员状态互相污染。",[279,465,466],{},"群成员变更频繁影响消息主链路。",[279,468,469],{},"大群消息扩散时，群聚合可能被错误放大。",[17,471,472],{},"更合理的方式是让群组上下文回答“这个群是什么，谁在里面，规则是什么”，让会话上下文回答“用户如何看到这个聊天入口”，让消息上下文回答“这条消息如何成为事实并被投递”。",[38,474,476],{"id":475},"_7-messagingim-的高频核心域","7. Messaging：IM 的高频核心域",[17,478,479],{},"消息上下文通常是协同办公 IM 的核心域之一。",[17,481,482],{},"它关注的是：",[276,484,485,488,491,494,497,500,503,506,509],{},[279,486,487],{},"消息 ID 和幂等。",[279,489,490],{},"消息内容类型。",[279,492,493],{},"消息发送状态。",[279,495,496],{},"撤回、编辑、引用、回复、转发。",[279,498,499],{},"已读未读。",[279,501,502],{},"多端同步游标。",[279,504,505],{},"离线补拉。",[279,507,508],{},"大群扇出。",[279,510,511],{},"加密消息和普通消息的差异。",[17,513,514,515],{},"飞书开放平台的 IM 消息 API 暴露了应用发送消息、消息内容、接收方类型等能力，可以作为公开能力观察入口。",[21,516,519],{"href":517,"rel":518},"https:\u002F\u002Fopen.feishu.cn\u002Fdocument\u002Fserver-docs\u002Fim-v1\u002Fmessage\u002Fcreate",[25],"飞书发送消息 API",[17,521,522],{},"但公开 API 只能说明产品开放了哪些能力，不能说明内部如何建模。我们能推导的是：成熟 IM 平台必然要把“消息事实”和“由消息触发的派生动作”区分开。",[17,524,525],{},"消息发送主链路应该尽量短：",[527,528,529,532,535,538,545],"ol",{},[279,530,531],{},"鉴权和基础校验。",[279,533,534],{},"会话和群组规则校验。",[279,536,537],{},"消息幂等写入。",[279,539,540,541,544],{},"产生 ",[310,542,543],{},"MessageSent"," 领域事件。",[279,546,547],{},"返回发送结果。",[17,549,550],{},"通知、搜索、机器人、审计、AI 摘要不应该阻塞主链路。",[38,552,554],{"id":553},"_8-workbenchworkflow-与-open-platformim-之外的协作能力","8. Workbench、Workflow 与 Open Platform：IM 之外的协作能力",[17,556,557],{},"协同办公产品的复杂度，往往从“聊天”扩展到“工作发生在哪里”。",[17,559,560],{},"工作台和流程上下文可能包含：",[276,562,563,566,569,572,575,578,581],{},[279,564,565],{},"应用入口。",[279,567,568],{},"审批。",[279,570,571],{},"表单。",[279,573,574],{},"公告。",[279,576,577],{},"任务。",[279,579,580],{},"日程。",[279,582,583],{},"低代码应用。",[17,585,586],{},"开放平台上下文可能包含：",[276,588,589,592,595,598,601,604,607,610],{},[279,590,591],{},"企业自建应用。",[279,593,594],{},"第三方应用。",[279,596,597],{},"机器人。",[279,599,600],{},"Webhook。",[279,602,603],{},"事件订阅。",[279,605,606],{},"API 凭证。",[279,608,609],{},"权限范围。",[279,611,612],{},"配额和审计。",[17,614,615,616,61,619],{},"飞书开放平台和钉钉开放平台都把开放能力作为重要入口，这说明协同办公 IM 不只是用户之间的通信系统，也是企业应用生态的承载层。",[21,617,74],{"href":72,"rel":618},[25],[21,620,82],{"href":80,"rel":621},[25],[17,623,624],{},"这里的建模重点是：开放平台不应该拥有内部业务事实。它应该通过授权、API、事件订阅和防腐层访问内部上下文。",[38,626,628],{"id":627},"_9-searchnotificationgovernance跨域支撑能力","9. Search、Notification、Governance：跨域支撑能力",[17,630,631],{},"搜索、通知、安全治理这些能力经常被误放。",[17,633,634],{},"搜索不是业务事实源。消息、联系人、文档、应用才是事实源，搜索只是索引和查询视图。搜索索引可以延迟，可以重建，不能反写消息事实。",[17,636,637],{},"通知也不是业务事实源。通知由业务事件触发，比如成员加入、审批通过、消息发送、文档分享。通知上下文负责偏好、渠道、频控、推送状态，不应该决定业务动作是否成立。",[17,639,640],{},"治理和安全更特殊。审计、风控、敏感词、水印、合规策略会影响多个域，但它们也不应该绕过业务模型直接改数据。更好的做法是：",[276,642,643,646,649,652],{},[279,644,645],{},"风控前置参与决策。",[279,647,648],{},"审计通过事件记录事实。",[279,650,651],{},"DLP 和水印通过策略影响文档、消息和文件上下文。",[279,653,654],{},"合规报表消费审计和业务事件。",[17,656,657],{},"这类横向能力要特别小心。它们既重要，又容易侵入所有模块。DDD 的边界设计，就是为了让它们通过清晰接口协作，而不是到处打补丁。",[38,659,661],{"id":660},"_10-第一版领域地图应该如何落地","10. 第一版领域地图应该如何落地",[17,663,664],{},"如果从零设计一个协同办公 IM，不建议一开始就拆十几个微服务。更务实的做法是：",[17,666,667],{},"第一阶段，先在代码里建立模块边界：",[276,669,670,673,676,679,682,685,688,691,694,697],{},[279,671,672],{},"identity",[279,674,675],{},"organization",[279,677,678],{},"relationship",[279,680,681],{},"group",[279,683,684],{},"messaging",[279,686,687],{},"notification",[279,689,690],{},"workflow",[279,692,693],{},"openplatform",[279,695,696],{},"search",[279,698,699],{},"governance",[17,701,702],{},"第二阶段，找出高变化、高吞吐、高故障隔离要求的上下文，优先拆部署：",[276,704,705,707,709,711,713],{},[279,706,684],{},[279,708,681],{},[279,710,693],{},[279,712,696],{},[279,714,687],{},[17,716,717],{},"第三阶段，再根据团队组织和业务增长拆更多服务。",[17,719,720],{},"领域地图不是服务拆分清单，而是讨论业务边界、数据所有权和演进方向的地图。",[17,722,723],{},"下一篇我们专门讨论最容易争议的边界：账号、组织、关系、群组和会话。",[17,725,726],{},[21,727,729],{"href":728},"\u002Fblog\u002F","返回博客列表",{"title":731,"searchDepth":732,"depth":732,"links":733},"",2,[734,735,736,737,738,739,740,741,742,743],{"id":40,"depth":732,"text":41},{"id":88,"depth":732,"text":89},{"id":267,"depth":732,"text":268},{"id":333,"depth":732,"text":334},{"id":386,"depth":732,"text":387},{"id":431,"depth":732,"text":432},{"id":475,"depth":732,"text":476},{"id":553,"depth":732,"text":554},{"id":627,"depth":732,"text":628},{"id":660,"depth":732,"text":661},"架构设计","2026-06-25","md",{},true,"\u002Fblog\u002Fddd-im-domain-map",{"title":5,"description":731},"DDD 实战",4,"blog\u002Fddd-im-domain-map",[755,756,757,758],"DDD","协同办公","IM","领域建模","71c_VEbozPHk0wzFOfv3UH1xX3WSOQKqUme_CvLNOQw",1784193099127]