系统总览

本文范围

本页是 AuraBoot 的架构地图。架构师或平台工程师在动手写代码之前需要先回答四个问题:运行时如何分层、插件贡献如何通过 Profile 注册制变成可运行的能力、控制面(Control Plane) 如何与业务面(Business Plane) 分离,以及多租户隔离在端到端是如何被强制保证的。本页系统回答这四个问题。

如果你还没读过 产品定位,请先读那一篇。本页假定你已经理解 AuraBoot 为何这样定位。如果你想看一次写操作的执行契约细节,读完本页后请继续看 Command 管线

页面中的图描述的是逻辑契约,而不是部署拓扑。开发期单 JVM 与生产环境多节点集群跑的是同一套层次,只是存储下方的基础设施不同。


系统分层

无论是浏览器点击、移动端轻触、外部 API 调用、自动化规则触发还是 AI Agent 调用,所有请求都走同一条纵向栈:

┌────────────────────────────────────────────────────────────────────────┐
│                          客户端与 Agent                                 │
│   浏览器 UI    │   移动端   │   外部 API    │  自动化   │  AI Agent     │
└────────────────────────────────┬───────────────────────────────────────┘
                                 │  (所有写操作走同一契约)
┌────────────────────────────────▼───────────────────────────────────────┐
│                          Command 管线                                  │
│  20 个事务内阶段:load → schema_validate → idempotency_check →         │
│    entitlement_check → sod_check → state_check → assert →              │
│    pre_invariant → cross_field_validation → auto_set → field_map →     │
│    computed_fields → change_tracking → handler → side_effect →         │
│    roll_up → post_action → effect → post_invariant                     │
│  4 个提交后阶段:domain_event → api_call → webhook →                  │
│    governance_snapshot                                                  │
└────────────────────────────────┬───────────────────────────────────────┘
                                 │
       ┌─────────────────────────┼─────────────────────────┐
       │                         │                         │
┌──────▼──────────┐    ┌─────────▼─────────┐    ┌──────────▼──────────┐
│ 元数据注册表    │    │  运行时服务       │    │  流程引擎           │
│  Model/Field    │    │  DSL 渲染器       │    │  BPMN 2.0 +         │
│  Page/Command   │    │  权限求值器       │    │  Command 任务       │
│  Permission     │    │  审计 / 事件      │    │  长流程编排         │
│  Menu/Process   │    │  自动化           │    │                     │
└──────┬──────────┘    └─────────┬─────────┘    └──────────┬──────────┘
       │                         │                         │
       └─────────────────────────┼─────────────────────────┘
                                 │
                  ┌──────────────▼──────────────┐
                  │     插件基座(Substrate)   │
                  │  PF4J 宿主,manifest 校验, │
                  │  类加载器隔离,依赖排序     │
                  └──────────────┬──────────────┘
                                 │
                  ┌──────────────▼──────────────┐
                  │  PostgreSQL(含 pgvector) │
                  │  Redis(缓存 / 锁 / 总线)  │
                  └─────────────────────────────┘

逐层简述:

客户端与 Agent — 浏览器、移动端、外部 API、自动化与 AI Agent 互为对等。没有任何一类客户端拥有"私有写路径"。Agent 与按钮点击共用同一条管线,正是 AI 执行可治理的前提。

Command 管线 — 唯一的写契约。20 个事务内阶段加 4 个提交后阶段把一个"意图"(命令码 + 载荷 + 主体)转化为一次可持久、可审计的状态变更。详见 Command 管线

元数据注册表 — 解析后的定义在运行时的存储:Model、Field、Command、Page、Permission、Menu、Process。管线在每一次请求都读取它;插件在加载时通过 Profile 注册制写入它。

运行时服务 — 管线编排所用的横向能力:DSL 页面渲染、权限求值、审计写入、事件分发、自动化调度、BPM 执行。它们不是插件,而是平台契约的一部分。

流程引擎 — 基于 BPMN 2.0 的长流程编排。流程中的每个服务任务都解析为一个 Command,因此工作流步骤永远不能成为"绕开授权与审计"的逃生通道。

插件基座 — 基于 PF4J 的宿主,加载 jar/配置型插件,验证 manifest,类加载器隔离,依赖排序后把贡献交给元数据注册表。

存储 — PostgreSQL 是系统事实源(事务行、JSONB 元数据、pgvector 嵌入);Redis 是运行时层(缓存、分布式锁、临时队列)。这是有意选择,不是占位,详见 存储架构


控制面 vs. 业务面

