Browse Source

docs: 更新HIS多医院路由交接说明

WangKang 6 days ago
parent
commit
7e80f624a7

+ 18 - 0
docs/initiatives/FEAT-202606-005-saas-tenant-isolation/HIS多医院路由详细设计.md

@@ -263,6 +263,24 @@ fallback-enabled: false
 
 本次不修改现有 HTTP URL、请求体和响应结构。
 
+## 实现状态
+
+截至 2026-06-27,以下代码已完成:
+
+- 路由配置对象、三元精确索引、严格模式和兼容回退。
+- Mock 客户端互斥注册与真实/Mock 类型标识。
+- MCP 标准工具入口和 `McpToolService` 上下文重载。
+- Agent、Card 与对话降级链医院上下文传递。
+- 跨租户会话不存在时禁止 Card 链调用 HIS。
+
+未完成内容:
+
+- 真实 HIS 厂商 `HisClientProvider` 实现。
+- 目标环境 endpoint、`credential-ref`、超时和网络策略配置。
+- 两家医院专线环境的真实联调与严格模式切换。
+
+本实现没有新增数据库表、字段或迁移 SQL。
+
 ## 测试策略
 
 ### 单元测试

+ 47 - 10
docs/initiatives/FEAT-202606-005-saas-tenant-isolation/SaaS化代码改造与下游交接说明.md

@@ -61,7 +61,11 @@ tags:
 | `db2555ac` | 补齐设备命令租户隔离 |
 | `c40b4779` | 补齐租户上下文与 HIS 路由上下文 |
 | `1875c356` | 补充 SaaS 化改造与 SQL 交接说明 |
-| 本轮续作提交 | 补齐任务写操作作用域和卡片动作幂等租户化,以分支 `HEAD` 为准 |
+| `a0c8a925` | 补齐任务与卡片动作租户隔离 |
+| `19a0447b` | 增加 HIS 多医院路由核心 |
+| `066a3d4c` | 接入 MCP 工具医院路由 |
+| `013c28ab` | 补充 HIS 路由上下文重载 |
+| `756ac3ee` | 贯通 Agent 与 Card 医院路由上下文 |
 
 文件数和行数会随第二阶段续作变化,下游应以
 `git diff --stat 074c4db4..HEAD` 的实时结果为准。
@@ -75,7 +79,9 @@ tags:
 但当前仍是 SaaS 第一阶段,不应直接判断为生产级完整 SaaS:
 
 - 数据库字段和索引尚未在目标环境确认或执行。
-- HIS 上下文已经传递,但尚未实现按医院选择不同客户端、地址和凭证。
+- HIS 路由框架和主要调用链已经按
+  `tenantId + projectId + hospitalId` 精确选择 Provider;真实医院 Provider、专线地址和
+  凭据仍需下游实现和配置。
 - 部分运行时状态仍保存在单 JVM 内存中,不支持可靠多实例部署。
 - Workflow、RAG 和管理后台权限未在本分支做完整的双租户实库验收。
 - 兼容旧逻辑时保留了无作用域重载,内部调用若继续使用旧方法,仍可能绕过严格隔离。
@@ -170,7 +176,7 @@ tags:
 - Agent 路由、卡片动作编排和 OpenPlatform Controller 已传递可信项目、租户上下文。
 - 旧的无作用域重载仍保留,未迁移内部调用可以继续工作。
 
-### 4.7 HIS 路由上下文
+### 4.7 HIS 多医院路由
 
 涉及模块:`emoon-ai-mcp-api`、`emoon-ai-mcp`。
 
@@ -179,12 +185,28 @@ tags:
   `X-Emoon-Project-Id`、`X-Emoon-Tenant-Id`、
   `X-Emoon-Hospital-Id`。
 - 上下文会写入工具调用请求,`hospitalId` 同时补充到工具输入。
