215 lines
12 KiB
Markdown
215 lines
12 KiB
Markdown
# HMS 功能审计 — Phase 3: 事件系统审计
|
||
|
||
> 日期: 2026-04-30 | 审计范围: 全系统事件总线
|
||
|
||
## 总览
|
||
|
||
| 指标 | 值 |
|
||
|------|-----|
|
||
| 事件类型常量定义 | 25 个(event.rs) |
|
||
| 事件发布调用 | 44 处 |
|
||
| 事件消费者 | 14 个(11 个 tokio::spawn 任务) |
|
||
| 已知未实现事件 | 2 个(PATIENT_VERIFIED / PATIENT_DECEASED,标记 KNOWN) |
|
||
|
||
---
|
||
|
||
## 1. 事件发布方清单
|
||
|
||
### erp-health 模块(30 处发布)
|
||
|
||
| 事件类型 | 发布者 Service | 函数 | Payload 字段 |
|
||
|----------|---------------|------|-------------|
|
||
| `patient.created` | patient_service.rs | create_patient | patient_id, name, phone |
|
||
| `patient.updated` | patient_service.rs | update_patient | patient_id, updated_fields |
|
||
| `appointment.created` | appointment_service.rs | create_appointment | appointment_id, patient_id, doctor_id, scheduled_at |
|
||
| `appointment.{status}` | appointment_service.rs | update_appointment_status | appointment_id, patient_id, doctor_id, status |
|
||
| `appointment.reminder` | appointment_service.rs | send_reminders | appointment_id, patient_id, doctor_id, scheduled_at |
|
||
| `follow_up.created` | follow_up_service.rs | create_task | task_id, patient_id, assigned_to |
|
||
| `follow_up.batch_created` | follow_up_service.rs | batch_create_tasks | count, task_ids |
|
||
| `follow_up.completed` | follow_up_service.rs | batch_complete_tasks | task_ids, completed_count |
|
||
| `follow_up.assigned` | follow_up_service.rs | batch_assign_tasks | task_ids, assigned_to |
|
||
| `follow_up.overdue` | follow_up_service.rs | check_overdue_tasks | task_id, assigned_to, patient_id |
|
||
| `consultation.opened` | consultation_service.rs | create_session | session_id, patient_id, doctor_id |
|
||
| `consultation.closed` | consultation_service.rs | close_session | session_id, patient_id, doctor_id |
|
||
| `consultation.new_message` | consultation_service.rs | create_message | session_id, sender_id, sender_type |
|
||
| `device.readings.synced` | device_reading_service.rs | sync_readings | patient_id, device_type, reading_count |
|
||
| `vital_signs.created` | health_data_service.rs | create_vital_signs | patient_id, record_id, indicators |
|
||
| `lab_report.uploaded` | health_data_service.rs | create_lab_report | patient_id, report_id, indicator_count |
|
||
| `lab_report.reviewed` | health_data_service.rs | review_lab_report | report_id, reviewer_id, status |
|
||
| `health_data.critical_alert` | health_data_service.rs | create_vital_signs | patient_id, alert_type, metric_name, metric_value, threshold_value |
|
||
| `daily_monitoring.created` | daily_monitoring_service.rs | create_daily_monitoring | patient_id, monitoring_id, record_date |
|
||
| `alert.triggered` | alert_engine.rs | evaluate_rules | patient_id, severity, rule_name, alert_id |
|
||
| `article.published` | article_service.rs | publish_article | article_id, title, author_id |
|
||
| `article.rejected` | article_service.rs | reject_article | article_id, reviewer_id, reason |
|
||
| `consent.granted` | consent_service.rs | grant_consent | patient_id, consent_type |
|
||
| `consent.revoked` | consent_service.rs | revoke_consent | patient_id, consent_type, reason |
|
||
| `points.earned` | points_service.rs | daily_checkin | patient_id, points, balance |
|
||
| `points.exchanged` | points_service.rs | exchange_product | patient_id, product_id, order_id, points |
|
||
| `points.expired` | points_service.rs | expire_points | count, expired_points_total |
|
||
| `doctor.online_status_changed` | doctor_service.rs | update_online_status | doctor_id, old_status, new_status |
|
||
|
||
### erp-ai 模块(2 处发布)
|
||
|
||
| 事件类型 | 发布者 | 函数 |
|
||
|----------|--------|------|
|
||
| `ai.analysis.failed` | handler/mod.rs | stream_lab_report 等 |
|
||
| `ai.analysis.completed` | handler/mod.rs | stream_lab_report 等 |
|
||
|
||
### erp-dialysis 模块(1 处发布)
|
||
|
||
| 事件类型 | 发布者 | 函数 |
|
||
|----------|--------|------|
|
||
| `dialysis.record.created` | dialysis_service.rs | create_record |
|
||
|
||
### erp-auth 模块(1 处发布)
|
||
|
||
| 事件类型 | 发布者 | 函数 |
|
||
|----------|--------|------|
|
||
| `user.login` | auth_service.rs | login |
|
||
|
||
### erp-workflow 模块(2+ 处发布)
|
||
|
||
| 事件类型 | 发布者 | 函数 |
|
||
|----------|--------|------|
|
||
| `workflow.instance.*` | instance_service.rs | start_instance 等 |
|
||
| `workflow.task.timeout` | module.rs | 后台超时检测 |
|
||
|
||
### erp-plugin 模块(3 处发布)
|
||
|
||
| 事件类型 | 发布者 | 函数 |
|
||
|----------|--------|------|
|
||
| `plugin.data.*` | data_service.rs | CRUD 操作 |
|
||
| `plugin.trigger.*` | data_service.rs | 通知触发 |
|
||
| 动态事件 | engine.rs | 插件自定义事件 |
|
||
|
||
---
|
||
|
||
## 2. 事件消费方清单
|
||
|
||
### erp-health 消费者(11 个 tokio::spawn 任务)
|
||
|
||
| # | 消费者名称 | 订阅前缀 | 处理事件 | 业务动作 |
|
||
|---|-----------|---------|---------|---------|
|
||
| 1 | workflow_task_consumer | `workflow.task.` | `workflow.task.completed` | 更新随访任务状态为 completed |
|
||
| 2 | message_consumer | `message.` | `message.sent` | 日志记录(预留扩展) |
|
||
| 3 | device_reading_consumer | `device.readings.` | `device.readings.synced` | 触发告警引擎评估 |
|
||
| 4 | alert_notifier | `alert.` | `alert.triggered` | 发送应用内告警通知 |
|
||
| 5 | patient_welcome | `patient.` | `patient.created` | 发送欢迎消息 |
|
||
| 6 | appointment_notifier | `appointment.` | `appointment.confirmed` | 发送预约确认通知 |
|
||
| 7 | appointment_cancel_handler | `appointment.` | `appointment.cancelled` | 日志记录(号源释放) |
|
||
| 8 | follow_up_escalator | `follow_up.` | `follow_up.overdue` | 发送逾期升级通知 |
|
||
| 9 | critical_alert_consumer | `health_data.` | `health_data.critical_alert` | 创建危急值告警记录 |
|
||
| 10 | ai_analysis_notifier | `ai.` | `ai.analysis.completed` | 通知关联医生 |
|
||
| 11 | dialysis_notifier | `ai.` | `dialysis.record.created` | 日志记录 |
|
||
| 12 | consent_notifier | `consent.` | `consent.granted` | 发送授予通知 |
|
||
| 13 | consent_revoked_notifier | `consent.` | `consent.revoked` | 发送撤回通知给医护 |
|
||
|
||
### 其他模块消费者
|
||
|
||
| 模块 | 消费者 | 订阅范围 |
|
||
|------|--------|---------|
|
||
| erp-message | SSE handler | 全部事件(转发给前端) |
|
||
| erp-plugin | notification handler | `plugin.trigger.` |
|
||
| erp-plugin | engine | 按插件 manifest 的 pattern |
|
||
|
||
---
|
||
|
||
## 3. 事件常量 vs 发布方 vs 消费方矩阵
|
||
|
||
| 事件常量 | 事件类型 | 发布方 | 消费方 | 状态 |
|
||
|----------|---------|--------|--------|------|
|
||
| APPOINTMENT_CREATED | `appointment.created` | ✓ appointment_service | ✓ appointment_notifier(前缀匹配) | **ALIVE** |
|
||
| ALERT_TRIGGERED | `alert.triggered` | ✓ alert_engine | ✓ alert_notifier | **ALIVE** |
|
||
| CONSENT_GRANTED | `consent.granted` | ✓ consent_service | ✓ consent_notifier | **ALIVE** |
|
||
| CONSENT_REVOKED | `consent.revoked` | ✓ consent_service | ✓ consent_revoked_notifier | **ALIVE** |
|
||
| ARTICLE_PUBLISHED | `article.published` | ✓ article_service | — | **NO CONSUMER** |
|
||
| ARTICLE_REJECTED | `article.rejected` | ✓ article_service | — | **NO CONSUMER** |
|
||
| CONSULTATION_OPENED | `consultation.opened` | ✓ consultation_service | — | **NO CONSUMER** |
|
||
| CONSULTATION_CLOSED | `consultation.closed` | ✓ consultation_service | — | **NO CONSUMER** |
|
||
| CONSULTATION_NEW_MESSAGE | `consultation.new_message` | ✓ consultation_service | — | **NO CONSUMER** |
|
||
| DEVICE_READINGS_SYNCED | `device.readings.synced` | ✓ device_reading_service | ✓ device_reading_consumer | **ALIVE** |
|
||
| DOCTOR_ONLINE_STATUS_CHANGED | `doctor.online_status_changed` | ✓ doctor_service | — | **NO CONSUMER** |
|
||
| FOLLOW_UP_CREATED | `follow_up.created` | ✓ follow_up_service | — | **NO CONSUMER** |
|
||
| FOLLOW_UP_COMPLETED | `follow_up.completed` | ✓ follow_up_service | — | **NO CONSUMER** |
|
||
| FOLLOW_UP_OVERDUE | `follow_up.overdue` | ✓ follow_up_service | ✓ follow_up_escalator | **ALIVE** |
|
||
| DAILY_MONITORING_CREATED | `daily_monitoring.created` | ✓ daily_monitoring_service | — | **NO CONSUMER** |
|
||
| LAB_REPORT_UPLOADED | `lab_report.uploaded` | ✓ health_data_service | — | **NO CONSUMER** |
|
||
| LAB_REPORT_REVIEWED | `lab_report.reviewed` | ✓ health_data_service | — | **NO CONSUMER** |
|
||
| HEALTH_DATA_CRITICAL_ALERT | `health_data.critical_alert` | ✓ health_data_service | ✓ critical_alert_consumer | **ALIVE** |
|
||
| PATIENT_CREATED | `patient.created` | ✓ patient_service | ✓ patient_welcome | **ALIVE** |
|
||
| PATIENT_UPDATED | `patient.updated` | ✓ patient_service | — | **NO CONSUMER** |
|
||
| PATIENT_VERIFIED | `patient.verified` | — | — | **KNOWN** 未实现 |
|
||
| PATIENT_DECEASED | `patient.deceased` | — | — | **KNOWN** 未实现 |
|
||
| POINTS_EXPIRED | `points.expired` | ✓ points_service | — | **NO CONSUMER** |
|
||
| POINTS_EARNED | `points.earned` | ✓ points_service | — | **NO CONSUMER** |
|
||
| POINTS_EXCHANGED | `points.exchanged` | ✓ points_service | — | **NO CONSUMER** |
|
||
|
||
---
|
||
|
||
## 4. 分析结论
|
||
|
||
### 4.1 活跃事件(有发布+有消费):11 个
|
||
这是系统核心业务链路,全部正常:
|
||
- `workflow.task.completed` → 随访自动完成
|
||
- `device.readings.synced` → 告警评估
|
||
- `alert.triggered` → 告警通知
|
||
- `patient.created` → 欢迎消息
|
||
- `appointment.confirmed/cancelled` → 预约通知
|
||
- `follow_up.overdue` → 逾期升级
|
||
- `health_data.critical_alert` → 危急值告警
|
||
- `ai.analysis.completed` → 医生通知
|
||
- `dialysis.record.created` → 日志
|
||
- `consent.granted/revoked` → 知情同意通知
|
||
|
||
### 4.2 有发布无消费事件:14 个
|
||
这些事件被发布到 EventBus 并持久化到 domain_events 表,但没有业务消费者。它们可能仅用于审计追踪或 SSE 前端推送。
|
||
|
||
**风险评估**:
|
||
| 事件 | 风险 | 说明 |
|
||
|------|------|------|
|
||
| `patient.updated` | LOW | 信息性事件,更新操作已直接处理 |
|
||
| `vital_signs.created` | LOW | 数据已写入 DB,无需后续触发 |
|
||
| `lab_report.uploaded` | LOW | 同上 |
|
||
| `lab_report.reviewed` | LOW | 同上 |
|
||
| `follow_up.created` | LOW | 任务已创建,无需后续触发 |
|
||
| `follow_up.completed` | LOW | 状态已更新,无需后续触发 |
|
||
| `consultation.*` | LOW | 会话管理已在 service 内直接处理 |
|
||
| `article.published/rejected` | LOW | 状态已更新,无需后续触发 |
|
||
| `points.earned/exchanged/expired` | LOW | 积分操作已在 service 内完成 |
|
||
| `daily_monitoring.created` | LOW | 数据已写入 |
|
||
| `doctor.online_status_changed` | LOW | 状态已更新 |
|
||
|
||
### 4.3 已知未实现事件(KNOWN):2 个
|
||
- `PATIENT_VERIFIED` — 患者认证流程未实现
|
||
- `PATIENT_DECEASED` — 死亡记录流程未实现
|
||
|
||
### 4.4 潜在问题
|
||
1. **message.sent 消费者仅为日志记录** — event.rs:119 的消费者仅做 tracing::info,实际业务逻辑(如更新 consultation last_message_at)已在 service 层直接处理,此消费者预留扩展但当前无实质作用。
|
||
2. **SSE 全事件转发** — erp-message 的 SSE handler 监听所有事件,意味着所有事件(包括 points.earned 等低优先级事件)都会被推送到前端,可能导致通知噪音。
|
||
|
||
---
|
||
|
||
## 5. Payload Schema 一致性验证(抽样 5 个)
|
||
|
||
| 事件 | 发布方字段 | 消费方解析 | 一致性 |
|
||
|------|-----------|-----------|--------|
|
||
| `workflow.task.completed` | `task_id` | `task_id` → Uuid | ✅ |
|
||
| `device.readings.synced` | `patient_id` | `patient_id` → Uuid | ✅ |
|
||
| `health_data.critical_alert` | `patient_id, alert_type, metric_name, metric_value, threshold_value` | 全部解析 | ✅ |
|
||
| `follow_up.overdue` | `task_id, assigned_to` | 全部解析 | ✅ |
|
||
| `appointment.confirmed` | `doctor_id, patient_id` | 全部解析 | ✅ |
|
||
|
||
**结论**:所有抽样的关键事件 payload schema 发布方与消费方完全一致。所有消费者都使用幂等检查(`is_event_processed`),防止重复处理。
|
||
|
||
---
|
||
|
||
## 6. 事件系统评分
|
||
|
||
| 检查项 | 评分 | 说明 |
|
||
|--------|------|------|
|
||
| 事件定义完整性 | 95% | 25/27 常量有发布者(2 个 KNOWN 未实现) |
|
||
| 消费者覆盖率 | 44% | 11/25 事件有活跃消费者 |
|
||
| Payload 一致性 | 100% | 抽样 5 个全部一致 |
|
||
| 幂等性保证 | 100% | 所有消费者使用 `is_event_processed` 检查 |
|
||
| 死信处理 | 100% | 消费失败自动进入 dead_letter_event 表 |
|