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 加密
103 lines
4.0 KiB
Markdown
103 lines
4.0 KiB
Markdown
---
|
||
title: erp-core
|
||
updated: 2026-04-25
|
||
status: stable
|
||
tags: [core, error, event-bus, module-trait, shared-types]
|
||
---
|
||
|
||
# erp-core
|
||
|
||
> 从 [[index]] 导航。关联: [[erp-server]] [[database]] [[wasm-plugin]] [[architecture]] [[erp-health]]
|
||
|
||
## 1. 设计决策
|
||
|
||
`erp-core` 是 L1 基础层,所有业务模块的唯一共同依赖。定义**跨模块共享的契约**,不含业务逻辑。
|
||
|
||
核心决策:
|
||
- **AppError 统一错误体系** — 6 种变体映射 HTTP 状态码,`?` 传播 + Axum `IntoResponse` 自动转换
|
||
- **EventBus 进程内广播** — `tokio::sync::broadcast` 实现零耦合通信
|
||
- **ErpModule 插件 trait** — 统一注册路由和事件处理器
|
||
- **BaseFields 强制多租户** — 所有实体基础字段模板
|
||
|
||
## 2. 关键文件 + 数据流
|
||
|
||
### 核心文件
|
||
|
||
| 文件 | 职责 |
|
||
|------|------|
|
||
| `crates/erp-core/src/error.rs` | AppError 定义、HTTP 映射、From 转换 |
|
||
| `crates/erp-core/src/events.rs` | DomainEvent、EventBus、EventHandler trait |
|
||
| `crates/erp-core/src/module.rs` | ErpModule trait、ModuleRegistry |
|
||
| `crates/erp-core/src/types.rs` | BaseFields、Pagination、ApiResponse、TenantContext |
|
||
| `crates/erp-core/src/sanitize.rs` | strip_html_tags()、sanitize_string() |
|
||
| `crates/erp-core/src/lib.rs` | 模块导出入口 |
|
||
|
||
### 集成契约
|
||
|
||
| 方向 | 模块 | 接口 | 触发时机 |
|
||
|------|------|------|---------|
|
||
| 提供 → | erp-auth | ErpModule trait, AppError, EventBus | 模块实现 |
|
||
| 提供 → | erp-config | ErpModule trait, AppError | 模块实现 |
|
||
| 提供 → | erp-workflow | ErpModule trait, AppError, EventBus | 模块实现 |
|
||
| 提供 → | erp-message | ErpModule trait, AppError, EventBus | 模块实现 |
|
||
| 提供 → | erp-plugin | ErpModule trait, AppError, EventBus | 模块实现 |
|
||
| 提供 → | [[erp-health]] | ErpModule trait, AppError, EventBus, sanitize | 模块实现 |
|
||
| 消费 ← | [[erp-server]] | ModuleRegistry 组装 | 启动时 |
|
||
| 桥接 ← | [[wasm-plugin]] | EventBus → 插件 handle_event | 运行时 |
|
||
|
||
## 3. 代码逻辑
|
||
|
||
### 错误处理链
|
||
|
||
```
|
||
业务 crate (thiserror) → AppError → IntoResponse → HTTP JSON
|
||
数据库 (sea_orm::DbErr) → From 转换 → AppError (自动识别 duplicate key → Conflict)
|
||
```
|
||
|
||
响应格式:`{ "error": "not_found", "message": "资源不存在", "details": null }`
|
||
|
||
### 事件总线
|
||
|
||
```
|
||
EventBus::publish(DomainEvent) → broadcast channel → Receiver<DomainEvent>
|
||
事件字段: id(UUIDv7), event_type("user.created"), tenant_id, payload(JSON), timestamp
|
||
```
|
||
|
||
命名规则:`{模块}.{动作}` 如 `user.created`, `workflow.task.completed`
|
||
|
||
健康模块事件:`patient.created`, `appointment.confirmed`, `appointment.cancelled`
|
||
|
||
### 模块注册
|
||
|
||
```
|
||
ErpModule trait → ModuleRegistry::register() →
|
||
build_router(): 折叠所有模块路由 → Axum Router
|
||
register_handlers(): 注册事件处理器 → EventBus
|
||
```
|
||
|
||
已注册模块:AuthModule → ConfigModule → WorkflowModule → MessageModule → PluginModule → **HealthModule**
|
||
|
||
### 共享类型
|
||
|
||
- `TenantContext` — 租户上下文(tenant_id, user_id, roles, permissions, department_ids)
|
||
- `Pagination` / `PaginatedResponse<T>` — 分页标准化(每页上限 100)
|
||
- `ApiResponse<T>` — 统一信封 `{ success, data, message }`
|
||
- `sanitize_string()` — HTML 标签过滤,用于用户输入清理
|
||
|
||
⚡ **不变量**: erp-core 不依赖任何业务 crate,只被依赖
|
||
⚡ **不变量**: 所有 API 使用 `/api/v1/` 前缀
|
||
⚡ **不变量**: tenant_id 从 JWT 中间件注入,应用层不可伪造
|
||
|
||
## 4. 活跃问题 + 陷阱
|
||
|
||
⚠️ crate 内部可用 `anyhow`,但跨 crate 边界必须转 `AppError`
|
||
⚠️ EventBus 当前为内存 broadcast,outbox 持久化通过后台任务实现
|
||
⚠️ 微信注册路径的 display_name 需调用 `sanitize_string()` 防止 XSS
|
||
|
||
## 5. 变更记录
|
||
|
||
| 日期 | 变更 |
|
||
|------|------|
|
||
| 2026-04-25 | 添加 erp-health 集成契约、健康模块事件、sanitize 模块引用 |
|
||
| 2026-04-23 | 重构为 5 节结构,更新为已完全集成状态 |
|