+- `HisClientRouter` 只按 `tenantId + projectId + hospitalId` 三字段精确匹配,不支持
+  单字段、通配符或跨医院回退。
+- `HisClientProvider` 作为厂商 SPI,根据路由定义创建对应 `HisClient`。
+- MCP 标准工具入口、`McpToolService`、Agent 对话降级和 Card 动作链已传递医院上下文。
+- Card 动作从 `conversationId + projectId + tenantId` 作用域会话读取医院,不接受
+  Card payload 覆盖。
+- 严格模式下,缺少上下文、路由或 Provider 会失败;兼容模式保留旧单客户端回退。
+- `HisClient.isMock()` 区分真实和 Mock 客户端,响应不再固定标记为 Mock。
+
+默认配置保持兼容,避免阻塞现有环境:
+
+```yaml
+emoon:
+  his:
+    routing:
+      strict: false
+      fallback-enabled: true
+      routes: []
+```
 
-必须注意:
-
-这只完成了“路由上下文传递”,没有完成“真实按医院路由”。当前 `HisClient`
-仍可能是单一实现。后续应增加按 `tenantId/projectId/hospitalId` 选择 endpoint、
-凭证、超时、熔断和协议适配器的路由组件。
+生产联调完成前不得开启严格模式。下游配置真实路由时只写
+`credential-ref`,不得在仓库中提交 Token、密码或私钥。
 
 ## 5. 对现有接口的影响
 
@@ -236,6 +258,20 @@ tags:
 | `emoon-openplatform -am -DskipTests compile` | 49 个 reactor 模块编译成功 |
 | `AiPlatformArchitectureTest` | 1 个通过,新增违规 0 |
 
+2026-06-27 HIS 多医院路由新增验证:
+
+| 模块/用例 | 结果 |
+|---|---|
+| `HisClientRouterTest` + `HisMockSqliteConfigTest` | 18 个通过 |
+| `HisToolInvokeServiceTest` | 15 个通过 |
+| `McpToolServiceTest` | 6 个通过 |
+| `emoon-ai-mcp` 全量测试 | 64 个通过 |
+| `emoon-ai-agent` 全量测试 | 78 个通过 |
+| `AgentChatApplicationServiceImplTest` | 4 个通过 |
+
+最终 reactor 编译、架构测试和 OpenPlatform 已知失败复核见本分支后续验证记录;下游
+仍需以目标环境重新执行。
+
 联合执行 `emoon-openplatform -am` 指定测试时,既有 `emoon-mcp-api` 模块因没有测试引擎
 却配置 Surefire groups 而提前失败。本轮通过先安装当前依赖、再单独运行目标测试规避,
 该构建配置问题不属于本次 SaaS 代码改造。
@@ -253,7 +289,7 @@ OpenPlatform 全量回归通过。
 
 | 优先级 | 项目 | 当前风险 | 建议 |
 |---|---|---|---|
-| P0 | 真实 HIS 多医院路由 | 不同医院可能仍共用同一个客户端配置 | 增加 `HisClientRouter` 或 Provider |
+| P0 | 真实 HIS Provider 与专线联调 | 路由框架已完成,但尚无真实厂商协议和网络配置 | 实现 Provider、配置两家医院并启用严格模式 |
 | P0 | 数据库字段和索引适配 | 新代码可能因缺列启动或运行失败 | 按数据库 Runbook 执行 |
 | P0 | 双租户实库越权测试 | 单元测试不能证明全链路隔离 | 准备两个租户和同名业务数据 |
 | P1 | `IntentStackService` 持久化 | 当前内存态不适合多实例 | 改为 Redis 或数据库并使用租户复合键 |
@@ -330,7 +366,8 @@ mvn -pl emoon-admin -DskipTests=false -Dprofiles.active= \
 | SAAS-009 | A 与 B 使用相同业务幂等键 | 不应互相影响 |
 | SAAS-010 | A、B 分别调用各自医院 HIS | 路由到不同 endpoint 和凭证 |
 
