独立事项包开发
读取、创建、完整更新和发布工作区独立事项包,以精确成员版本供 Workflow human 节点引用。
事项包由 issue-definition Owner 独立管理,归属于工作区,不属于 Bundle,不进入 Bundle Manifest,也不通过 Bundle 安装或升级发布。
一个事项包文档包含多个具名事项定义;Workflow 的 human 节点引用已发布包的精确成员版本。
事项包身份是 environmentKey + packageId,packageKey 是工作区内的作者键。草稿修订号 revision 与不可变 semanticVersion 分开管理。
更新草稿不会改变已发布版本,事项包发布也不会自动更新 Workflow 引用。
1. 确认 CLI 和授权
baijimu --version
baijimu workspace issue-definition --help
baijimu workspace issue-definition update --help
baijimu workspace issue-definition publish --help
baijimu auth status --verify命令参数以目标机器分级帮助为准。没有 workspace issue-definition 表示该 CLI 尚未提供此作者入口;
不能用 bundle resource object、通用 Bundle 作者命令或 Runtime 查询接口替代。
所有操作显式提供工作区。Owner 校验当前用户、工作区权限、来源所有权及草稿修订,不以安装基础套件作为作者授权。
2. 编写完整事项包 document
将下例保存为 issue-definition.json。输入、输出和状态采用 Type14 类型系统;
审核结果字段属于业务合同,平台不预置 accepted、approved 或 decision。
{
"schemaVersion": "1.0.0",
"typeProtocol": "14.0.0",
"issues": {
"business.review": {
"name": "业务审核",
"description": "核对业务摘要并提交审核结果",
"tags": [
"review"
],
"inputType": {
"@type": "JsonSchema",
"schema": {
"type": "object",
"properties": {
"summary": {
"type": "string"
}
},
"required": [
"summary"
],
"additionalProperties": false
}
},
"outputType": {
"@type": "JsonSchema",
"schema": {
"type": "object",
"properties": {
"accepted": {
"type": "boolean"
},
"comment": {
"type": "string"
}
},
"required": [
"accepted",
"comment"
],
"additionalProperties": false
}
},
"processActions": [
"manual_process"
],
"statusType": null
}
}
}- 文档顶层声明
schemaVersion: "1.0.0"、typeProtocol: "14.0.0"和非空issues对象。每个成员使用显式 key;例子的business.review与 human 引用中的成员名一致。 name必填,最多 200 个字符;description可省略,填写时最多 4000 个字符;文本不得为空或有首尾空白。- 每个成员声明
tags和processActions数组,无内容时填写[];每项最多 100 个字符。处理动作不能代替输出字段定义。 inputType、outputType和可选的statusType使用同一平台 Type 合同。用于工作流 human 的定义必须声明outputType。- 成员定义不包含
enabled、分配或执行策略。正式引用使用 Owner 返回的精确包版本和成员 key;分配与执行策略由 human 节点配置。 - 事项包 key 在创建时通过
--package-key指定,不放进 document;来源环境、packageId、修订号和版本由 Owner 管理。 - 不使用旧的
inputSchema/outputSchema/statusSchema字段;完整 Type 位置填写{"@type":"JsonSchema","schema":...},标准 JSON Schema 正文放在schema中。
完整更新必须提交同一份包含 schemaVersion、typeProtocol 和 issues 的完整文档。历史草稿读取可能保留原有 DataType 或空类型;
应以业务源码编写完整的 Type14 定义并显式更新,再回读核对输入、输出及状态类型。
已有不可变版本不会随草稿更新而改变,不能通过读取时补字段或改写旧版本完成迁移。
3. 创建、读取、更新与发布
先查询当前工作区拥有的包,再对目标执行操作:
baijimu workspace issue-definition list --workspace-id <WORKSPACE_ID> --json
baijimu workspace issue-definition create --workspace-id <WORKSPACE_ID> \
--package-key <PACKAGE_KEY> --document @issue-definition.json --json
baijimu workspace issue-definition get <PACKAGE_ID> --workspace-id <WORKSPACE_ID> \
--environment-key <SOURCE_ENVIRONMENT_KEY> --json
baijimu workspace issue-definition update <PACKAGE_ID> --workspace-id <WORKSPACE_ID> \
--environment-key <SOURCE_ENVIRONMENT_KEY> --expected-revision <READ_REVISION> \
--document @issue-definition.json --json
baijimu workspace issue-definition publish <PACKAGE_ID> <ISSUE_VERSION> --workspace-id <WORKSPACE_ID> \
--environment-key <SOURCE_ENVIRONMENT_KEY> --expected-revision <CURRENT_REVISION> --json
baijimu workspace issue-definition versions <PACKAGE_ID> --workspace-id <WORKSPACE_ID> \
--environment-key <SOURCE_ENVIRONMENT_KEY> --json
baijimu workspace issue-definition version <PACKAGE_ID> <ISSUE_VERSION> --workspace-id <WORKSPACE_ID> \
--environment-key <SOURCE_ENVIRONMENT_KEY> --json使用 create/get 返回的 package.environmentKey、package.packageId 和 revision,不使用 Bundle ID、资源 key 或名称代替身份。
完整更新使用读取时的 revision;更新成功后使用返回的新 revision 发布。修订冲突时回读并核对差异,不能自动刷新修订号重试覆盖。
发布严格 SemVer 的不可变版本,不能覆盖已有版本。分别评估事项包、Workflow 和 Bundle 自身版本,不把它们当作同一发布单元。
list 使用 --page-size 和 --cursor 分页,cursor 是 Owner 返回的 nextCursor JSON,也可保存为文件后使用 --cursor @cursor.json。
versions 的 --cursor 是 Owner 返回的精确版本字符串;CLI 不自动遍历或猜测下一页。
version 返回精确包版本的 JSON 制品,包含 version 和 document,不是安装台账。
人工作业引用形式是 baijimu-issue://<environmentKey>/<packageId>@<semanticVersion>#<memberKey>。
身份、版本和成员必须来自真实 Owner 目录或发布结果,示例身份不能直接套用。跨工作区消费还需按 Owner 当前共享及精确版本使用权合同授权,知道 URI 不等于获得访问权。
正式 Owner API
公开 Partner 前缀为 /partner/v1/issue-definition/api/issue-definition-packages,通过当前环境平台入口,使用 CLI 当前已授权的工作区凭据调用;不填写内部服务地址。
| 操作 | 方法和相对路径 | 请求 |
|---|---|---|
| 工作区拥有目录 | POST /pages | workspaceId、catalog: "owned"、pageSize、cursor |
| 创建 | POST /(前缀本身,无尾斜杠) | workspaceId、packageKey、document |
| 读取草稿 | GET /{environmentKey}/{packageId} | 无请求体 |
| 完整更新草稿 | PUT /{environmentKey}/{packageId}/draft | expectedRevision、document |
| 发布版本 | POST /{environmentKey}/{packageId}/versions | expectedRevision、semanticVersion |
| 版本目录 | POST /versions/pages | workspaceId、package: {environmentKey, packageId}、pageSize、cursor |
| 精确版本制品 | GET /{environmentKey}/{packageId}/versions/{semanticVersion}/artifact?workspaceId=... | 无请求体 |
workspaceId 是字符串;expectedRevision 是正整数。读取/写入/发布的成功及错误使用 CModel;artifact 成功直接返回 application/json 不可变制品,错误仍为 CModel。
例如更新正文为 {"expectedRevision":3,"document":<完整事项包文档>},发布正文为 {"expectedRevision":4,"semanticVersion":"<ISSUE_VERSION>"};这些片段说明请求结构,需替换为合法 JSON 和实际值。
4. 配置 human 节点与验证
下例与上面的输入输出合同配套。替换目录返回的事项定义身份、版本和候选用户后,将节点加入完整 Workflow:
{
"type": "human",
"id": "review",
"name": "人工审核",
"input": {
"summary": "{{input.summary}}"
},
"assignment": {
"mode": "candidates",
"candidates": [
{
"identityType": "user",
"identityId": "{{input.reviewerUserId}}"
}
]
},
"executionPolicy": {
"completionTimeoutSecs": 86400
},
"issueDefinitionReference": "baijimu-issue://example-origin/00000000-0000-4000-8000-000000000001@1.0.0#business.review"
}工作流输入需要声明 summary 和 reviewerUserId。reviewerUserId 必须来自当前工作区有效用户目录,
不能将用户姓名、设备 ID 或其他工作区用户 ID 当作候选用户。
input显式映射到事项的inputPayload;不会隐式发送整个 Workflow 输入或上下文。assignment.mode: "candidates"必须有非空候选列表。identityType支持user / department / group / role;角色候选的identityId对 Bundle 角色使用完整ROLELocator,对工作区角色保留该工作区的roleKey;Bundle 角色匹配必须具有正确的 Runtime 上下文。旧工作流合同中的裸 BundleroleKey需显式迁移,不能按同名解析。参见角色开发。- 明确用户列表校验、去重后,单人直接分配到
Issue.assignee,多人由其中一人领取。含角色、部门或群组时始终是候选范围;领取或转交后的唯一处理者是Issue.assignee。 - 对工作区成员开放领取时显式使用
assignment: {"mode":"workspace_members"},不能用空候选列表表达。 - 结果以节点
id为身份,例子写入context.review;输出类型始终归 IssueDefinition,Human 不配置result或节点级outputSchema。 completionTimeoutSecs是人工等待期限,必须大于零;它不是 HTTP 请求超时,省略表示不配置期限。
人工完成时提交与 outputType 一致的结果,例如 {"accepted":true,"comment":"核对通过"}。
Issue 校验通过后,由平台回传结果并推进 human 节点;下游据 context.review.accepted 判断业务分支。
accepted:false 仍是合法业务结果,不自动等于 Workflow 执行失败。
从前置节点读取候选人
前置节点若使用 id: "ownerLookup",其结果写入 context.ownerLookup。
例如实际输出为以下对象,reviewerUserId 的值必须是当前工作区有效用户目录中的真实 ID:
{
"summary": "待审核的报告摘要",
"reviewerUserId": "<VALID_WORKSPACE_USER_ID>"
}把上面完整 human 节点中的 input 和 assignment 替换为以下片段,保留原有的
issueDefinitionReference 和执行策略。连线必须让前置节点先完成,再执行 human:
{
"input": {
"summary": "{{context.ownerLookup.summary}}"
},
"assignment": {
"mode": "candidates",
"candidates": [
{
"identityType": "user",
"identityId": "{{context.ownerLookup.reviewerUserId}}"
}
]
}
}路径必须按实际节点输出合同填写;若返回值还有外层 data,应引用真实的嵌套路径,不能只凭节点 ID
猜输出位置。identityId 引用的是一个主体 ID,不是用户对象、用户姓名或数组。运行时解析为空或用户身份无效会报错,不会自动开放给全工作区;相同类型与 ID 的重复候选主体会去重。
动态用户列表:单人分配,多人领取
需要使用前置节点返回的任意长度用户列表时,继续使用 assignment.mode: "candidates",将整组引用直接放在 candidates。
前置节点应返回真实的当前工作区用户 ID 字符串数组,例如:
{
"summary": "待审核的报告摘要",
"userIds": ["<VALID_WORKSPACE_USER_ID>", "<ANOTHER_VALID_WORKSPACE_USER_ID>"]
}假设该节点的 id 是 ownerLookup,完整 human 节点可以写成:
{
"id": "reviewReport",
"type": "human",
"name": "审核报告",
"input": {
"summary": "{{context.ownerLookup.summary}}"
},
"assignment": {
"mode": "candidates",
"candidates": "{{context.ownerLookup.userIds}}"
},
"issueDefinitionReference": "baijimu-issue://example-origin/00000000-0000-4000-8000-000000000001@1.0.0#business.review"
}替换示例中的身份占位符;事项定义的 inputType / outputType 与本页定义保持一致。
Workflow 保存的是运行时数据引用,实际员工来自执行时所在工作区的用户目录。
若名单由 Event Trigger 传入 Workflow,改用 "candidates": "{{input.userIds}}",并在 Workflow inputSchema
声明对应的字符串数组。也可直接提供真实用户 ID 的非空 JSON 字符串数组;跨工作区复用的 Bundle 应使用引用。
平台使用固定规则,无需配置“直接分配”或“领取”策略:
| 校验并去重后的名单 | 行为 |
|---|---|
| 1 人 | 创建 Issue 时直接设置 Issue.assignee,该用户无需先领取。 |
| 多人 | 创建一个候选池;其中一人领取后成为唯一处理者,其他候选人不能再领取。 |
空名单、缺失路径、null 或错误类型 | human 执行失败,不创建开放事项。 |
| 任一用户不属于当前工作区 | 整组失败;不会丢弃无效用户后继续分配。 |
字符串 ID 去掉首尾空白后必须是标准正整数格式;重复 ID 只保留一份。["7","7"] 的有效人数为 1,
适用单人自动分配。数值数组、用户对象数组、姓名数组和 JSON 字符串化数组均不接受;前置节点需要先输出
字符串 ID 数组。这里的数值仅说明格式,实际配置必须使用目录返回的身份。
candidates 整组引用必须完整指向 input 或 context 中的数组;不支持拼接、隐式取第一人或在此处执行 =CEL。
多候选不代表会签,也不会创建多份事项。human 重试复用原 Issue,不覆盖已领取或转派后的负责人。
一个候选入口,统一分配规则
assignment.candidates 接受三种形式:
| 形式 | 示例 | 用途 |
|---|---|---|
| 用户 ID 字符串数组 | ["7", "8"] | 已知的当前工作区用户列表。 |
| 完整数组引用 | "{{context.ownerLookup.userIds}}" | 读取前置节点返回的用户 ID 字符串数组,也可引用 input。 |
| 候选主体对象数组 | [{"identityType":"role","identityId":"reviewer"}] | 指定 user / department / group / role 主体;每项 identityId 可引用单个值。 |
前两种形式解析为 user 候选主体,与直接填写用户主体对象使用相同的校验、去重和分配规则。
示例数字只说明格式,必须替换为目录返回的真实用户身份。字符串数组与主体对象不能混在同一个数组中。
整组引用的结果必须是用户 ID 字符串数组,不能是用户对象数组或候选主体对象数组。
纯用户候选去重后只有一人时直接分配;多人时由其中一人领取。如果包含角色、部门或群组,保留候选范围,
即使只配置一个角色,也不会将其当成一个用户直接分配。混合用户与角色的主体对象数组同样需要领取,
其中显式用户仍必须通过工作区成员校验。workspace_members 继续表示显式开放工作区领取。
不再使用独立的 mode: "users" / assignment.userIds;也不添加 mode: "direct"、分配策略开关或节点级
assignee。不要把用户数组放进某一项 identityId,该字段仍只表示一个主体 ID。
从旧配置升级
旧 users 配置应把 mode 改为 candidates,将 assignment.userIds 的原值移到
assignment.candidates,然后创建新的 Workflow 版本。该收敛合同拒绝旧 users 模式,平台升级前需核对
不可变资源版本、运行时投影和执行快照;不可变版本不能原地改写。
原有纯用户 candidates 也使用上述人数规则:新建事项的单一用户无需领取。已经创建的 Issue 不会因此
重新分配,重试继续保留现有负责人和领取状态。需要维持旧行为的在途流程应按旧合同完成后再切换,
不能只更新文档或平台镜像而跳过存量检查。
事件绑定、输入映射和两种表达式语法见 Event Trigger 教程。
不要用公开 wait.signal 接口绕过人工事项处理。
Workflow 按工作流开发创建、更新并创建精确不可变版本。当前 human 使用上述
issueDefinitionReference/input/assignment 字段;历史 Workflow Schema 5.0.0 的 human 示例
采用旧字段,不能用它校验或生成本页的新节点。历史合同保持原样,遇到 CLI 字段不兼容时应先核对版本,不能混用两套合同。
5. 交付与验收
事项包发布完成后,让 Workflow human 引用该包的精确版本和成员 key。Workflow 仍按自身所属 Bundle 的交付规则创建版本并安装, Bundle 清单仅纳入 Workflow,不纳入事项包。发布事项包本身无需创建 Bundle 版本或安装。
- 回读草稿和精确版本制品,核对输入、输出、状态类型及发布版本。
- 在实际消费工作区校验精确成员可访问;共享和版本使用权失败保持真实错误,不回退旧 Bundle 台账。
- 启动 Workflow,核对 human 输入、单人直接分配、多候选领取、空/无效名单拒绝。
- 提交符合 outputType 的结果,核对下游 context;另以缺失必填字段或错误类型确认校验生效。
- 根据业务需要验证拒绝分支及人工等待超时。事项包发布成功不能替代业务链路验收。
公共 Rust 合同包
公开 baijimu-issue-definition-contract 提供精确事项包身份与成员引用;需要文档类型时启用 document feature。
合同类型不授予访问权,HTTP 用户凭据、工作区授权和实际执行由 Owner 校验。