# ERP 平台发散式探讨记录 > 日期: 2026-04-18 | 形式: 无主题发散式互动讨论 --- ## 项目当前状态快照 **已完成:** - Phase 1-6 核心平台 (core/auth/config/workflow/message/plugin) - WASM 插件系统 (Wasmtime + WIT + 动态表 + 热更新) - 2 个行业插件 (CRM 5实体 + 进销存 6实体) - Q2-Q4 成熟度路线图 (安全/架构/测试/插件生态) - 13 个 Rust crate, 37 个迁移, 15+ 前端页面 **进行中 (29 个未提交文件):** - P0 平台能力升级 (实体关系增强/字段校验/前端去硬编码) - 插件系统增强 (混合执行模型/聚合查询扩展/热更新原子回滚/Schema演进) **代码中的 TODO:** - Workflow 超时自动完成/升级逻辑 - Redis 缓存层 (data_service) --- ## 发散探讨方向 ### 方向 A: 技术纵深 — 平台能力的下一个突破点 **插件系统能力边界在哪里?** - 混合执行模型 (WASM + Host Query) 的安全边界如何界定? - 插件能否拥有自己的定时任务?事件订阅后的异步处理链? - WASM 组件之间的通信机制 — 插件 A 能否调用插件 B 的能力? - 插件市场/分发机制 — 如何做到"一键安装"? **性能与规模化的隐藏挑战:** - 动态表在海量数据下的查询性能 — 索引策略? - 多租户隔离在大规模场景下的瓶颈 — schema-per-tenant 何时比 row-level 更优? - WASM 执行的 Fuel 限制如何平衡安全与灵活性? - 热更新期间的请求如何处理 — 连接排空? ### 方向 B: 业务纵深 — ERP 领域的深度探索 **CRM 插件的完整度缺口:** - 商机/销售漏斗 — 从线索到成单的全链路 - 合同管理 — 模板、电子签章、履约跟踪 - 报价单 — 产品目录、价格策略、审批流 - 客户画像 — 标签体系、行为追踪、智能推荐 **下一个行业插件应该是什么?** - 财务 (总账/应收/应付/固定资产) - 采购 (供应商/询价/采购订单/入库) - 制造 (BOM/工单/排产/质检) - 人力 (员工/考勤/薪资/绩效) - 电商 (商品/订单/物流/售后) **跨模块业务流程:** - 从销售订单 → 采购 → 入库 → 付款 的端到端流程 - 插件间的数据如何流转?订单确认触发采购申请? - 工作流引擎如何编排跨插件流程? ### 方向 C: 体验纵深 — 前端与用户交互 **低代码/零代码的可能性:** - 插件的前端页面能否完全由 schema 驱动生成? - 可视化表单设计器 — 拖拽生成插件页面 - 自定义 Dashboard — 用户拼装自己的工作台 - 报表引擎 — 从数据到图表的可视化配置 **移动端/多端体验:** - PWA 方案 — 离线能力 + 推送通知 - Tauri 桌面端何时启动?哪些场景需要桌面端? - 小程序/企业微信集成 — 中国市场的刚需? **AI 增强交互:** - 自然语言查询 — "帮我查上个月销售额最高的 10 个客户" - 智能推荐 — 基于操作习惯的快捷入口 - 数据洞察 — 自动发现异常趋势并提醒 - AI 辅助填单 — 自动补全/智能校验 ### 方向 D: 商业纵深 — SaaS 化与商业化 **多租户高级能力:** - 租户级别的功能开关 — 不同套餐解锁不同插件 - 计量计费 — 按用户数/存储/API调用量计费 - 租户数据导出/迁移 — 保障数据主权 - 白标/品牌定制 — 租户自定义 Logo/主题 **开放平台战略:** - API Gateway + 开发者门户 - Webhook 系统 — 外部系统集成 - 第三方插件审核/上架流程 - 合作伙伴生态 — ISV 开发行业插件 ### 方向 E: 团队与工程效率 **开发体验提升:** - 插件开发脚手架 CLI — `erp-plugin create crm` - 本地开发热重载 — 改 WASM 代码即时生效 - 插件调试工具 — 断点/日志/性能分析 - 一键生成插件 CRUD — 从 schema 到完整页面 **DevOps 与运维:** - 蓝绿部署 / 金丝雀发布策略 - 数据库迁移的零停机方案 - 多环境管理 (dev/staging/prod) - 监控告警体系 (APM + 日志聚合) --- ## 讨论记录 > 以下是互动讨论的要点,按时间顺序记录 ### Round 1: "造一个财务插件来验证平台" — 立刻暴露了跨插件数据引用的缺失 **用户意图:** 希望通过搭建第二个行业插件(财务/应收),验证基座和插件系统,特别是与 CRM 插件的数据交互。 **已发现的系统缺陷 — 跨插件数据引用完全不支持:** | 能力 | 现状 | 影响 | |------|------|------| | `ref_entity` 跨插件引用 | 仅限当前插件表空间 | 财务插件的 `customer_id` 无法声明指向 CRM 的 customer | | Host API 跨插件查询 | `db-query` 无 plugin_id 参数 | WASM 插件无法查询其他插件数据 | | PluginRelation 跨插件 | `entity` 字段无插件限定 | 无法声明跨插件的关联关系 | | 前端 entity_select | 仅加载当前插件数据源 | 下拉框无法显示其他插件的实体列表 | | 引用完整性校验 | 仅校验当前插件表空间 | 跨插件的外键约束无法生效 | **进销存插件已有的"绕路":** `customer_id` 作为裸 UUID 存在,没有 `ref_entity` 声明 — 证明这是一个已知的痛点。 **唯一现有机制:** EventBus 事件广播(松耦合通知),但无法支持同步查询或声明式引用。 **财务插件与 CRM 的理想交互场景:** ``` CRM.customer ──引用──→ Finance.invoice.customer_id (外键 + 下拉选择) CRM.opportunity ──引用──→ Finance.sales_order.opportunity_id CRM.contact ──引用──→ Finance.quote.contact_id ``` **要实现这些,需要改造:** 1. `manifest.rs` — PluginField/PluginRelation 增加 `ref_plugin` 字段 2. `data_service.rs` — validate_ref_entities 支持跨插件表名解析 3. `plugin.wit` + `host.rs` — 新增跨插件查询 API 4. `dynamic_table.rs` — 表名解析支持目标 plugin_id 5. 前端 entity_select — 支持加载其他插件数据源 6. 权限模型 — 跨插件数据访问控制 ### Round 2: 方案收敛 — 软引用 + 实体注册表 + 优雅降级 **决策记录:** | 问题 | 决策 | 理由 | |------|------|------| | 引用模式 | **声明式** (plugin.toml) | 与现有 schema-driven 模式一致,插件作者零代码 | | 依赖严格度 | **完全独立,无硬依赖** | SaaS 用户必须能自由组合/卸载插件 | | 实体归属 | **插件自拥有,平台注册表发现** | 不改变现有模型,通过注册表实现运行时发现 | | 悬空引用 | **软警告 + 后台对账** | 永不阻塞用户操作,对账工具引导修复 | **架构设计:** ``` ┌────────────────────────────────────────────────┐ │ Layer 3: Plugin (财务/采购/制造...) │ │ - optional_dependencies 声明 │ │ - ref_scope = "external" 跨插件引用字段 │ ├────────────────────────────────────────────────┤ │ Layer 2: Entity Registry (平台实体注册表) │ │ - 插件安装时注册实体、卸载时标记 inactive │ │ - 查询时动态发现源插件 │ │ - 悬空引用检测 + 对账报告 │ ├────────────────────────────────────────────────┤ │ Layer 1: Plugin System (现有基础设施) │ │ - 动态表、Host API、EventBus 不变 │ │ - 新增 Entity Registry 接入点 │ └────────────────────────────────────────────────┘ ``` **plugin.toml 声明示例:** ```toml [dependencies.crm] optional = true description = "客户管理 — 自动关联客户数据" [[schema.entities.fields]] name = "customer_id" field_type = "uuid" ref_entity = "customer" ref_scope = "external" ref_display_field = "name" ref_fallback_label = "外部客户" ``` **运行时行为:** | 源插件状态 | 写入 | 读取 | 展示 | |-----------|------|------|------| | 已安装 | 强校验 | JOIN 富化 | ✅ 绿色链接 "张三" | | 未安装 | 无校验 | 原始 UUID | ⬜ 灰色 "外部客户" | | 刚重新启用 | 新写入强校验 | 后台对账 | ⚠️ 黄色警告 (悬空) | **悬空引用处理 (CRM 重新启用时):** 1. 后台扫描所有 `ref_scope=external` 的字段 2. 生成引用对账报告(有效/悬空分类) 3. 前端提示用户逐条处理(映射/清空/忽略) 4. 永不硬阻塞用户操作 **需改造的 6 个点:** 1. `manifest.rs` — 新增 `ref_scope`, `ref_display_field`, `ref_fallback_label`, `dependencies` 段 2. `entity_registry` (新模块) — 实体注册/发现/inactive 标记 3. `data_service.rs` — validate_ref_entities 支持运行时发现 4. `host.rs` + `plugin.wit` — 新增 resolve-ref-entity API 5. 前端 `entity_select` — 检测注册表,有源插件加载下拉,无则降级 6. 对账工具 — 后台扫描 + 前端对账 UI ### Round 3: 插件生态与商业化 — 技术优先路径 **用户选择:** 技术优先 → 市场,先做好平台能力再考虑商业模式。 **发现的三大技术缺口:** 1. **插件质量保障** — 安全扫描、性能基准、兼容性检测、运行时监控全部缺失 2. **插件配置与数据管理** — 导入导出、打印模板、配置 UI、自定义视图全部缺失 3. **插件市场/商店** — 浏览、发现、一键安装、评分全部缺失 **决策: 这些能力应该是平台级通用服务,不是插件各自实现。** 新增架构层: ``` 插件 → Plugin Platform Services → Plugin System → ERP Core ↑ 导入导出 / 打印 / 配置 / 视图 / 通知 / 编号 ``` **平台 P1 通用服务清单:** | 服务 | 接入方式 | 财务插件示例 | |------|---------|-------------| | 数据导入导出 | plugin.toml 声明 importable/exportable | 导入客户清单、导出发票明细 | | 打印模板 | 模板文件 + schema 映射 | 发票 PDF、收款凭证 | | 插件配置 UI | plugin.toml 声明 settings | 税率表、付款条件、发票前缀 | | 自定义视图 | 用户保存列/筛选配置 | 财务看不同列、销售看不同列 | | 通知规则 | 插件定义触发事件 | 发票逾期 → 通知负责人 | | 编号规则 | 复用 erp-config 的编号服务 | INV-2026-0001 | ### Round 4: 收敛 — 全部整合为一份设计规格 用户确认将所有讨论成果写入一份"插件平台演进设计规格"文档。 --- ## 设计规格: ERP 插件平台演进路线图 > 基于 2026-04-18 发散式探讨的成果,涵盖跨插件引用、平台通用服务、质量保障、插件市场四个维度。 ### 1. 背景与动机 ERP 平台已完成 Phase 1-6 核心开发和 Q2-Q4 成熟度路线图。当前有两个行业插件(CRM + 进销存)运行在 WASM 插件系统上。但通过分析发现: - **跨插件数据引用完全不支持** — 进销存的 `customer_id` 只能存裸 UUID - **插件无通用业务能力** — 导入导出/打印/配置/视图每个插件都要自己实现 - **无质量保障机制** — 第三方插件的安全性和性能无法保证 - **无发现和分发渠道** — 用户无法自助发现和安装插件 目标:通过搭建财务/应收插件来验证和推动这些平台能力的实现。 ### 2. 跨插件数据引用系统 #### 2.1 设计原则 - **插件完全独立** — 任何插件可独立安装/卸载,不受其他插件影响 - **声明式配置** — 跨插件引用通过 plugin.toml 声明,插件作者零代码 - **优雅降级** — 源插件不存在时功能降级,不阻塞用户操作 - **软警告** — 外部引用问题永远是警告,不是错误 #### 2.2 实体注册表 (Entity Registry) **数据结构:** ``` entity_registry: - entity_name: string # 实体名 (如 "customer") - plugin_id: string # 注册该实体的插件 ID - display_fields: string[] # 用于下拉显示的字段列表 - search_fields: string[] # 用于搜索的字段列表 - status: active | inactive # 插件卸载时标记 inactive - registered_at: timestamp - tenant_id: uuid # 多租户隔离 ``` **生命周期:** - 插件安装 → 注册所有 entities 到 registry - 插件启用 → status = active - 插件禁用 → status = inactive(数据保留) - 插件卸载 → status = inactive + 标记为 orphaned #### 2.3 plugin.toml 扩展 ```toml # 可选依赖声明 [dependencies.crm] optional = true description = "客户管理 — 自动关联客户数据,未安装时客户字段为手动输入" [dependencies.inventory] optional = true description = "进销存 — 自动关联商品数据" # 跨插件引用字段 [[schema.entities.fields]] name = "customer_id" field_type = "uuid" display_name = "客户" ref_entity = "customer" # 目标实体名 ref_scope = "external" # "internal" (默认) | "external" ref_display_field = "name" # 下拉框显示字段 ref_search_fields = ["name", "phone"] # 搜索字段 ref_fallback_label = "外部客户" # 降级时显示文本 ``` #### 2.4 运行时行为 **写入时校验:** ``` IF ref_scope == "external": registry = EntityRegistry.find("customer") IF registry.status == "active": 强校验: customer_id 必须存在于 registry.plugin_id 的对应表中 ELSE: 无校验: 接受任意 UUID ``` **读取时富化:** ``` IF ref_scope == "external" AND registry.status == "active": JOIN plugin_{registry.plugin_id}_{ref_entity} 获取 display_field 前端显示: "张三 (CRM)" (绿色可点击链接) ELIF ref_scope == "external" AND registry.status == "inactive": 前端显示: "外部客户 ({uuid})" (灰色) ``` **悬空引用处理:** ``` ON plugin.activate: 1. 后台扫描所有 ref_scope="external" 且指向本插件实体的字段 2. 验证每个 UUID 是否存在于本插件表中 3. 生成对账报告: { valid: N, dangling: M, details: [...] } 4. 前端展示对账结果,用户逐条处理 ``` #### 2.5 需要改造的文件 | 文件 | 改动 | 复杂度 | |------|------|--------| | `crates/erp-plugin/src/manifest.rs` | 新增 `ref_scope`, `ref_display_field`, `ref_search_fields`, `ref_fallback_label`; 新增 `DependenciesSection` | 低 | | `crates/erp-plugin/src/entity_registry.rs` (新) | 实体注册/发现/inactive 标记/对账 | 中 | | `crates/erp-plugin/src/data_service.rs` | `validate_ref_entities` 支持运行时发现外部引用 | 中 | | `crates/erp-plugin/src/host.rs` | 新增 `resolve_ref_entity` Host API | 中 | | `crates/erp-plugin/wit/plugin.wit` | 新增 `resolve-ref-entity` 接口 | 低 | | `crates/erp-plugin/src/service.rs` | 插件安装/卸载时维护 Entity Registry | 中 | | `apps/web/src/` 前端 | entity_select 组件支持跨插件数据源 + 降级显示 + 对账 UI | 高 | ### 3. 插件平台通用服务层 (P1) #### 3.1 数据导入导出服务 **设计思路:** 插件在 plugin.toml 中声明哪些实体支持导入导出,平台提供统一的导入导出 UI 和引擎。 ```toml # plugin.toml 中的声明 [[schema.entities]] name = "invoice" display_name = "发票" importable = true exportable = true import_template = "invoice_import_template.xlsx" # 可选: 自定义导入模板 [[schema.entities]] name = "payment" display_name = "收款" importable = true exportable = true ``` **平台能力:** - 自动生成导入模板(基于 schema entities fields) - Excel/CSV 解析 + schema 字段校验 - 批量写入(支持事务 + 错误行级报告) - 导出为 Excel/CSV(支持筛选条件) - 导入历史记录 + 回滚 **实现位置:** 新增 `crates/erp-plugin/src/import_export.rs`,前端新增 `ImportExportModal` 通用组件。 #### 3.2 打印模板引擎 **设计思路:** 平台提供 HTML → PDF 的模板渲染能力,插件定义模板和字段映射。 ```toml # plugin.toml 中的声明 [[templates]] name = "invoice_pdf" display_name = "发票" entity = "invoice" format = "pdf" template_file = "templates/invoice.html" # HTML 模板 ``` **平台能力:** - HTML 模板渲染 → PDF 下载 - 模板变量替换(基于实体字段) - 租户级模板自定义(覆盖默认模板) - 打印预览 **实现位置:** 后端使用 `wkhtmltopdf` 或 `headless-chrome` 渲染,前端新增 `PrintPreviewModal` 组件。 #### 3.3 插件配置 UI **设计思路:** 插件在 plugin.toml 中声明配置项,平台自动生成配置页面。 ```toml # plugin.toml 中的声明 [settings] [[settings.fields]] name = "default_tax_rate" display_name = "默认税率" field_type = "number" default_value = 0.13 [[settings.fields]] name = "invoice_prefix" display_name = "发票前缀" field_type = "text" default_value = "INV" [[settings.fields]] name = "payment_terms" display_name = "默认付款条件" field_type = "select" options = ["net_15", "net_30", "net_60", "cod"] default_value = "net_30" ``` **平台能力:** - 根据 settings 声明自动生成配置表单 - 配置数据存储在 `plugin_settings` 表(tenant_id + plugin_id + key/value) - 配置变更时通知插件(通过事件) - 支持配置权限控制(仅管理员可改) #### 3.4 自定义视图 **设计思路:** 用户可以保存列表页的列配置和筛选条件。 ``` user_views: - id: uuid - user_id: uuid - plugin_id: string - entity_name: string - view_name: string - columns: string[] # 显示的列 - filters: json # 筛选条件 - sort: json # 排序条件 - is_default: boolean ``` **平台能力:** - 列表页支持列拖拽排序、显示/隐藏 - 筛选条件保存/加载 - 每个用户可以有多个视图 - 支持共享视图给同角色用户 #### 3.5 通知规则 **设计思路:** 插件在 plugin.toml 中声明可触发的事件,平台提供通知规则配置 UI。 ```toml # plugin.toml 中的声明 [[trigger_events]] name = "invoice.overdue" display_name = "发票逾期" description = "发票超过付款期限未收款" [[trigger_events]] name = "payment.received" display_name = "收款确认" ``` **平台能力:** - 规则引擎: WHEN event THEN notify [user/role/department] - 复用 erp-message 的通知渠道 - 租户级规则配置 - 通知模板自定义 #### 3.6 编号规则 (已有基础扩展) **设计思路:** 复用 erp-config 的编号规则服务,扩展为插件可接入。 ```toml # plugin.toml 中的声明 [[numbering]] entity = "invoice" prefix = "INV" format = "{PREFIX}-{YEAR}-{SEQ:4}" reset_rule = "yearly" # daily/monthly/yearly/never ``` ### 4. 插件质量保障 #### 4.1 上传时校验 ``` 插件上传 → Schema 校验 → WASM 二进制验证 → 安全扫描 → 性能基准 → 发布/拒绝 ``` | 阶段 | 校验内容 | 现状 | |------|---------|------| | Schema 校验 | plugin.toml 格式、字段类型、权限码一致性 | ✅ 已有部分 | | WASM 验证 | 二进制格式、WIT 兼容性、导出函数检查 | ✅ 已有 | | 安全扫描 | 动态表 SQL 注入风险、Fuel 耗尽、内存泄漏 | ❌ 缺失 | | 性能基准 | 标准 CRUD 操作在 N 条数据下的响应时间 | ❌ 缺失 | | 兼容性 | 平台版本匹配、依赖插件版本兼容 | ❌ 缺失 | #### 4.2 运行时监控 ``` plugin_runtime_metrics: - plugin_id: string - error_rate: float # 24h 错误率 - avg_response_ms: float # 平均响应时间 - fuel_consumption: float # 平均 Fuel 消耗 - memory_peak_mb: float # 内存峰值 - active_instances: int # 活跃实例数 ``` **告警规则:** - 错误率 > 5% → 警告 - 平均响应 > 2s → 警告 - Fuel 消耗异常 → 警告 - 内存持续增长 → 疑似泄漏 ### 5. 插件市场/商店 #### 5.1 功能范围 | 功能 | 说明 | |------|------| | 插件目录 | 按行业/功能分类浏览 | | 搜索 | 按名称/标签/行业搜索 | | 详情页 | 截图、演示、功能描述、权限说明 | | 一键安装 | 上传 → 自动安装 → 配置 → 启用 | | 评分/评论 | 用户评分和使用反馈 | | 版本管理 | 版本列表、更新日志、回滚 | | 依赖提示 | 安装时提示可选依赖("推荐配合 CRM 使用") | #### 5.2 技术实现 - 后端: 新增 `plugin_store` 表 + API - 前端: 新增 `PluginStore` 页面 - 管理端: 管理员审核/上架/下架 ### 6. 验证计划 — 财务/应收插件 #### 6.1 实体设计 | 实体 | 字段概要 | 跨插件引用 | |------|---------|-----------| | invoice (发票) | 编号/客户/金额/税额/状态/到期日 | customer_id → CRM.customer | | invoice_line (发票行) | 发票/商品/数量/单价/税额 | product_id → Inventory.product | | payment (收款) | 发票/金额/方式/日期/状态 | invoice_id → 本插件内部 | | quote (报价单) | 编号/客户/有效期/状态 | customer_id → CRM.customer | | quote_line (报价行) | 报价单/商品/数量/单价 | product_id → Inventory.product | #### 6.2 验证矩阵 | 能力 | 验证方式 | 预期结果 | |------|---------|---------| | 跨插件引用 (CRM 安装) | 创建发票时选择客户 | entity_select 下拉显示 CRM 客户列表 | | 跨插件引用 (CRM 卸载) | 创建发票时输入客户 | 降级为文本输入,不阻塞 | | 悬空引用对账 | CRM 卸载→创建发票→重新安装 CRM | 对账报告显示悬空引用,用户可修复 | | 数据导入 | 导入 Excel 客户清单 | 解析+校验+批量写入 | | 数据导出 | 导出发票列表为 Excel | 筛选+下载 | | 打印模板 | 打印发票 PDF | HTML→PDF 渲染 | | 插件配置 | 设置税率/发票前缀 | 自动生成的配置页面 | | 编号规则 | 创建发票自动编号 | INV-2026-0001 | | 通知规则 | 发票逾期通知 | 规则引擎触发通知 | | 独立安装 | 不安装 CRM 单独安装财务 | 所有功能正常,客户字段降级 | ### 7. 实施优先级 ``` P0 (已完成/进行中): P0 平台能力升级 (实体关系增强/字段校验/前端去硬编码) 插件系统增强 (混合执行模型/聚合查询/热更新回滚/Schema演进) P1 (跨插件引用): Entity Registry + ref_scope 扩展 + 前端 entity_select 改造 这是所有后续能力的基础 P2 (平台通用服务): 数据导入导出 → 插件配置 UI → 编号规则扩展 → 通知规则 按业务迫切程度排序 P3 (质量保障): 上传时安全扫描 → 性能基准 → 运行时监控 逐步建立信任体系 P4 (插件市场): 插件目录 → 一键安装 → 版本管理 → 评分评论 商业化的最后一块拼图 验证: 财务/应收插件贯穿 P1-P2,每完成一个 P 就用财务插件验证 ``` ### 8. 风险与缓解 | 风险 | 影响 | 缓解措施 | |------|------|---------| | Entity Registry 查询性能 | 每次数据操作都要查注册表 | 内存缓存 + DashMap,注册表数据量极小 | | 悬空引用数据量过大 | 对账扫描耗时长 | 异步后台任务 + 分批处理 + 进度条 | | Excel 导入内存占用 | 大文件解析 OOM | 流式解析 + 批量提交 + 文件大小限制 | | 打印模板安全 | 模板注入攻击 | 沙箱渲染 + 变量白名单 | | 插件市场审核成本 | 人工审核效率低 | 自动化扫描 + 人工抽查 + 社区举报 |