spec.md 22 KB


title: 公式能力二期扩展 version: 1.0 date_created: 2026-06-13 last_updated: 2026-06-14 tags: ['formula', 'lookup', 'cross-object', 'debugger', 'function-market', 'condition-rule'] status: done complexity: high

base_change: code-copilot/changes/formula-capability-extension/spec.md

背景

公式能力 V1 已建立字段级公式体系,覆盖 CALC、AGGREGATE、CONDITIONAL、STORED/VIRTUAL、公式预览、语法校验、DAG 依赖分析、循环依赖检测和基础函数列表。下一阶段需要从“单对象字段计算”升级到“对象图公式 + 可观测性 + 可配置函数生态”,支撑更复杂的低代码业务规则。

本次变更规划以下能力:

  • LOOKUP 公式
  • 跨对象公式
  • 自定义函数
  • 公式调试器
  • 执行日志
  • Dependency 可视化
  • 函数市场
  • 条件规则设计器

1. 目标与成功标准

用户价值

  • 业务人员可以通过 LOOKUP / 跨对象公式读取关联对象字段,减少冗余字段和手工同步。
  • 设计人员可以通过调试器、执行日志和依赖图快速定位公式错误。
  • 平台管理员可以治理函数能力,按需启用内置函数、自定义函数和市场函数。
  • 普通配置人员可以通过条件规则设计器生成条件公式,减少手写表达式门槛。

业务目标

  • 将公式能力从“字段计算”扩展为“业务对象关系图计算”。
  • 为复杂公式上线前后提供可解释、可追踪、可审计的运维闭环。
  • 为后续 AI 公式生成、规则推荐、函数模板市场打基础。

成功判定

  • 公式执行失败时,可以在执行日志中看到输入、输出、耗时、错误原因和 traceId。
  • 公式调试器可以展示样例数据、依赖字段值、执行顺序和每一步结果。
  • 依赖图可以展示对象内和跨对象依赖,并高亮循环路径。
  • 字段可以配置 LOOKUP 公式读取一跳关联对象字段。
  • 跨对象公式支持受控的一跳路径表达式,并在发布时进行对象图依赖校验。
  • 函数列表不再硬编码,函数市场可查询、安装、启用、禁用函数。
  • 条件规则设计器可以生成 Aviator 表达式,并与公式配置双向同步。

2. 代码现状

2.1 已有能力

能力 现状
公式领域模型 FormulaConfig, AggregateConfig, ConditionConfig, FormulaType, FormulaMode
表达式执行 ExpressionExecutor, FormulaExecutionEngine
聚合公式 AggregateEngine, DbAggregateDataProvider
依赖分析 FormulaDependencyAnalyzer, DependencyAnalysisResult
校验服务 FormulaValidationService, FormulaPublishValidator
REST API /api/ai/business/formula/validate, /preview, /dependency, /functions
前端配置 BusinessFieldPropertyPanel.vue 内嵌公式配置、校验和预览
前端 API forge-admin-ui/src/api/formula.js

2.2 当前限制

  • /formula/functions 返回静态内置函数列表,无法治理函数状态、版本和市场来源。
  • /formula/dependency 返回字段依赖信息,但没有图形化节点/边结构,也不覆盖跨对象依赖。
  • ExecutionResult 只返回当前执行结果,不持久化执行日志,不支持运行后审计。
  • 公式预览只能做整体结果预览,不能展示每个依赖字段的执行过程。
  • V1 明确不支持跨对象公式引用。
  • 条件公式仍以表达式输入为主,普通用户配置门槛较高。

3. 分阶段范围

Phase 1: 可观测性与调试底座

优先级:P0

包含:

  • 执行日志
  • 公式调试器
  • Dependency 可视化

目标:

  • 先让公式“可解释、可追踪、可排错”,再扩展 LOOKUP 和跨对象引用。
  • 所有后续公式能力必须接入同一套日志、调试和依赖图结构。

Phase 2: LOOKUP 与跨对象公式

优先级:P1

