2. 医疗业务领域建模
医疗SaaS与普通业务系统最大的区别在于:它同时承载“临床安全”与“多租户隔离”两条硬约束。一次预约冲突可能只是体验问题,但一次处方剂量错误、一份病历被跨租户读取,都是合规与医疗安全事件。因此,领域建模不能停留在“建几张表”的层面,而要先识别出业务中真正稳定、可独立演进的核心实体,再用限界上下文把它们按业务能力切开。
一、从业务事件反推核心实体
识别实体最可靠的方法不是看数据库范式,而是问“哪些业务事件必须被记录、追溯和审计”。在医疗SaaS中,典型事件包括:患者建档、医生排班、预约挂号、就诊接诊、病历书写、处方开具、收费结算。围绕这些事件,可以提炼出六类核心实体:
- 患者(Patient):以租户内唯一患者编号为标识,包含基本信息、过敏史、既往史。注意患者是“租户内的患者”,同一自然人在不同医院可能是不同患者实体。
- 医生(Doctor):包含执业资质、职称、所属科室、可排班时段。资质与排班是预约可行性的前置条件。
- 预约(Appointment):连接患者、医生、时段与号源,具有明确的状态机(待确认→已确认→已签到→已完成/已取消/爽约)。
- 病历(MedicalRecord):就诊过程中产生的临床记录,一旦提交即进入只读或版本化修订,不允许物理删除。
- 处方(Prescription):包含药品、剂量、频次、疗程,必须与诊断和患者过敏史做校验。
- 收费单(Charge):由诊疗项目、药品、耗材组成,与预约/就诊关联,是财务对账的依据。
这些实体之间存在明确的引用关系,但引用不等于耦合。例如预约需要引用患者和医生,但预约的取消不应修改患者档案;处方需要引用病历诊断,但处方作废不应回写病历。这种“引用而不拥有”的边界意识,正是限界上下文划分的起点。
二、DDD在医疗SaaS中的落地方式
领域驱动设计在医疗SaaS中主要解决三个问题:统一语言、聚合边界、上下文映射。统一语言要求开发、产品与临床人员对“号源”“接诊”“医嘱”等词有同一含义。例如“号源”不是简单的剩余数量,而是“某医生某时段可被预约的容量”,它受排班、停诊、加号策略共同影响。
聚合边界决定事务一致性范围。以预约聚合为例,根实体是 Appointment,内部包含时段快照和状态;患者与医生以 ID 引用,不放入同一聚合。这样预约创建时只需保证“该时段号源未被占用”,而不必锁住患者档案。处方聚合则以 Prescription 为根,内部包含处方明细行,校验过敏史时通过领域服务读取患者聚合的过敏信息,而不是把患者塞进处方聚合。
上下文映射方面,医疗SaaS通常采用“共享内核 + 客户/供应商 + 防腐层”的组合。租户、用户、权限属于共享内核;收费上下文作为客户,向预约上下文订阅“就诊已完成”事件;外部医保接口或检验系统则通过防腐层转换,避免外部模型污染内部领域模型。
三、限界上下文划分与协作关系
结合医疗业务能力,可将系统划分为六个限界上下文:患者上下文、排班与预约上下文、接诊上下文、病历上下文、处方上下文、收费上下文。它们各自拥有独立的领域模型和数据存储,通过领域事件协作。下图展示了核心实体、上下文边界以及事件流向:
图中每个上下文都拥有自己的聚合根,跨上下文只传递 ID 和领域事件。例如预约上下文发布“预约已确认”事件,接诊上下文订阅后生成待接诊记录;接诊上下文发布“就诊已完成”事件,病历、处方、收费三个上下文分别订阅并各自处理。这样,收费逻辑变化不会影响病历书写,处方规则调整也不会波及预约排班。
四、多租户下的建模约束
在医疗SaaS中,租户隔离必须体现在领域模型层,而不仅是数据库加一个 tenant_id 字段。具体做法是:所有聚合根都携带 tenantId,仓储接口在方法签名中强制传入租户上下文,领域事件也携带 tenantId,消费者按租户分区处理。这样即使某处代码忘记加过滤条件,类型系统和仓储层也能提供第二道防线。
五、一个可执行的上下文划分检查清单
在实际项目中,可以用以下问题检验限界上下文划分是否合理:
| 检查项 | 判断标准 | 示例 |
|---|---|---|
| 聚合根是否唯一 | 每个上下文只有一个入口聚合根 | 预约上下文以 Appointment 为根 |
| 跨上下文是否只传 ID | 不直接引用其他上下文实体对象 | 处方只存 patientId、recordId |
| 事务边界是否清晰 | 一个事务只修改一个聚合 | 开处方不修改病历状态 |
| 事件是否携带租户 | 所有领域事件含 tenantId | PrescriptionIssued{tenantId,...} |
| 外部系统是否隔离 | 通过防腐层转换模型 | 医保接口不直接进处方聚合 |
完成这一步后,后续的数据库分库分表、微服务拆分、权限校验和审计日志设计,都可以围绕这些上下文边界展开,而不是在代码写完后才回头补隔离逻辑。领域建模的价值,正是在系统还没有变复杂之前,先把边界画清楚。