高级与扩展功能的原理说明
适合需要接入数据库、自定义 API、公共扩展,或负责权限、安全与部署的开发者。建议先使用AI Agent 集成指南完成开发;需要理解设计时先看原理说明,再按问题查阅本页。
按任务查阅
本页是专题索引与关键约束,链接的协议文档提供完整字段、请求格式和示例。各专题里的版本标记用于说明引入时间,当前网站版本为 v0.20.4。
已上线的四个协同扩展(v0.20)
工作流中心、统一待办、站内通知、附件中心已经提供独立应用及公共能力接口,数据分别存入各自 PostgreSQL 空间。先看简明操作指南,或查阅能力接口、参与人授权、附件分片及一致性边界。已有 CMS 等业务不会自动改用新引擎。
先理解三个层次
先按职责区分核心、公共服务和业务,再看具体模块及部署方式。
| 层级 | 放哪些功能 | 职责 |
|---|---|---|
| 核心底座 | 身份认证、权限执行、统一网关、扩展注册与路由、运行隔离、基础审计 | 确保请求身份可信、能力调用受控、模块生命周期可靠。保持小而稳定。 |
| 公共能力扩展 | 工作流、待办、通知、附件、搜索、定时任务、报表、外部连接器 | 提供可被多个业务应用复用的服务。按能力契约申请、授权和调用。 |
| 业务应用 | 请假、报销、合同、资产、采购、CMS | 定义自有 H5、业务 API、业务规则和业务数据,使用公共扩展完成协作。 |
模块与层次的关系:模块是交付和运行的单元;公共能力扩展和业务应用都可以做成模块。两者区别在职责及授权:公共扩展需要管理员明确批准为服务提供者,普通业务应用只能申请并调用已批准能力。
谁负责业务正确性:核心检查真实用户、动作权限和能力授权;工作流扩展负责流程实例、节点及审批任务;报销等应用负责金额、额度、单据状态和自己的数据库事务。扩展不能绕过核心授权,也不代替业务规则。
三层如何协作:接入工作流后的目标路径是:报销 H5 → 核心网关 → 报销应用 → 核心能力路由 → 工作流扩展。人工审批等待时保存状态并返回,不占用持续 RPC;跨模块状态同步还需可靠事件/outbox方案。
概念与当前实现:v0.20 已提供工作流、统一待办、站内通知和附件四个独立公共扩展,各有自定义 H5、Docker 容器及 PostgreSQL 账号/schema;工作流基础版支持顺序审批。定时任务保持可选内置扩展;records、通讯录、数据库和云连接器暂为宿主兼容适配器。搜索、报表、通用事件总线等仍待接入。
部署方式与层次不同:公共扩展可以是独立 Docker 进程,也可以是独立代码包的内置扩展。当前采用兼容方式逐步迁出,不能把“可扩展”理解为“所有能力均已独立进程化”。
小核心与公共能力扩展(v0.19)
新增提供者批准、接口版本、依赖拓扑与受控扩展调用;调度引擎已独立为可选内置扩展,旧能力通过兼容适配器保留。阅读架构、协议和开发示例。
定时任务(v0.18.0)
参考RuoYi的任务分组、Cron、启停、错过策略和日志;执行已注册模块动作,绑定真实账号并重新鉴权。查看定时任务指南及API。
默认基础只读能力(v0.17.10)
启用用户自动拥有基础组织通讯录读取;应用声明并通过发布测试,业务权限和显式 Key 限权保持。查看基础能力设计。
v0.17.5:注册即获得Key,自行发布本人应用
注册邮件包含完整个人API Key和提交/模拟/发布示例;每个用户均可审核发布自己名下的应用,无须管理员审批。提交和发布结果通知本人。应用归属、测试、能力范围和Docker隔离继续有效;旧指南中的管理员审批步骤现由应用所有者自行确认。详见 自助发布与邮件示例。
自定义 H5 与应用声明
manifest.ui 必须声明 mode=h5、entry、bridge_version=1 和完整 files 白名单。缺少 ui、generated 或其他模式均拒绝安装和注册。底座已移除根据 Descriptor 字段生成表单、列表、工作流和通讯录的功能。
{
"id": "workorder",
"name": "工单登记",
"version": "0.2.0",
"protocol": 1,
"entry": "workorder",
"capabilities": [
"identity.get",
"records.list",
"records.create"
],
"ui": {
"mode": "h5",
"entry": "ui/index.html",
"bridge_version": 1,
"files": [
"ui/index.html",
"ui/app.js"
]
}
}后端和前端分工
下面以兼容的 Go 原生模块为例;Python、Java 或公开协议 v2 请直接查阅后面的“语言无关模块协议”。下载 SDK,在 go.mod 使用 replace collab.local/platform => ./platform-sdk。实现 Describe、Execute,并在 main 调用 modulekit.Serve。Descriptor 仅包含 ID、Name、Version、Protocol、Description 和可选 Actions;动作只声明 Name、Label,不声明界面字段、状态或所有者提示。
H5 自己编写表单、表格、卡片、棋盘或组织树。底座在沙箱 iframe 的 head 自动注入主题和 window.PlatformUI;HTML/CSS/JS 使用包内相对路径,依赖随包发布。导航、登录、账号和角色配置仍由统一工作空间提供。后端 Execute 负责所有输入、状态、所有权、版本冲突和幂等校验。
const platform = window.PlatformUI;
const context = await platform.ready;
const rows = await platform.execute('list');
const requestId = crypto.randomUUID();
await platform.execute('create', {title:'示例',reporter:'张三'}, requestId);
await platform.notice('已保存');统一权限和接口
浏览器登录后,POST /api/modules/{id}/ui-session 创建短期资源地址。H5 只通过消息桥调用本模块被授权的动作,不接收 API Key、Cookie 或 CSRF,也不能选择任意 URL、模块 ID 或调用人。list/create 为基础动作,edit/submit/publish/reject 需要显式动作及权限声明。HTTP 和反向 RPC 都检查当前账号权限,业务模块继续检查业务规则。
后端可调用 identity.get、records.list、records.create;只读通讯录使用 directory.read。Record 包含 id、created_at、created_by、values。记录按模块隔离,写入与审计、幂等结果原子保存。登录用户可自行生成个人 API Key 给 Agent;密钥继承实时权限,可限权、到期及撤销,完整密钥只展示一次。启用账号可以提交、模拟测试并发布自己名下的普通业务应用,无须管理员审批;系统管理员可治理全部应用。公共服务提供者仍须运维安装并由管理员明确批准。
打包、模拟和发布
ZIP 根目录含 manifest.json、原生入口和可选 simulation.json;ui/ 下只能包含 ui.files 声明的资源。最多128个资源、单个2MiB、总计8MiB,整包压缩和解压总量各限64MiB。拒绝未声明资源、路径穿越、符号链接、大小写冲突和不可移植文件名。前端和二进制共同计入 SHA256,通过同一候选包审核、安装和失败回退。
使用 scripts/package_module.py 打包,Agent 通过个人 API Key 调用 /api/module-submissions 提交,或使用兼容的模块限定提交令牌。应用所有者先执行隔离模拟,测试通过后自行确认平台能力并发布;敏感能力和公共扩展提供者仍需平台管理员授权。simulation.json 提供 valid_payload、conflict_payload,可提供 invalid_payload(缺省为 {});测试不再依赖 UI 字段声明。
统一体验与安全边界
遵守 adminui-v1 规范,使用注入的主题变量,支持深浅主题和手机宽度。沙箱只允许脚本和 JS 表单交互,不授予同源权限;CSP 禁止直接网络、原生表单提交、外部脚本、Worker 和子框架。所有数据通过消息桥。
v0.10 在服务器设置 OA_MODULE_RUNTIME=docker 时,每个原生模块及候选包模拟都使用独立容器:非 root、只读根目录、默认断网、限制内存与 CPU,只挂载本应用通信目录和只读程序。容器不可读取宿主业务目录或凭据;Docker 不可用时不会回退到本机。原生开发模式仍只适用于可信程序。Docker 共享宿主内核,不等同虚拟机。JSON 存储采用单进程目录锁,适合小数据验证;正式使用需结合数据量规划数据库、备份和运行资源隔离。
角色数据范围(v0.11)
后台角色可配置本人、本部门、本部门及下级、自定义部门、全部。底座过滤 records.*,多角色仅合并当前动作对应的范围,API Key 限权继续生效。旧角色保留范围,新角色默认本人。修订须传 record_id 并继承原归属。参见 完整配置与模块契约。
Docker 模式的权限控制方案
采用“容器限制系统资源、底座授予业务能力、应用校验业务规则”的三层授权。容器只获得运行本模块所需的最小环境;能够启动程序不代表能够读取业务数据,也不代表拥有当前用户的所有权限。
| 控制范围 | 当前底座实际策略 |
|---|---|
| 文件与持久化 | 根文件系统只读,只挂载本模块的只读程序副本和独立 Unix socket 通信目录。/tmp 是 16 MiB 的内存临时盘,带 noexec、nosuid、nodev,容器删除后不保留。宿主业务目录、其他模块目录、云凭据和 Docker socket 不挂载到容器。通信目录是可写宿主挂载,当前尚无磁盘容量配额;16 MiB 只约束 /tmp,不代表应用全部写入的上限。简单数据可经 records 服务保存;获批 database.connect 的应用可通过专用 PostgreSQL Unix socket 访问自己的账号与 schema,不能读取宿主数据库文件。 |
| 网络与端口 | 默认使用 --network none,不发布端口,不共享宿主网络。模块不能直接访问公网、其他容器服务或云实例元数据;容器自身回环仍存在。H5 通过浏览器消息桥,后端通过专用 Unix socket 调用底座,不需要为模块开放 HTTP 端口。 |
| 用户与系统调用 | 以非 root 用户运行,删除全部额外 Linux capabilities,启用 no-new-privileges 和 Docker 默认 seccomp;不开放特权模式、宿主 PID 命名空间或设备透传。各容器隔离进程与文件视图;当前未为每个应用单独分配宿主 UID,不能把 UID 相同理解为可共享宿主目录。 |
| 资源与可用性 | 每模块内存上限 192 MiB、禁用 swap、CPU 配额 0.5 核、最多 64 个进程/线程、1024 个文件描述符。当前小规格服务器上,所有应用容器合计内存上限 256 MiB、CPU 配额 1.5 核、512 个任务;这是共享总预算,不是每个应用的保底份额。超过限制可能被限速或终止,不能保证恶意模块不会造成资源竞争。 |
| 数据、动作与 API Key | 容器隔离之外,底座继续核验已批准 capability、当前账号权限和 API Key 的限权范围,绑定模块 ID、ActorID 和请求号。records.* 按模块隔离;目录资料通过 directory.read 等专用服务授权。租户、部门、记录归属和业务状态不能由 Docker 判断;records.* 已按角色的模块/动作数据范围过滤;外部连接器和通讯录另行授权,应用继续校验业务状态。 |
| 外部服务与密钥 | 模块不能自行获取生产密钥或随意出网。开发环境管理使用受控 cloud.request 连接器:底座限定模块、操作者、动作及固定原站接口,并在宿主侧签名、审计和去重。当前没有面向任意应用的通用 HTTP 代理;新增外部服务需由底座实现并审核专用连接器。 |
| 发布、运维与日志 | 线上候选包模拟同样使用容器和独立数据,禁用真实云连接器。启动失败不回退本机执行。modules.manage 用户可查看容器状态和最近日志、启动、停止及重启;接口只接受 OA 模块 ID,不接受任意 Docker 命令、exec、镜像、挂载或清理参数。日志按每容器 1 MiB × 2 轮转,管理界面显示最近日志;手动停止状态跨底座重启保持。 |
开发者如何申请权限
在 manifest.capabilities 声明实际需要的底座服务,在 permissions 和 role_templates 声明模块业务动作;普通应用由所有者通过模拟后确认自助发布范围内的 capability;敏感能力需管理员授权。发布后所有者自动获得本应用业务权限,其他用户通过角色授权。看到目录不等于可以操作业务数据。已有角色中的 business.read/business.create 是可覆盖以后模块的兼容权限,敏感应用应像 cloud-admin 一样要求精确的模块权限。API Key 默认跟随所属账号的实时权限,可能随账号授权扩大;建议显式限制 permissions,密钥有效权限始终不能超过所属账号。以 CMS 为例:编辑申请撰稿与提交,总编申请审核发布;Docker 无法区分这两个角色,必须由底座和 CMS 后端共同检查。
当前容器参数采用平台统一模板,manifest 不支持开发者自行指定 Docker 参数、目录、网络、设备、镜像或逐应用资源额度。新增文件访问、外部接口或更大额度,应先说明用途、数据范围、目标服务及资源需求,由平台运维评估和调整,不应通过特权容器或挂载 Docker socket 实现。
隔离边界与后续增强
Docker 能限制程序能接触的系统资源,不能证明上传包没有木马,也不能判断文章能否审核、发票能否报销或已经授予的业务操作是否合理。容器共享宿主 Linux 内核,Docker 控制端属于高权限受信任组件;当前使用系统 Docker,尚未启用 Rootless、gVisor、独立执行主机或虚拟机。对公开接收的高风险代码,应继续增加更强运行隔离,并维护内核和运行时更新。当前也未统一限制通信目录磁盘用量、业务记录总容量、磁盘 I/O 或底座服务调用频率,不能把容器 CPU/内存配额理解为完整的存储与 API 配额。现有措施不等于全面的恶意程序检测,也不保证业务数据的租户隔离。
单机并发、请求身份与过载保护(v0.13)
不同模块的业务调用可以并行,执行期间不再持有底座模块管理器的全局锁。同一模块仍串行执行,避免旧协议回调绑定和现有多步骤审批产生竞态;这不是同一模块的多副本扩容。JSON 存储仍采用串行写入,本次未迁移数据库。
每次调用通过现有协议的 Initialize 建立独立的反向 RPC 连接,绑定不可变的模块、操作者、动作、请求号与 API Key 限权快照。执行结束或超时会关闭该连接;旧回调不能借用下一次请求的身份,即使重用了请求号。底座在回调时仍按账号实时状态核验角色和数据范围。现有协议 v1 二进制无需重编译。
| 保护项 | 默认策略 |
|---|---|
| 请求期限 | 每次动作调用总预算 10 秒,涵盖管理器访问、排队、回调初始化和模块执行。客户端断开会取消请求;已开始的写入不能保证撤销。 |
| 总量与用户并发 | 底座最多接纳 16 个动作请求,每用户最多 4 个,均包含排队中的请求。同一账号的浏览器与多个 API Key 共用用户额度;16 是接纳槽位数,不代表 16 个模块执行线程。 |
| 单模块排队 | 每模块最多接纳 4 个请求,即 1 个执行、最多 3 个等待;排队最长 250 ms。管理器正在处理启停、安装等操作时,也只允许短暂等待,随后返回繁忙,不无限堆积。 |
| 用户速率 | 按用户 ID 的令牌桶,平均每秒补充 20 个令牌,最多突发 40 个。这约束业务动作入口,不是所有 HTTP 接口或所有反向 RPC 的统一配额。 |
| 过载返回 | 超过并发、速率或队列限制返回 HTTP 429 / RATE_LIMITED,并带 Retry-After: 1;该请求未进入业务执行,可稍后使用原请求号重试。 |
| 执行超时 | 读请求执行超时返回 HTTP 504 / DEADLINE_EXCEEDED;已进入调用的写请求在超时或断连时保守返回 HTTP 504 / OUTCOME_UNKNOWN。排队时取消的请求未执行。失败实例退出正常调度并由既有监督机制恢复,旧实例失败不会停止替代它的新实例。 |
写请求不能因超时就换新请求号自动重发。先查询业务状态,或在应用支持幂等的前提下使用原 request_id 重试。底座记录服务的去重仍生效,但模块自己的多步骤流程和外部系统副作用需要各自的幂等与审计设计。请求取消不是数据库回滚,也不能保证外部操作已经终止。
验收包含竞争检测、跨模块重叠执行、同模块串行、账号及 API Key 隔离、过期回调、队列与速率限制、HTTP 状态、8 个现有 Docker 模块兼容,以及隔离容器压测。4 模块、4 客户端、每请求模拟 50 ms 等待的 32 次读取测试中,串行参考约 18 次/秒、并行约 75 次/秒,约 4.1 倍;该数字只说明此测试条件下消除了全局串行,不能作为真实业务吞吐或硬件容量承诺。复现入口为 cmd/concurrency-probe 和 cmd/concurrency-acceptance,必须使用独立测试数据,不能对生产资源做写入压测。
开发环境管理请求调度
模块1.1.1将启动查询统一调度、优先加载关键数据,合并重复读取;只对明确未执行的读取有限重试,云资源写操作不自动重试。详见 模块繁忙、刷新与重试说明。
语言无关模块协议(v0.17)
公开协议 v2 为双向 JSON-RPC 2.0,Go/Python 通过相同身份、权限、H5、网关和能力接入。保留 Go v1 兼容通道。解释器镜像和命令由运维配置,应用不能自行指定 Docker 参数;未启用的运行配置拒绝启动。详见 跨语言协议、运行配置与 SDK。
应用专属 PostgreSQL(v0.16)
应用可申请 database.engine=postgres 与 database.connect。底座分配独立账号和 schema,经后端 RPC 提供连接配置,只有获批容器挂载数据库 Unix socket,仍不放开网络。OA 使用独立实例,原有应用不自动迁移。后台「应用数据库」查看空间与轮换凭据。详见 数据库接入、安全与备份指南。
模块自定义 API 路由(v0.15)
应用可声明 /apps/<module>/api 下的 JSON 路由,由底座统一认证、动作授权、参数校验、超时和限流,再经现有 RPC 交给模块处理。H5 使用 PlatformUI.request;Agent 使用限权 Key。CMS 0.4.0 提供完整示例。详见 路由声明与接入指南。
H5、双向 RPC 与模块数据设计
应用自定义页面运行在浏览器 iframe,Go 后端运行在服务器容器;页面通过 PlatformUI 消息桥进入底座 HTTP 动作网关,再由底座以可信用户身份调用模块 Execute。模块反向调用身份、记录等公共服务。CMS 提交与发布、同模块串行原因、当前数据库访问限制及独立数据库的扩展设计见 架构处理路径详解。
运行监控(v0.14)
后台「运行监控」展示 HTTP 与动作请求、延迟直方图、错误/限流/超时、模块队列及恢复、Go 运行时与容器资源。monitor.read 为只读权限,系统管理员默认具备,可单独授予监控角色与限权 API Key。提供受鉴权的 /api/monitoring 与 /api/monitoring/metrics,/readyz 提供通用就绪状态。指标内存保留、重启清零;最近请求仅保留 100 条,凭据与业务正文不记录。详细口径、Trace ID、采集限制与 Prometheus 示例见 监控接入说明。本次不自动安装外部历史监控或发送告警。
Docker 后台管理
modules.manage 用户可在 Docker 管理查看应用容器状态、隔离配置和最近日志,执行启动、停止、重启。管理接口只接受已注册模块 ID,不提供任意 Docker 命令、exec、挂载、镜像配置或全局清理。手动停止状态跨底座重启保持。cloud.request 仅供审核后的 cloud-admin 使用,凭据由底座保管,发布模拟禁用真实云连接器。
示例与历史升级说明
工单、报销、请假、CMS、组织通讯录、发票、五子棋均有完整 H5。CMS 保留编辑撰稿与总编审核发布流程;五子棋直接点击棋盘落子。发票和五子棋保留原有 Linux amd64 后端二进制,源码未在本仓库,来源指纹在各自 backend/provenance.json。
v0.9 必须先把全部在用模块迁为 H5,再整体升级底座和模块。保留旧底座及完整旧模块目录以便配套回退,业务数据、模块 ID、用户、角色和 API Key 保持原有标识。完整声明、消息格式和迁移说明见 H5 协议;Windows 服务运维见 服务指南。
单层应用标题(v0.17.4)
业务模块只保留底座顶栏这一个标题区;说明、状态和常用操作合并到顶栏,下面直接展示业务内容。现有应用通过受限消息桥兼容,无需修改业务后端或数据库。详见 H5 协议与标题集成。