包含:

  • LOOKUP 公式
  • 一跳跨对象公式
  • 跨对象依赖校验
  • 跨对象公式日志与调试接入

目标:

  • 在对象关系配置明确的前提下读取关联对象字段。
  • 发布时发现跨对象循环依赖和非法路径。
  • 先支持一跳关系,暂不开放任意深度路径。

Phase 3: 条件规则设计器

优先级:P2

包含:

  • 条件规则 JSON AST
  • 表达式生成器
  • 条件公式 UI 改造
  • 调试器展示条件节点命中情况

目标:

  • 普通配置人员不手写表达式即可配置条件公式。
  • 保留表达式模式,支持高级用户继续手写。

Phase 4: 自定义函数与函数市场

优先级:P3

包含:

  • 函数注册中心
  • 自定义函数元数据
  • 函数市场
  • 函数安装、启用、禁用、版本管理

目标:

  • 将公式函数从静态列表升级为可治理、可扩展、可审计的函数生态。
  • 第一版只支持 Java Bean 注册和受控配置,不开放任意脚本执行。

4. 非目标

  • 不在本阶段开放任意 SQL 函数。
  • 不允许用户函数访问文件、网络、系统命令或环境变量。
  • 不支持无限层级跨对象路径;首期只支持一跳,后续再评估多跳。
  • 不改变 V1 公式配置兼容性;已有 CALC / AGGREGATE / CONDITIONAL 配置必须继续可用。
  • 不替换 Aviator 表达式引擎。
  • 不把公式引擎改造成通用工作流引擎。
  • 不在本阶段实现 AI 自动生成公式。

5. Requirements, Constraints & Guidelines

5.1 执行日志

  • REQ-LOG-001: 每次公式运行必须可选记录执行日志,包含 objectCode、recordId、fieldCode、formulaType、mode、expression、inputSnapshot、outputValue、success、errorMessage、elapsedMs、traceId。
  • REQ-LOG-002: 公式异常必须记录 ERROR 级日志和业务执行日志,不能静默吞掉。
  • REQ-LOG-003: 日志记录必须支持按 objectCode、recordId、fieldCode、success、traceId、时间范围分页查询。
  • REQ-LOG-004: 日志中涉及手机号、身份证、银行卡、Token、AK/SK 等敏感值必须脱敏。
  • REQ-LOG-005: 日志开关必须可配置,默认记录失败日志和调试日志,不强制记录所有成功日志。

5.2 公式调试器

  • REQ-DBG-001: 调试器支持输入 sampleValues 并运行单个字段公式或当前对象全部公式。
  • REQ-DBG-002: 调试结果必须返回 executionPlan、steps、contextBefore、contextAfter、result、errors。
  • REQ-DBG-003: 每一步必须显示字段编码、公式类型、表达式、输入变量、输出值、耗时和错误。
  • REQ-DBG-004: CONDITIONAL 公式调试时必须展示条件表达式结果和 true/false 分支选择。
  • REQ-DBG-005: LOOKUP / 跨对象公式调试时必须展示关联对象、关联字段、查询条件和返回字段。

5.3 Dependency 可视化

  • REQ-DAG-001: 依赖分析接口必须返回图结构 nodes / edges。
  • REQ-DAG-002: 节点类型至少包含 FIELD、FORMULA、OBJECT、FUNCTION、RELATION。
  • REQ-DAG-003: 边类型至少包含 DEPENDS_ON、LOOKUP、CROSS_OBJECT、AGGREGATE、FUNCTION_CALL。
  • REQ-DAG-004: 检测到循环依赖时必须返回 cyclePath,并在前端高亮。
  • REQ-DAG-005: 图结构必须兼容对象内依赖和跨对象依赖。