AuraBoot 在两个职责之间画了一条明确的线,而其它低代码平台常常把它们混在一起:

                ┌──────────────────────────────────────┐
                │              控制面                  │
                │                                      │
                │  元数据注册表                        │
                │  插件生命周期(安装 / 升级)         │
                │  Profile 注册                        │
                │  身份 / 租户 / 成员                  │
                │  权限定义(不是求值)                │
                │  审计写入 + 审计日志查询             │
                │  可观测性 + 健康检查                 │
                │  Entitlement 注册                    │
                └─────────────────┬────────────────────┘
                                  │  读取并强制
                ┌─────────────────▼────────────────────┐
                │              业务面                  │
                │                                      │
                │  Command 执行                        │
                │  页面渲染(list / form / detail)    │
                │  流程实例                            │
                │  自动化规则触发                      │
                │  报表 / 搜索 / 导出                  │
                └──────────────────────────────────────┘

控制面管"系统能做什么"。业务面真正去"做"。

控制面拥有定义:有哪些 Model、可被调用的 Command、被认可的 Permission、安装了哪些插件、租户持有哪些 entitlement、审计如何成形。它是唯一被允许变更注册表的一层。

业务面拥有操作:基于 Model 派发 Command、渲染页面、推进流程、生成报表。它对注册表是只读的,不会在运行途中改写自己的定义。

这个分界为什么重要:

  • 可治理 — 审计日志本身就是控制面的产物。业务操作不能压制自己的审计记录,因为审计写入是管线契约的一部分,由控制面强制执行。
  • AI 安全 — Agent 调用业务面 Command 无法改写该 Command 的风险等级、幂等属性或权限要求;这些都在控制面,Agent 对那里没有写入面。
  • 升级安全 — 插件升级触动控制面(重新注册 Model、刷新页面 DSL),无需让业务面流量停服。长时运行的流程实例继续沿用启动时的注册表版本。
  • 多租户 — 租户共享业务面运行时,但在控制面拥有各自独立的切片(entitlement、角色绑定、配置覆盖)。跨租户操作必须穿越双面,因此永远是显式的。

Profile 注册制

Profile 是某种渲染上下文(如 admin 控制台、storefront、合作伙伴门户)所暴露的、解析完成后的能力集合。一个 profile 打包了它认识的 block 类型、能渲染的页面 Kind、每个 block 与 kind 的渲染组件、组件清单与布局预设。

插件贡献不可直接调用。它们先在 manifest 中声明,在插件加载阶段被合并进一个或多个 profile。合并发生前贡献处于"暂存区";合并完成后才对运行时可见。

插件 A manifest                  插件 B manifest
─────────────────                ─────────────────
models: [order, ...]             models: [contract, ...]
commands: [order.submit, ...]    commands: [contract.sign, ...]
pages: [admin/order/list, ...]   pages: [admin/contract/list, ...]
permissions: [...]               permissions: [...]
blockTypes: [order-card]         blockTypes: [signature-pad]
                  │                       │
                  └───────────┬───────────┘
                              ▼
                ┌──────────────────────────┐
                │     插件基座加载         │
                │   - 依赖排序             │
                │   - manifest 校验        │
                │   - 冲突检测             │
                └─────────────┬────────────┘
                              ▼
                ┌──────────────────────────┐
                │   Profile resolver       │
                │   合并进:               │
                │     admin profile        │
                │     storefront profile   │
                │     report profile       │
                └─────────────┬────────────┘
                              ▼
                ┌──────────────────────────┐
                │      元数据注册表        │
                │     (活、可查询)       │
                └──────────────────────────┘

Profile 注册制有几条值得记的属性:

  • Profile 是有名字、可注册、可解析的。 页面 DSL 文档声明它所属的 profile;渲染器向 ProfileRegistry 请求对应的 block 组件。默认 profile 是 admin,新 profile 与之并列注册。
  • 贡献是带类型的。 每一项条目——Model、Command、Page、Permission、block 类型——都有 schema。manifest 校验器在加载期拒绝非法插件,而不是延后到首次调用才报错。
  • 冲突是显式失败。 两个插件如果在没有显式 override 声明的前提下贡献同一个 model code 或 permission code,加载直接失败。没有"后写覆盖前写"的静默兜底。
  • 热重载是有界的。 新增或升级插件会重新解析其 profile,刷新相关注册表切片。已在飞的 Command 继续沿用其启动时的注册表版本;新 Command 才看到新版本。如果要永久移除一项已被业务数据引用的贡献,会被拒绝。
  • Profile 边界强制了交付形态。 Storefront 专属的 block 类型不会泄漏到 admin profile;Report 专属的 kind 不会和 admin 的 kind 冲突。这正是为何同一套 DSL schema 能在不同渲染上下文里复用而不会互相耦合。

