# 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` 参数 - 内部新增 `export_csv()` 和 `export_xlsx()` 私有方法,返回 `Vec` bytes - format 为空/json 时返回原 JSON;csv/xlsx 时返回二进制 - 返回类型改为 enum `ExportPayload { Json(Vec), Csv(Vec), Xlsx(Vec) }` 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 }` - `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>` 字段 - `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. 每批完成后独立提交推送