5.4 LOOKUP 公式

  • REQ-LOOKUP-001: FormulaType 新增 LOOKUP。
  • REQ-LOOKUP-002: LOOKUP 公式必须基于已配置的业务对象关系或显式 lookup 配置,禁止自由拼接表名。
  • REQ-LOOKUP-003: LOOKUP 支持根据当前对象字段值查询目标对象字段值。
  • REQ-LOOKUP-004: LOOKUP 首期支持一跳关系,不支持任意多跳。
  • REQ-LOOKUP-005: LOOKUP 查询必须遵守租户隔离和数据权限规则。
  • REQ-LOOKUP-006: LOOKUP 失败时按公式错误处理策略降级,并写入执行日志。

5.5 跨对象公式

  • REQ-XOBJ-001: 跨对象公式支持一跳路径表达式,例如 customer.levelowner.realName
  • REQ-XOBJ-002: 跨对象路径必须能解析到已发布对象关系,不能引用不存在的对象、关系或字段。
  • REQ-XOBJ-003: 发布时必须进行对象图 DAG 校验,检测跨对象循环依赖。
  • REQ-XOBJ-004: STORED 跨对象公式必须定义重算策略:同步重算、异步队列或手动重算,首期默认异步队列。
  • REQ-XOBJ-005: 查询时 VIRTUAL 跨对象公式必须避免 N+1 查询,支持批量预取。

5.6 自定义函数

  • REQ-FN-001: 函数必须有唯一 functionCode、displayName、category、description、argumentSchema、returnType、example、status。
  • REQ-FN-002: 函数实现首期支持 Java Bean 注册,不开放任意脚本。
  • REQ-FN-003: 函数执行必须有超时限制和异常隔离。
  • REQ-FN-004: 函数参数必须按 argumentSchema 校验。
  • REQ-FN-005: 函数调用必须接入公式校验、预览、调试器和执行日志。

5.7 函数市场

  • REQ-MKT-001: 函数市场支持分页、搜索、分类筛选、查看详情。
  • REQ-MKT-002: 函数支持安装、启用、禁用和版本回滚。
  • REQ-MKT-003: 市场函数必须标记来源:BUILTIN、SYSTEM、TENANT、MARKET。
  • REQ-MKT-004: 未启用函数不能被新公式引用;已保存旧公式引用禁用函数时,发布必须给出阻断错误。
  • REQ-MKT-005: 函数市场操作必须记录操作日志。

5.8 条件规则设计器

  • REQ-RULE-001: 条件规则设计器输出 JSON AST,并同步生成 Aviator 表达式。
  • REQ-RULE-002: 支持 AND / OR 分组、字段选择、操作符选择和值输入。
  • REQ-RULE-003: 支持操作符 EQ、NE、GT、GTE、LT、LTE、IN、NOT_IN、CONTAINS、STARTS_WITH、ENDS_WITH、IS_NULL、NOT_NULL。
  • REQ-RULE-004: 条件公式支持在表达式模式和规则设计模式之间切换。
  • REQ-RULE-005: 调试器必须展示每个规则节点是否命中。

6. 数据模型与配置协议

6.1 FormulaConfig 扩展

兼容 V1 配置,新增 lookup、crossObject、rule、functionRefs 元数据。

{
  "type": "LOOKUP",
  "mode": "VIRTUAL",
  "expression": "",
  "dependsOn": ["ownerUserId"],
  "lookup": {
    "relationCode": "customer_owner",
    "targetObjectCode": "sys_user",
    "sourceField": "ownerUserId",
    "targetField": "id",
    "returnField": "realName",
    "notFoundValue": null
  },
  "crossObject": null,
  "rule": null,
  "functionRefs": []
}

6.2 LOOKUP 配置

字段 类型 必填 说明
relationCode String 对象关系编码
targetObjectCode String 目标对象编码
sourceField String 当前对象关联字段
targetField String 目标对象匹配字段
returnField String 返回字段
notFoundValue Object 未命中时返回值

6.3 跨对象路径配置

{
  "path": "customer.level",
  "relationCode": "order_customer",
  "targetObjectCode": "crm_customer",
  "returnField": "level",
  "recomputeMode": "ASYNC"
}

6.4 条件规则 AST

