Files
erp/plans/skill-cosmic-pancake.md
iven 841766b168
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled
fix(用户管理): 修复用户列表页面加载失败问题
修复用户列表页面加载失败导致测试超时的问题,确保页面元素正确渲染
2026-04-19 08:46:28 +08:00

23 KiB
Raw Blame History

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 声明示例:

[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 扩展

# 可选依赖声明
[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 和引擎。

# 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 的模板渲染能力,插件定义模板和字段映射。

# plugin.toml 中的声明
[[templates]]
name = "invoice_pdf"
display_name = "发票"
entity = "invoice"
format = "pdf"
template_file = "templates/invoice.html"  # HTML 模板

平台能力:

  • HTML 模板渲染 → PDF 下载
  • 模板变量替换(基于实体字段)
  • 租户级模板自定义(覆盖默认模板)
  • 打印预览

实现位置: 后端使用 wkhtmltopdfheadless-chrome 渲染,前端新增 PrintPreviewModal 组件。

3.3 插件配置 UI

设计思路: 插件在 plugin.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_settingstenant_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。

# 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 的编号规则服务,扩展为插件可接入。

# 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 流式解析 + 批量提交 + 文件大小限制
打印模板安全 模板注入攻击 沙箱渲染 + 变量白名单
插件市场审核成本 人工审核效率低 自动化扫描 + 人工抽查 + 社区举报