-`SAAS-009` 和 `SAAS-010` 在当前阶段可能失败,属于明确的下一阶段验收门禁。
+`SAAS-009` 已完成代码与候选 SQL,仍需目标数据库验证;`SAAS-010` 已完成路由框架和
+自动化客户端隔离验证,仍需真实 Provider、专线和两家医院环境联调。
 
 ## 10. 完成交接的判断标准
 

+ 14 - 0
docs/initiatives/FEAT-202606-005-saas-tenant-isolation/SaaS化数据库候选变更与执行清单.md

@@ -43,6 +43,19 @@ tags:
 
 - `ai_task_instance.tenant_id`
 - `ai_device_command.project_id`
+
+HIS 多医院路由采用“配置文件 + `HisClientProvider` SPI”,没有新增持久化表或字段,
+因此该方案本身:
+
+- 不需要新增 DDL。
+- 不需要新增 DML 或 Seed 数据。
+- 不需要执行医院路由迁移 SQL。
+- 只依赖 `ai_conversation` 已有的 `conversation_id`、`project_id`、`tenant_id` 和
+  `hospital_id` 做作用域查询。
+
+如果下游改为数据库动态维护路由,必须另开需求和设计,补充加密、审计、缓存一致性与
+迁移 Runbook;不得在联调期间临时建表。本文件后续 SQL 只服务此前任务、设备、卡片等
+SaaS 隔离改造,不能作为 HIS 路由建表依据。
 - `ai_device_command.tenant_id`
 - `ai_card_action_log.tenant_id`
 
@@ -547,6 +560,7 @@ ALTER TABLE ai_card_action_log
 | `ai_conversation` | 应已有框架租户字段,只需检查和回填 |
 | `sys_project` | 应已有 `tenant_id`,必须保证数据正确 |
 | Workflow/RAG 相关表 | 本分支未直接修改,是否迁移需结合实际启用模块另行审计 |
+| HIS 路由表 | 本方案不建表;路由来自配置文件和 Provider SPI |
 
 ## 9. 执行后核验
 

+ 5 - 4
docs/initiatives/FEAT-202606-005-saas-tenant-isolation/专题索引.md

@@ -30,7 +30,7 @@ tags:
 | 基线提交 | `074c4db4` |
 | SaaS 分支 | `codex/saas-phase1-refactor` |
 | 初始交接文档提交 | `1875c356` |
-| 代码改造时间 | 2026-06-26 |
+| 代码改造时间 | 2026-06-26 至 2026-06-27 |
 | 第二阶段续作时间 | 2026-06-27 |
 
 ## 文档索引
@@ -59,8 +59,8 @@ tags:
 
 ## 当前状态
 
-代码侧第一阶段租户上下文传递、主要查询隔离,以及第二阶段的任务写作用域
-卡片动作幂等租户化已经完成。
+代码侧第一阶段租户上下文传递、主要查询隔离,以及第二阶段的任务写作用域
+卡片动作幂等租户化和 HIS 三元动态路由已经完成。
 
 尚未完成:
 
@@ -69,7 +69,8 @@ tags:
 - 后端完整启动验证
 - 前端工程适配和接口联调
 - 两家医院以上的交叉租户越权测试
-- HIS/LIS 等院内系统的按医院动态路由
+- 真实 HIS/LIS 厂商 Provider、专线和凭据配置
+- 两家医院以上的 HIS 严格路由联调
 - 内存态组件的多实例持久化改造
 
 因此当前状态为 `reviewing`,不能标记为已上线或生产可用。

+ 4 - 0
emoon-openplatform/src/main/resources/application.yml

@@ -24,6 +24,10 @@ emoon:
     mock:
       enabled: true
       reset-on-start: true
+    routing:
+      strict: false
+      fallback-enabled: true
+      routes: []
   matching:
     url: http://8.136.61.90:5666/api
     username: test