{
  "operator": "AND",
  "children": [
    { "field": "amount", "op": "GT", "value": 1000 },
    { "field": "status", "op": "EQ", "value": "ACTIVE" }
  ]
}

生成表达式:

amount > 1000 && status == 'ACTIVE'

6.5 执行日志表

新增 Flyway 脚本,建议表名:ai_formula_execution_log

核心字段:

字段 类型 说明
id bigint 主键
tenant_id bigint 租户
trace_id varchar(64) 本次公式执行链路 ID
object_code varchar(64) 对象编码
record_id varchar(64) 记录 ID
field_code varchar(64) 公式字段编码
formula_type varchar(32) 公式类型
formula_mode varchar(32) 计算模式
expression text 表达式或配置摘要
input_snapshot json 输入快照,脱敏后存储
output_value text 输出值摘要
success tinyint 是否成功
error_message text 错误信息
elapsed_ms bigint 耗时
create_by bigint 创建人
create_time datetime 创建时间
create_dept bigint 创建部门
update_by bigint 更新人
update_time datetime 更新时间

6.6 函数注册表

建议新增:

  • ai_formula_function
  • ai_formula_function_version
  • ai_formula_function_install

函数注册核心字段:

字段 类型 说明
function_code varchar(64) 函数编码
display_name varchar(128) 展示名称
category varchar(64) 分类
source_type varchar(32) BUILTIN / SYSTEM / TENANT / MARKET
argument_schema json 参数 schema
return_type varchar(32) 返回类型
example text 示例
status varchar(32) ENABLED / DISABLED

7. API 设计

7.1 公式调试

方法 路径 说明
POST /api/ai/business/formula/debug 调试单公式或当前对象全部公式

请求示例:

{
  "objectCode": "crm_order",
  "fieldCode": "totalAmount",
  "recordId": "1001",
  "sampleValues": {
    "price": 100,
    "quantity": 3
  },
  "includeDependencyGraph": true
}

响应核心:

{
  "success": true,
  "traceId": "FML-20260613-0001",
  "executionPlan": ["amount", "discount", "totalAmount"],
  "steps": [
    {
      "fieldCode": "totalAmount",
      "formulaType": "CALC",
      "expression": "price * quantity",
      "input": { "price": 100, "quantity": 3 },
      "output": 300,
      "elapsedMs": 4,
      "success": true
    }
  ],
  "errors": []
}

7.2 执行日志

方法 路径 说明
GET /api/ai/business/formula/log/page 分页查询执行日志
GET /api/ai/business/formula/log/{id} 查询日志详情

查询参数:

  • pageNum
  • pageSize
  • objectCode
  • recordId
  • fieldCode
  • success
  • traceId
  • beginTime
  • endTime

7.3 Dependency 图

方法 路径 说明
POST /api/ai/business/formula/dependency/graph 返回依赖图 nodes / edges

响应核心:

{
  "valid": true,
  "hasCycle": false,
  "nodes": [
    { "id": "field:amount", "type": "FIELD", "label": "金额" },
    { "id": "formula:totalAmount", "type": "FORMULA", "label": "总金额" }
  ],
  "edges": [
    { "source": "field:amount", "target": "formula:totalAmount", "type": "DEPENDS_ON" }
  ],
  "cyclePath": []
}

7.4 函数市场

方法 路径 说明
GET /api/ai/business/formula/function-market/page 函数市场分页
GET /api/ai/business/formula/function-market/{functionCode} 函数详情
POST /api/ai/business/formula/function-market/{functionCode}/install 安装函数
PUT /api/ai/business/formula/functions/{functionCode}/enable 启用函数
PUT /api/ai/business/formula/functions/{functionCode}/disable 禁用函数

7.5 条件规则

方法 路径 说明
POST /api/ai/business/formula/rule/compile 规则 JSON 编译为表达式
POST /api/ai/business/formula/rule/validate 校验规则 JSON 和生成表达式

8. 前端设计

8.1 字段属性面板

