8.6 KiB
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;前端同时支持。
后端改动:
Cargo.toml(workspace): 新增csv = "1"和rust_xlsxwriter = "0.82"crates/erp-plugin/Cargo.toml: 添加csv和rust_xlsxwriter依赖crates/erp-plugin/src/data_service.rs:export()签名增加format: Option<String>参数- 内部新增
export_csv()和export_xlsx()私有方法,返回Vec<u8>bytes - format 为空/json 时返回原 JSON;csv/xlsx 时返回二进制
- 返回类型改为 enum
ExportPayload { Json(Vec<Value>), Csv(Vec<u8>), Xlsx(Vec<u8>) }
crates/erp-plugin/src/data_dto.rs: ExportParams 的 format 字段已有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
- JSON:
- 返回类型改为
axum::response::Response(不是 Json<>)
- 前端
pluginData.ts:exportPluginData支持 format 参数,CSV/XLSX 时用responseType: 'blob' - 前端
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 handlercrates/erp-plugin/src/entity/market_entry.rs: SeaORM Entitycrates/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: 新增 DTOcrates/erp-plugin/src/handler/data_handler.rs: 新增reconcile_refshandlercrates/erp-plugin/src/module.rs: 注册路由POST /plugins/{plugin_id}/reconcile
前端: 暂不实现完整对账 UI(低优先级),仅提供 API 供后续使用。
第二批:中优先级(运行时监控 + 通知规则 + 编号 reset)
2.1 P3 运行时监控
后端改动:
- 新建迁移
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
crates/erp-plugin/src/engine.rs:LoadedPlugin新增metrics: Arc<RwLock<RuntimeMetrics>>字段execute_wasm中采集指标: 记录开始时间、成功/失败计数、fuel 消耗- 定期持久化到 DB(每 10 次调用或 60 秒)
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_confighandler 从 state 获取 event_bus 传入crates/erp-plugin/src/engine.rs: 订阅plugin.config.updated事件,刷新内存中的plugin_config
3.2 P2 自定义视图
后端改动:
- 新建迁移
plugin_user_views表 - 新建
crates/erp-plugin/src/service/view_service.rs: CRUD user views - 新建 handler:
GET/POST/PUT/DELETE /plugins/{plugin_id}/{entity}/views - 前端: 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 |
导出格式选择 |
验证计划
cargo check— 全 workspace 编译通过pnpm build— 前端构建通过- 启动后端 + 前端,浏览器中验证:
- CRM customer 导出 CSV/Excel 下载
- 市场 API 返回数据(curl 测试)
- 插件 health 接口返回 metrics
- 每批完成后独立提交推送