Files
hms/wiki/architecture.md
iven 40b5141832
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: 全面更新 wiki 文档至当前实现状态
9 个 wiki 页面全部更新:
- index: 关键数字更新(15 crate/48 表/50 迁移/6 模块)
- erp-health: 从"规划中"更新为"已实现"(18 实体/14 权限)
- erp-server: 6 模块注册/8 环境变量/5 后台任务
- database: 50 迁移/48 表/健康模块迁移(m000042-m000050)
- frontend: 10 健康路由/12 共享组件/7 健康 API/3 单元测试
- miniprogram: 20 页面/10 服务/9 组件
- testing: 93 后端测试+3 前端测试/全链路验证结果
- erp-core: 新增 erp-health 集成契约
- architecture: 6 模块实现状态表/预约 CAS/PII 加密
2026-04-25 11:57:20 +08:00

123 lines
4.9 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.
---
title: 架构决策记录
updated: 2026-04-25
status: stable
tags: [architecture, decisions, design-principles]
---
# 架构决策记录
> 从 [[index]] 导航。关联: [[erp-core]] [[erp-server]] [[database]] [[wasm-plugin]] [[erp-health]]
## 1. 设计决策
### 模块化单体 + 渐进式拆分
模块间零直接依赖,跨模块通信通过事件总线和 trait 接口。`ErpModule` trait 天然支持未来按模块拆分为微服务。
### HMS 架构:原生模块 + 插件并存
HMS 继承 ERP 底座的所有基础模块,`erp-health` 作为原生 Rust 模块承载医疗业务。WASM 插件系统保留但非 HMS 主要扩展方式。
```
HMS 平台
├── 基础模块(继承 ERP: auth, config, workflow, message, plugin
├── 核心业务模块: erp-health原生 Rust18 实体/14 权限/13 页面)★ 已实现
└── 可选插件: crm, inventory, freelance, itopsWASM
```
### 为什么 erp-health 用原生模块?
医疗业务需要 18 强类型实体、自定义 API趋势分析/统计报表、PII 数据加密AES-256-GCM、文件上传、未来 AI 集成。WASM 插件的 JSONB 动态存储和 20 实体上限无法满足。详见 [[erp-health]]。
### 为什么用 UUIDv7
时间排序 + UUID 唯一性 + 接近自增 ID 的索引性能。多租户 SaaS 下不同租户数据不会因 ID 冲突互相影响。
### 为什么 tenant_id 不在 API 路径中?
从 JWT 提取,中间件注入 `TenantContext`。防止:手动改 URL 越权 / API 暴露租户信息 / 忘记检查权限。管理员接口例外。
### 为什么错误类型跨 crate 用 thiserror
`anyhow` 无类型信息,无法精确映射 HTTP 状态码。`thiserror``AppError` → 400/401/403/404/409/500。
### 为什么预约用原子 CAS
防止并发创建预约时超额。事务内 `UPDATE current_appointments + 1 WHERE current < max`CAS 成功后才 INSERT 预约记录。
## 2. 关键文件 + 数据流
### 模块依赖图
```
erp-core (L1)
|
+--------------+--------------+--------------+-----------+
| | | | |
erp-auth erp-config erp-workflow erp-message erp-health (L2)
| | | | |
+--------------+--------------+--------------+-----------+
|
erp-server (L3: 唯一组装点)
|
erp-plugin (WASM 插件运行时)
```
**禁止**: L2 间直接依赖 / L1 依赖业务模块 / 绕过事件总线
### 模块实现状态
| 模块 | 状态 | 实体数 | 权限数 | 页面数 |
|------|------|--------|--------|--------|
| erp-auth | ✅ 完成 | 11 表 | - | 用户/角色/组织 |
| erp-config | ✅ 完成 | 6 表 | - | 设置/字典/菜单 |
| erp-workflow | ✅ 完成 | 5 表 | - | 工作流管理 |
| erp-message | ✅ 完成 | 3 表 | - | 消息中心 |
| erp-plugin | ✅ 完成 | 4 表 | - | 插件管理/市场 |
| erp-health | ✅ 完成 | 18 表 | 14 | 13 页面 + 11 组件 |
### 技术选型
| 选择 | 理由 |
|------|------|
| Axum 0.8 | Tokio 团队维护tower 生态,类型安全路由 |
| SeaORM 1.1 | 异步、类型安全、迁移工具完善 |
| PostgreSQL 18 | 企业级JSON 支持,扩展丰富 |
| Redis 7 | 缓存 + 限流 token bucket |
| React 19 + Ant Design 6 | 企业后台 UI 标配 |
| Zustand 5 | 极简状态管理 |
| Wasmtime 43 | WASM 沙箱Component ModelFuel 限制 |
### 集成契约
| 方向 | 模块 | 触发时机 |
|------|------|---------|
| 定义 → | [[erp-core]] | 所有模块的 trait 和类型 |
| 组装 ← | [[erp-server]] | 6 模块注册和启动 |
| 扩展 ← | [[wasm-plugin]] | 插件通过 Host Bridge 桥接 |
| 业务 ← | [[erp-health]] | 健康模块原生集成 |
## 3. 代码逻辑
**不变量**: 模块间只通过 EventBus 和 trait 通信,无直接依赖
**不变量**: 所有数据表必须含 `tenant_id`,查询自动过滤
**不变量**: UUID v7 作为主键
**不变量**: 软删除,不硬删除
**不变量**: 所有 API 使用 `/api/v1/` 前缀
**不变量**: 预约创建必须走原子 CAS不能用 read-then-write
**不变量**: PII 数据(身份证、手机号)加密存储 + 脱敏展示
## 4. 活跃问题 + 陷阱
⚠️ 当前共享数据库 + tenant_id 过滤,未来可扩展为 Schema 隔离或数据库隔离
⚠️ EventBus 内存 broadcast 需 outbox 持久化保障(已通过后台任务实现)
⚠️ 微信登录固定到 default_tenant_id — 多租户场景需设计解析策略
## 5. 变更记录
| 日期 | 变更 |
|------|------|
| 2026-04-25 | 全面更新6 模块已实现状态表、预约 CAS 决策、PII 加密不变量、健康模块集成 |
| 2026-04-23 | 重构为 5 节结构,删除 erp-common 引用,精简技术选型表 |