修改 BusinessFieldPropertyPanel.vue

  • 公式类型新增 LOOKUP。
  • 公式配置区拆分为组件:
    • FormulaConfigPanel.vue
    • FormulaExpressionEditor.vue
    • FormulaLookupPanel.vue
    • FormulaCrossObjectPanel.vue
    • FormulaConditionRuleDesigner.vue
    • FormulaDebuggerPanel.vue
    • FormulaDependencyGraph.vue
    • FormulaExecutionLogDrawer.vue

8.2 对象设计器入口

在对象设计器中增加公式工具入口:

  • 公式调试
  • 依赖图
  • 执行日志
  • 函数市场

这些入口应服务于当前对象上下文,默认带入 objectCode。

8.3 交互要求

  • 调试器和执行日志不放在字段属性表单内挤占编辑区域,建议使用内嵌面板或弹窗。
  • Dependency 图支持缩放、拖拽、节点筛选、循环路径高亮。
  • 函数市场以工具型管理界面呈现,避免营销式卡片堆叠。
  • 条件规则设计器必须支持键盘和鼠标高频编辑。

9. 后端设计

9.1 新增领域服务

服务 责任
FormulaExecutionLogService 执行日志落库、查询、脱敏
FormulaDebugService 构建调试上下文、逐步执行、返回 trace
FormulaDependencyGraphService 将依赖分析结果转换为 nodes / edges
FormulaLookupResolver 解析 LOOKUP 配置并读取关联对象字段
FormulaCrossObjectResolver 解析一跳跨对象路径和预取数据
FormulaObjectDependencyAnalyzer 发布期将跨对象公式转换为对象图依赖并检测循环
CrossObjectRecomputeTaskService 生成 STORED 跨对象公式待重算任务和幂等键
FormulaFunctionRegistry 注册、查询、启停函数
FormulaFunctionMarketService 市场函数安装和版本管理
ConditionRuleCompiler 规则 JSON 转 Aviator 表达式

9.2 运行时接入

  • FormulaExecutionEngine 增加 step trace 输出能力。
  • ExpressionExecutor 增加函数注册表集成。
  • StoredFormulaRuntimeVirtualFormulaRuntime 接入日志服务。
  • FormulaPublishValidator 增加 LOOKUP、跨对象路径、函数状态、条件规则校验。
  • DbAggregateDataProvider 的批量查询经验复用到 LOOKUP / 跨对象 VIRTUAL 预取。

9.3 数据权限

  • LOOKUP / 跨对象查询必须走对象关系元数据和动态 CRUD 查询能力。
  • 禁止公式配置直接提交表名、SQL 片段或 Mapper 方法名。
  • VIRTUAL 跨对象公式批量预取仍必须保留 tenant_id 和数据权限边界。

10. 安全与合规

  • 公式日志必须脱敏输入快照和输出值。
  • 自定义函数不得访问网络、文件系统、环境变量、系统命令。
  • 函数执行必须设置超时时间和最大调用深度。
  • 函数市场安装、启用、禁用必须记录操作日志。
  • 跨对象公式不得绕过对象关系和权限模型读取数据。
  • 调试器只允许有对象设计权限的用户访问。

11. 风险

风险 说明 缓解
跨对象 N+1 查询 列表查询时每行触发 LOOKUP VIRTUAL 模式批量预取,限制一跳
跨对象循环依赖 A 对象依赖 B,B 又依赖 A 发布时对象图 DAG 校验
日志过大 成功公式大量执行导致日志膨胀 默认仅记录失败和调试日志,成功日志可配置采样
敏感数据泄露 inputSnapshot 可能含敏感字段 字段敏感标记 + 统一脱敏器
自定义函数安全 函数可能执行危险逻辑 首期仅 Java Bean 注册,禁脚本
函数禁用兼容 旧公式引用被禁用函数 发布阻断,运行态给出明确错误
条件规则与表达式不一致 UI JSON 和表达式双写漂移 保存时以 rule JSON 编译表达式,保留 expression 快照

12. 测试与验证策略

