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

8.6 KiB
Raw Blame History

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: 添加 csvrust_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_entriesplugin_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_entrieswasm_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.rsmaybe_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. 每批完成后独立提交推送