Profile 注册制是 AuraBoot 保持"插件交付"而不是"单体交付"的机制:平台从不为某个行业垂类开特例,因为行业垂类就只是另一个向 profile 贡献内容的插件而已。


元数据注册表

元数据注册表是运行时为响应请求所需的、内存 + 数据库支撑的"解析完成的定义"投影:

条目类型在何时被读取
Model每次动态 CRUD 调用、每次页面渲染
Field校验、页面渲染、权限检查
Command每次写操作,含管线派发
Page每次 DSL 页面请求
Permission每次授权检查
Menu导航渲染、能力清单
Process工作流实例化、任务恢复
BindingRuleCommand 到 handler 的解析

查询路径走带类型的访问器(MetaModelServiceMetaCommandService 等),而不是 ad-hoc SQL。两条运行时性质很重要:

  • 读路径热,写路径冷。 运行时基本上每个请求都读注册表;写入只发生在插件安装 / 升级 / 卸载、配置应用以及显式管理操作。
  • 缓存失效以插件加载事件为单位。 注册表缓存(Model 定义、页面 DSL、Permission 图)随插件重新加载一起失效。没有"逐字段渐进过期"窗口,因为加载事件就是边界。

注册表之外的东西——运行时状态、业务记录、审计日志条目——都不是注册表数据。注册表回答"系统能发生什么";数据库回答"系统发生了什么"。


多租户隔离

租户是一等概念,不是事后加进来的行级补丁。每一次请求都跑在一个 MetaContext 之下,该上下文从认证一直透传到存储层,携带 (tenantId, userId, userPid, username, roleIds)

HTTP 请求
   │
   ▼
认证 filter ─────► 解析 tenant_member 主体
   │                  (用户 × 租户 × 角色)
   ▼
MetaContext.setContext(tenantId, userId, userPid, username, roleIds)
   │
   ▼
Command 管线(每一阶段都读 MetaContext)
   │
   ▼
仓储层
   - 自动应用行级 tenant 过滤
   - 跨租户查询需要显式升权
   │
   ▼
存储

隔离的真正含义:

  • 数据隔离 — 业务表都带 tenant_id 列;仓储层拒绝未约束该列的查询。跨租户读取必须来自被显式标注的跨租户服务,并且会产生审计事件。
  • 配置隔离 — 权限绑定、菜单可见性、自动化规则、插件 entitlement 都是按租户独立。一个租户禁用某插件,只是禁用它自己看到的注册表切片,并不影响插件本身的全局加载。
  • 主体模型 — 授权基于租户成员而不是裸用户。同一个用户在两个租户里持有两套独立的角色集合;某一个租户的角色变更不会泄漏到另一个。
  • 流程隔离 — 一个 BPMN 实例归属于某个租户。任务、历史、定时器都是租户作用域。跨租户共享的流程定义在渲染上等同,但实例化彼此独立。
  • 跨租户操作显式且必审计 — 平台管理员操作(批量迁移、支持类操作、系统级报表)必须声明跨租户意图,并在审计日志中记录访问过的每一个租户。

把租户放在主体层而不是行级,理由和"Command 是唯一写路径"完全相同:把安全性做成架构性质而不是单个 handler 的性质,才能在系统扩展到几十个插件、上百条 Command 时依然守得住。


运行时服务

平台层托管少量横向服务,由 Command 管线编排。每一项都是平台契约的一部分,而不是插件。

DSL 渲染器 — 把页面 DSL 文档基于当前 profile 解析出来,调用匹配的 block 渲染组件,输出 HTML/React 树。它是契约驱动的:不认识的 block 类型 fail fast,而不是静默渲染成空占位符。页面 DSL 是数据,不是代码。

权限求值器 — 按定义顺序对租户成员应用五层模型(RBAC、ReBAC、组织数据范围、ABAC、字段级可见性)。求值是主体、资源、操作的纯函数,无副作用,可缓存。

审计写入 — 接收管线 effect 阶段发来的审计事件并持久化。审计日志是可查询的产物,不是 debug 日志——它的形态既能给合规读,也能给 AI 回放消费。

事件分发器 — 接收管线 domain_event 阶段发出的领域事件并路由到订阅方:自动化规则、通知通道、变更日志写入器、Inbox feed。

自动化调度器 — 拥有 cron 触发器、事件触发规则执行、自动化失败重试 / 退避、死信队列处理。每一条自动化最终都派发一条 Command —— "系统行为"没有单独的写路径。

