# multi-source-sync **Repository Path**: medical-light-years/multi-source-sync ## Basic Information - **Project Name**: multi-source-sync - **Description**: 面向医院信息科的接口配置预演与推送平台:上传 desired-state 后即时给出字段、CIDR 白名单、凭证轮换的差异预览与影响面,经多角色会签再统一推送至 HIS/EMR/LIS/PACS/医保/卫健,全部动作写入 append-only 审计台账,支持 5 分钟内一键回滚与等保可核对的报表导出。 - **Primary Language**: Python - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-23 - **Last Updated**: 2026-08-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 接口配置预演与推送平台 > 信息科上传一份接口 desired-state(目标字段、调用凭证、CIDR 白名单),平台立即给出"现在 vs 期望"的差异清单与影响面预览,会签后再统一推送到 HIS/EMR/LIS/PACS/医保前置机/卫健上报,全部动作进入等保可核对的审计台账。 ## 适用场景 / 目标岗位 | 岗位 | 什么时候用 | 得到什么 | |------|------------|----------| | 信息科接口管理员 | 给 HIS/EMR/LIS/PACS/医保/卫健上线一条接口、修改字段映射或调用凭证 | 上传前就看到"现在 vs 期望"的差异清单与影响面预览,会签通过后再推送,所有动作可导出审计台账 | | 医务科 / 对应业务科室 | 字段口径或调用范围变更需要会签 | Web 端看到与自己科室相关的差异条目,逐条确认或驳回(含理由),未通过会签时推送按钮不会解锁 | | 等级评审 / 卫健飞检对接人 | 等保测评、卫健检查、医保核查前 | 一键导出按时间/接口/操作人/动作分类的 append-only 审计台账,含 actor、before/after 摘要、commit_id | | 院领导 / 科室主任 | 月度复盘过去 30 天接口变更 | Dashboard 总览:哪些接口被改过、由谁发起、影响几个下游、有无失败与回滚 | > **表格纪律**:本表只写岗位口语 + 业务时刻 + 可核对产出;字段名、REST 路径、状态枚举等一律放到「命令 / API / 配置说明」。 ## 能力要点 - **声明式 desired-state**:一份 YAML 即写即存版本(接口 ID、目标端点、CIDR 白名单、字段表、心跳间隔、重试策略)。 - **多连接器推送**:HIS / EMR / LIS / PACS / 医保前置机 / 卫健上报各一类连接器,统一 schema 校验 + 凭证校验 + 推送 + 回滚。 - **预演差异**:上传后立即出 diff(新增/删除/修改字段、CIDR 收放、凭证轮换),影响面在推送之前就一目了然。 - **强制会签 + 撤销窗口**:医务科 / 对应科室 / 审计员任一驳回即退回信息科改写;推送后 5 分钟内可一键回滚,超窗需走人工审批。 - **append-only 审计台账**:声明、预览、确认、推送、回滚、轮换动作全部留痕,按时间 / 接口 / 操作人 / 动作类型检索与导出。 - **凭证轮换队列**:连接器凭证按周期轮换,状态机推进 + 失败重试 + 指数退避,失败自动告警。 ## 快速开始 ```bash # 1. 安装依赖 python -m venv .venv && source .venv/bin/activate pip install -r requirements.txt cd web && npm install && cd .. # 2. 复制配置(占位、无真实密钥) cp .env.example .env # 3. 跑通核心单测(不含网络) PYTHONPATH=backend DEPLOYMENT_MODE=ci pytest backend/tests/unit/ -q # 4. 一键起后端 + 前端 + 3 mock(Docker compose,详见 scripts/dev.sh) bash scripts/dev.sh # 后台起 + 等 healthcheck + 打印 URL bash scripts/dev.sh --down # 关闭并清理 volumes # 5. 端到端验证(上传 desired-state → preview → confirm → push → rollback → 导出审计) bash scripts/verify_e2e.sh # 6. 看一眼导出与样例 ls docs/ # audit_sample.csv · 等保脱敏审计台账(10 字段列固定) # diff_sample.json · preview 响应脱敏片段 # openapi.json / openapi.yaml · OpenAPI 3.1 契约 # architecture.mmd · 架构与数据流图 ``` ## 命令 / API / 配置说明 > 详细子命令表、REST 路径表、字段表、错误码见 **`docs/`** 目录与 `spec.md`;本节列出对外契约总览。 ### CLI(CI 集成入口,后续 task 落地) | 子命令 | 用途 | 关键参数 | |--------|------|----------| | `push` | 对一个连接器执行推送 | ` --commit-id` | | `rollback` | 在撤销窗口内回滚一次推送 | ` --reason` | | `export-audit` | 导出审计台账(CSV/JSON) | `--since --until --connection-id --format` | | `rotate` | 立即触发凭证轮换 | `` | ### REST(信息科 / 会签端 / 审计端) | 路径 | 方法 | 用途 | |------|------|------| | `/api/connections` | GET / POST | 连接器清单与新增 | | `/api/connections/{id}/desired-state` | PUT | 上传 desired-state YAML | | `/api/connections/{id}/preview` | POST | 触发差异预览 | | `/api/connections/{id}/confirm` | POST | 信息科确认进入会签 | | `/api/connections/{id}/approvals` | POST | 会签方确认/驳回 | | `/api/push/{commit_id}` | POST | 执行推送 | | `/api/push/{commit_id}/rollback` | POST | 撤销窗口内回滚 | | `/api/audit/events` | GET | 审计事件多维检索 | | `/api/audit/export` | GET | 导出 CSV / JSON | | `/api/rotation/{connection_id}` | POST | 触发凭证轮换 | | `/healthz`、`/readyz`、`/openapi.json` | GET | 健康检查 / 契约导出 | ### 错误码(统一) `E_FIELD_MISSING` / `E_INVALID_CIDR` / `E_UNSUPPORTED_TYPE` / `E_INVALID_TRANSITION` / `E_PUSH_FAILED` / `E_ROLLBACK_WINDOW_EXPIRED` / `E_CONCURRENT_CONFLICT` / `E_IDEMPOTENT_REPLAY`。 ### 配置文件 - **`.env.example`**:DATABASE_URL / REDIS_URL / JWT_SECRET / SM_KEY_PATH / 下游 mock 地址 / `ROLLBACK_WINDOW_SECONDS=300` - **`docker-compose.yml`**:FastAPI + Postgres + Redis + Web + 3 mock 服务编排骨架 ## 典型场景 ### 场景一:信息科上线 LIS 新接口字段映射 1. 信息科在 Web 上传一份 `desired_state_lis.yaml`(3 个字段改 + 1 个 CIDR 新增 + 凭证轮换)。 2. 平台自动比 `connection.id=lis-orm-r03` 当前态,输出 diff:3 字段改、1 CIDR 新增、0 删除、凭证变更 1 条。 3. 信息科点"请求会签",医务科与对应科室在 Web 看到与自己相关条目,逐条确认(含必填理由)。 4. 信息科点"推送",连接器逐条写入下游 LIS 网关(CI 阶段写入本地 mock LIS server)。 5. 平台生成 `audit_event{action=push, status=ok}` 并落 WORM 表。 6. 5 分钟内任意会签方点"撤销",平台触发回滚 + `audit_event{action=rollback}`。 ### 场景二:医保前置机字段口径变更 1. 信息科上传 `desired_state_medinsur.yaml`,新增 `dip_group` 字段 + 删除 `legacy_dr_group`。 2. 平台 preview 出 diff,医保办与医务科会签(医保办重点核对 DIP 病种字典)。 3. 推送后导出"过去 7 天医保接口变更"CSV,供医保核查。 ### 场景三:等保测评前导出审计报表 1. 审计员用 `export-audit --since 2026-07-01 --until 2026-08-16 --format csv` 导出全量审计。 2. CSV 含 actor / action / connection_id / before_hash / after_hash / commit_id / status,与 `spec.md` 字段表对齐。 3. 报表可直接附在等保测评材料中。 ## 输出样例 > 完整脱敏样例见 `docs/`: > - [`docs/audit_sample.csv`](docs/audit_sample.csv):等保可核对的 append-only 审计台账(10 字段列固定,演示数据用 `` 占位)。 > - [`docs/diff_sample.json`](docs/diff_sample.json):`POST /api/v1/connections/{id}/preview` 响应示例(含字段增删改 / CIDR 收放 / 凭证轮换元数据)。 > - [`docs/architecture.mmd`](docs/architecture.mmd):架构与数据流图(mermaid,可在 mermaid.live 直接渲染)。 > - [`docs/openapi.json`](docs/openapi.json) / `docs/openapi.yaml`:OpenAPI 3.1 正式对接规范,供信息科线下对接 HIS/EMR/LIS 厂商。 ```csv # audit_sample.csv(脱敏片段) ts,actor,action,connection_id,before_hash,after_hash,reason,commit_id,status 2026-08-12T09:14:03Z,info-dept-zhang,preview,lis-orm-r03,,,"weekly ORU mapping",c-7af3,ok 2026-08-12T09:18:11Z,med-affairs-li,confirm,lis-orm-r03,,,"approver signoff",c-7af3,ok 2026-08-12T09:21:45Z,info-dept-zhang,push,lis-orm-r03,h:f1,h:f2,"fields updated",c-7af3,ok 2026-08-12T09:24:02Z,info-dept-zhang,rollback,lis-orm-r03,h:f2,h:f1,"5-min window revert",c-7af3,ok ``` ```json // diff_sample.json(脱敏片段) { "connection_id": "lis-orm-r03", "commit_id": "c-7af3", "summary": {"added": 0, "removed": 0, "changed": 3, "cidrs_added": 1, "credentials_changed": 1}, "fields_changed": [ {"path": "order.code", "before": "", "after": ""}, {"path": "result.unit", "before": "", "after": ""} ] } ``` ## 架构与数据流 ``` ┌─────────────┐ desired-state.yaml ┌──────────────┐ 信息科 ──► │ Web SPA │ ───────────────────────► │ FastAPI │ └─────┬───────┘ │ Backend │ │ REST + JWT └──────┬───────┘ 医务科 / 审计员 ─►│ │ ▼ ▼ ApprovalQueue ┌────────────┐ Confirm / Reject │ Connectors │ ──► HIS / EMR / LIS / PACS │ Registry │ 医保 / 卫健 └─────┬──────┘ │ push ──► Audit (WORM) ◄── rollback (5 min) CSV / JSON 导出 ``` 完整 mermaid 图见 [`docs/architecture.mmd`](docs/architecture.mmd);可在 [mermaid.live](https://mermaid.live) 直接渲染。核心数据流: 1. **声明**:信息科上传 `desired-state.yaml` → `lib/yaml_loader.py` 校验字段 / CIDR / vocabulary → 落 `desired_state_versions` 表 + 写 `audit_event{action=upload_desired_state}`。 2. **预览**:`POST /preview` → `core/diff.py` 比 desired vs current → `PreviewDiffResult`(字段增删改 / CIDR 收放 / 凭证轮换元数据)→ Web 端三色 diff 可视化 → 写 `audit_event{action=preview_diff}`。 3. **会签**:三角色(owner / approver / auditor)按顺序逐条签批 + 必填理由;全部通过才解锁 Push 按钮;任一驳回即退回信息科改写。 4. **推送**:`POST /push` → 6 类 connector 调下游 mock(CI)/ 真实厂商接口(生产)→ `commit_id` 幂等键 + 行锁串行化 → 写 `audit_event{action=push}`。 5. **撤销**:`POST /push/{commit_id}/rollback` → 5 分钟硬窗口中间件校验 → connector.rollback 反向写入 → 写 `audit_event{action=rollback}`;窗口外返回 403 `E_ROLLBACK_WINDOW_EXPIRED`。 6. **审计导出**:`POST /audit/export` → `audit/exporter.py` 过滤 + 序列化为 CSV/JSON + 等保报表头部(hospital_name / report_period / auditor / exported_by_role)→ 写 `audit_event{action=export_audit}`。 ## 安全与合规边界 仅作接口配置层面的"声明 → 预览 → 推送 → 审计"工具,**不**做临床辅助决策,**不**自动写入 EMR 业务数据,**不**输出诊断或治疗建议。所有推送动作**必须**经会签 + 审计留痕;撤销窗口外的任何回滚需走人工审批。凭证字段以国密 SM2/SM4 envelope 加密落库;JWT 校验 + 三角色 RBAC 覆盖信息科 / 医务科会签 / 审计员。**禁止**将本平台改写为临床决策或病历内容生成工具。 ## 项目结构 ``` multi-source-sync/ ├── README.md # 本文件(产品说明) ├── README_EN.md # 英文版(Phase 5 自动生成) ├── requirements.txt ├── pyproject.toml # ruff / mypy / pytest 配置 ├── .env.example # 占位配置(不含真实密钥) ├── docker-compose.yml # FastAPI + Postgres + Redis + Web + 6 mock ├── backend/ │ ├── api/ # FastAPI 路由与 Pydantic v2 schemas │ │ ├── main.py # create_app + CORS + 统一 error handler │ │ ├── routes/ # connections / preview / push / audit / rotation │ │ └── schemas/ # 6 类契约(Pydantic v2,extra=forbid) │ ├── core/ # 状态机、diff、CIDR、统一错误码 │ │ ├── state_machine.py # 8 状态 + 合法迁移矩阵 + 幂等键 + 行锁 │ │ ├── diff.py # compare_fields / diff_cidrs / diff_credentials │ │ ├── cidrs.py # parse / validate / supernet / overlap │ │ ├── errors.py # 统一错误码 + HTTP 状态映射 │ │ ├── idempotency.py # commit_id 幂等键 │ │ └── locking.py # 行锁串行化 │ ├── connectors/ # BaseConnector + 6 类 connector + registry │ │ ├── base.py # ABC:type/schema/validate_credentials/push/rollback │ │ ├── his.py emr.py lis.py pacs.py medinsur.py healthreport.py │ │ └── registry.py # @register 装饰器 + REGISTRY dict │ ├── rotation/ # 凭证轮换 │ │ ├── state_machine.py # 4 状态 PENDING/IN_PROGRESS/SUCCEEDED/FAILED │ │ ├── queue.py # Celery 任务 + eager 模式 │ │ ├── executor.py # execute_rotate + audit_event 副作用 │ │ ├── scheduler.py # Celery beat 周期调度 │ │ └── retry.py # 指数退避 │ ├── audit/ # WORM 审计 + 三角色 RBAC + 报表导出 │ │ ├── worm.py # AuditEvent + InMemoryAuditLog + 触发器 │ │ ├── rbac.py # Role + JWT HS256 + require_action │ │ └── exporter.py # export_csv / export_json │ ├── crypto/ # SM2/SM4 envelope(凭证落库前加封) │ ├── db/ # SQLAlchemy 2 模型 + Alembic 迁移 + WORM 触发器 │ ├── lib/ # yaml_loader / dotenv / vocab │ ├── observability/ # structlog + Prometheus + /healthz /readyz │ ├── cli/ # Click 4 子命令:push / rollback / export-audit / rotate │ ├── celery_app.py # Celery 应用工厂 │ └── tests/ # unit / integration / mocks(含 3 mock 下游 server) ├── web/ # React 18 + Vite + TypeScript SPA │ └── src/ │ ├── types/connectors.ts # 6 类 connector TS 类型契约 │ ├── api/ # fetch wrapper + mockData 回退 │ ├── pages/ # Dashboard / ConnectionList / ConnectionDetail / ApprovalQueue / Audit │ └── components/ # DiffView / CidrList / ApprovalCard / AuditTable ├── scripts/ # dev.sh / dev_down.sh / verify_e2e.sh / verify_compose.sh ├── docs/ # openapi.json / openapi.yaml / audit_sample.csv / diff_sample.json / architecture.mmd / field_schemas.csv / perf_report.json / seed_demo/ ├── data/ # .gitignore 排除;本地 SQLite / 国密密钥对 ├── logs/ # .gitignore 排除;运行日志 └── qrcode.jpg # 公众号关注二维码 ``` ## License MIT --- ## 关注我们 欢迎扫码关注公众号,获取项目更新与交流加群: ![关注我们](qrcode.jpg)