|
|
@@ -3,7 +3,7 @@ doc_id: DEV-202606-006
|
|
|
feature_id: FEAT-202606-005-saas-tenant-isolation
|
|
|
type: dev-progress
|
|
|
title: HIS 多医院动态路由实施计划
|
|
|
-status: reviewing
|
|
|
+status: implemented
|
|
|
owner: 医梦研发团队
|
|
|
created_at: 2026-06-27
|
|
|
updated_at: 2026-06-27
|
|
|
@@ -43,12 +43,12 @@ Mockito、AssertJ、Maven。
|
|
|
|
|
|
## 范围门禁
|
|
|
|
|
|
-- [ ] 不修改现有 HTTP URL、方法、请求体和响应结构。
|
|
|
-- [ ] 不接受前端覆盖租户或项目。
|
|
|
-- [ ] 不在配置文件写入 HIS 密钥、Token、密码和私钥。
|
|
|
-- [ ] 不执行任何 DDL/DML;如实现发现 SQL 需求,只更新数据库 Runbook。
|
|
|
-- [ ] 不改动 Workflow、RAG、Agent、Card 已有隔离语义。
|
|
|
-- [ ] 严格模式不允许跨医院回退。
|
|
|
+- [x] 不修改现有 HTTP URL、方法、请求体和响应结构。
|
|
|
+- [x] 不接受前端覆盖租户或项目。
|
|
|
+- [x] 不在配置文件写入 HIS 密钥、Token、密码和私钥。
|
|
|
+- [x] 不执行任何 DDL/DML;如实现发现 SQL 需求,只更新数据库 Runbook。
|
|
|
+- [x] 不改动 Workflow、RAG、Agent、Card 已有隔离语义。
|
|
|
+- [x] 严格模式不允许跨医院回退。
|
|
|
|
|
|
## 文件结构
|
|
|
|
|
|
@@ -84,7 +84,7 @@ Mockito、AssertJ、Maven。
|
|
|
- Test:
|
|
|
`emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp/src/test/java/com/emoon/mcp/his/routing/HisClientRouterTest.java`
|
|
|
|
|
|
-- [ ] **Step 1: 写精确匹配红灯测试**
|
|
|
+- [x] **Step 1: 写精确匹配红灯测试**
|
|
|
|
|
|
```java
|
|
|
@Test
|
|
|
@@ -131,7 +131,7 @@ private HisRoutingProperties properties(boolean strict, boolean fallbackEnabled,
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 2: 运行测试确认失败**
|
|
|
+- [x] **Step 2: 运行测试确认失败**
|
|
|
|
|
|
```bash
|
|
|
mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp \
|
|
|
@@ -141,7 +141,7 @@ mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp \
|
|
|
|
|
|
预期:因路由类不存在而编译失败。
|
|
|
|
|
|
-- [ ] **Step 3: 实现最小路由对象和 SPI**
|
|
|
+- [x] **Step 3: 实现最小路由对象和 SPI**
|
|
|
|
|
|
```java
|
|
|
public record HisRouteContext(String tenantId, String projectId, String hospitalId) {
|
|
|
@@ -166,7 +166,7 @@ public interface HisClientProvider {
|
|
|
|
|
|
`HisClientRouter.route` 必须按三个字段完整匹配,禁止单字段或通配符匹配。
|
|
|
|
|
|
-- [ ] **Step 4: 补严格模式和回退测试**
|
|
|
+- [x] **Step 4: 补严格模式和回退测试**
|
|
|
|
|
|
```java
|
|
|
@Test
|
|
|
@@ -193,7 +193,7 @@ void compatibilityModeUsesLegacyClientWhenRouteIsMissing() {
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 5: 实现严格模式、回退和配置校验**
|
|
|
+- [x] **Step 5: 实现严格模式、回退和配置校验**
|
|
|
|
|
|
`HisClientRouter` 构造时建立不可变索引并校验:
|
|
|
|
|
|
@@ -213,11 +213,11 @@ HIS_PROVIDER_NOT_FOUND
|
|
|
HIS_ROUTE_DUPLICATED
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 6: 运行路由测试确认通过**
|
|
|
+- [x] **Step 6: 运行路由测试确认通过**
|
|
|
|
|
|
运行 Step 2 命令,预期全部通过。
|
|
|
|
|
|
-- [ ] **Step 7: 提交路由核心**
|
|
|
+- [x] **Step 7: 提交路由核心**
|
|
|
|
|
|
```bash
|
|
|
git add emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp
|
|
|
@@ -239,7 +239,7 @@ git commit -m "feat: 增加HIS多医院路由核心"
|
|
|
- Test:
|
|
|
`emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp/src/test/java/com/emoon/mcp/his/application/HisToolInvokeServiceTest.java`
|
|
|
|
|
|
-- [ ] **Step 1: 写请求上下文路由红灯测试**
|
|
|
+- [x] **Step 1: 写请求上下文路由红灯测试**
|
|
|
|
|
|
```java
|
|
|
@Test
|
|
|
@@ -261,7 +261,7 @@ void invokesHospitalClientResolvedFromRequestScope() {
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 2: 运行测试确认失败**
|
|
|
+- [x] **Step 2: 运行测试确认失败**
|
|
|
|
|
|
```bash
|
|
|
mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp \
|
|
|
@@ -271,7 +271,7 @@ mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp \
|
|
|
|
|
|
预期:`HisToolInvokeService` 仍直接使用单一 `HisClient`。
|
|
|
|
|
|
-- [ ] **Step 3: 将 dispatch 改为显式客户端**
|
|
|
+- [x] **Step 3: 将 dispatch 改为显式客户端**
|
|
|
|
|
|
```java
|
|
|
HisRouteContext routeContext = new HisRouteContext(
|
|
|
@@ -285,7 +285,7 @@ Map<String, Object> result = dispatch(
|
|
|
|
|
|
`dispatch`、`markMockPaid` 和 `result` 接收本次路由得到的客户端,不使用共享可变上下文。
|
|
|
|
|
|
-- [ ] **Step 4: 修正 Mock 标记**
|
|
|
+- [x] **Step 4: 修正 Mock 标记**
|
|
|
|
|
|
在 `HisClient` 增加:
|
|
|
|
|
|
@@ -298,11 +298,11 @@ default boolean isMock() {
|
|
|
现有两个 Mock 客户端覆盖为 `true`。工具响应使用 `hisClient.isMock()`,真实 Provider
|
|
|
不得被标记为 Mock。
|
|
|
|
|
|
-- [ ] **Step 5: 运行 MCP 应用测试**
|
|
|
+- [x] **Step 5: 运行 MCP 应用测试**
|
|
|
|
|
|
运行 Step 2 命令,预期全部通过。
|
|
|
|
|
|
-- [ ] **Step 6: 提交标准入口路由**
|
|
|
+- [x] **Step 6: 提交标准入口路由**
|
|
|
|
|
|
```bash
|
|
|
git add emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp
|
|
|
@@ -318,7 +318,7 @@ git commit -m "feat: 接入MCP工具医院路由"
|
|
|
- Test:
|
|
|
`emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp/src/test/java/com/emoon/ai/mcp/application/McpToolServiceTest.java`
|
|
|
|
|
|
-- [ ] **Step 1: 写带上下文调用红灯测试**
|
|
|
+- [x] **Step 1: 写带上下文调用红灯测试**
|
|
|
|
|
|
```java
|
|
|
@Test
|
|
|
@@ -333,7 +333,7 @@ void queryDepartmentsUsesScopedHospitalClient() {
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 2: 运行测试确认失败**
|
|
|
+- [x] **Step 2: 运行测试确认失败**
|
|
|
|
|
|
```bash
|
|
|
mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp \
|
|
|
@@ -343,7 +343,7 @@ mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp \
|
|
|
|
|
|
预期:不存在带 `HisRouteContext` 的重载。
|
|
|
|
|
|
-- [ ] **Step 3: 增加上下文重载并保留旧方法**
|
|
|
+- [x] **Step 3: 增加上下文重载并保留旧方法**
|
|
|
|
|
|
以下方法增加末尾 `HisRouteContext context` 重载:
|
|
|
|
|
|
@@ -375,7 +375,7 @@ public List<HisDepartment> queryDepartments(HisRouteContext context) {
|
|
|
|
|
|
支付、挂号响应中的 `mock` 使用实际路由客户端的 `isMock()`。
|
|
|
|
|
|
-- [ ] **Step 4: 验证旧方法仍使用兼容回退**
|
|
|
+- [x] **Step 4: 验证旧方法仍使用兼容回退**
|
|
|
|
|
|
```java
|
|
|
@Test
|
|
|
@@ -385,11 +385,11 @@ void legacyMethodUsesCompatibilityFallback() {
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 5: 运行测试确认通过**
|
|
|
+- [x] **Step 5: 运行测试确认通过**
|
|
|
|
|
|
运行 Step 2 命令,预期全部通过。
|
|
|
|
|
|
-- [ ] **Step 6: 提交 Agent 工具重载**
|
|
|
+- [x] **Step 6: 提交 Agent 工具重载**
|
|
|
|
|
|
```bash
|
|
|
git add emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp
|
|
|
@@ -415,7 +415,7 @@ git commit -m "feat: 补充HIS路由上下文重载"
|
|
|
- Test:
|
|
|
`emoon-openplatform/src/test/java/com/emoon/openplatform/service/impl/AgentChatApplicationServiceImplTest.java`
|
|
|
|
|
|
-- [ ] **Step 1: 写会话作用域查询红灯测试**
|
|
|
+- [x] **Step 1: 写会话作用域查询红灯测试**
|
|
|
|
|
|
```java
|
|
|
@Test
|
|
|
@@ -430,7 +430,7 @@ void findByScopeRequiresConversationProjectAndTenant() {
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 2: 实现 `findByScope`**
|
|
|
+- [x] **Step 2: 实现 `findByScope`**
|
|
|
|
|
|
在 `AiConversationMapper` 新增:
|
|
|
|
|
|
@@ -450,7 +450,7 @@ AiConversation selectByConversationAndScope(
|
|
|
|
|
|
`findByScope` 调用该方法。项目 ID 非数字、参数为空或记录不存在时返回空,不回退到仅会话查询。
|
|
|
|
|
|
-- [ ] **Step 3: 写卡片动作医院路由红灯测试**
|
|
|
+- [x] **Step 3: 写卡片动作医院路由红灯测试**
|
|
|
|
|
|
```java
|
|
|
@Test
|
|
|
@@ -470,12 +470,12 @@ void scopedCardActionUsesHospitalFromTenantConversation() {
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 4: 在 Orchestrator 中一次解析上下文**
|
|
|
+- [x] **Step 4: 在 Orchestrator 中一次解析上下文**
|
|
|
|
|
|
每次 `execute` 开始时,通过作用域会话生成 `HisRouteContext`,后续所有 HIS 查询和写操作
|
|
|
复用该不可变对象。会话不属于当前租户时,不得调用 HIS。
|
|
|
|
|
|
-- [ ] **Step 5: 对话降级查询使用命令医院上下文**
|
|
|
+- [x] **Step 5: 对话降级查询使用命令医院上下文**
|
|
|
|
|
|
`AgentChatApplicationServiceImpl` 已持有可信项目和租户,并从会话创建链得到
|
|
|
`command.hospitalId()`。`buildFallbackDepartmentData` 和
|
|
|
@@ -487,7 +487,7 @@ new HisRouteContext(tenantId, projectId, command.hospitalId())
|
|
|
|
|
|
不修改 `AgentChatRequest`、Controller URL 或响应结构。
|
|
|
|
|
|
-- [ ] **Step 6: 运行 Agent 和 OpenPlatform 目标测试**
|
|
|
+- [x] **Step 6: 运行 Agent 和 OpenPlatform 目标测试**
|
|
|
|
|
|
```bash
|
|
|
mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-agent \
|
|
|
@@ -501,7 +501,7 @@ mvn -pl emoon-openplatform \
|
|
|
|
|
|
预期全部通过。
|
|
|
|
|
|
-- [ ] **Step 7: 提交主链路上下文**
|
|
|
+- [x] **Step 7: 提交主链路上下文**
|
|
|
|
|
|
```bash
|
|
|
git add emoon-infra/emoon-modules/emoon-ai/emoon-ai-agent emoon-openplatform
|
|
|
@@ -523,7 +523,7 @@ git commit -m "feat: 贯通Agent与Card医院路由上下文"
|
|
|
- Modify:
|
|
|
`docs/initiatives/FEAT-202606-005-saas-tenant-isolation/专题索引.md`
|
|
|
|
|
|
-- [ ] **Step 1: 增加无真实医院数据的默认配置**
|
|
|
+- [x] **Step 1: 增加无真实医院数据的默认配置**
|
|
|
|
|
|
```yaml
|
|
|
emoon:
|
|
|
@@ -536,7 +536,7 @@ emoon:
|
|
|
|
|
|
不得提交 endpoint、credentialRef 实值或真实医院标识。
|
|
|
|
|
|
-- [ ] **Step 2: 更新交接文档**
|
|
|
+- [x] **Step 2: 更新交接文档**
|
|
|
|
|
|
记录:
|
|
|
|
|
|
@@ -548,7 +548,7 @@ emoon:
|
|
|
自动化测试结果
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 3: 审核 SQL 影响**
|
|
|
+- [x] **Step 3: 审核 SQL 影响**
|
|
|
|
|
|
本方案预期无新增 DDL/DML。在数据库 Runbook 增加明确结论:
|
|
|
|
|
|
@@ -559,7 +559,7 @@ HIS 配置文件 + Provider SPI 不新增表,不需要执行 SQL。
|
|
|
|
|
|
不得连接数据库或执行文档中的任何 SQL。
|
|
|
|
|
|
-- [ ] **Step 4: 检查接口影响**
|
|
|
+- [x] **Step 4: 检查接口影响**
|
|
|
|
|
|
执行:
|
|
|
|
|
|
@@ -569,7 +569,7 @@ git diff -- docs/api docs/initiatives/FEAT-202606-001-unified-entry-client/对
|
|
|
|
|
|
预期无外部接口契约差异。如出现差异,停止提交并先更新专题接口说明。
|
|
|
|
|
|
-- [ ] **Step 5: 提交配置和文档**
|
|
|
+- [x] **Step 5: 提交配置和文档**
|
|
|
|
|
|
```bash
|
|
|
git add emoon-openplatform/src/main/resources/application.yml \
|
|
|
@@ -583,34 +583,34 @@ git commit -m "docs: 更新HIS多医院路由交接说明"
|
|
|
|
|
|
- Modify only when verification reveals a defect directly caused by Tasks 1-5.
|
|
|
|
|
|
-- [ ] **Step 1: MCP 全量测试**
|
|
|
+- [x] **Step 1: MCP 全量测试**
|
|
|
|
|
|
```bash
|
|
|
mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp \
|
|
|
-DskipTests=false -Dprofiles.active= test
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 2: Agent 全量测试**
|
|
|
+- [x] **Step 2: Agent 全量测试**
|
|
|
|
|
|
```bash
|
|
|
mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-agent \
|
|
|
-DskipTests=false -Dprofiles.active= test
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 3: Reactor 编译**
|
|
|
+- [x] **Step 3: Reactor 编译**
|
|
|
|
|
|
```bash
|
|
|
mvn -pl emoon-openplatform -am -DskipTests compile
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 4: 架构测试**
|
|
|
+- [x] **Step 4: 架构测试**
|
|
|
|
|
|
```bash
|
|
|
mvn -pl emoon-admin -DskipTests=false -Dprofiles.active= \
|
|
|
-Dtest=AiPlatformArchitectureTest test
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 5: 已知失败复核**
|
|
|
+- [x] **Step 5: 已知失败复核**
|
|
|
|
|
|
```bash
|
|
|
mvn -pl emoon-openplatform -DskipTests=false -Dprofiles.active= test
|
|
|
@@ -619,7 +619,7 @@ mvn -pl emoon-openplatform -DskipTests=false -Dprofiles.active= test
|
|
|
必须分别记录本次新增失败和既有失败。不得把既有
|
|
|
`TerminalMvpAcceptanceTest`、Weaviate 配置错误描述为本次通过。
|
|
|
|
|
|
-- [ ] **Step 6: 差异和安全审查**
|
|
|
+- [x] **Step 6: 差异和安全审查**
|
|
|
|
|
|
检查:
|
|
|
|
|
|
@@ -632,7 +632,7 @@ mvn -pl emoon-openplatform -DskipTests=false -Dprofiles.active= test
|
|
|
无 SQL 实际执行记录
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 7: 更新最终验证记录并提交**
|
|
|
+- [x] **Step 7: 更新最终验证记录并提交**
|
|
|
|
|
|
```bash
|
|
|
git diff --check
|