Files
hms/docs/superpowers/plans/2026-04-26-event-driven-architecture.md
iven b410fa9f78
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled
docs: 5 份实施计划 — 性能/安全/事件/前端/可观测性
对应 5 份设计规格,共 75 个 Task:

1. 性能优化 (12 Task) — 批量INSERT/N+1内联name/合并COUNT/按需重绘/chunk拆分
2. 安全纵深防御 (8 Task) — RLS/行级数据范围/Redis session_key/审计哈希链
3. 事件驱动架构 (10 Task) — 11个缺失事件补发/LISTEN+NOTIFY/schema版本化
4. 前端工程化 (10 Task) — hook统一/组件拆分/Bundle优化
5. 可观测性运维 (10 Task) — 深度健康检查/Prometheus/OTel/生产Docker/告警
2026-04-27 08:00:50 +08:00

107 lines
5.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 事件驱动架构增强实施计划
> 设计规格: `docs/superpowers/specs/2026-04-26-event-driven-architecture-design.md`
> 日期: 2026-04-26 | 状态: draft | 总周期: 2 周
---
## Phase 1: 高优先级事件补发Week 1
### Task 1: dialysis_service 添加 dialysis_record.created/reviewed 事件
**涉及文件**: `crates/erp-health/src/service/dialysis_service.rs`
**步骤**: `create_dialysis_record()` 成功后发布 `dialysis_record.created`data: patient_id, dialysis_type, status, dialysis_date, duration, ultrafiltration_volume。审核状态变更时发布 `dialysis_record.reviewed`data: patient_id, reviewer_id, complication_notes。payload 遵循统一信封schema_version: "v1")。发布失败仅 warn 不阻断业务。
**验收**: 创建/审核后 domain_events 表出现对应事件;`cargo test` 通过。
### Task 2: diagnosis_service 添加 diagnosis.created/updated 事件
**涉及文件**: `crates/erp-health/src/service/diagnosis_service.rs`
**步骤**: `create_diagnosis()` 后发布 `diagnosis.created`data: patient_id, icd_code, diagnosis_name, severity`update_diagnosis()` 后发布 `diagnosis.updated`,计算变更 diffchanged_fields[], old_values{}, new_values{})。
**验收**: diagnosis.updated 事件 data 含 changed_fields 差异;`cargo test` 通过。
### Task 3: consent_service 添加 consent.granted/revoked 事件
**涉及文件**: `crates/erp-health/src/service/consent_service.rs`
**步骤**: 签署时发布 `consent.granted`data: patient_id, consent_type, consent_scope, granted_by, expires_at。撤销时发布 `consent.revoked`data: patient_id, consent_type, revoked_by, reason
**验收**: 签署/撤销后 domain_events 表出现事件;`cargo test` 通过。
---
## Phase 2: 中低优先级事件 + Outbox 优化Week 2
### Task 4: points_service 添加 points.earned/exchanged 事件
**涉及文件**: `crates/erp-health/src/service/points_service.rs`
**步骤**: earn 成功后发布 `points.earned`data: patient_id, points, source_type, balance_after。exchange 成功后发布 `points.exchanged`data: patient_id, points, product_name, order_id, balance_after。确保在事务提交后发布。
**验收**: 积分变动后 domain_events 出现事件balance_after 正确反映余额。
### Task 5: article_service 添加 article.published/rejected 事件
**涉及文件**: `crates/erp-health/src/service/article_service.rs`
**步骤**: 审核通过发布 `article.published`data: title, author_id, category_id, tags[])。审核驳回发布 `article.rejected`data: title, reviewer_id, reason
**验收**: 审核操作后 domain_events 出现事件;`cargo test` 通过。
### Task 6: daily_monitoring_service 添加 daily_monitoring.created 事件
**涉及文件**: `crates/erp-health/src/service/daily_monitoring_service.rs`
**步骤**: 记录创建后发布 `daily_monitoring.created`data: patient_id, monitoring_date, monitoring_type, values{})。
**验收**: 创建记录后 domain_events 出现事件;`cargo test` 通过。
### Task 7: Outbox relay 从轮询改为 LISTEN/NOTIFY
**涉及文件**: `crates/erp-server/src/outbox.rs`, `crates/erp-core/src/events.rs`
**步骤**: `EventBus::publish()` 持久化后执行 `NOTIFY outbox_channel, '<event_id>'`。outbox relay 用 `sqlx::PgListener` 监听 + `tokio::select!`LISTEN 触发 + 30s 兜底轮询)。保留 `process_pending_events()` 不变仅改变触发方式。PgListener 添加断线自动重连。
**验收**: 事件延迟 < 100msDB 轮询频率从 5s 降为 30s 兜底;`cargo test --workspace` 通过。
---
## Phase 3: 事件 schema 版本化 + 清理Week 2
### Task 8: 事件 payload 添加 schema_version 字段
**涉及文件**: `crates/erp-core/src/events.rs`, `crates/erp-health/src/service/` 下所有发布事件的 service
**步骤**: 在 erp-core 创建 `build_event_payload()` 辅助函数,自动填充 schema_version/timestamp/metadata。逐个 service14 个模块)替换手动构建为调用辅助函数,统一信封格式。
**验收**: 所有事件 payload 含 schema_version 字段;`cargo test --workspace` 通过。
### Task 9: Outbox 表分区或定期清理策略
**涉及文件**: `migration/src/m000075_domain_events_cleanup.rs`(新增), `erp-server/src/tasks/events_cleanup.rs`(新增)
**步骤**: 迁移创建 `domain_events_archive` 表,添加 `cleanup_old_published_events()` SQL 函数(>90 天 published 事件迁移到归档表)。后台任务每日执行清理。归档表只读防篡改。
**验收**: 清理任务正确迁移 >90 天事件;`cargo test` 通过。
### Task 10: 消费者幂等性dedup key 检查)
**涉及文件**: `migration/src/m000076_processed_events.rs`(新增), `crates/erp-core/src/events.rs`
**步骤**: 迁移创建 `processed_events`event_id + consumer_id 联合主键 + processed_at。erp-core 添加 `is_processed()` / `mark_processed()` 辅助函数。消费者模式:收到事件 -> 查已处理 -> 跳过或执行 -> 插入记录。添加 7 天 TTL 清理任务。
**验收**: 重复消费同一事件时第二次被跳过;`cargo test --workspace` 通过。
---
## 执行原则
1. **每 Task 完成后立即提交** — 不积压
2. **Phase 1 优先** — P0 事件(透析/诊断)是核心医疗流程
3. **事件发布不阻断业务** — publish 失败仅 warnOutbox relay 兜底
4. **统一信封格式** — 使用 `build_event_payload` 保证一致性
5. **LISTEN/NOTIFY 保留兜底轮询** — 30s 轮询防 NOTIFY 丢失