openxiangda-skill-kit 2.3.57 → 2.3.89
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/skills/openxiangda-v2/references/administration.md +40 -1
- package/skills/openxiangda-v2/references/backend.md +189 -3
- package/skills/openxiangda-v2/references/data-authz.md +72 -2
- package/skills/openxiangda-v2/references/declarations-cheatsheet.md +11 -1
- package/skills/openxiangda-v2/references/development.md +7 -0
- package/skills/openxiangda-v2/references/field-components.md +80 -0
- package/skills/openxiangda-v2/references/frontend.md +8 -0
- package/skills/openxiangda-v2/references/getting-started.md +53 -0
- package/skills/openxiangda-v2/references/managed-concurrency-frontend.md +10 -4
- package/skills/openxiangda-v2/references/testing.md +17 -0
- package/skills/openxiangda-v2/references/workflow-events.md +403 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openxiangda-skill-kit",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.89",
|
|
4
4
|
"description": "OpenXiangda 2.0 中文 AI 技能的校验、分发与安装。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"README.md"
|
|
18
18
|
],
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"openxiangda-devkit-core": "2.
|
|
20
|
+
"openxiangda-devkit-core": "2.51.1"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"tsx": "4.23.12",
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
平台的应用管理控制台维护应用成员、角色授权和流程运行参数。应用自身声明的 `/admin` 业务菜单展示业务页面,两者职责不同。可见入口和可执行操作以当前用户与目标环境返回结果为准。
|
|
4
4
|
|
|
5
|
+
角色成员的范围维度也支持模型字段的 `userCandidates.scope` 引用,不要求为审批人职责增加无关的数据读写策略。目录 `scopeDimensions[].applicability.candidateFields` 返回字段所在的资源、数据修订、字段、角色与操作;当前环境及仍在办理的历史流程所引用的字段均可贡献范围适用性。实例完成或发起命令取消后,旧字段不再单独贡献适用性。配置成员的范围不会自动授予数据读写、菜单或应用管理权限;实际选人与提交仍核验范围、操作、成员有效期及账号状态。
|
|
6
|
+
|
|
7
|
+
流程的 `app_role_in_scope` 绑定也贡献范围适用性,包括审批、抄送、兼容的节点人员覆盖及路由补充来源。目录 `scopeDimensions[].applicability.workflowBindings` 返回流程、节点、角色、定义/绑定版本、配置修订、来源和 `active`/`in_flight` 上下文;不包含业务事实或标题。当前启用定义和仍在办理的固定版本均可维护其职责,终态实例或已取消发起命令不再单独贡献适用性。
|
|
8
|
+
|
|
9
|
+
自定义管理页面按“候选字段引用该角色、有效流程范围职责引用该角色,或任一数据策略规则适用于该角色”筛选维度。每条策略须单独处理 `unrestrictedRoleCodes`;不能仅依据汇总 `allRoles`、`roleCodes` 或全局排除列表判断。未返回 `candidateFields` 或 `workflowBindings` 时按空列表处理。流程职责的范围维护不授予普通数据读写权限,也不改变已创建任务的参与人快照。
|
|
10
|
+
|
|
5
11
|
## 发现当前入口 {#context}
|
|
6
12
|
|
|
7
13
|
```bash
|
|
@@ -85,10 +91,43 @@ export function ResponsibilityMembers() {
|
|
|
85
91
|
|
|
86
92
|
读取沿用原流程管理权限。仅获成员管理委托的用户可能可以维护角色,同时没有权限读取关联流程;组件单独呈现该拒绝。返回不含成员、实例标识或业务事实,每页最多 100 条;最多 1000 个版本组合、32 MiB 源 JSON、10000 节点/引用,超限明确拒绝。
|
|
87
93
|
|
|
94
|
+
### 多职责成员合并
|
|
95
|
+
|
|
96
|
+
审批或抄送的 `app_role` / `app_role_in_scope` 来源可用 `roleCodes` 声明 2–8 个不同职责,
|
|
97
|
+
与单职责 `roleCode` 互斥。例如:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
jointReviewers: {
|
|
101
|
+
provider: 'app_role',
|
|
102
|
+
roleCodes: ['student-office', 'organization'],
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
节点进入时读取这些职责的当前有效成员;范围角色共用同一份代码计算的 `scope`。
|
|
107
|
+
同一人员只占一个审批席位或抄送名额,解析解释保留各职责来源。
|
|
108
|
+
职责顺序决定重叠人员席位使用哪个职责的代理规则:采用首个匹配职责,
|
|
109
|
+
不会借用后续职责的代理。已有任务保持原人员快照。
|
|
110
|
+
|
|
111
|
+
管理员仅在代码开放人员来源配置的节点中调整职责组合;单选仍保存 `roleCode`,
|
|
112
|
+
多选保存 `roleCodes`。保存、版本激活均检查所有职责,任何职责失效或查询失败都不能
|
|
113
|
+
变成部分名单。总候选最多 200 个成员身份;去重后的审批上限仍受原 binding 限制,
|
|
114
|
+
自动抄送最多 20 人。声明自动协商 `workflow.role-union@1.0.0`,无需初始化开关。
|
|
115
|
+
|
|
88
116
|
管理范围检索使用 `listRoleManagementScopeValues(dimensionCode, { keyword, limit, offset })`,返回 `NativeRoleManagementScopeValuePage` 的 `id/label` 与 `limit/offset`。它使用 `openxiangda.native-role-management-scope-value-page/v2`,与 Data 字段选择器的 `value/label/cursor` 协议分开。权限仍要求对成员的分配或更新能力;只读权限不因此扩张。
|
|
89
117
|
|
|
90
118
|
## 限时审批代理 {#workflow-delegations}
|
|
91
119
|
|
|
120
|
+
限定流程后,可进一步选择该职责在某个审批节点的代理。共享维护页的节点选项来自本人有效
|
|
121
|
+
职责下的真实审批引用,包含当前及在途定义;不同节点可分别委托不同人员。不选节点覆盖
|
|
122
|
+
范围内全部适用节点,全节点代理与重叠的单节点代理不能同时生效。预览和原操作回执保留范围,
|
|
123
|
+
旧回执缺少节点仍按原规则读取;创建、撤销或到期均不改派已创建的任务。
|
|
124
|
+
|
|
125
|
+
自定义页面使用 `WorkflowDelegationMutationRequest` 的create操作,在非空 `workflowCode`
|
|
126
|
+
下传可选 `nodeId`;候选查询也携带同样的流程与节点。`delegationCatalog().sources[].nodeScopes`
|
|
127
|
+
提供可选节点,服务器重新核验职责和范围,不能从客户端指定审批人身份。
|
|
128
|
+
按节点创建必须使用预览/execute/receipt协议;旧 `createDelegation` 入口拒绝 `nodeId`,
|
|
129
|
+
避免与不支持节点限制的旧服务联调时意外扩大范围。平台自动支持,无新增默认关闭开关。
|
|
130
|
+
|
|
92
131
|
平台自动提供 `workflow.delegation-management@1.0.0`,没有额外的默认关闭开关。本人只能委托自己的有效审批职责;代理人必须具有同角色、覆盖原范围且有效期覆盖整个代理窗口的成员身份。采用平台数据库时间与 `[开始, 结束)` 区间,禁止自己代理、重叠链和环。管理员可全应用查看和撤销,创建由原审批人本人完成;成员管理委托不会扩大后台或代理管理权。
|
|
93
132
|
|
|
94
133
|
标准管理入口、应用后台工具与门户个人页可复用 `WorkflowDelegationManager`。组件读取当前挂载应用和环境;`initialAll` 只是筛选意图,平台仍核验超管权限。宿主把草稿回调交给已有导航保护,避免切页时丢失输入或未知操作:
|
|
@@ -158,7 +197,7 @@ export function ReadableWorkflow({ workflowCode, version }: {
|
|
|
158
197
|
|
|
159
198
|
开发者在审批节点的 `administration` 声明可维护的模式、人员来源和任务按钮。未声明这些项的节点保留名称、说明及原人员来源维护;拓扑、分支、范围计算仍由代码控制。使用新声明的应用需要平台 `workflow.node-administration@1.0.0`,编译与激活均检查该能力。
|
|
160
199
|
|
|
161
|
-
模式为 `single/any/all/sequence` 的允许子集;可维护来源限 `fixed_users/app_role/app_role_in_scope`,范围角色必须已有代码声明的 scope。按钮 code
|
|
200
|
+
模式为 `single/any/all/sequence` 的允许子集;可维护来源限 `fixed_users/app_role/app_role_in_scope`,范围角色必须已有代码声明的 scope。按钮 code 保持同意、拒绝、退回、转交、委托、加签的稳定语义;同意和拒绝不能关闭。只有同意/拒绝支持意见规则;拒绝默认必填,固定节点代码可用 operationPolicy.reject.commentRequired: false 显式选填。管理员可收紧选填规则,也可恢复代码明确允许的选填;不能放宽代码必填或未声明时的拒绝默认必填。已进入的任务保留冻结规则。字段显隐、填写与必填行为由应用页面和代码维护,不提供流程节点的字段管理覆盖。可编译声明见 `examples/workflow-administration/declaration.ts`。
|
|
162
201
|
|
|
163
202
|
自动抄送节点仅开放名称、说明和显式声明的 `administration.assigneeProviders`;未开放时接收来源只读。共享编辑器显示“抄送人”,不显示审批方式或审批按钮,固定名单最多20人。`next`、空人策略和通知策略仍归代码;新配置只影响以后进入,过去抄送名单保持冻结。完整例子见 `examples/workflow-administration/automatic-cc.ts`,执行及读取边界见[自动抄送](workflow-events.md#automatic-cc)。
|
|
164
203
|
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
平台网关验证当前用户完整的应用角色并集,并把经平台重验的角色、capability 与可选 Perspective 交给 Nest SDK。业务 controller 使用生成的 operation 合同和 capability 装饰器;平台仍是身份与授权的唯一所有者。请求作用域 `OpenXiangdaDataApiService` 自动继承 Perspective 读取投影;绕过 Data API 的自定义读取才使用 `@CurrentPerspective()` 显式投影。应用代码不替换身份、不保存平台凭据,也不建立第二套用户或权限状态。
|
|
6
6
|
|
|
7
|
+
`OpenXiangdaBusinessDataApiService` 的跨模型读写使用固定 operation 的受信业务证明,不向 Native 转发用户读取 Perspective。原请求的视角保持,普通 Data API 读取仍收窄;业务动作继续按当前用户角色并集授权,并在平台事务内核验当前成员范围、状态和 revision。不要通过清除浏览器所有请求的 Perspective 来修复业务提交,也不要把业务 facade 当作任意读取接口。
|
|
8
|
+
|
|
7
9
|
```bash
|
|
8
10
|
pnpm openxiangda dev
|
|
9
11
|
pnpm openxiangda check
|
|
@@ -16,7 +18,11 @@ operation、事件消费者、人员提供器,然后运行 `pnpm openxiangda c
|
|
|
16
18
|
|
|
17
19
|
依赖安装失败会保留新源码并报告 `OPENXIANGDA_BACKEND_INSTALL_FAILED`;重试相同命令
|
|
18
20
|
即可继续。关闭 backend 不自动删除用户源码。仅删除已经确认不用的后端目录和其依赖。
|
|
19
|
-
|
|
21
|
+
开发者本地 `/api` 经过 connected proxy 进入 Nest;普通浏览器身份经过平台实时授权,
|
|
22
|
+
在支持 `application.development-backend-invocations` 的预发布开发配置上通过当前
|
|
23
|
+
CLI 反向连接到本地 Nest。仅开放已声明 operation,保持短 invocation、请求断言和
|
|
24
|
+
原业务幂等键。有限缓冲 HTTP 的预算与关闭/版本失效规则见
|
|
25
|
+
[普通角色与应用登录联调](getting-started.md#普通角色与应用登录联调)。发布态由同源应用网关转发。
|
|
20
26
|
|
|
21
27
|
| 需求 | 使用的 SDK | 权威边界 |
|
|
22
28
|
| --- | --- | --- |
|
|
@@ -46,10 +52,118 @@ SDK 继承当前环境与身份,平台沿用发起人或既有超级管理员
|
|
|
46
52
|
`committed` 才有可信回执;`not_observed` 可能仍在提交,不能据此生成新键或宣称回滚。
|
|
47
53
|
前端可用 `resolveBusinessProcessOriginal`(`openxiangda/react`),传原 workflowCode、
|
|
48
54
|
operationCode、idempotencyKey;SDK 绑定当前环境并核验返回关联。Named Action 如果业务无需
|
|
49
|
-
|
|
55
|
+
审批,使用下面的 Native 数据命令恢复;没有流程回执并不代表业务没写入。
|
|
50
56
|
标准 PC/移动发起页在响应未知时保留原操作定位信息,刷新可继续查询;同一页面、原身份和
|
|
51
57
|
版本内可手动重试冻结的标准输入,绝不自动重发或悄悄换键。
|
|
52
58
|
|
|
59
|
+
### 补正重提的业务操作 {#correction-business-command}
|
|
60
|
+
|
|
61
|
+
使用固定 Workflow 的 resubmit handler 执行业务重校验;请求是生成操作契约的
|
|
62
|
+
`WorkflowBusinessCommandInvocation`,身份、环境与具名动作由网关和请求作用域 SDK 验证。
|
|
63
|
+
禁止接受页面自报的申请人、资格快照或下游节点。
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
// 必须在当前资料读取和业务校验之前恢复同一用户的原任务结果。
|
|
67
|
+
const original = await businessProcess.resolveOriginalTaskCommand(invocation);
|
|
68
|
+
if (original.status === 'succeeded') return original.result;
|
|
69
|
+
if (original.status === 'failed') throw new Error(original.errorCode || 'WORKFLOW_COMMAND_FAILED');
|
|
70
|
+
|
|
71
|
+
// 合并当前申请与 task form 的受限字段,重验业务规则并准备当前资料的 guards。
|
|
72
|
+
// form.expectedRevision 与 invocation.expectedRevision 保持一致,不给系统字段赋客户端值。
|
|
73
|
+
return businessProcess.commandWithData({
|
|
74
|
+
workflow: invocation,
|
|
75
|
+
subject: { fromOperation: 'request' },
|
|
76
|
+
data: {
|
|
77
|
+
guards,
|
|
78
|
+
operations: [{ key: 'request', kind: 'update', resourceCode: 'requests',
|
|
79
|
+
id: invocation.recordId, expectedRevision: invocation.expectedRevision,
|
|
80
|
+
data: { lastValidatedAt: platformResolvedAt } }],
|
|
81
|
+
},
|
|
82
|
+
expectedTransition: { kind: 'correction-replay' },
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`lastValidatedAt` 为本例应用声明的非路由审计字段。任务 form 由平台在同一事务先应用,
|
|
87
|
+
平台自动衔接其产生的主体 revision;业务 mutation 不能改写固定事实映射。
|
|
88
|
+
守卫、字段、资格、下游解析或流转失败时,Native 更新与任务、会话、事件一起回滚。
|
|
89
|
+
原结果查询使用既有 `/workflow/tasks/:id/commands/original`,核对当前 operation、任务、
|
|
90
|
+
原键、命令、流程、业务记录和原用户输入摘要,不新建恢复表或自动换键重试。
|
|
91
|
+
`not_observed` 仅表示尚未看到确定回执;保留原输入、原 token 和原键,按用户显式操作恢复。
|
|
92
|
+
声明及限制见[工作流](workflow-events.md#correction-business-command)。
|
|
93
|
+
|
|
94
|
+
### 数据修改的原结果恢复 {#data-business-commands}
|
|
95
|
+
|
|
96
|
+
仅修改业务资料的具名动作,在 `platformAccess` 声明
|
|
97
|
+
`dataCommands: { mode: 'recoverable-native' }`,使用请求作用域的
|
|
98
|
+
`OpenXiangdaBusinessDataApiService.commitCommand` 与 `resolveOriginalCommand`。
|
|
99
|
+
编译器自动要求 `data.business-commands` 1.0.0;平台初始化默认提供,无额外开关。
|
|
100
|
+
此声明不授予用户普通 UPDATE,也不替代应用的业务校验、同成员数据范围或附件输入授权。
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
// 固定动作代码从原请求组装;目标、原 revision、字段与原因共同构成稳定意图。
|
|
104
|
+
const original = {
|
|
105
|
+
idempotencyKey: input.idempotencyKey,
|
|
106
|
+
intent: { id: input.id, expectedRevision: input.expectedRevision,
|
|
107
|
+
name: input.name, reason: input.reason },
|
|
108
|
+
};
|
|
109
|
+
const observed = await businessData.resolveOriginalCommand(original);
|
|
110
|
+
if (observed.outcome === 'committed') return observed.receipt;
|
|
111
|
+
|
|
112
|
+
// 这是用户明确提交或同键重试的动作处理器;只查询结果的接口在上面直接返回。
|
|
113
|
+
// 在此读取合法字典/人员,并把业务规则转为原 Native guards,避免读写竞争。
|
|
114
|
+
const committed = await businessData.commitCommand({
|
|
115
|
+
...original,
|
|
116
|
+
data: { operations: [{ operation: 'update', resourceCode: 'requests',
|
|
117
|
+
id: input.id, expectedRevision: input.expectedRevision, data: { name: input.name } }] },
|
|
118
|
+
});
|
|
119
|
+
return committed.receipt;
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
响应丢失时保留原输入和原键,调用只读恢复。`not_observed` 仅表示本次未看到已提交回执,
|
|
123
|
+
另一请求仍可能正在执行;SDK 不自动重放、更换键或提交。显式同键重试在事务锁内最多生效一次,
|
|
124
|
+
相同键但不同意图返回 `OPENXIANGDA_DATA_COMMAND_IDEMPOTENCY_CONFLICT`。
|
|
125
|
+
恢复发生在当前业务校验之前,因此原资料或字典后来变化不会遮蔽已成功结果。
|
|
126
|
+
|
|
127
|
+
身份、应用、环境和动作来自原验证证明;普通用户直调、Worker、未声明动作与伪造请求拒绝。
|
|
128
|
+
平台另外核对当前动作能力,失权后拒绝读取。用户、动作、能力或环境不同均不能复用原结果。
|
|
129
|
+
同环境升级后可用当前同动作查询,回执保留原 `appVersionId`、`environmentHeadRevision`
|
|
130
|
+
和事务条目;不会把原结果重写为当前版本。恢复不要求原资料仍然存在。
|
|
131
|
+
|
|
132
|
+
意图只允许 JSON 对象,最多 64 KiB、32 层、10000 个值;不接受 undefined、循环对象或 Date。
|
|
133
|
+
键最多 128 字符;数据仍沿 Native 1000 操作/2 MiB、CAS、guard 和文件规则。
|
|
134
|
+
服务端只持久保存意图和公开键的摘要,复用原 Native 回执,不建立第二份状态表。
|
|
135
|
+
结果仅返回可信应用后端,应用按已声明的 responseSchema 向用户投影。
|
|
136
|
+
|
|
137
|
+
### 数据写入的流程阶段前置条件 {#workflow-native-stage-guard}
|
|
138
|
+
|
|
139
|
+
证明生成等具名动作需要把当前流程阶段与 Native 写入放在同一事务中时,声明固定条件:
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
platformAccess: {
|
|
143
|
+
dataCommands: { mode: 'recoverable-native' },
|
|
144
|
+
workflow: { codes: ['certificate'] },
|
|
145
|
+
workflowStage: {
|
|
146
|
+
workflowCode: 'certificate', resourceCode: 'requests', actor: 'initiator',
|
|
147
|
+
runningNodeIds: ['applicant-confirm'], allowedStatuses: ['approved'],
|
|
148
|
+
},
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
编译器核对固定流程、来源资源与节点,并要求 `workflow.native-stage-guard` 1.0.0。
|
|
153
|
+
声明后每次 `commitCommand` 必须在 `data.workflowStage` 传入所观测的
|
|
154
|
+
`instanceId`、`subjectRecordId`、`expectedInstanceSequence`;同时传入该来源记录的
|
|
155
|
+
`record-match` 或 `record-assert` guard,包含 `revision eq 原版本`。
|
|
156
|
+
这些值由动作代码从授权读取结果组装,不允许用户指定可用阶段或替换策略。
|
|
157
|
+
`runningNodeIds` 限定运行中的主节点;`allowedStatuses` 明确列出其他允许状态,
|
|
158
|
+
包括需要保留的 returned,未列出的状态拒绝。
|
|
159
|
+
`actor: 'reader'` 复用 Kernel 的实例读取权限;动作能力与 Native 数据范围仍独立核对。
|
|
160
|
+
|
|
161
|
+
平台先恢复已提交的原回执,再获取 Kernel 实例锁、重验当前身份和阶段,然后持锁
|
|
162
|
+
执行来源版本守卫、数据修改及回执提交。阶段、来源或序号变化明确拒绝;锁冲突返回
|
|
163
|
+
可重试错误,保留原业务意图和键。已提交结果可在后续阶段或同环境新 Head 下恢复。
|
|
164
|
+
此条件不属于通用 Data API guard,也不能与 decimalReservation 合并使用。
|
|
165
|
+
上传准备仍在事务外:失败后不得关联文件,未关联上传由既有托管文件清理机制处理。
|
|
166
|
+
|
|
53
167
|
自定义表单页若先用 `createResourceFormDraftClient` 保存认证草稿,并由 Named Action
|
|
54
168
|
提交业务记录和流程,则在同一次 `OpenXiangdaBusinessProcessService.commit` 中传入
|
|
55
169
|
`formDraft: { resourceCode, id, expectedRevision, mode, recordId?, viewCode? }`。草稿必须
|
|
@@ -68,7 +182,14 @@ operationCode、idempotencyKey;SDK 绑定当前环境并核验返回关联。N
|
|
|
68
182
|
重、不自行加锁、不在重试时重新生成业务时间。
|
|
69
183
|
|
|
70
184
|
只读前置条件使用 `record-exists` 或 `record-match`,它们不要求同记录 mutation,
|
|
71
|
-
但仍执行 read capability
|
|
185
|
+
但仍执行 read capability、字段权限与行级授权。多行申请引用同一类主数据时使用
|
|
186
|
+
`record-set-match`:`resourceCode`、`errorCode`、`records: [{ id, expectedRevision }]`
|
|
187
|
+
及可选公共 `where`。每组1–500个不同UUID,所有组累计最多500条,守卫总数仍最多20条。
|
|
188
|
+
同一资源只能使用一条集合守卫,应合并选择集合以保持资源及记录的固定锁序。
|
|
189
|
+
例如国家选择可用 `where: { field: 'enabled', operator: 'eq', value: true }`;
|
|
190
|
+
平台先确认全部记录有read授权,再锁定集合并重读,任一记录缺失、失权、停用或版本
|
|
191
|
+
改变均原子拒绝。它不授予update,也不替代increment所需的record-assert。原成功回执
|
|
192
|
+
恢复优先于主数据重新核验。需要与数据库当前时间比较时使用
|
|
72
193
|
`databaseNowAssertion('publishAt', 'lte')`;平台在守卫行锁及写入前校验完成后,
|
|
73
194
|
用一次 PostgreSQL `clock_timestamp()` 完成所有动态断言,并把该接受时刻作为
|
|
74
195
|
`evaluatedAt` 存入幂等回执。它不是最终提交时刻。相同幂等键重放不会重新
|
|
@@ -226,6 +347,36 @@ await businessData.transaction({
|
|
|
226
347
|
分派已接受后撤销角色,不会自动撤销历史分派;后续处理动作必须重新验证当前权限,
|
|
227
348
|
由管理员重新分派。此规则应写入 AppSpec,并实测撤销先发生和分派先发生两种顺序。
|
|
228
349
|
|
|
350
|
+
## 在事务中核对当前办理人的操作和范围 {#actor-authority}
|
|
351
|
+
|
|
352
|
+
管理动作需要同时具备操作权限和业务范围时,在具名动作声明
|
|
353
|
+
`platformAccess: { roleAssertions: { roleCodes: ['college-admin'], actorAuthority: true } }`。
|
|
354
|
+
这会要求平台 `data.transaction-actor-authority@1.0.0`。提交同一业务事务时增加:
|
|
355
|
+
|
|
356
|
+
```ts
|
|
357
|
+
{ kind: 'actor-authority', errorCode: 'OPENXIANGDA_MANAGEMENT_SCOPE_DENIED',
|
|
358
|
+
anyOf: [{ roleCode: 'college-admin',
|
|
359
|
+
scope: { dimensionCode: 'college', value: authoritativeCollegeCode, operation: 'manage' } }],
|
|
360
|
+
allowAppSuperAdmin: false }
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
`anyOf` 为 1–20 个不同的角色/精确范围分支;角色必须在动作声明和当前授权定义内,
|
|
364
|
+
范围维度必须在当前定义内。省略 scope 的分支仍需角色与本动作 capability 属于同一成员。
|
|
365
|
+
当前办理人和 capability 仅从已验证动作取得,守卫不接收 userId、成员 ID 或能力输入。
|
|
366
|
+
平台在同一事务锁定账号、相关有效 package 成员和授权投影,锁后以数据库时间重新解释;
|
|
367
|
+
不能把不同成员的能力和范围拼接,也不使用账号部门、前端权限缓存或选人候选替代管理授权。
|
|
368
|
+
scope operations 省略、null、空数组或包含 `*` 表示允许全部,否则必须包含指定操作。
|
|
369
|
+
|
|
370
|
+
`allowAppSuperAdmin` 默认 false;只有明确设为 true 且当前应用管理员授权被锁定并验证时
|
|
371
|
+
才能通过这个分支,它不代表审批参与人。单事务最多核对 400 条相关成员;超限返回
|
|
372
|
+
`OPENXIANGDA_ACTOR_AUTHORITY_BUSY`。锁冲突沿用 `OPENXIANGDA_ROLE_ASSERTION_CONFLICT`,
|
|
373
|
+
锁等待最多 1 秒、单条 SQL 最多 10 秒(保留更紧的已有上限)。已先完成撤权则新提交拒绝;
|
|
374
|
+
已先锁定并接受的事务结束后才能撤权。守卫失败返回应用声明的失败码及 `/guards/<index>`,
|
|
375
|
+
业务写入、事件和回执一起回滚。结果未知继续查询原请求;已有成功回执重放不重复写入。
|
|
376
|
+
普通 Data SDK、应用凭据、事件和队列上下文不能使用;未声明返回
|
|
377
|
+
`OPENXIANGDA_ACTOR_AUTHORITY_NOT_DECLARED`。仪器归属等业务事实仍由应用在同一事务
|
|
378
|
+
使用 Native revision/CAS/记录守卫冻结;prepare 不授予后续提交权限。
|
|
379
|
+
|
|
229
380
|
## AI 能力目录与 MCP Facade {#ai-catalog}
|
|
230
381
|
|
|
231
382
|
编译器为每个应用生成不可变的 AI 能力目录:资源的标准 CRUD 面(query/get/create/update/delete,
|
|
@@ -369,6 +520,13 @@ import {
|
|
|
369
520
|
用户动作 send 的 schemaVersion 使用 OPENXIANGDA_NOTIFICATION_BUSINESS_SEND_V2;事件处理 sendFromEvent 使用 OPENXIANGDA_NOTIFICATION_EVENT_SEND_V2。二者的调用上下文和收件人来源不同,不能混用。
|
|
370
521
|
## 外部处理受控文件
|
|
371
522
|
|
|
523
|
+
证明等业务动作需要核对真实审批状态时,可调用
|
|
524
|
+
`workflow.recordHistory(resourceCode, recordId, { instanceId?, limit: 1 })`(注入
|
|
525
|
+
`OpenXiangdaWorkflowService`)。它沿当前用户的 Native 读取和流程历史权限,返回实际
|
|
526
|
+
`recordRevision` 与 `instance.status`;不能用流程命令的执行成功推断审批已批准。
|
|
527
|
+
记录修订不一致应重新核对;403/404/409 直接拒绝,不回退业务字段或应用缓存。
|
|
528
|
+
此读取不授予任务办理或服务身份权限,offset 上限500、limit 上限100。
|
|
529
|
+
|
|
372
530
|
需要水印或归档处理时,Nest DataApi 可签发短期对象下载地址。不要把要求登录态的 content URL 或用户 Cookie 交给外部服务。
|
|
373
531
|
|
|
374
532
|
```ts
|
|
@@ -394,6 +552,19 @@ if (output.status === 'pending') {
|
|
|
394
552
|
主子记录共享精确金额额度、撤回修订和审批释放,请使用[精确金额占用](decimal-reservations.md)的受管提交及终态事务。
|
|
395
553
|
|
|
396
554
|
|
|
555
|
+
## 本人业务联系信息
|
|
556
|
+
|
|
557
|
+
本人报名等确需联系电话的具名动作,显式声明
|
|
558
|
+
`platformAccess: { directory: { mode: 'current-initiator', fields: ['displayName', 'primaryDepartment', 'phone'] } }`,
|
|
559
|
+
然后调用 `businessDirectory.currentInitiator()`。平台从当前账号返回只读 `phone: string | null`,
|
|
560
|
+
修剪空白且最多80字符;未设置时返回 null,由业务规则处理资料缺失。调用方不能指定人员 ID
|
|
561
|
+
或信任浏览器提交的联系信息,关键提交仍须核对 `snapshotRevision`;电话变化会改变该修订。
|
|
562
|
+
|
|
563
|
+
`phone` 只在该动作显式声明时查询和返回;默认 SubjectProfile、人员搜索和 `selected-user`
|
|
564
|
+
不提供此投影。使用此字段需要平台能力 `directory.current-initiator-phone` 1.0.0,编译器从声明
|
|
565
|
+
自动派生,不手写能力目录。受管 `backend-plan` 命令可在 execution.directory 中以相同方式
|
|
566
|
+
声明本人电话;平台保留执行证明和有效 lease 边界。本能力不提供电话查人或联系方式修改。
|
|
567
|
+
|
|
397
568
|
## 解析管理员选定的组织人员
|
|
398
569
|
|
|
399
570
|
管理员补录或身份订正应使用平台目录,不创建第二份人员主数据。具名动作声明
|
|
@@ -401,3 +572,18 @@ if (output.status === 'pending') {
|
|
|
401
572
|
后,调用 `businessDirectory.selectedUser(userId)`。仅传标准人员选择器返回的确定 ID;姓名、工号和部门均由平台返回,不能相信表单传入快照。
|
|
402
573
|
|
|
403
574
|
此动作的调用者还需要既有 `app:<appCode>:directory:read` 权限;平台复核当前租户、环境、目录范围和人员有效期,一次只解析一人。普通用户本人报名继续使用 `currentInitiator()`。身份快照不是永久授权凭据,后续业务事务仍需检查角色、状态与额度。平台能力为 `directory.selected-user` 1.0.0;失败时保留原操作,不回退姓名匹配或应用人员表。
|
|
575
|
+
## 具名资料编辑的字段输入
|
|
576
|
+
|
|
577
|
+
action-owned 资源需要跨字段业务校验时,可在具名动作声明
|
|
578
|
+
`platformAccess: { dataCommands: { mode: 'recoverable-native' }, recordEdit: { resourceCode: 'requests', fieldCodes: ['name', 'reason'] } }`。
|
|
579
|
+
只允许一个资源、最多200个已声明可更新的普通字段;系统字段、流水号和子表不适用。普通CRUD权限不会因此开放。
|
|
580
|
+
声明自动要求 `data.record-edit` 1.0.0 平台能力;仅支持旧具名数据命令的平台需要先升级。
|
|
581
|
+
|
|
582
|
+
Field Kit 的 `SurfaceFieldRenderers.recordEditInput` 接受 `{ operationCode, recordId, expectedRevision }`,
|
|
583
|
+
字典与受限人员通过现有接口读取保存资料的范围,不能用浏览器bindings替代。
|
|
584
|
+
上传继续使用 `uploadOperationManagedFile` 的update意图及同记录ID。
|
|
585
|
+
平台验证同一成员同时拥有动作能力与资料read,再按原RLS读取;首次commitCommand仅接受同资源的一条update和声明字段,
|
|
586
|
+
CAS与写后范围检查同事务执行。应用仍负责业务规则和字典guards。
|
|
587
|
+
|
|
588
|
+
保存与核对共用同一operation,首次业务读取前先resolveOriginalCommand;not_observed只表示观察时未见回执,
|
|
589
|
+
不自动重试或换键。管理员资料修改不会重写已完成意见、已走路径或已派审批人,后续任务按平台原Native修订协议处理。
|
|
@@ -28,13 +28,47 @@ pnpm openxiangda check
|
|
|
28
28
|
|
|
29
29
|
角色成员、维度授权和平台管理员由平台管理面维护,不属于应用开发 CLI。
|
|
30
30
|
|
|
31
|
+
### 登录用户的公共字段与管理范围
|
|
32
|
+
|
|
33
|
+
同一资源需要保留公共目录、同时按学院或负责人读取私有字段时,在只读策略声明
|
|
34
|
+
`publicRead: { fields: ['name', 'category'] }`。这仅适用于已认证用户,基线角色由
|
|
35
|
+
`authenticatedUserRoleCode` 确定,不传入角色、身份或范围。`operations` 必须恰好是
|
|
36
|
+
`['read']`,不能搭配 `readExpression` 或 `writeBoundary`。
|
|
37
|
+
|
|
38
|
+
公共字段是 1–1000 个唯一的真实业务字段,必须允许基线角色读取;不能包含平台元数据
|
|
39
|
+
或子表。所有未列出的业务字段都必须通过 `access.read` 拒绝基线角色,有私有字段时
|
|
40
|
+
`audit.read` 也必须拒绝基线角色。缺失字段策略、把私有能力授给基线、遗漏历史限制都会
|
|
41
|
+
在两侧编译器校验失败。平台基础元数据保持原读取协议,不计入业务公共白名单。
|
|
42
|
+
|
|
43
|
+
源声明仍禁止把基线角色直接放入 `unrestrictedRoleCodes`。编译器只在上述证明通过后
|
|
44
|
+
物化公共读取,并保留公共字段意图;需要 `data.authenticated-public-projection@1.0.0`。
|
|
45
|
+
每次列表、筛选、排序、聚合或导出使用整组请求字段筛选同一个有效成员,再执行其行策略。
|
|
46
|
+
因此管理私有字段不能借用公共成员的全行范围,不同成员的字段能力和范围也不能拼接。
|
|
47
|
+
管理 Perspective 可以进一步收窄读取;关键写入仍独立验证当前角色并集和事务条件。
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
{
|
|
51
|
+
code: 'catalogue-read', name: '公共目录与管理读取', resourceCode: 'catalogue',
|
|
52
|
+
operations: ['read'], publicRead: { fields: ['name', 'category'] },
|
|
53
|
+
unrestrictedRoleCodes: ['school-admin'], matchMode: 'OR',
|
|
54
|
+
rules: [{ dimensionCode: 'college', field: 'college', valuePath: 'value',
|
|
55
|
+
operation: 'manage', roleCodes: ['college-admin'] }],
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
这不是匿名公开数据接口;对外无账号读取仍使用独立的 `frontend.publicAccess` 合同。
|
|
60
|
+
|
|
31
61
|
### 条件唯一键
|
|
32
62
|
|
|
33
63
|
需要“同一编号只能有一条有效主档”时,在模型声明 `uniqueKeys`。平台在环境
|
|
34
64
|
激活时安装约束;普通 CRUD、导入和业务事务共用该约束。应用无需先查重再创建,
|
|
35
|
-
|
|
65
|
+
也无需另建锁服务。基础规则要求平台能力 `data.unique-keys@1.0.0`;单人键或布尔条件
|
|
66
|
+
要求 `data.unique-keys@1.1.0`,两者由同一共享编译器确定。旧平台在
|
|
36
67
|
发布前明确报告缺少能力。未声明的模型不增加这一要求。
|
|
37
68
|
|
|
69
|
+
支持1.1.0的平台同时支持原1.0.0基础规则;工具预检只接受这项已知兼容关系,
|
|
70
|
+
不会按版本大小推断其他版本或能力可用。要求1.1.0的应用不能在1.0.0平台部署。
|
|
71
|
+
|
|
38
72
|
```ts
|
|
39
73
|
const partners = defineDataModel({
|
|
40
74
|
code: 'partners', name: '往来单位',
|
|
@@ -59,12 +93,16 @@ const partners = defineDataModel({
|
|
|
59
93
|
|
|
60
94
|
- 每模型最多 8 条,稳定 `code` 使用最长 20 字符的 lower-kebab-case;每条包含
|
|
61
95
|
1–4 个不重复字段、最多 4 个 AND 条件。
|
|
62
|
-
- 字段支持短文本、UUID
|
|
96
|
+
- 字段支持短文本、UUID、单选、单记录引用和单人;单选/引用/人员比较保存的 `value`,忽略标签。
|
|
63
97
|
- `exact-v1` 原样比较(默认);文本可用 `nfkc-space-v1` 做 NFKC 归一化、Unicode
|
|
64
98
|
空白折叠和首尾修剪,或 `nfkc-upper-ascii-v1` 再将 ASCII 小写转大写。非文本只
|
|
65
99
|
支持 exact;不按操作系统 locale 折叠其他文字大小写。
|
|
66
100
|
- 文本条件是 `empty` / `nonempty`,按 NFKC 空白规则判断;单选条件是 `in` /
|
|
67
101
|
`notIn`,包含 1–16 个已声明选项值。缺失选项不满足 `notIn`。
|
|
102
|
+
- 布尔条件是 `eq` / `ne`,使用真实布尔 `value`,例如
|
|
103
|
+
`when: [{fieldCode:'enabled',operator:'eq',value:true}]`。两种比较均不包含 NULL。
|
|
104
|
+
用 `user.single` 唯一键配合 enabled eq:true,可维护同一平台用户唯一有效资料;
|
|
105
|
+
禁用历史记录可共存,改为有效、调整人员或并发创建都由同一数据库约束保护。
|
|
68
106
|
- 任一键字段为空或归一化后为空,该行不参加比较。需要每行填写时仍应声明字段
|
|
69
107
|
必填。参与比较的每个字段归一化后最多 256 个 UTF-8 字节。
|
|
70
108
|
|
|
@@ -175,3 +213,35 @@ publicSubtableFields: { items: ['sku', 'quantity'] },
|
|
|
175
213
|
业务分派需要目标人员具有指定角色时,使用[事务中的角色条件](backend.md#role-member),
|
|
176
214
|
由平台在写入事务中核对当前有效成员。候选查询、页面隐藏、应用管理员身份和历史
|
|
177
215
|
角色列表都不能替代这一规则,也不应在应用中复制一份权限状态。
|
|
216
|
+
|
|
217
|
+
## 独立资料打印 {#record-print}
|
|
218
|
+
|
|
219
|
+
模型可显式声明 `recordPrint: { read: ['app:my-app:record:print'] }`,能力须在本应用 `authz.capabilities` 定义并授给适当职责。`read: true` 绑定本资源读取能力,`false` 关闭,缺省不提供打印。平台自动提供 `data.record-print@1.0.0`,无需初始化SQL或全局开关;应用打印许可仍由声明拥有。
|
|
220
|
+
|
|
221
|
+
### 单记录评论
|
|
222
|
+
|
|
223
|
+
`recordComments: { read: ['app:my-app:comments:read'], create: ['app:my-app:comments:create'] }` 分别声明评论读取与新增,能力在本应用定义并授给职责。`true` 绑定本资源read,`false`关闭对应操作,省略整个声明关闭评论。每组最多20项、全部满足;同一个成员须同时拥有资料read及相应评论能力,不能把ALL-read职责和本人评论职责拼成ALL评论。平台自动注册 `data.record-comments@1.0.0`,fresh/update通过正式SQL迁移建表,不需手动开关。
|
|
224
|
+
|
|
225
|
+
标准资料详情提供懒加载评论面板;应用定制页面使用 `ResourceRecordComments`、`loadNativeRecordComments`、`createNativeRecordComment`、`loadNativeRecordCommentReceipt`(`openxiangda/react`),沿平台Runtime和导航保护Provider。读取跟随当前Perspective,新增和本人回执由原始当前用户角色并集与相同Native范围决定;界面能力初筛不代替服务端许可。正文为纯文本,4000字上限;分页默认20/最多50,使用返回的nextCursor,单记录最多2000条。
|
|
226
|
+
|
|
227
|
+
新增前固定 `schemaVersion: 'openxiangda.data-record-comment-create/v1'`、body及idempotencyKey。网络或超时结果不确定时保留原请求,先查本人原键回执;仅 `OPENXIANGDA_NATIVE_RECORD_COMMENTS_RECEIPT_NOT_FOUND` 表明可显式重试原请求,同一键/正文只写一条,改变正文或目标返回409。未解决前标准面板阻止页内导航;刷新/关闭浏览器会提示,当前尚无跨刷新自动保存,需保留原键与正文后通过SDK核对。读评论不获得他人的提交键。
|
|
228
|
+
|
|
229
|
+
评论属于平台附属数据,不修改申请revision/最后修改人、不推进流程或发业务updated事件,不授给匿名/应用联合主体。当前不含回复、附件、提及、编辑/删除、自动通知和旧评论导入;审批意见继续由Workflow拥有。源宜搭这些附加语义尚未运行核实,不能据COMMENT=y宣称完整等价。
|
|
230
|
+
|
|
231
|
+
### 按资料权限删除关联流程
|
|
232
|
+
|
|
233
|
+
模型或直接资源可显式声明 `recordDeletion: { delete: ['app:my-app:record:delete'] }`,引用能力须在同应用定义并授给维护职责。`true` 使用本资源 Native delete,`false` 或缺省关闭。每组最多20项,全部满足;编译器自动派生 `data.workflow-record-deletion@1.0.0`,平台自动注册,不需要初始化开关。标准详情在启用且当前用户具备资料 read、delete 和维护能力时提供“删除资料”,action/workflow拥有普通写入的模型也可单独启用资料维护。
|
|
234
|
+
|
|
235
|
+
服务端在预览、执行和回执恢复时重新检查当前用户。必须由同一个成员同时持有资源 read/delete 及全部维护能力,再沿该成员原 RLS;不能把全部资料读取职责与本人删除职责拼成全部删除。应用管理员称谓不自动授权,匿名、应用后台断言及工作流任务断言不能调用此浏览器入口。维护能力不授予编辑资料、改派任务或整套流程管理员权限。Perspective 不改变写权限,维护沿当前用户原角色并集。
|
|
236
|
+
|
|
237
|
+
先填写非空原因(trim后最多1000字符),再预览,确认使用原预览Token和幂等键。无关联实例时复用 Native 事务;一个根关联实例时复用 Workflow Kernel 的 `admin_delete`,同事务删除资料及 owned 明细、关闭任务/参与人/返回会话并记录审计。共享 resource-ref 不级联。待启动命令、多个实例或明细关联其他实例会阻止全部删除;最多根记录加400条后代(合计401条)、深度8,超限明确拒绝。嵌套后代共用总预算,不能按每层累乘;末行关联与revision也参与核对。关联流程仍最多100条,读取101条拒绝。普通 Native 删除的流程关联保护保持,不能用它绕开维护协议。
|
|
238
|
+
|
|
239
|
+
同一受控请求只选择一条根记录,SDK输入不随容量扩大改变。管理员公开批量请求仍最多100个所选根或普通操作;只有服务器核对并展开的内部DELETE集合可用401条总上限,多个根也共用总量。整管理员请求1MiB、Native事务1000操作/2MiB与原Kernel预算保持。七张各50行的子表属于这个预算;声明和当前资料授权仍须逐项验证,没有新的初始化开关。
|
|
240
|
+
|
|
241
|
+
预览有效五分钟,绑定当前账号/登录会话/CSRF、环境Head、根revision及全部owned摘要。变化或到期须重新预览。未知结果先读取原回执,只有 `OPENXIANGDA_NATIVE_RECORD_DELETION_RECEIPT_NOT_FOUND` 且预览有效时可显式原键重试,不能创建新键。回执恢复允许预览到期,但仍检查当前权限、原账号/会话/CSRF和同一Head,成功后不重读已删除资料。两类回执的 `receiptOwner` 分别为 `native-transaction` 和 `workflow-command`。
|
|
242
|
+
|
|
243
|
+
SDK复用现有应用CSRF与512条命令绑定缓存,预览到期不会自动丢弃原header。身份退出、缓存容量淘汰或刷新后不保证恢复原CSRF;标准弹层不跨刷新自动保存原请求。页内导航和关闭保护保留未确认操作,无法确认的请求不得用重新预览掩盖。删除不可由代码回滚恢复;应用须按自身保留和归档要求决定是否开启。
|
|
244
|
+
|
|
245
|
+
打印先筛选同一成员同时具备资料read及所有打印能力的资格,再沿原RLS、Perspective、字段读取与脱敏;不能把ALL-read职责和own-print职责合并成ALL-print。普通app-admin与平台超管分别验收。SDK `loadNativeRecordPrint(resourceCode, recordId, { viewCode? })` 只读当前单记录投影;公开 `ResourceRecordPrintPreview` 与生成Native详情中的“打印”入口共用它。字段权限仍使用页面/模型规则,不增加流程节点字段权限配置。
|
|
246
|
+
|
|
247
|
+
预览显示读取时间、当前详情可见字段和分组。打印前重新读取当前授权数据,失败清除旧预览,身份/授权/Perspective变化和关闭淘汰过期请求。附件/图片只列名称及大小、富文本转安全文本,没有自动外部下载;系统打印取消不写业务资料。当前版本只支持主记录,详情包含可读子表返回409,超2MiB返回413,不静默漏项;专用PDF模板、签章与子表完整打印另行提供。独立权限保护平台的打印接口和标准入口,已读资料的截图/浏览器自行打印不属于可撤销许可。
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# 声明速查:一次写对 openxiangda.config.ts {#cheatsheet}
|
|
2
2
|
|
|
3
|
+
资料维护删除用模型或直接资源的 `recordDeletion: { delete: true | false | string[] }`。缺省关闭;`true`绑定本资源Native delete;能力数组最多20项并须在同应用定义。平台自动注册 `data.workflow-record-deletion@1.0.0`,无需手动初始化开关。维护职责还必须同时持有资料read/delete,同一成员与RLS决定实际可删范围;不使用整套流程管理员替代业务资料权。仅支持零关联实例或一个根关联实例,待启动、多实例、明细其他流程及owned超100/深度8均阻塞。详见[数据与权限](data-authz.md)。
|
|
4
|
+
|
|
3
5
|
按"错误码 → 规则 → 正确片段"组织。这些规则全部来自真实返工:先扫一遍本页,再写声明,能省掉绝大多数首轮校验迭代。普通 CRUD 的完整可过检骨架见文末。
|
|
4
6
|
|
|
5
7
|
## 模块与 CRUD 视图
|
|
@@ -28,7 +30,7 @@
|
|
|
28
30
|
| `labelField` 必须指向目标资源的 `text.short` / `text.long` 字段 | 不要用流水号/选项字段当 label |
|
|
29
31
|
| 列表可排序列用视图级 `sortableFields` 表达(`defaultSort.field` 隐式可排序);平台审计列(如 `created_at`)同样合法 | `list: { sortableFields: ['capacity'], defaultSort: { field: 'name', order: 'asc' } }`;`defaultSort: { field: 'created_at', order: 'desc' }` |
|
|
30
32
|
| 每个字段都必须带中文/业务 `label`(含子表外键与排序字段) | `{ code: 'requestId', type: 'uuid', label: '所属申请', required: true }` |
|
|
31
|
-
| 子表 `subtable` 的外键是子资源的 **uuid** 字段,排序字段是**可写 number.integer** | 子资源:`{ code: 'requestId', type: 'uuid', required: true }` + `{ code: 'sortOrder', type: 'number.integer', required: true }`;父表:`subtable: { resourceCode: 'repair-items', foreignKey: 'requestId', orderField: 'sortOrder', maxRows: 20 }
|
|
33
|
+
| 子表 `subtable` 的外键是子资源的 **uuid** 字段,排序字段是**可写 number.integer** | 子资源:`{ code: 'requestId', type: 'uuid', required: true }` + `{ code: 'sortOrder', type: 'number.integer', required: true }`;父表:`subtable: { resourceCode: 'repair-items', foreignKey: 'requestId', orderField: 'sortOrder', minRows: 1, maxRows: 20 }`;minRows默认0、不能超过maxRows |
|
|
32
34
|
| 图片/附件的 `file` 限定数量与大小 | `file: { maxCount: 3, maxSizeMb: 10, accept: ['image/png', 'image/jpeg'] }` |
|
|
33
35
|
|
|
34
36
|
## 权限声明
|
|
@@ -37,6 +39,7 @@
|
|
|
37
39
|
| --- | --- |
|
|
38
40
|
| 数据策略是**白名单**语义:规则 `roleCodes` 之外的角色若不在 `unrestrictedRoleCodes` 中会被 RLS 全拒(报错只有 FIELD_ROW_FORBIDDEN) | `unrestrictedRoleCodes: ['admin']` 必须列出所有"不受限"角色 |
|
|
39
41
|
| 基线角色(`authenticatedUserRoleCode`)进 `unrestrictedRoleCodes` = 策略对所有人失效(角色并集必含基线角色),编译器直接报错 | 把基线角色移出 unrestrictedRoleCodes,为其单独声明 rules |
|
|
42
|
+
| 登录公共字段与管理私有范围共存不能直接放开基线角色 | 只读策略显式 `publicRead: { fields: [...] }`,全部非公开字段及变更历史须拒绝基线,详见 data-authz;不支持公共子表 |
|
|
40
43
|
| 匿名公开策略的 `ownRecordFields` 必须是 `fields` 的子集;`create` 必须配套 `draft`;`requiredFields` ⊆ `fields` | 先定 fields,再从中选 required/own |
|
|
41
44
|
| workflow definition 必须显式 `launch`(编译器强制) | `definitions: [{ version: 1, definition, launch: { mode: 'standalone' } }]` |
|
|
42
45
|
| option/user/department/resource-ref/cascade 字段投影进工作流事实是 { label, value } 对象,不能声明为标量;条件比较用 `<fact>.value` | `inputSchema.properties.urgency = { type: 'object', ... }` + `path: 'urgency.value'` |
|
|
@@ -212,3 +215,10 @@ export default defineOpenXiangdaApp({
|
|
|
212
215
|
## 图片上传的像素上限
|
|
213
216
|
|
|
214
217
|
image/signature/富文本图片字段在上传计划(initiate)里返回 `maxPixels`;超过上限的图片会被标准组件自动压缩后重新发起上传。用 API 直传时自行按 `maxPixels` 预检。当前平台上限覆盖主流手机主摄(48/50/64MP);超出会得到带实际尺寸的 `OPENXIANGDA_NATIVE_DATA_IMAGE_PIXEL_LIMIT_EXCEEDED` 错误。
|
|
218
|
+
|
|
219
|
+
## 业务查看组的流程办理历史
|
|
220
|
+
|
|
221
|
+
在模型或直接资源声明中设置 `workflowHistory: { read: true | false | string[] }`。
|
|
222
|
+
省略/false关闭新入口;true绑定资源read,数组引用已有能力,不隐式生成能力。
|
|
223
|
+
同一角色成员须同时满足资源read和全部历史能力,原行权限继续约束旧固定实例;该项独立于Native `audit.read`。
|
|
224
|
+
标准Native详情和公开 `WorkflowRecordHistoryPanel` 可复用,参见[工作流历史](workflow-events.md#record-history-read)。
|
|
@@ -52,4 +52,11 @@
|
|
|
52
52
|
|
|
53
53
|
开发使用 `pnpm openxiangda dev`,过程中运行必要的聚焦测试。交接前按[检查与验收](testing.md)验证;授权发布后按[交付](delivery.md)部署。失败保留错误码、位置和原始候选,依据平台恢复指令继续。
|
|
54
54
|
|
|
55
|
+
多流程迁移可一次选择 3–5 条代表业务,先集中核对字段、审批人、操作、分支和
|
|
56
|
+
副作用,再按公共能力主题修复。开发期间使用本地源码及 connected development,
|
|
57
|
+
完整开发配置的覆盖与限制见[连接开发](getting-started.md#connected-development)。
|
|
58
|
+
小改动执行相关检查,复用原申请和成功证据;一批能力完成后再统一冻结工具链、
|
|
59
|
+
构建和正式测试激活,集中验收普通角色的 PC 与手机任务。源码检查、配置同步、
|
|
60
|
+
正式激活和业务运行证据分别记录,不用通过的 fixture 替代真实业务验收。
|
|
61
|
+
|
|
55
62
|
[AppSpec](appspec.md)保存业务意图、设计与交付记录,不复制字段 Schema、生成契约和部署状态。新应用维护具体设计和评审,复杂度随业务展开;既有小变更沿用有效设计,仅修订受影响记录,无行为变化可引用已有记录。每轮先读取当前规则、澄清业务、评估架构、权限和性能,随后实施与验证,发布后更新当前规格及交接。测试部署前需要设计和验收计划,生产晋级前需要绑定测试运行及包摘要的实际验收报告。
|
|
@@ -68,6 +68,8 @@ import { AttachmentFileList } from 'openxiangda/field-kit';
|
|
|
68
68
|
|
|
69
69
|
组件按文件引用选择缩略图,预览和下载经过平台接口。自定义活动封面同样先选择 `cover.thumbnailUrl`;只有平台引用没有缩略图时才回退 `cover.previewUrl`。不要写 `previewUrl || thumbnailUrl`,否则小卡片也会下载完整原图。保留真实宽高或稳定的封面比例,非首屏图片使用懒加载;不得在列表渲染时预取所有原图。
|
|
70
70
|
|
|
71
|
+
视频或音频需要在原任务界面播放时,使用 `ManagedMediaPlayer`,例如 `<ManagedMediaPlayer file={record.media[0]} resourceCode="lessons" />`。组件先核对官方预览元信息,再鉴权读取内容;当前身份、文件或绑定变化以及卸载会释放播放器与 ObjectURL,不接受任意 `src`。默认单文件容量100MiB,可由应用按实际任务显式配置 `maxSizeMb`,超限明确失败并保留附件下载任务。提供加载、拒绝和重新读取状态,浏览器编码支持须实际播放验证。播放本身不提交业务进度或观看时长。
|
|
72
|
+
|
|
71
73
|
受限文件的缓存必须保留权限核验。配套平台支持私有条件缓存时,浏览器可以保存文件响应,再次访问由平台先核对当前权限,内容未变化返回 304,从本地复用字节;`no-cache` 表示复用前校验,和 `no-store` 禁止保存不同。缺少可靠实体标识或请求失败时仍禁止缓存。不应由应用添加长期免校验缓存、公开 CDN 缓存或跨账号 Blob 缓存来绕过该规则。公开长期缓存需要独立、明确的公开发布契约,不能仅因字段名叫封面就视为公开。
|
|
72
74
|
|
|
73
75
|
验收时同时记录原图/缩略图字节、列表实际请求的变体、重复访问传输量和权限撤销结果。仅看到 `blob:` 地址不能判断用了 Base64,HTTP 200 也不能证明命中了缓存。
|
|
@@ -128,6 +130,13 @@ import { AttachmentFileList } from 'openxiangda/field-kit';
|
|
|
128
130
|
平台按来源资源的字段权限和 PostgreSQL RLS 查询并返回完整资源快照。来源记录改名或删除后,
|
|
129
131
|
已经保存的 `{label,value,resourceCode,snapshot}` 仍可直接展示,不需要再次查询。
|
|
130
132
|
|
|
133
|
+
过滤条件绑定其他表单字段时,可显式设置 `source.clearOnBindingChange: true`。
|
|
134
|
+
用户改变绑定值后,标准表单、任务补填和同一子表行会清除对应旧选择:单选清空、
|
|
135
|
+
多选变为空数组,依赖链中的可写关联字段也会清除。只比较引用的真实 `value`;
|
|
136
|
+
同值重选、显示标签刷新、无关字段或其他子表行的修改不清除当前选择。
|
|
137
|
+
默认缺省或 `false` 保留选择;程序预填、草稿与资料恢复不会触发这项用户事件联动。
|
|
138
|
+
这项设置只管理当前输入,提交是否合法仍由平台事务与字段权限判断。
|
|
139
|
+
|
|
131
140
|
成员和部门同样保存完整显示快照:
|
|
132
141
|
|
|
133
142
|
```ts
|
|
@@ -140,13 +149,76 @@ import { AttachmentFileList } from 'openxiangda/field-kit';
|
|
|
140
149
|
成员快照可包含头像、工号、职务、手机号、邮箱和所属部门;部门快照可包含完整路径、
|
|
141
150
|
路径节点和父部门。凭证、Token 和认证秘密永远不能进入快照。
|
|
142
151
|
|
|
152
|
+
### 限定职责候选(合同已定义,运行时接入中)
|
|
153
|
+
|
|
154
|
+
`user.single` / `user.multiple` 可在代码中声明 `userCandidates`,引用本应用职责和可选范围。
|
|
155
|
+
它与资源选择的显示 `source` 分开,编译产物中的字段和 Surface 必须一致。
|
|
156
|
+
使用前确认平台已开放 `data.user-candidates@1.0.0`。SDK已接入候选读取和双端字段组件,
|
|
157
|
+
平台运行时仍在本地集成验收;未广告能力时不能部署该声明。不能以普通通讯录过滤替代服务端约束。
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
{
|
|
161
|
+
code: 'unitLeaders', type: 'user.multiple', label: '单位负责人',
|
|
162
|
+
userCandidates: {
|
|
163
|
+
kind: 'app-role', roleCode: 'unit-leader', pageSize: 20,
|
|
164
|
+
scope: { dimensionCode: 'college', operation: 'approve', field: 'college' },
|
|
165
|
+
},
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
职责和范围维度必须在同包声明。`pageSize` 为1–50,默认20;范围使用代码常量 `value`,
|
|
170
|
+
或同资源的 `text.short`、`uuid`、`option.single`、`resource-ref.single` 字段 `field`,两者互斥。
|
|
171
|
+
单选范围取稳定的 `.value`,不按显示标签决定身份。记录范围必须来自已授权、已保存的记录或当前任务,
|
|
172
|
+
首版新建不接受非空的记录范围选人。修改范围须清空相依选择并保存,再按新范围重选。
|
|
173
|
+
候选显示失败不能当作空名单;旧选择失效须保留显示快照并提示重选。
|
|
174
|
+
|
|
175
|
+
具名流程原子创建申请时,可显式声明 `scope: { dimensionCode, operation, field,
|
|
176
|
+
creation: 'prospective' }`。编译器自动要求 `data.user-candidate-launch-scope@1.0.0`。
|
|
177
|
+
维度必须使用uuid的Native资源来源;资源引用范围字段指向同一来源。发起候选查询
|
|
178
|
+
使用`scopeValue`,平台先核验具名发起绑定及范围记录的read权限、RLS和enabled。
|
|
179
|
+
查询值仅为搜索意图;服务端业务操作从可信资料重新取得实际范围,并在原写事务
|
|
180
|
+
重新核验职责成员、规范化姓名。普通Native创建和无平台业务证明的Application
|
|
181
|
+
写入不能消费此模式。已有字段不加`creation`时保持原已保存范围要求。
|
|
182
|
+
|
|
183
|
+
标准`WorkflowSubmissionPage`从正在填写的字段取得范围;范围来自可信准备资料、
|
|
184
|
+
未绑定为可提交输入时,使用`formOptions.candidateScopeValues`提供。该参数不进入
|
|
185
|
+
提交或草稿。自定义Field Kit通过`renderers.candidateScopeValues`提供相同搜索上下文。
|
|
186
|
+
更新和任务候选仍从平台已保存资料取范围,不能传`scopeValue`覆盖。
|
|
187
|
+
|
|
188
|
+
流程使用 `{ provider: 'form_field_users', inputPath: 'leaders', candidateField: 'unitLeaders' }`,
|
|
189
|
+
其中 `subject.factProjection.leaders` 必须精确指向 `unitLeaders`,范围字段也须有唯一事实投影。
|
|
190
|
+
不能另写职责、范围或路由覆盖来源,不能用嵌套输入路径绕过候选字段。
|
|
191
|
+
办理页不能同时修改范围字段与相依选人字段。首版任务候选只支持主体字段,任务中可写子表候选字段明确拒绝;
|
|
192
|
+
普通子表记录的 Native 约束和历史只读显示仍按各自合同处理。
|
|
193
|
+
流程进入节点时再次核验原职责成员,随后解释职责代理;历史已创建任务保留当时快照。
|
|
194
|
+
|
|
195
|
+
标准表单、流程发起和任务补填自动传递候选上下文。自定义页使用Field Kit的
|
|
196
|
+
`SurfaceFieldControl`/`MobileSurfaceFieldControl`,更新时提供`recordId`和`expectedRevision`;
|
|
197
|
+
任务页额外提供`workflowCandidateBinding: { taskId, expectedTaskVersion }`。缺失任务版本会要求刷新,
|
|
198
|
+
不会转用普通数据或通讯录接口。使用`ResourceFormContent`时也提供已加载记录的`expectedRevision`。
|
|
199
|
+
|
|
200
|
+
自定义选人交互可从`openxiangda/react`调用`queryFieldUserCandidates(resourceCode, fieldCode, input)`
|
|
201
|
+
或`queryWorkflowTaskUserCandidates(taskId, fieldCode, input)`。查询schema固定为
|
|
202
|
+
`openxiangda.user-candidates-query/v2`,支持keyword/cursor/selectedIds;Native更新绑定recordId/expectedRevision,
|
|
203
|
+
任务绑定expectedRevision/expectedTaskVersion。不要传入职责或学院覆盖参数。返回`UserCandidatePage`只包含
|
|
204
|
+
稳定ID、名称、已选项valid/invalid及下一页游标;invalid不返回无权读取的名称,页面保留原显示快照。
|
|
205
|
+
确认前复核选择只能改善交互,不能替代保存及节点进入时的服务器核验。
|
|
206
|
+
|
|
143
207
|
仅选择时间时使用 `time`,并显式决定精度:
|
|
144
208
|
|
|
145
209
|
```ts
|
|
146
210
|
{ code: 'reminderMinute', type: 'time', label: '提醒时间', timePrecision: 'minute' }
|
|
147
211
|
{ code: 'checkpointSecond', type: 'time', label: '检查时间', timePrecision: 'second' }
|
|
212
|
+
{ code: 'meetingStart', type: 'datetime', label: '会议开始', timePrecision: 'minute' }
|
|
213
|
+
{ code: 'usageTimes', type: 'datetime-range', label: '使用时间', rangeBoundary: 'closed', timePrecision: 'minute' }
|
|
148
214
|
```
|
|
149
215
|
|
|
216
|
+
`datetime`和`datetime-range`也可声明`timePrecision`。分钟声明同时驱动PC/手机
|
|
217
|
+
输入、筛选和只读显示;保存仍为ISO instant,秒及小数秒非零时服务端拒绝,
|
|
218
|
+
不会自动截断原值。区间的精度应用于两端,闭/半开边界分别保留。直接组件已有
|
|
219
|
+
`minuteStep`时继续使用更严格步长;无需在每个页面重复设置步长。未声明或声明
|
|
220
|
+
`second`沿用既有日期时间保存行为。`date`与`date-range`不使用时间精度。
|
|
221
|
+
|
|
150
222
|
定位只支持钉钉定位或浏览器 Geolocation 采集 WGS84 经纬度。组件没有地址输入、
|
|
151
223
|
手工定位或地图选点;服务商返回的地址/POI 只能作为该坐标的只读显示快照。
|
|
152
224
|
|
|
@@ -259,3 +331,11 @@ ISO instant)与 `minuteStep`(1 到 60 且整除 60)。设置步长后只
|
|
|
259
331
|
|
|
260
332
|
`rating` 需要支持该控件的编译器、前端包与服务端 Surface 校验组合;存储、查询和校验仍为
|
|
261
333
|
整数。它不会修改已有 `number.integer` 字段的默认数值输入控件。
|
|
334
|
+
|
|
335
|
+
### 子表提交行数
|
|
336
|
+
|
|
337
|
+
`subtable.minRows`为可选整数,默认0,不能超过`maxRows`(默认20);恰好一行可用
|
|
338
|
+
`minRows: 1, maxRows: 1`。它约束父表提交的owned计划,独立子表写权限仍应关闭。
|
|
339
|
+
普通新建即使省略表也检查;编辑只检查本次提交的表。任务草稿/保存允许不足,
|
|
340
|
+
完成时对可见可写表检查最终行数,删除标记不算行。旧固定声明不隐式补造数据。
|
|
341
|
+
标准PC/移动表单显示下限并保留字段校验;应用可提供初始空行,平台不生成可信资料。
|