BPM 引擎 — 内嵌的 BPMN 2.0 运行时(SmartEngine)。服务任务解析为 Command;用户任务解析为 Inbox 项;网关与定时器跑在引擎内。引擎是管线的参与者,而不是与之并列的另一条管线。


插件基座

插件是交付单元。基座是负责安全加载它们的层。

  • 基于 PF4J 的宿主 — 每个插件是一个 jar(Java 扩展)和 / 或一个配置目录(Model、Page、Command、Permission)。Java 插件拿到独立的类加载器,使其依赖不会与宿主或其它插件冲突。
  • 声明式 manifestplugin.yaml / plugin.json 声明插件 id、版本、对其它插件的依赖、能力声明,以及贡献 Model/Page/Command/Permission 的资源目录。
  • 依赖排序加载 — 插件被拓扑排序。声明依赖 platform.core 的插件在它之后加载;依赖 crm 的在 crm 之后。循环依赖被拒绝。
  • 能力声明 — 插件声明它消费哪些平台能力(如需要 BPM 引擎、需要 pgvector、需要对象存储)。宿主对所声明能力不可用的插件拒绝加载,而不是放任它在第一次调用时崩。
  • ConfigOnly / 混合 / 解决方案包 — 支持三种插件形态:纯配置(无 Java)、混合(配置 + Java 扩展)、解决方案包(一个伞包,绑入若干插件并附行业主题)。三者共用同一 manifest 格式。

完整 manifest 参考见 插件 manifest


存储架构

AuraBoot 不是数据库无关平台,这是有意的选择。

  • PostgreSQL 是事实源。 事务行、JSONB 元数据(用于灵活的 DSL 文档与能力声明)、pgvector 嵌入(用于检索与语义搜索)全部在同一个引擎里。用同一引擎承载"结构化 + 半结构化 + 向量",消除了混合栈累积的一类一致性问题。
  • Redis 是运行时层。 热门注册表查询的缓存、Command 幂等的分布式锁、自动化用的临时队列、限流计数器。Redis 不是事实源,其内容可由 PostgreSQL 恢复。
  • 对象存储可插拔。 附件、导出、大二进制走 S3 兼容存储。基座自带本地文件适配器供开发使用。

为何不抽象多数据库?因为 AuraBoot 提供的合同保证——pgvector 支持的 AI 检索与事务行共址、JSONB 承载 evolving manifest、仓储层强制的行级租户隔离、审计日志按时间分区——都与 PostgreSQL 的特性集深度绑定。"数据库无关"层要么稀释这些保证,要么在应用层重新实现 PostgreSQL 的特性。两者都比直接押注一个高质量引擎更糟。

开发、部署与运维指南见 Operations 章节。


可观测性钩子

可观测性内建于管线,不是事后挂上去的。

  • 结构化日志 — 每个管线阶段都输出带 command_idtenant_idprincipalstagelatency_msresult 标签的日志。日志是 JSON,无需做字符串日志解析。
  • OpenTelemetry tracing — 一次 Command 运行就是一条 trace;每个管线阶段是一个 span。副作用(事件、自动化、下游 Command)继承 trace 上下文。分布式部署的端到端关联无需手动拼。
  • Command 阶段指标 — 每个阶段(schema_validate / entitlement_check / state_check / handler / effect ...)有延迟直方图。哪个阶段在拖慢某条 Command,一目了然。同一套指标驱动 预算告警
  • 审计日志本身就是可观测性。 与 debug 日志不同,审计日志是可查询、有保留策略、专门给人 / 合规工具 / AI 回放读的产物。它不可选、不允许 per-command 关闭。

社区版有意不包含的内容

:::note[企业版扩展] 社区版平台是 Command / Permission / Plugin / Tenant / Profile / Process 如何被定义的事实源。下列能力跑在同一组契约之上,但只随商业发行版交付:

  • Marketplace + License/Entitlement 运行时 — 产品化的插件分发,配合管线 entitlement_check 阶段的按租户许可强制。OSS 管线保留该阶段但默认放行。
  • Agent Control Plane — 跨租户 Agent 编排、审计回放、风险分级审批门、预算护栏。
  • Observability Pro — 预配置的分布式 tracing 看板(基于管线 Command 阶段 span),每阶段端到端延迟预算。
  • 进阶多地多活租户 — 租户数据跨区域 active-active 路由,流程引擎与审计日志的跨区域故障转移。

这些是上述架构之上的扩展,不是并行的另一套运行时。OSS 发行版本身足以支撑单区域生产部署。 :::


下一步