工作流 API 与运行目录
# 工作流 API 与运行目录
# 目的
通过实际 API/worker 运行面显式登记运行版本、发布标量表单和定义、受理本人发起,再由当前审批人读取允许字段并处理任务。 本页覆盖后端接口、参与人历史和固定原提交读取。首批真实用户页面见审批中心与表单发起,定义准入与运行管理见管理页面手册。
# 前置条件
业务库须显式升级至 schema v48,Redis 与原有身份服务可用。API/worker 不自动迁移、登记运行版本、创建账号或开通套餐。
平台目录需要 platform:workflow-runtime:read/write;租户需套餐能力 workflow.definitions、workflow.execution、workflow.forms,
以及当前操作对应权限;会话须已完成初始改密且当前未撤销。平台身份不能进入租户工作流,租户头不能覆盖主库身份。
下文 curl 仅用于 development/test 明文环境;启用加密的环境必须用统一内容协议封装同样的方法、路径、查询和JSON正文。 生产强制内容加密,RSA-AES 与 SM2-SM4 均使用原认证、Origin、重放检查和统一响应,不能改用裸 JSON 绕过。 本机配置、连接和访问凭据由操作者提供,先按登录说明取得平台及租户凭据。
export FAGO_WORKFLOW_API_BASE='http://127.0.0.1:8081'
export FAGO_WORKFLOW_ORIGIN='<已配置的精确Origin>'
export FAGO_WORKFLOW_PLATFORM_TOKEN='<操作者提供的平台访问凭据>'
export FAGO_WORKFLOW_ADMIN_TOKEN='<操作者提供的租户访问凭据>'
# 步骤与规则
# 1. 先开放目录,显式登记
fago-form-approval-v3 显式冻结审批受理能力,并要求持续API/worker池;本页的受理接口及现有审批页面已经接入。旧v1/v2仍使用同步决策合同。页面只依据已授权当前任务正文的 acceptedSignals === true 选择受理入口,不根据版本名称或角色猜测能力,详见下方审批受理、查询与继续。
首次部署选择代码内的受池保护标量表单模板。目录管理可独立启动,避免“未登记不能加入池、没有管理入口不能登记”的依赖环; 该模式不挂载租户工作流接口。配置来自当前环境 YAML,环境变量优先,修改后重启而非热加载。
workflow:
catalog_enabled: true
api_enabled: false
worker_enabled: false
runtime_versions: [fago-form-approval-v2]
poll_millis: 1000
lease_millis: 30000
retry_millis: 1000
从外层仓库根目录启动 API,再用平台身份读取实际构建。这里只返回代码模板、合同及摘要,不发布目标URL、凭据路径或私有清单正文。
bash scripts/fago.sh api
# 另一个终端执行:
curl "$FAGO_WORKFLOW_API_BASE/api/platform/v1/workflow/runtimes/build" \
-H "Authorization: Bearer $FAGO_WORKFLOW_PLATFORM_TOKEN"
登记只传代码中已有的版本和受控审计追踪号commandId;不能从请求提供指纹、能力或任意处理器。成功后该版本为 enabled、version=1、admissionEpoch=1。
同一精确清单重复登记返回原目录身份,不覆盖旧语义,也不会将 draining 自动恢复为 enabled。
curl -X POST "$FAGO_WORKFLOW_API_BASE/api/platform/v1/workflow/runtimes/fago-form-approval-v2/register" \
-H "Authorization: Bearer $FAGO_WORKFLOW_PLATFORM_TOKEN" \
-H "Origin: $FAGO_WORKFLOW_ORIGIN" \
-H 'X-App-Request: platform' \
-H 'Content-Type: application/json' \
--data '{"version":0,"commandId":"runtime-register-1"}'
目录 GET /api/platform/v1/workflow/runtimes?after=<上一页nextCursor> 按主键返回最多50项 items,空游标从第一页开始,空 nextCursor 表示本次快照结束。
包括 retired 历史,并不把历史变成当前构建支持的版本。1/50条均只查询一次目录元数据,不读取清单正文。
# 2. 部署实际 API/worker 池
登记后分别启动同一精确构建的 API 与 worker。以下环境覆盖配合前一份 YAML,版本名单整体替换;旧版本仍有引用时必须同时保留。 业务 API 在监听前完成实际 api 角色的 Acquire;worker 使用独立 worker 角色。缺已登记版本、清单不匹配或遗漏仍 enabled/draining 的处理器都会非零退出。
export APP_WORKFLOW_CATALOG_ENABLED=true
export APP_WORKFLOW_API_ENABLED=true
export APP_WORKFLOW_WORKER_ENABLED=true
export APP_WORKFLOW_RUNTIME_VERSIONS=fago-form-approval-v2
bash scripts/fago.sh api
在另一个具备同样配置的终端启动后台进程。两种角色均覆盖且所有存活工作流池兼容后,才能启用定义或首次发起;单一角色不是另一种角色的替身。
bash scripts/fago.sh worker
# API 的 /api/health/ready 同时检查自身工作流池;worker覆盖由具体发布/发起事务再次检查。
每个工作流业务请求独立 Bind,保留当前身份并捕获固定池截止;管理请求只绑定进程取消和操作超时,不要求池。 两类请求均受 lease_millis 操作时限约束,后续心跳不延长在途操作。 心跳失权会取消在途请求并停止正式 API 监听,不能只记录错误后继续服务。停机先取消、join请求及心跳,再释放调用器和数据库。 本地进程退出不等于最后兼容池已成功卸载;未成功 Close 的 presence 保留至原截止,受控卸载规则见配置手册。
从正式v2升级到v3时,先通过平台目录登记v3,再部署同时保留两版处理器的新构建。API和worker分别使用下面的版本名单;先保持旧定义,不在只有一对新池就绪时立即启用v3定义。
# 在仓库根目录,API与worker终端都设置相同名单;其他身份/连接配置沿用前述前置条件。
export APP_WORKFLOW_RUNTIME_VERSIONS=fago-form-approval-v2,fago-form-approval-v3
bash scripts/fago.sh api
# 另一个终端设置相同环境后运行:bash scripts/fago.sh worker
确认新API就绪、实际worker兼容池已登记后,逐一卸载只支持v2的旧池。旧presence仍存活时,启用v3定义返回409003;不能靠删除池记录绕过。全部存活API/worker都覆盖v3后,才重投原发布命令。旧定义的新发起仍固定v2,旧待办的任务/激活/版本与同步审批能力保持,新发布的v3定义才使用审批受理入口。
准备移除v2处理器时,先drain关闭新的运行版本准入,继续保留两版处理器以完成旧实例;关闭所有仍可发起的旧定义入口并排空权威引用后才能retire。零活动实例仍可能被可发起旧定义阻止退役。retired后可部署仅v3的池,旧实例安全历史元数据仍可读。恢复旧版时,先让所有存活池重新覆盖v2,再显式reopen;只增加一对兼容池仍不够,reopen也不会自动启用旧定义。
上述顺序已有固定历史二进制与当前构建的双库专项,覆盖人工等待、并行join、循环、timer与受理命令租约。它不替代生产拓扑或容量验收。启动失败日志现在保留公开数值业务码,秘密字段和未知对象继续遮盖;固定历史二进制的原日志仍可能把码显示为***,不能据此读取内部错误原因。
# 3. 发布表单并保存本人草稿
POST /api/admin/v1/workflow/forms 需要 bpm:form:publish。首次 expectedVersion=0,后续必须提交当前最新表单版本。
当前只支持 text/integer/boolean 标量,未实现设计器、附件或脚本。相同主体、命令号和载荷返回原结果;不同载荷冲突,不覆盖旧版。
POST /api/admin/v1/workflow/forms
Authorization: Bearer <租户访问凭据>
Origin: <精确Origin>
X-App-Request: admin
Content-Type: application/json
{"schema":{"schemaVersion":"fago-scalar-form-v1","key":"simple-request","name":"简单申请","fields":[{"name":"amount","type":"integer","required":true},{"name":"note","type":"text","required":false}]},"expectedVersion":0,"commandId":"form-publish-1"}
GET /api/admin/v1/workflow/forms/simple-request/versions/1 读取精确schema。POST /form-instances 需要 bpm:form:write,创建本人草稿并返回id及修订version。
修改时在同一端点增加id并提供当前 expectedVersion,不能替换原 formVersion。读取 GET /form-instances/:id 仍需本人资格;审批任务读取权不等于全局草稿读取权。
POST /api/admin/v1/workflow/form-instances
Authorization: Bearer <租户访问凭据>
Origin: <精确Origin>
X-App-Request: admin
Content-Type: application/json
{"form":{"key":"simple-request","version":1},"expectedVersion":0,"values":{"amount":{"integer":10},"note":{"text":"申请说明"}},"commandId":"draft-save-1"}
保留返回的id和version。值必须且只能使用一个类型字段,如 { "integer":10 };不能用浮点ID、动态对象或普通字符串替代。
原提交快照从 GET /form-instances/:id/submissions/:version 读取,仍按本人资格隔离,审批人须走任务正文入口。
# 4. 发布固定表单版本的定义
POST /definitions 需要 workflow:definition:publish。model固定 engineVersion、resource合同和formVersion;allowSelf省略时默认禁止自审批。
将示例中的审批用户ID替换为当前租户真实可用账号,并先确认候选/角色权限。发布不会创建审批用户或给候选补权限。
POST /api/admin/v1/workflow/definitions
Authorization: Bearer <租户访问凭据>
Origin: <精确Origin>
X-App-Request: admin
Content-Type: application/json
{
"engineVersion":"fago-form-approval-v2","expectedVersion":0,"enable":true,"commandId":"definition-publish-1",
"model":{
"schemaVersion":"fago-workflow-v1","key":"simple-approval","name":"简单审批","engineVersion":"fago-form-approval-v2",
"variables":[{"name":"amount","type":"integer","required":true},{"name":"note","type":"text","required":false}],
"resources":[{"type":"form-instance","contractVersion":"scalar-form-v1","formKey":"simple-request","formVersion":1}],
"nodes":[
{"id":"start","kind":"start","name":"开始","next":"approval"},
{"id":"approval","kind":"approve","name":"审核","mode":"single","next":"done","rejected":"reject","candidates":[{"kind":"users","ids":["<当前租户审批用户ID>"]}],"readFields":["amount","note"],"outputs":["amount"]},
{"id":"done","kind":"end","name":"通过","outcome":"approved"},
{"id":"reject","kind":"end","name":"拒绝","outcome":"rejected"}
]
}
}
成功响应包含不可变 definition 和独立 admission,其中定义version=1、准入version=1。
GET /definitions/:key/versions?before=<发布版本> 每页最多50项发布元数据;GET /definitions/:key/versions/:version 返回经过摘要复核的规范模型。
全key目录见下文“目录与本人列表”;停用使用精确版本的独立准入命令,不取消旧实例、不改变历史模型:
PUT /api/admin/v1/workflow/definitions/simple-approval/versions/1/admission
Authorization: Bearer <租户访问凭据>
Origin: <精确Origin>
X-App-Request: admin
Content-Type: application/json
{"expectedVersion":1,"enable":false,"commandId":"definition-disable-1"}
该接口需要 workflow:definition:manage,expectedVersion属于准入而非定义。继续后续发起前应以当前准入版本重新启用,或不要执行上面的停用示例。
# 5. 受理发起并读取原命令
POST /instances 需要 workflow:instance:start,引用返回的本人草稿ID与修订版本,values须和资源中的受控值一致。
不能修改readonly字段来伪造金额/身份。命令、合法初始检查点、提交快照、活动占位及唤醒记录同事务提交,失败全部回滚。
POST /api/admin/v1/workflow/instances
Authorization: Bearer <租户访问凭据>
Origin: <精确Origin>
X-App-Request: admin
Content-Type: application/json
{"key":"simple-approval","version":1,"resource":{"type":"form-instance","id":"<返回的草稿id>","version":"1","contractVersion":"scalar-form-v1","purpose":"approval"},"values":{"amount":{"integer":10},"note":{"text":"申请说明"}},"commandId":"start-1"}
首次成功返回 HTTP 202、code=0,data包含 commandId、state:"accepted" 和安全实例检查点 result。202不代表审批或外部动作已完成。
原主体可读 GET /commands/start-1;后台完成发起命令后为done,人工审批实例仍可能running。相同载荷重投 accepted返回202,已完成命令返回200及冻结原结果;不同载荷返回409001。
GET /instances/:id 是需 workflow:instance:read 的租户安全元数据,不包含资源正文,也不替代未来参与人历史读取合同。
# 6. 当前审批人读取并处理任务
审批人使用自己的租户访问凭据读取 GET /api/admin/v1/workflow/tasks?before=<上一页最后taskId>,需要 workflow:task:read。
只列本人当前候选/分配元数据,不能把列表可见当作此刻可操作;领域写入仍复核原候选来源与当前用户资格。
通过返回的instanceId、activationId、taskId和任务version读取正文。只有当前合法任务资格、精确资源版本和节点readFields交集可以返回;读取审计失败也不给部分正文。
GET /api/admin/v1/workflow/instances/<instanceId>/activations/<activationId>/tasks/<taskId>/resource?taskVersion=1
Authorization: Bearer <当前审批人的租户访问凭据>
审批需要 workflow:task:decide。任务版本、决定、允许输出字段和业务命令号必须完整提供;私有意见仅进入受控历史,不进入通用日志/事件。
会签、或签和串行模式仍由领域规则决定是否结束,不能把一次 approved 投票当作整个实例已批准。
POST /api/admin/v1/workflow/instances/<instanceId>/activations/<activationId>/tasks/<taskId>/decision
Authorization: Bearer <当前审批人的租户访问凭据>
Origin: <精确Origin>
X-App-Request: admin
Content-Type: application/json
{"taskVersion":1,"decision":"approved","values":{"amount":{"integer":20}},"opinion":"同意","commandId":"approve-1"}
成功为 HTTP 200,安全实例视图的state可能running、approved或rejected。已结束/转办后的旧任务不能再读取正文。
其他任务操作均为上面任务路径的POST后缀,使用 expectedVersion(任务版本)、commandId,可选reason;目标用户必须是规范十进制字符串。
| 后缀 | 权限 | 额外字段与限制 |
|---|---|---|
claim | workflow:task:claim | 只允许当前合法候选领取,不传目标用户 |
transfer | workflow:task:transfer | targetUserId;不能借转办修改变量 |
delegate | workflow:task:delegate | targetUserId;保留原委派来源,归还仍复核 |
return | workflow:task:return | 可传节点允许的values,不重新选择目标 |
reassign | workflow:task:manage | 仅管理补分配;不替代原候选/资源规则 |
实例内管理任务页为 GET /instances/:id/tasks?cursor=<上页next>,需要 workflow:task:manage,固定分页不静默截断。
取消实例为 POST /instances/:id/cancel,需要 workflow:instance:manage,正文为 { "expectedVersion":<实例版本>, "commandId":"cancel-1" }。
# 审批受理、查询与继续
部署受理审批时,先按步骤1、2显式加入并登记 fago-form-approval-v3,API和worker的 runtime_versions 均须包含它。
保留仍有enabled/draining定义、实例或job引用的旧版本;不要为了启用v3移除旧池覆盖。为新发起发布固定v3的新定义版本,已经发布的旧定义与实例不会自动升级。
当前任务正文顶层的 acceptedSignals 为true才选择下面入口;字段省略或false继续使用 /decision。这个提示不代替写入时的权限与版本复核,历史原提交不会新增该字段。
受理、查询和继续均要求原提交者当前的 workflow:task:decide。发起或管理权限不能替代它;审批者无需是流程发起人。
请求字段与同步审批相同,投票、检查点、job与outbox同事务提交,失败时整体回滚。不要同时向两个入口提交同一投票:
POST /api/admin/v1/workflow/instances/<instanceId>/activations/<activationId>/tasks/<taskId>/decision-commands
Authorization: Bearer <当前审批人的租户访问凭据>
Origin: <精确Origin>
X-App-Request: admin
Content-Type: application/json
{"taskVersion":1,"decision":"approved","values":{"amount":{"integer":20}},"opinion":"同意","commandId":"approve-accepted-1"}
存在自动后继时返回HTTP 202及安全检查点。部分会签等无需独占自动执行的情况可直接返回HTTP 200、state:"done",但实例仍可能running或等待其他人:
{"code":0,"data":{"commandId":"approve-accepted-1","state":"accepted","result":{"id":"<instanceId>","definitionKey":"example-flow","definitionVersion":1,"engineVersion":"fago-form-approval-v3","state":"running","version":2,"waiting":[],"needsRun":true}},"message":"ok","requestId":"<服务器生成>"}
查询只读取原命令,不推进执行,即使收据仍accepted也返回HTTP 200。其他操作者或租户不能读取;撤销当前审批权限后原操作者同样不能读取:
GET /api/admin/v1/workflow/approval-commands/approve-accepted-1
Authorization: Bearer <原提交者当前租户访问凭据>
worker会恢复已提交的自动后继;需要显式继续时,以下POST只接受空对象 {},没有query参数,也不能传替换投票、变量、版本或lease。
每次至多推进128步,仍未完成返回202/accepted,完成返回200/done。后台不会再次投票,也不保存或复用旧会话:
POST /api/admin/v1/workflow/approval-commands/approve-accepted-1/resume
Authorization: Bearer <原提交者当前租户访问凭据>
Origin: <精确Origin>
X-App-Request: admin
Content-Type: application/json
{}
网络响应丢失时结果尚未确认,保留原commandId、原载荷和原入口,可先GET查询或原样重投;不要生成新命令或自动退回同步入口。 相同载荷返回原检查点/冻结结果,异载荷409001。done只说明这次命令结算,最终是否批准以实例结果为准。 与后台worker竞争时,继续处理读取原命令的当前检查点,不重复投票。取消仍须匹配当前实例CAS;worker先推进后使用旧版本取消会返回409001,应先重读实例,不自动覆盖获胜者。在线继续或取消成功会撤销旧job租约;迟到worker不能覆盖收据,详见真实进程竞争记录。 拒绝恢复替换字段的示例为HTTP 400;未知query使用400002,当前权限不足403001、不可见404001、不支持受理能力409003:
{"code":400001,"data":null,"message":"请求格式不正确","requestId":"<服务器生成>"}
单个text值仍最多4096 UTF-8字节,输出只能包含节点允许的已声明变量,不能靠切换传输协议绕过。精确 decision-commands 路径的明文传输上限512 KiB、JWE封装1 MiB;resume 仍使用普通16 KiB正文额度。
# 7. 外部动作管理与运行版本退役
只有选择固定外部动作模板的v6运行版本才会创建外部job。
GET /instances/:id/activations/:activation/external-action 使用当前 workflow:instance:manage 和资源ACL,返回job安全状态,
不包含输入、原响应、目标URL、凭据或lease owner。retry/compensate使用job version,不能使用实例version,也不能传替换输入/目标。
POST /api/admin/v1/workflow/instances/<instanceId>/activations/<activationId>/external-action/retry
Authorization: Bearer <当前管理者的租户访问凭据>
Origin: <精确Origin>
X-App-Request: admin
Content-Type: application/json
{"expectedVersion":<job版本>,"commandId":"external-retry-1"}
将后缀换成 compensate 可按同一合同排队受控补偿。HTTP 200只说明本地管理命令提交,HTTP处理器不发远端请求;
实际worker继续使用原业务键、固定输入和独立原响应收据。补偿只接受允许恢复的dead未知效果,不支持撤销已正常完成的任意服务任务。
未知效果未结算时,取消、拒绝、定时终态和退役仍被拒绝,不能通过改库状态清fence。
平台 POST /runtimes/:engine/drain|retire|reopen 使用 { "version":<当前目录版本>, "commandId":"..." },仍需write权限和平台Origin。
GET /runtimes/:engine/references 查看七类引用阻塞项。关闭定义准入并排空所有权威引用后才可retire;Reopen还要求兼容api/worker覆盖,历史清单不删除。
# 目录与本人列表
五类列表都需要当前租户会话,固定每页最多50条;data.items为空时为[],data.nextCursor为空表示当前快照没有下一页。
每次翻页重新校验账号、套餐及权限,不保证跨请求固定快照,不支持总数、offset、任意排序、tenantId或ownerId参数。
| 完整路径(均为GET) | 当前权限 | 可选查询 | 顺序与内容 |
|---|---|---|---|
/api/admin/v1/workflow/definitions | workflow:definition:read | after | key正序,每key最新发布元数据及当前准入;不含model |
/api/admin/v1/workflow/forms | bpm:form:read | after | key正序,每key最新version/digest/createdAt;不含schema及其名称/字段 |
/api/admin/v1/workflow/form-instances | bpm:form:read | before | 本人当前草稿ID倒序,含固定formKey/formVersion和修订/时间;不含values |
/api/admin/v1/workflow/my-instances | workflow:instance:start | before | 本人发起,创建时间及ID倒序;含定义/运行版本、状态与时间,不含资源ID/正文 |
/api/admin/v1/workflow/completed-tasks | workflow:task:read | before | 本人实际投票ID倒序,含taskId/instanceId/activationId/taskVersion、决定、时间及实例定义/状态;不含意见/字段值 |
先读取定义目录。定义最新发布的准入可能为disabled;目录存在不代表当前运行版本可发起,发起仍按精确版本和当前运行面校验。
curl "$FAGO_WORKFLOW_API_BASE/api/admin/v1/workflow/definitions" \
-H "Authorization: Bearer $FAGO_WORKFLOW_ADMIN_TOKEN"
# 下一页用服务端返回的nextCursor原值,curl负责URL编码。
curl -G "$FAGO_WORKFLOW_API_BASE/api/admin/v1/workflow/definitions" \
--data-urlencode 'after=<上一页nextCursor>' \
-H "Authorization: Bearer $FAGO_WORKFLOW_ADMIN_TOKEN"
表单目录不加载大schema,选择key/version后再调用本页已有的精确版本接口。
curl "$FAGO_WORKFLOW_API_BASE/api/admin/v1/workflow/forms" \
-H "Authorization: Bearer $FAGO_WORKFLOW_ADMIN_TOKEN"
curl -G "$FAGO_WORKFLOW_API_BASE/api/admin/v1/workflow/forms" \
--data-urlencode 'after=<上一页nextCursor>' \
-H "Authorization: Bearer $FAGO_WORKFLOW_ADMIN_TOKEN"
本人草稿只列当前修订;表单管理员也不能列出其他人的草稿。填写详情仍使用/form-instances/:id逐次检查本人归属。
curl -G "$FAGO_WORKFLOW_API_BASE/api/admin/v1/workflow/form-instances" \
--data-urlencode 'before=<上一页nextCursor;第一页省略此参数>' \
-H "Authorization: Bearer $FAGO_WORKFLOW_ADMIN_TOKEN"
本人发起列表无需租户全局workflow:instance:read,也不能借管理员权限指定别人。游标为服务端生成的创建毫秒和ID组合,按原值传回。
curl "$FAGO_WORKFLOW_API_BASE/api/admin/v1/workflow/my-instances" \
-H "Authorization: Bearer $FAGO_WORKFLOW_ADMIN_TOKEN"
curl -G "$FAGO_WORKFLOW_API_BASE/api/admin/v1/workflow/my-instances" \
--data-urlencode 'before=<上一页nextCursor>' \
-H "Authorization: Bearer $FAGO_WORKFLOW_ADMIN_TOKEN"
已办只承认不可变投票中的实际actor,不能按当前持有人或旧候选推断。一次流程多次实际审批各占一行;领取、转办、委派和代理归还不计入当前已办列表。 管理员不继承他人的已办;列表出现也不授予旧任务正文的永久访问权。
curl "$FAGO_WORKFLOW_API_BASE/api/admin/v1/workflow/completed-tasks" \
-H "Authorization: Bearer $FAGO_WORKFLOW_ADMIN_TOKEN"
curl -G "$FAGO_WORKFLOW_API_BASE/api/admin/v1/workflow/completed-tasks" \
--data-urlencode 'before=<上一页nextCursor>' \
-H "Authorization: Bearer $FAGO_WORKFLOW_ADMIN_TOKEN"
成功的空列表使用统一响应,三种内容协议解密后的业务结构相同:
{"code":0,"data":{"items":[],"nextCursor":""},"message":"ok","requestId":"<服务器生成>"}
非法游标不会回退第一页,未知查询字段也拒绝。以下调用尝试指定他人,返回HTTP 400、code=400002;修正参数后重试,不生成业务命令。
GET /api/admin/v1/workflow/completed-tasks?ownerId=1
Authorization: Bearer <当前租户访问凭据>
HTTP/1.1 400 Bad Request
Content-Type: application/json
{"code":400002,"data":null,"message":"字段校验失败","requestId":"<服务器生成>"}
# 本人非投票操作记录
GET /api/admin/v1/workflow/task-activities使用当前workflow:history:read权限与workflow.execution套餐能力,
列出本人实际执行的task.claim、task.transfer、task.delegate、task.return。当前会话、账号及权限在每页同一只读快照重新复核,
只保留旧context或曾有操作权限不能继续读取。无需另有当前workflow:task:read,也不要求任务还在待办中。
同一任务的多次真实动作各占一行,成功命令重投不新增事件。候选、收到指派、系统事件和管理补分配不进入这个列表。
completed-tasks继续只包含同意/拒绝的真实投票;代理归还进入操作记录,不算最终审批。
第一页不传参数;后续只允许before=<上一页nextCursor>。游标是规范正整数事件ID字符串,必须原样传回,不能自行递减、改成毫秒或任务版本。
固定ID倒序,每页最多50条,空页items=[]、结束nextCursor="";不接受pageSize、actorId、ownerId或租户覆盖参数。
GET /api/admin/v1/workflow/task-activities
Authorization: Bearer <当前租户访问凭据>
HTTP/1.1 200 OK
Content-Type: application/json
{"code":0,"data":{"items":[{"id":"21","taskId":"<任务ID>","instanceId":"<实例ID>","activationId":5,"taskVersion":3,"action":"task.transfer","occurredAt":1700000000000,"definitionKey":"example","definitionVersion":1,"instanceState":"approved"}],"nextCursor":""},"message":"ok","requestId":"<服务器生成>"}
在生产加密协议下,上例是解密后的业务结构。id固定为字符串,避免浏览器整数精度损失;taskVersion是该动作完成后的不可变事件版本,
instanceState是当前查询快照里的流程状态,不是当时任务状态。列表没有原因、值、他人身份或命令号。
用instanceId进入下节参与人详情,无需当前任务参数;用id定位本人私有任务事件,不能把该ID当作投票ID:
GET /api/admin/v1/workflow/participant-instances/<实例ID>/history/task/21
Authorization: Bearer <当前租户访问凭据>
条目详情仍逐次授权;claim/transfer/delegate不授予原提交正文。只有真实投票或精确归还事件另满足原提交权限与原节点字段白名单,才可调用原提交入口。 不按列表展示结果恢复旧临时授权,也不把历史任务版本用于当前任务写操作。
未知/重复查询参数与非规范游标返回HTTP 400、400002;修正后可重试。依赖失败503001不给已读的部分页,恢复后可重读,读取不创建业务命令。
GET /api/admin/v1/workflow/task-activities?before=01
Authorization: Bearer <当前租户访问凭据>
HTTP/1.1 400 Bad Request
Content-Type: application/json
{"code":400002,"data":null,"message":"字段校验失败","requestId":"<服务器生成>"}
本接口依赖schema v46的跨实例actor/action索引,每动作各取最多51条再合并,固定四条相关业务SQL,不逐条恢复流程或读取正文。 浏览器页面入口仍待实现;迁移与验证边界见迁移手册。
# 参与人详情与追加历史
本组接口使用新权限workflow:history:read(套餐能力workflow.execution);旧workflow:instance:read只读管理元数据,不自动取得参与人历史。
当前候选分支另需当前workflow:task:read。原提交还需新bpm:form:history-read(workflow.forms);旧表单read权限不能代替。
迁移为保留租户管理员登记新权限,但管理员也只能按本人实际关系读取,不能借此查看任意他人正文。
发起人无需任务参数,实际投票或领取/转办/委派/归还人可凭追加证据读取元数据。仅被分配或进入过候选名单不构成过去参与。
尚未实际操作的当前候选/持有人须提交完整activationId/taskId/taskVersion,每次复核活动任务与原候选来源;后来加入成员不会继承旧任务。
管理补分配、后台ready/cancelled事件的actor不作为过去参与证据。
任务关系在定义读取/版本检查前筛选;完整当前资格确认前,模型/清单恢复诊断统一按资格拒绝,不向已撤销来源者透露500或409003。
恢复记录缺失也在持久化错误归一化后统一资格拒绝。真正的依赖不可用仍503001;当前资格成功后才对过期任务版本返回409001。管理员可通过已授权的精确定义详情检查存储诊断。
# 以下值从受理命令/本人任务的真实响应取得,不填写其他租户或其他人的定位。
export FAGO_WORKFLOW_INSTANCE_ID='<服务器返回的instanceId>'
export FAGO_WORKFLOW_ACTIVATION_ID='<服务器返回的activationId>'
export FAGO_WORKFLOW_TASK_ID='<服务器返回的taskId>'
export FAGO_WORKFLOW_TASK_VERSION='<服务器返回的任务version>'
# 发起人/实际过去参与人:
curl "$FAGO_WORKFLOW_API_BASE/api/admin/v1/workflow/participant-instances/$FAGO_WORKFLOW_INSTANCE_ID" \
-H "Authorization: Bearer $FAGO_WORKFLOW_ADMIN_TOKEN"
# 尚未操作的当前任务参与人:
curl -G "$FAGO_WORKFLOW_API_BASE/api/admin/v1/workflow/participant-instances/$FAGO_WORKFLOW_INSTANCE_ID" \
--data-urlencode "activationId=$FAGO_WORKFLOW_ACTIVATION_ID" \
--data-urlencode "taskId=$FAGO_WORKFLOW_TASK_ID" \
--data-urlencode "taskVersion=$FAGO_WORKFLOW_TASK_VERSION" \
-H "Authorization: Bearer $FAGO_WORKFLOW_ADMIN_TOKEN"
成功data包含id、definitionKey/definitionVersion、engineVersion、state/version、createdAt/updatedAt、原定义name、initiatorId和membership。
membership为initiator、past-actor或current-task,不含资源正文、变量或候选名单。
时间线将生命周期、投票和任务事件合并,固定50条一页。每个来源最多取51条,再按occurredAt/source/id倒序有界合并,
游标同时绑定租户、实例及完整位置;每页仍重新授权,不保证跨请求固定数据库快照。后台actorId为字符串"0"。
curl "$FAGO_WORKFLOW_API_BASE/api/admin/v1/workflow/participant-instances/$FAGO_WORKFLOW_INSTANCE_ID/history" \
-H "Authorization: Bearer $FAGO_WORKFLOW_ADMIN_TOKEN"
curl -G "$FAGO_WORKFLOW_API_BASE/api/admin/v1/workflow/participant-instances/$FAGO_WORKFLOW_INSTANCE_ID/history" \
--data-urlencode 'before=<上一页nextCursor>' \
-H "Authorization: Bearer $FAGO_WORKFLOW_ADMIN_TOKEN"
当前任务参与人翻页时还须传上面的三元组,不能只用游标代替资格。成功data仍为{items:[],nextCursor:""}结构;条目包含source、字符串id、
action、actorId、activationId、taskId/taskVersion、instanceVersion、commandId、时间及可空的beforeAssignee/afterAssignee/delegatorId。
不批量读取意见、原因、字段值、工作ID或fence;canReadDetails只表示当前角色可尝试读取该条私有说明,下次请求仍重验。
| source | 来源 | 私有详情路径中的source |
|---|---|---|
| 0 | 生命周期元数据 | 无私有详情,不接受execution |
| 1 | 实际同意/拒绝投票 | decision |
| 2 | 任务追加事件 | task |
私有意见/原因只允许发起人或条目actor读取,其他当前/过去参与人只看元数据。使用条目的原ID,不能混用不同表的自增ID。
export FAGO_WORKFLOW_HISTORY_ID='<时间线返回的字符串id>'
curl "$FAGO_WORKFLOW_API_BASE/api/admin/v1/workflow/participant-instances/$FAGO_WORKFLOW_INSTANCE_ID/history/decision/$FAGO_WORKFLOW_HISTORY_ID" \
-H "Authorization: Bearer $FAGO_WORKFLOW_ADMIN_TOKEN"
# 任务条目改用/history/task/<id>;当前任务分支仍须附完整三元组。
成功data在条目元数据上增加nodeId、opinion、reason和values;values仅包含原节点Outputs允许且类型正确的实际提交值。
空值固定为对象{},不会把损坏输出或已读取的部分意见带出失败事务。
# 固定原提交读取
新读取合同为workflow-original-resource-v1,当前真实资源只实现form-instance/scalar-form-v1。
它返回固定原schema和原提交,既不是当前草稿、最终汇总,也不是某节点当时完整输入;独立展示的审批输出请使用上一组私有详情。
原任务正文入口仍只允许活动任务及当前资格,不因新历史入口而永久开放。
发起人可读本人原提交全部字段,还要检查原资源owner与实例用途绑定。管理员不是发起人时没有这个入口的旁路。
curl "$FAGO_WORKFLOW_API_BASE/api/admin/v1/workflow/participant-instances/$FAGO_WORKFLOW_INSTANCE_ID/original" \
-H "Authorization: Bearer $FAGO_WORKFLOW_ADMIN_TOKEN"
实际同意/拒绝人、实际代理归还人可读取其精确处理版本对应的原提交,仅投影原节点ReadFields。 仅领取/转办/委派、收到指派或曾是候选人不足以取得历史原提交。代理归还的版本取该事件taskVersion,投票版本取该投票taskVersion,不能改用当前任务版本。
curl -G "$FAGO_WORKFLOW_API_BASE/api/admin/v1/workflow/participant-instances/$FAGO_WORKFLOW_INSTANCE_ID/activations/$FAGO_WORKFLOW_ACTIVATION_ID/tasks/$FAGO_WORKFLOW_TASK_ID/original" \
--data-urlencode "taskVersion=$FAGO_WORKFLOW_TASK_VERSION" \
-H "Authorization: Bearer $FAGO_WORKFLOW_ADMIN_TOKEN"
下面示例中原提交amount=10,即使审批输出后来为20,原提交仍为10;note未列入该节点白名单就不出现。 生产内容协议解密后的结构相同,示例ID都是占位符。
{
"code": 0,
"data": {
"contract": "workflow-original-resource-v1",
"instanceId": "<实例ID>", "activationId": 3, "taskId": "<任务ID>", "taskVersion": 1,
"resource": {"type":"form-instance","id":"<原提交资源ID>","version":"1","contractVersion":"scalar-form-v1","purpose":"approval"},
"data": {
"contract":"scalar-form-original-v1", "form":{"key":"expense","version":1},
"fields":[{"name":"amount","type":"integer","required":true}],
"values":{"amount":{"integer":10}}
}
},
"message":"ok", "requestId":"<服务器生成>"
}
每次成功原提交读取在同一当前身份事务中追加两层无正文审计;相同requestId仍重新授权/审计,不缓存私有响应。 任一审计、资源授权、存储摘要或提交失败都回滚,响应不带部分正文。grant/slot结束后不会被复活,实例和任务版本不增长。 退役后依赖原目录/定义摘要和已实现的纯编译器解释,不装配旧执行bundle;这不授予旧实例执行或新发起资格。
旧v3没有ReadFields时,实际处理人原提交返回409003,不能默认开放全部字段;未知历史编译器同样明确拒绝正文解释。 当前会话或历史权限撤销会拒绝,即使context、游标、任务ID或旧grant仍存在。
非法、重复或部分任务参数返回400002;不相关主体/跨租户/他人私有条目统一404001。例如他人意见读取:
HTTP/1.1 404 Not Found
Content-Type: application/json
{"code":404001,"data":null,"message":"资源不存在或不可见","requestId":"<服务器生成>"}
# 参数
| 参数 | 规则 |
|---|---|
catalog_enabled | 默认false;APP_WORKFLOW_CATALOG_ENABLED优先;独立平台管理面,不自动登记 |
api_enabled | 默认false;APP_WORKFLOW_API_ENABLED优先;监听前实际池/构建预检 |
runtime_versions | 最多32个显式版本;未知、重复或未登记业务版本拒绝;旧v1/v2字节不因配置扩容改变 |
commandId | 表单/定义/实例/任务/动作管理命令按主体与载荷绑定,重试保留原值;目录命令仅作受控审计追踪,按目标状态/目录版本幂等,不承诺冻结原响应 |
expectedVersion | 按具体对象区分表单最新版本、草稿修订、定义最新发布、准入、实例、任务或job;不相互替换 |
| 正文额度 | 精确POST定义/表单/草稿/发起及合法任务decision/return为512KiB;模型/表单值领域仍各限256KiB,其余普通端点16KiB |
| 路径/查询 | 未知参数、重复参数和非规范正整数拒绝;字段/租户/身份不从请求头覆盖 |
# 失败与重试
所有业务响应沿用 code/data/message/requestId,失败不会输出内部错误链、配置或私有正文。明文示例的重复/未知DTO键返回:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{"code":400001,"data":null,"message":"请求格式不正确","requestId":"<服务器生成>"}
400002是领域字段/版本格式非法;403001是当前权限拒绝,403004是来源拒绝;404001不区分不存在与不可见。 409001表示版本或同命令不同载荷冲突,应先重读对象再决定业务动作,不能盲目生成新命令重复执行。 409003表示准入/覆盖/未知外部效果等当前状态阻止操作;修复原因后再按原业务重投。503001表示当前依赖/进程池不可用, 恢复兼容运行面后可使用原commandId重试,不能把连接失败当作“未执行”。加密环境错误也通过原响应密钥加密。
# OpenAPI合同与生成类型
正式工作流46个操作、63个schema现已纳入根api/openapi.yaml。模块唯一编辑源及生成物位于fago应用仓库:
scripts/workflow-openapi.mjs生成internal/auth/testdata/workflow.openapi.json,外层脚本只聚合标记为工作流所有的操作及Wf前缀schema。
根合同保留其他模块,工作流片段自身也可独立lint或供SDK生成。
# 外层仓库根目录;修改模块编辑源后同步,再校验并重新生成真实前端类型。
node scripts/sync-workflow-openapi.mjs
bash scripts/web.sh contract
# 只检查源/片段/根聚合一致性,不写文件:
node scripts/sync-workflow-openapi.mjs --check
生成类型写入fago/fago-vben5/apps/web-antd/src/api/schema.d.ts;运行目录、构建、引用、实例、外部job、版本命令及审批收据 ApprovalReceipt 的客户端类型直接引用生成schema。生成器保留上游头并写明来源/命令;generate-api-types.mjs --check可只检查类型产物漂移。
JSON整数继续为int64数字,账号/事件ID和路径/查询的规范版本保留字符串;浏览器安全整数边界不改变服务端合同。
assigneeId、delegatorId可为null,不能改成缺失或0。普通实例version为正数,历史非执行条目中的instanceVersion可为0,不能拿来做当前CAS。
合同明确平台/租户realm、当前权限交集、生产JSON/JWE、精确正文额度、202受理及安全错误envelope。 读取历史原提交须同时有workflow:history:read与bpm:form:history-read;完整当前任务三元组和历史任务版本各按原端点规则传入。
源码检查以实际Gin注册路由、Go DTO及注册表达式为权威,核对方法/路径、权限、query/根DTO白名单、可空、嵌入展开和字符串ID。 实库专项额外逐条校验按原协议处理的真实响应,并用真实单模式领取、委派、归还、表单版本和提交读取补齐操作覆盖。
# 自建专用数据库与Redis;每方言均运行完整同一OpenAPI专项,包含三种实际内容协议。
bash scripts/test-workflow.sh --driver postgres --application-run '^TestIntegrationWorkflowOpenAPI$'
bash scripts/test-workflow.sh --driver mysql --application-run '^TestIntegrationWorkflowOpenAPI$'
# 成功后结果status=passed、cleanup=true;原样例仅存testing私有临时文件,结束即清理。
本专项要求本地已安装锁定前端依赖及Node,缺失时失败而非跳过。每库已校验414条真实响应和105个成功请求、覆盖46个操作; 该计数包含成功/拒绝场景,不表示每个状态/输入组合或完整恢复容量都已穷举。JSON Schema不代替重复键检查、语义编译或当前授权。 详细结果见M6受理接口与页面记录。
# 边界
当前已有五类目录/本人列表与独立个人操作记录、参与人详情/时间线、私有条目和固定原提交接口;真实Vben本人审批/历史与标量表单草稿/发起页面已接入,定义准入、平台目录、实例/任务和外部动作管理已有真实页面。 本人已办列表仍仅含真实投票;领取/转办/委派/归还同时可从个人操作记录及实例时间线定位。原提交不是节点当时完整输入快照。其他accepted命令种类、W07其他资源、完整滚动/积压/锁等待和容量仍继续验收。 正式v3审批受理已有真实API/worker进程恢复专项:撤销会话/当前审批权不撤回已提交投票,响应丢失后仍使用原命令查询或重投。该专项不覆盖完整组合恢复或实际浏览器,不能据此跳过兼容池部署与后续验收。 既有v6外部模板的受理发起、同步审批、自动续跑、外部动作与自然超时已有同实例四队列组合恢复专项。旧外部模板不因该专项新增审批受理能力,仍按当前正文的acceptedSignals选择实际入口;v2→v3固定历史构建滚动专项已另行补齐,更广泛组合、容量和浏览器验收仍继续。 MySQL/PostgreSQL专项通过不等于生产部署、七库或外部接收方厂商已认证;达梦仅构建验证。浏览器因Work设置禁用未运行,不用静态检查代替真实产品页面验收。
运行中可从API独立回环指标口观察四类工作流队列,具体状态、年龄口径、采样失败与告警示例见积压观测。指标不返回任务正文或执行许可,不能把消息已确认数代替流程完成数。