12.1 后端单元测试

  • FormulaExecutionLogServiceTest
  • FormulaDebugServiceTest
  • FormulaDependencyGraphServiceTest
  • FormulaLookupResolverTest
  • FormulaCrossObjectResolverTest
  • FormulaObjectDependencyAnalyzerTest
  • FormulaFunctionRegistryTest
  • ConditionRuleCompilerTest

12.2 后端集成测试

  • LOOKUP 公式读取一跳关联对象字段。
  • VIRTUAL 跨对象公式列表查询批量预取。
  • STORED 跨对象公式依赖对象变更后进入重算队列。
  • 自定义函数启用后可调用,禁用后发布阻断。
  • 执行失败写入日志并返回 traceId。

12.3 前端验证

  • 字段属性面板可配置 LOOKUP。
  • 调试器展示 executionPlan 和 steps。
  • 依赖图展示节点和边,循环路径高亮。
  • 函数市场查询、安装、启用、禁用流程可用。
  • 条件规则设计器可生成表达式并预览结果。

12.4 构建验证

  • 后端:mvn -pl forge-framework/forge-plugin-parent/forge-plugin-generator -am test
  • 前端:source ~/.nvm/nvm.sh && nvm use v20.19.0 && pnpm --dir forge-admin-ui build
  • 数据库:Flyway 脚本在空库和已有库均可重复校验。

13. 验收标准

  • AC-001: Given 公式执行失败, When 查询执行日志, Then 能看到 objectCode、recordId、fieldCode、expression、inputSnapshot、errorMessage、traceId。
  • AC-002: Given 字段 A 依赖字段 B 和 C, When 打开依赖图, Then 图中展示 A、B、C 节点和 DEPENDS_ON 边。
  • AC-003: Given 字段配置 LOOKUP 读取客户负责人姓名, When 当前记录 ownerUserId 有值, Then 公式返回对应用户姓名。
  • AC-004: Given 跨对象公式引用不存在的关系路径, When 发布对象, Then 发布失败并提示非法路径。
  • AC-005: Given A 对象公式依赖 B,B 对象公式依赖 A, When 发布, Then 对象图循环依赖校验阻断发布。
  • AC-006: Given 管理员禁用函数 tax.amount, When 公式引用该函数并发布, Then 发布失败并提示函数未启用。
  • AC-007: Given 条件规则为 amount > 1000 AND status = ACTIVE, When 保存条件公式, Then 系统生成表达式 amount > 1000 && status == 'ACTIVE' 并可预览。
  • AC-008: Given 调试 LOOKUP 公式, When 调试执行, Then step 中展示 relationCode、targetObjectCode、sourceField、targetField 和 returnField。
  • AC-009: Given 输入快照包含敏感字段, When 查看执行日志, Then 敏感值已脱敏。
  • AC-010: Given V1 旧公式配置, When 打开字段设计器并发布对象, Then 旧配置继续可用,无需迁移。

14. 推荐实施顺序

  1. Phase 1: 可观测性与调试底座
  2. Phase 2A: LOOKUP 公式
  3. Phase 2B: 一跳跨对象公式
  4. Phase 3: 条件规则设计器
  5. Phase 4A: 函数注册中心
  6. Phase 4B: 函数市场

15. 待澄清项

  • LOOKUP 首期是否只允许基于 AiBusinessObjectRelation,还是允许显式 sourceField -> targetField 配置。
  • STORED 跨对象公式首期是否必须自动重算,还是允许先提供“待重算队列 + 手动重算”。
  • 函数市场是否只做本地内置市场,还是需要远程市场源。
  • 执行日志保留周期和清理策略。
  • 条件规则设计器是否需要复用低代码触发器的现有条件构建器。

归档记录(HARD-GATE)

  • 状态:done
  • 归档时间:2026-06-27
  • 归档人:yaomd(批量归档)
  • 归档路径:code-copilot/changes/archive/2026-06-27-formula-next-capabilities/
  • 判定依据:任务清单全部完成,execution-log 验证通过(编译/构建/lint 闭环)。