从页面生成器到受控业务运行平台
1. 低代码真正要解决什么
很多低代码平台从拖拽页面开始:放一个表格,摆几个输入框,再给按钮绑定接口。
这种方式很容易做出 Demo,但进入 ERP 以后,真正困难的并不是把页面画出来,而是长期回答下面这些问题:
- 字段、页面、接口和数据库结构由谁定义?
- 一次模型修改怎样安全地进入正式环境?
- 页面能不能绕过权限直接调用接口?
- 数据库变更怎样预览、确认、执行和审计?
- 标准页面与高度定制页面怎样共用一套业务能力?
- AI 生成的内容怎样被约束、检查和追踪?
所以,这套架构的目标不是做一个普通页面搭建器,也不是让 AI 到处生成业务代码,而是建立一套受控的业务运行平台:
把业务定义沉淀为可版本化、可校验、可发布的元数据,再由稳定模板和统一运行时执行;身份、权限、业务规则和数据库操作始终由后端作最终裁决。
低代码只是表现形式。真正的基础设施是模型、约定、运行时和治理流程。
2. 四种事实,四个权威来源
“元数据是唯一真相源”很容易被误解成所有东西都塞进一个巨大的 JSON。实际情况不是这样。
系统里存在四类不同事实,每类事实都有自己的权威来源。
| 事实类型 | 权威来源 | 负责内容 |
|---|---|---|
| 页面业务定义 | 已发布元数据 | 字段、列、筛选、文案、动作、数据源、权限键 |
| 页面执行骨架 | 模板代码 | 稳定区域、布局关系、交互方式、错误边界 |
| 正式业务数据 | 数据库记录 | 客户、订单、物料、单据等真实数据 |
| 可信业务裁决 | 后端 | 身份、权限、校验、状态、事务、并发和审计 |
这四类事实不能互相冒充,也不能同时维护两份。
例如,页面标题来自元数据,模板就不能再写一个备用标题;权限由后端裁决,前端按钮隐藏就不能被当成安全机制;数据库记录是业务事实,模板不能为了展示效果伪造正式数据。
因此,“唯一真相源”的准确含义是:
同一个事实只能有一个权威来源。
3. 领域模型不是万能 JSON
一份配置驱动前后端,不等于一个 JSON 同时写按钮颜色、数据库字段、SQL 和接口地址。
更合理的做法是建立一个分层的领域模型包:
Entity描述业务实体。Field描述字段含义、类型和约束。Relation描述实体关系。View描述业务对象的页面投影。Action描述允许执行的业务动作。Rule描述显隐、只读、派生和联动规则。DataSource描述受控数据能力。Service描述业务动作怎样组织数据请求。
同一个领域模型可以投影出不同产物:
flowchart LR
A["领域模型包"] --> B["数据库结构与迁移计划"]
A --> C["Resource 与权限约定"]
A --> D["Page Schema"]
A --> E["Action 与联动定义"]
D --> F["模板页面"]
C --> G["后端运行时"]
这里最重要的边界是:数据库结构可以生成默认页面骨架,但数据库表不能永久等于页面。
一个实体可以拥有列表、详情、维护、审批等多个 View;聚合页、工作台和复杂单据也可能同时使用多个实体。页面是业务视图,不是数据表的镜像。
4. 正式运行只相信已发布元数据
元数据不能保存以后立即在线生效。正式平台需要一条完整的变更生命周期:
flowchart LR
A["已发布版本"] --> B["创建草稿"]
B --> C["受控编辑"]
C --> D["结构检查"]
D --> E["数据库变更计划"]
E --> F["发布预检"]
F --> G["精确确认"]
G --> H["发布新版本"]
H --> I["正式 Runtime 生效"]
这条流程解决了几个关键问题:
4.1 草稿与正式环境隔离
草稿只用于编辑、检查和发布准备。正式路由只能读取已发布版本,不能读取草稿,也不能在元数据缺失时退回前端常量或测试夹具。
4.2 修订号防止互相覆盖
每次保存都携带修订号。如果编辑期间草稿已经被其他操作修改,后端返回冲突,而不是让后一次保存悄悄覆盖前一次结果。
4.3 发布前重新裁决
草稿检查通过不代表一定可以发布。发布前还需要确认基础版本没有变化、检查结果仍对应当前修订,并重新生成数据库变更计划。
4.4 危险操作需要精确确认
发布、数据库计划和高风险迁移动作不能只靠一个“确定”按钮。确认内容必须与当前模块、版本、草稿、修订号或计划精确匹配,避免用户确认的是旧现场,系统执行的却是新内容。
这说明低代码平台不仅是一个配置系统,还是一套变更治理系统。
5. 模板负责工作方式,元数据负责业务内容
模板的价值不是少写几个组件,而是沉淀一类页面稳定的工作方式。
例如,记录列表模板可以固定:
- 页头、筛选区、视图切换、工具栏、表格和分页的位置。
- 查询、排序、选择、批量动作和行级动作的交互流程。
- 加载、空数据、筛选为空、错误、无权限和冲突状态的呈现位置。
但模板不能固定:
- 客户名称、订单编号等具体业务字段。
- 页面标题、按钮文案、状态值和枚举选项。
- 具体 Action、权限键、Resource 键或 Service 方法。
/api/...地址、SQL、数据库表名和后端 Handler。- 针对某个行业或客户的业务分支。
可以把这个关系概括为:
模板固定页面的工作方式,已发布元数据填入页面的业务定义。
每一种生产模板都应该拥有自己的 Page Schema Builder 和区域白名单。Builder 负责把领域模型和 View 投影成该模板需要的 Page Schema,校验器负责拒绝缺失、越界或不匹配的配置。
配置只描述模板明确开放的区域,不能动态指定任意 React 组件、任意 JSX、CSS、JavaScript 或容器嵌套。否则所谓低代码 DSL 最终只是用 JSON 重新发明了一遍 React,而且更难调试。
6. 组件、模板与展示容器
组件、模板和容器解决的是三个不同层次的问题。
6.1 组件解决局部能力
例如输入框、字段渲染器、表格、分页、动作栏、看板、日历、甘特图和透视表。
组件只通过明确的 props 接收数据与事件,不知道当前业务模块,也不知道接口地址。
6.2 模板解决完整页面流程
例如记录列表、对象详情、主数据维护、交易单据、工作队列、分析工作台和对账匹配。
模板负责组合组件,并固定一类页面的区域关系和交互模型。
6.3 容器解决如何呈现
Page、Dialog 和 Drawer 只负责挂载、尺寸、焦点、滚动和生命周期。它们不重新实现模板的业务流程。
同一个详情模板可以显示在独立页面里,也可以放进弹窗或抽屉里。由 Action 选择受控目标模板和容器,而不是让模板自己判断“我现在应该是页面还是弹窗”。
7. 运行时是整套架构的脊柱
元数据不会直接渲染页面。它必须经过一条受控装配链:
flowchart TB
A["已发布 DomainModel / View / Action / DataSource / Service"] --> B["模板专用 Page Schema Builder"]
B --> C["Page Schema 校验"]
C --> D["受控模板路由"]
D --> E["Runtime Assembly"]
E --> F["TemplateRuntime"]
F --> G["已注册模板"]
G --> H["通用组件与 Renderer"]
其中,模板只接收两个共同输入:
pageSchema:告诉模板要展示什么业务内容。runtime:提供可信上下文、状态、动作和受控数据能力。
模板不能自己创建 Service,不能直接访问 DataSource,也不能调用 HTTP。这样做不是为了增加层级,而是为了让权限、错误、重试、审计和测试拥有稳定的接入点。
8. 前端数据与动作必须单向流动
正式页面的前端执行链固定为:
flowchart TB
A["Template"] --> B["Action Runtime"]
B --> C["Action Handler"]
C --> D["Service"]
D --> E["DataSource"]
E --> F["HTTP Adapter"]
各层职责如下:
- Template 展示状态并发出用户意图。
- Action Runtime 解析动作的显隐、禁用、权限、确认和效果。
- Action Handler 组织一次受控动作。
- Service 表达业务数据能力。
- DataSource 管理请求状态、列表作用域、表单草稿和选择现场。
- HTTP Adapter 负责统一协议、请求与响应映射。
页面状态可以按照列表作用域、表单实例或局部运行域组织,但不应变成各组件私有状态互相监听的网络。
组件只消费状态、触发 Action。跨区域联动通过 Reaction Runtime,也就是统一联动运行时完成。这样可以集中处理依赖关系、执行顺序、循环检测和错误传播。
9. Expression、Reaction 与 Action 的边界
三者不能混成一个任意脚本系统。
9.1 Expression 只做纯判断
适合处理显隐、禁用、只读、必填和简单派生值。它应该无副作用、可静态分析,也不能访问浏览器全局对象。
9.2 Reaction 负责声明式联动
Reaction 监听受控状态变化或标准事件,再执行有限的状态更新或调用已注册 Action。它不能成为组件之间互发命令的隐藏网络。
9.3 Action 负责正式副作用
查询、保存、删除、跳转、打开容器、刷新数据和发布元数据等操作都应该通过 Action 进入统一执行链。
当前架构不开放任意 JavaScript 字符串函数。复杂能力应优先沉淀为命名 Action、受控 Handler、专用模板或经过审批的定制页面,而不是把代码藏进配置。
10. 后端统一为 Resource Runtime
前端不应该知道任意接口地址。它只声明要访问哪个受控 Resource,以及执行哪一种操作。
统一 Resource 可以覆盖六类稳定操作:
querygetcreateupdatedeleteexecute
后端执行链固定为:
flowchart TB
A["Koa Route"] --> B["Resource Service"]
B --> C["Resource Handler"]
C --> D["Domain Service / Repository"]
D --> E["Database Adapter"]
Resource Registry 负责登记允许访问的资源和操作,Handler 负责具体业务处理,Repository 负责数据访问,Database Adapter 隔离具体数据库。
路由不拼业务 SQL,模板也不选择 Handler。所有资源键、操作、字段、筛选、排序和动作都必须在白名单或已发布元数据中有明确来源。
11. 权限的最终裁决必须在后端
ERP 权限远不止“按钮能不能看见”。完整权限至少涉及:
- 页面和 View 访问权限。
- 记录读取、新增、修改和删除权限。
- 字段可见与可写权限。
- Action 执行权限。
- 组织、租户和账套范围。
- 流程状态和业务状态限制。
前端可以根据权限隐藏或禁用按钮,但这只是体验层控制。每一次 Resource 请求,后端仍要根据可信身份、已发布 View 和操作类型重新计算所需权限。
即使用户绕过前端直接发请求,也不能获得额外能力。
12. 数据库变更不是点一下就执行
当元数据能够影响数据库结构时,平台必须把“模型修改”和“执行 SQL”隔开。
安全流程应该包含:
- 根据当前已发布模型和候选草稿生成差异。
- 将差异编译为受控数据库变更计划。
- 标出风险级别、执行步骤和 SQL 预览。
- 对高风险动作执行专项检查。
- 使用与当前计划匹配的确认文案。
- 后端重新校验计划后执行。
- 记录执行人、请求标识、确认时间、步骤结果和失败原因。
数据库执行器只能处理平台认识的结构化动作。前端不能提交任意 SQL、表名、连接信息或 Handler 路径。
13. 标准页面和定制页面可以共存
这套架构不追求把所有页面都配置化。
当多个业务场景拥有相同区域和主流程,而且差异主要是字段、列、文案、动作和数据源时,应该抽成通用生产模板。
当页面只服务一个业务族群,但交互模型仍然稳定时,可以建立专用生产模板。
当页面依赖复杂画布、特殊拖拽、高密度可视化或独特算法交互时,可以写正式定制页面。
但“定制”不是绕过架构的通行证。默认情况下,定制页面仍要接入:
- 已发布元数据。
- 受控页面注册与路由。
- Action Runtime。
- Service 与 DataSource Runtime。
- Resource API。
- 后端权限、事务和审计。
如果某一层确实不适用,需要逐页、逐版本、逐层说明原因和替代方案,并获得精确确认。无论如何,可信身份、后端权限、业务校验、事务、并发、审计和数据库安全都不能绕过。
14. AI 应该工作在平台边界之内
AI 很适合把自然语言业务需求转换为结构化候选内容,例如:
- 领域字段和关系草案。
- View 与模板选择。
- 筛选、列和表单配置。
- ActionRef 与权限配置。
- 联动规则和测试用例草案。
- 数据库变更计划的解释。
AI 不应该直接做这些事:
- 生成任意接口 URL 并让页面调用。
- 把任意 JavaScript 或 SQL 写进正式配置。
- 绕过后端权限和业务裁决。
- 跳过检查直接发布元数据。
- 自动确认高风险数据库操作。
所以 AI 在这里不是系统最高权限,而是一个受约束的配置生产者和工程协作者。
flowchart LR
A["自然语言需求"] --> B["AI 生成候选元数据"]
B --> C["协议与结构校验"]
C --> D["人工审查"]
D --> E["自动化测试"]
E --> F["发布预检与确认"]
F --> G["正式版本"]
AI 生成的是候选业务定义,平台负责证明它能安全运行。
15. 配置即源码,交付必须有证据
元数据一旦能够驱动前端、后端和数据库,它就已经是源码的一部分。
因此,元数据需要具备普通源码应有的工程属性:
- 明确协议和版本号。
- 结构校验和兼容检查。
- 草稿、发布和历史版本。
- 数据库迁移记录。
- 可追踪的变更摘要。
- 自动化测试与回归证据。
一个正式模板不能因为页面能打开就算完成。完整闭环至少需要:
- Page Schema 静态约定与校验。
- 真实 DOM 渲染和 Action Runtime 行为测试。
- 历史正式 Schema 兼容测试。
- 真实路由、HTTP、Resource API 和独立数据库浏览器流程。
- 稳定页面或 Overlay 的视觉回归。
此外,架构依赖方向也需要机器检查。否则随着项目增长,模板直连 HTTP、Handler 绕过 Service 之类的捷径迟早会重新出现。
16. 当前模板体系的落地范围
生产型模板不是一个万能 CRUD 模板,而是一组语义明确、边界稳定的页面工作方式。当前规划包括:
- 记录列表。
- 对象详情。
- 主数据维护。
- 交易单据。
- 工作队列。
- 业务工作台。
- 分析工作台。
- 引导流程。
- 流程看板。
- 日历排程。
- 时间线计划。
- 对账匹配。
- 对比分析。
- 矩阵录入。
- 报表透视。
这些模板需要逐个完成 Schema、Builder、运行时、后端资源和五层测试闭环,不能因为名字已经登记,就宣称能力已经上线。
当前只有生产型记录列表模板完成第一轮正式闭环,其余模板仍按业务生命周期逐步实现。复杂模板如果引入事务、并发、拖拽状态变更、时间冲突或聚合查询,也必须同步补齐后端能力,而不是只做一张前端效果图。
17. 明确不做什么
为了守住边界,这套平台明确不做:
- 任意拖拽页面设计器。
- 能解释任意 React 树的万能 DSL。
- 一个包含所有页面形态的万能模板。
- 配置中的任意 JavaScript 执行。
- 前端下发 SQL、表名、Handler 或接口地址。
- 动态下载未经登记的远程模板。
- 为了展示效果而伪造正式业务能力。
- 自然语言直接生成并发布正式元数据。
这些限制不是功能不足,而是平台保持可理解、可检查、可审计的前提。
18. 总结
这套低代码架构的核心,不是“少写多少 React”,而是建立一条可信的业务定义与执行链:
flowchart TB
A["领域模型"] --> B["元数据草稿"]
B --> C["检查与数据库计划"]
C --> D["已发布元数据"]
D --> E["Page Schema"]
E --> F["生产模板"]
F --> G["Action / Service / DataSource"]
G --> H["Resource Runtime"]
H --> I["后端权限与业务裁决"]
I --> J["数据库"]
模板让重复的页面工作方式可以复用,元数据让业务差异可以配置,运行时让数据和动作保持统一,后端保证安全与一致性,工程门禁保证系统能够长期演进。
AI 可以加速模型、配置和测试的生产,但不能取代这些边界。
最终要建设的不是一个“什么都能拖出来”的页面工具,而是一套规则有限、职责清楚、变更可控、证据完整的业务运行平台。
