Files
erp/plans/calm-forging-puddle.md

173 lines
8.6 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.

# P1-P4 审计修复实施计划
## Context
对 P1-P4 审计发现 8 项高/中优先级缺失Excel/CSV 导入导出、市场后端 API、对账扫描、运行时监控、通知规则、编号 reset_rule。本计划按优先级分 3 批推进,每批独立可提交。
---
## 第一批高优先级Excel/CSV + 市场后端 + 对账扫描)
### 1.1 Excel/CSV 导入导出
**思路**: 后端新增 `csv` + `rust_xlsxwriter` 依赖export handler 支持 format 参数输出 CSV/XLSX前端同时支持。
**后端改动**:
1. `Cargo.toml` (workspace): 新增 `csv = "1"``rust_xlsxwriter = "0.82"`
2. `crates/erp-plugin/Cargo.toml`: 添加 `csv``rust_xlsxwriter` 依赖
3. `crates/erp-plugin/src/data_service.rs`:
- `export()` 签名增加 `format: Option<String>` 参数
- 内部新增 `export_csv()``export_xlsx()` 私有方法,返回 `Vec<u8>` bytes
- format 为空/json 时返回原 JSONcsv/xlsx 时返回二进制
- 返回类型改为 enum `ExportPayload { Json(Vec<Value>), Csv(Vec<u8>), Xlsx(Vec<u8>) }`
4. `crates/erp-plugin/src/data_dto.rs`: ExportParams 的 format 字段已有
5. `crates/erp-plugin/src/handler/data_handler.rs`:
- `export_plugin_data` 根据 format 参数返回不同 Content-Type:
- JSON: `application/json`
- CSV: `text/csv` + `Content-Disposition: attachment`
- XLSX: `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`
- 返回类型改为 `axum::response::Response`(不是 Json<>
6. 前端 `pluginData.ts`: `exportPluginData` 支持 format 参数CSV/XLSX 时用 `responseType: 'blob'`
7. 前端 `PluginCRUDPage.tsx`: 导出按钮增加下拉菜单选择格式JSON/CSV/Excel
**注意**: 导入仍保持 JSON复杂度低模板生成和导入历史不在本批范围。
### 1.2 P4 市场后端 API
**思路**: 新建 `market_service.rs` + `market_handler.rs`,复用 DB 迁移已建好的 `plugin_market_entries``plugin_market_reviews` 表。
**新增文件**:
- `crates/erp-plugin/src/service/market_service.rs`: 市场业务逻辑
- `crates/erp-plugin/src/handler/market_handler.rs`: 市场 API handler
- `crates/erp-plugin/src/entity/market_entry.rs`: SeaORM Entity
- `crates/erp-plugin/src/entity/market_review.rs`: SeaORM Entity
**后端 API**:
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/api/v1/market/entries` | 浏览市场目录(分类/搜索/分页) |
| GET | `/api/v1/market/entries/{id}` | 市场条目详情 |
| POST | `/api/v1/market/entries/{id}/install` | 从市场一键安装 |
| GET | `/api/v1/market/entries/{id}/reviews` | 查看评论 |
| POST | `/api/v1/market/entries/{id}/reviews` | 提交评分/评论 |
**一键安装逻辑**: 从 `plugin_market_entries``wasm_binary` + `manifest_toml`,调用已有的 `PluginService::upload` + `PluginService::install` + `PluginService::enable`
**依赖提示**: install 时检查 manifest.dependencies若目标插件未安装则返回警告软提示不阻塞
**前端改动**:
- `apps/web/src/api/plugins.ts`: 新增市场 API 函数
- `apps/web/src/pages/PluginMarket.tsx`: 对接真实 API替换 mock 数据;增加评分提交 UI安装按钮对接真实 API
### 1.3 P1 对账扫描
**思路**: 新增 `reconcile` service 方法和 handler在插件重新启用时扫描悬空引用。
**后端改动**:
- `crates/erp-plugin/src/data_service.rs`: 新增 `reconcile_references()` 方法
- 查找所有指向目标插件的 `ref_entity` 字段(从 plugin_entities schema_json 解析)
- 扫描这些字段的 UUID 值,验证目标表中是否存在
- 返回 `ReconciliationReport { valid: N, dangling: M, details: Vec<DanglingRef> }`
- `crates/erp-plugin/src/data_dto.rs`: 新增 DTO
- `crates/erp-plugin/src/handler/data_handler.rs`: 新增 `reconcile_refs` handler
- `crates/erp-plugin/src/module.rs`: 注册路由 `POST /plugins/{plugin_id}/reconcile`
**前端**: 暂不实现完整对账 UI低优先级仅提供 API 供后续使用。
---
## 第二批:中优先级(运行时监控 + 通知规则 + 编号 reset
### 2.1 P3 运行时监控
**后端改动**:
1. 新建迁移 `m20260420_000041_plugin_runtime_metrics.rs`:
- `plugin_runtime_metrics` 表: plugin_id, tenant_id, error_count, total_invocations, avg_response_ms, fuel_consumption_avg, memory_peak_bytes, last_error, updated_at
2. `crates/erp-plugin/src/engine.rs`:
- `LoadedPlugin` 新增 `metrics: Arc<RwLock<RuntimeMetrics>>` 字段
- `execute_wasm` 中采集指标: 记录开始时间、成功/失败计数、fuel 消耗
- 定期持久化到 DB每 10 次调用或 60 秒)
3. `crates/erp-plugin/src/handler/plugin_handler.rs`:
- 扩展 `health_check` 返回 RuntimeMetrics
- 新增 `GET /admin/plugins/{id}/metrics` 端点
### 2.2 P2 通知规则引擎
**思路**: 复用 EventBus 的 `subscribe_filtered` + erp-message 的 `send_system`,在 plugin 模块启动时监听 `plugin.trigger.*` 前缀事件。
**后端改动**:
- `crates/erp-plugin/src/module.rs`: 启动事件监听(参考 erp-message 的 `start_event_listener` 模式)
- 新建 `crates/erp-plugin/src/notification.rs`:
- 订阅 `plugin.trigger.*` 事件
- 查询 trigger_events 声明,匹配事件名
- 调用 erp-message 的系统消息发送(通过 EventBus 发布 `message.send` 事件,或直接调用 message service 的 REST API
- 通知对象: 通过 manifest 声明扩展(当前简化为通知所有管理员)
### 2.3 P2 编号 reset_rule
**思路**: 参考 erp-config 的 `numbering_service.rs``maybe_reset_sequence` 模式,替换 PostgreSQL 序列为表行 + advisory lock。
**后端改动**:
- `crates/erp-plugin/src/host.rs`: 重写 `numbering_generate`
- 改用 `pg_advisory_xact_lock` + 表行序列(而非 PostgreSQL SEQUENCE
- 在事务内: 读序列行 → 检查 reset_rule 是否需要重置 → 递增/重置 → 写回
- 序列表: 使用已有的动态表模式,或新建 `plugin_numbering_sequences`
- `crates/erp-plugin/src/engine.rs`: `NumberingRule` 中 reset_rule 字段已被传递但未使用,直接在 host.rs 中消费
---
## 第三批:低优先级(配置变更通知 + 自定义视图)
### 3.1 P2 配置变更通知
**后端改动**:
- `crates/erp-plugin/src/service.rs`: `update_config` 增加 `event_bus: &EventBus` 参数,更新成功后发布 `plugin.config.updated` 事件
- `crates/erp-plugin/src/handler/plugin_handler.rs`: `update_plugin_config` handler 从 state 获取 event_bus 传入
- `crates/erp-plugin/src/engine.rs`: 订阅 `plugin.config.updated` 事件,刷新内存中的 `plugin_config`
### 3.2 P2 自定义视图
**后端改动**:
1. 新建迁移 `plugin_user_views`
2. 新建 `crates/erp-plugin/src/service/view_service.rs`: CRUD user views
3. 新建 handler: `GET/POST/PUT/DELETE /plugins/{plugin_id}/{entity}/views`
4. **前端**: PluginCRUDPage 增加视图保存/加载 UI
---
## 关键文件清单
| 文件 | 改动类型 |
|------|---------|
| `Cargo.toml` (workspace) | 新增 csv, rust_xlsxwriter 依赖 |
| `crates/erp-plugin/Cargo.toml` | 新增依赖 |
| `crates/erp-plugin/src/data_service.rs` | export format 支持, reconcile 方法 |
| `crates/erp-plugin/src/data_dto.rs` | ExportPayload enum, ReconciliationReport |
| `crates/erp-plugin/src/handler/data_handler.rs` | export 返回 Response, reconcile handler |
| `crates/erp-plugin/src/handler/market_handler.rs` | **新建** 市场 API |
| `crates/erp-plugin/src/service/market_service.rs` | **新建** 市场业务逻辑 |
| `crates/erp-plugin/src/entity/market_entry.rs` | **新建** SeaORM Entity |
| `crates/erp-plugin/src/entity/market_review.rs` | **新建** SeaORM Entity |
| `crates/erp-plugin/src/notification.rs` | **新建** 通知规则引擎 |
| `crates/erp-plugin/src/engine.rs` | LoadedPlugin 增加 metrics, 配置热更新 |
| `crates/erp-plugin/src/host.rs` | numbering_generate 重写 |
| `crates/erp-plugin/src/service.rs` | update_config 增加 event_bus |
| `crates/erp-plugin/src/module.rs` | 注册新路由, 启动通知监听 |
| `crates/erp-plugin/src/lib.rs` | 导出新模块 |
| `crates/erp-server/migration/src/m20260420_*.rs` | **新建** metrics 表迁移 |
| `apps/web/src/api/plugins.ts` | 市场前端 API |
| `apps/web/src/api/pluginData.ts` | export format 支持 |
| `apps/web/src/pages/PluginMarket.tsx` | 对接真实 API |
| `apps/web/src/pages/PluginCRUDPage.tsx` | 导出格式选择 |
## 验证计划
1. `cargo check` — 全 workspace 编译通过
2. `pnpm build` — 前端构建通过
3. 启动后端 + 前端,浏览器中验证:
- CRM customer 导出 CSV/Excel 下载
- 市场 API 返回数据curl 测试)
- 插件 health 接口返回 metrics
4. 每批完成后独立提交推送