openxiangda 2.55.1 → 2.59.2

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.
Files changed (152) hide show
  1. package/README.md +1 -0
  2. package/dist/browser/AuthoritativeSelector.d.ts +3 -2
  3. package/dist/browser/AuthoritativeSelector.d.ts.map +1 -1
  4. package/dist/browser/AuthoritativeSelector.js +20 -11
  5. package/dist/browser/AuthoritativeSelector.js.map +1 -1
  6. package/dist/browser/components/platform-fields/DateTimeField.d.ts +1 -1
  7. package/dist/browser/components/platform-fields/DateTimeField.d.ts.map +1 -1
  8. package/dist/browser/components/platform-fields/DateTimeField.js +15 -8
  9. package/dist/browser/components/platform-fields/DateTimeField.js.map +1 -1
  10. package/dist/browser/components/platform-fields/MobileDateTimeField.d.ts +1 -1
  11. package/dist/browser/components/platform-fields/MobileDateTimeField.d.ts.map +1 -1
  12. package/dist/browser/components/platform-fields/MobileDateTimeField.js +5 -3
  13. package/dist/browser/components/platform-fields/MobileDateTimeField.js.map +1 -1
  14. package/dist/browser/components/platform-fields/MobileZonedDateTimeField.js +2 -2
  15. package/dist/browser/components/platform-fields/MobileZonedDateTimeField.js.map +1 -1
  16. package/dist/browser/components/platform-fields/ResourceReferenceField.d.ts +3 -2
  17. package/dist/browser/components/platform-fields/ResourceReferenceField.d.ts.map +1 -1
  18. package/dist/browser/components/platform-fields/ResourceReferenceField.js +3 -3
  19. package/dist/browser/components/platform-fields/ResourceReferenceField.js.map +1 -1
  20. package/dist/browser/components/platform-fields/SubtableField.d.ts +11 -2
  21. package/dist/browser/components/platform-fields/SubtableField.d.ts.map +1 -1
  22. package/dist/browser/components/platform-fields/SubtableField.js +55 -24
  23. package/dist/browser/components/platform-fields/SubtableField.js.map +1 -1
  24. package/dist/browser/components/platform-fields/ZonedDateTimeField.js +2 -2
  25. package/dist/browser/components/platform-fields/ZonedDateTimeField.js.map +1 -1
  26. package/dist/browser/components/platform-fields/reference-binding-change.d.ts +6 -0
  27. package/dist/browser/components/platform-fields/reference-binding-change.d.ts.map +1 -0
  28. package/dist/browser/components/platform-fields/reference-binding-change.js +32 -0
  29. package/dist/browser/components/platform-fields/reference-binding-change.js.map +1 -0
  30. package/dist/browser/components/platform-fields/user-candidate-context.d.ts +3 -0
  31. package/dist/browser/components/platform-fields/user-candidate-context.d.ts.map +1 -1
  32. package/dist/browser/components/platform-fields/user-candidate-context.js +12 -4
  33. package/dist/browser/components/platform-fields/user-candidate-context.js.map +1 -1
  34. package/dist/browser/components/platform-fields/zoned-date-time.d.ts +4 -0
  35. package/dist/browser/components/platform-fields/zoned-date-time.d.ts.map +1 -1
  36. package/dist/browser/components/platform-fields/zoned-date-time.js +9 -1
  37. package/dist/browser/components/platform-fields/zoned-date-time.js.map +1 -1
  38. package/dist/browser/components/resource/GeneratedResourceCrud.d.ts.map +1 -1
  39. package/dist/browser/components/resource/GeneratedResourceCrud.js +2 -2
  40. package/dist/browser/components/resource/GeneratedResourceCrud.js.map +1 -1
  41. package/dist/browser/components/resource/GeneratedResourceForm.js +2 -2
  42. package/dist/browser/components/resource/GeneratedResourceForm.js.map +1 -1
  43. package/dist/browser/components/resource/ResourceFormFrame.d.ts +1 -1
  44. package/dist/browser/components/resource/ResourceFormFrame.d.ts.map +1 -1
  45. package/dist/browser/components/resource/ResourceFormFrame.js +12 -1
  46. package/dist/browser/components/resource/ResourceFormFrame.js.map +1 -1
  47. package/dist/browser/components/resource/SurfaceFields.d.ts +5 -1
  48. package/dist/browser/components/resource/SurfaceFields.d.ts.map +1 -1
  49. package/dist/browser/components/resource/SurfaceFields.js +13 -5
  50. package/dist/browser/components/resource/SurfaceFields.js.map +1 -1
  51. package/dist/browser/components/resource/generated-resource-definition.d.ts +1 -0
  52. package/dist/browser/components/resource/generated-resource-definition.d.ts.map +1 -1
  53. package/dist/browser/components/resource/resource-field-selection.d.ts +1 -0
  54. package/dist/browser/components/resource/resource-field-selection.d.ts.map +1 -1
  55. package/dist/browser/components/resource/resource-form-operations.d.ts.map +1 -1
  56. package/dist/browser/components/resource/resource-form-operations.js +3 -2
  57. package/dist/browser/components/resource/resource-form-operations.js.map +1 -1
  58. package/dist/browser/components/resource/useResourceFormDrafts.d.ts.map +1 -1
  59. package/dist/browser/components/workflow/StandardWorkflowPages.d.ts +15 -3
  60. package/dist/browser/components/workflow/StandardWorkflowPages.d.ts.map +1 -1
  61. package/dist/browser/components/workflow/StandardWorkflowPages.js +80 -20
  62. package/dist/browser/components/workflow/StandardWorkflowPages.js.map +1 -1
  63. package/dist/browser/components/workflow/WorkflowDelegationManager.js +13 -8
  64. package/dist/browser/components/workflow/WorkflowDelegationManager.js.map +1 -1
  65. package/dist/browser/components/workflow/WorkflowDiagram.d.ts.map +1 -1
  66. package/dist/browser/components/workflow/WorkflowDiagram.js +5 -2
  67. package/dist/browser/components/workflow/WorkflowDiagram.js.map +1 -1
  68. package/dist/browser/components/workflow/WorkflowFlowCanvas.d.ts.map +1 -1
  69. package/dist/browser/components/workflow/WorkflowFlowCanvas.js +2 -1
  70. package/dist/browser/components/workflow/WorkflowFlowCanvas.js.map +1 -1
  71. package/dist/browser/components/workflow/WorkflowNodeCard.d.ts +1 -1
  72. package/dist/browser/components/workflow/WorkflowNodeCard.d.ts.map +1 -1
  73. package/dist/browser/components/workflow/WorkflowNodeCard.js +7 -5
  74. package/dist/browser/components/workflow/WorkflowNodeCard.js.map +1 -1
  75. package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.d.ts.map +1 -1
  76. package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.js +14 -11
  77. package/dist/browser/components/workflow/WorkflowNodeConfigurationEditor.js.map +1 -1
  78. package/dist/browser/components/workflow/WorkflowTaskForm.d.ts +3 -1
  79. package/dist/browser/components/workflow/WorkflowTaskForm.d.ts.map +1 -1
  80. package/dist/browser/components/workflow/WorkflowTaskForm.js +17 -8
  81. package/dist/browser/components/workflow/WorkflowTaskForm.js.map +1 -1
  82. package/dist/browser/components/workflow/standard-process-values.d.ts +10 -2
  83. package/dist/browser/components/workflow/standard-process-values.d.ts.map +1 -1
  84. package/dist/browser/components/workflow/standard-process-values.js +22 -1
  85. package/dist/browser/components/workflow/standard-process-values.js.map +1 -1
  86. package/dist/browser/components/workflow/workflow-flow-layout.d.ts.map +1 -1
  87. package/dist/browser/components/workflow/workflow-flow-layout.js +33 -3
  88. package/dist/browser/components/workflow/workflow-flow-layout.js.map +1 -1
  89. package/dist/browser/components/workflow/workflow-submission-form.d.ts +4 -0
  90. package/dist/browser/components/workflow/workflow-submission-form.d.ts.map +1 -1
  91. package/dist/browser/components/workflow/workflow-submission-form.js +20 -0
  92. package/dist/browser/components/workflow/workflow-submission-form.js.map +1 -1
  93. package/dist/browser/durable-command.js +2 -2
  94. package/dist/browser/durable-command.js.map +1 -1
  95. package/dist/browser/managed-read-recovery.d.ts +2 -0
  96. package/dist/browser/managed-read-recovery.d.ts.map +1 -1
  97. package/dist/browser/managed-read-recovery.js +6 -1
  98. package/dist/browser/managed-read-recovery.js.map +1 -1
  99. package/dist/browser/platform-client.d.ts +8 -1
  100. package/dist/browser/platform-client.d.ts.map +1 -1
  101. package/dist/browser/platform-client.js +39 -2
  102. package/dist/browser/platform-client.js.map +1 -1
  103. package/dist/browser/runtime-authorization-recovery.d.ts.map +1 -1
  104. package/dist/browser/runtime-authorization-recovery.js +36 -9
  105. package/dist/browser/runtime-authorization-recovery.js.map +1 -1
  106. package/dist/browser/runtime.d.ts +3 -1
  107. package/dist/browser/runtime.d.ts.map +1 -1
  108. package/dist/browser/runtime.js.map +1 -1
  109. package/dist/browser/workflow-operation-input.js +1 -1
  110. package/dist/browser/workflow-operation-input.js.map +1 -1
  111. package/dist/config.d.ts +2 -1
  112. package/dist/config.d.ts.map +1 -1
  113. package/dist/config.js +2 -1
  114. package/dist/config.js.map +1 -1
  115. package/dist/core.d.ts +5 -1
  116. package/dist/core.d.ts.map +1 -1
  117. package/dist/core.js +3 -1
  118. package/dist/core.js.map +1 -1
  119. package/dist/expressions.d.ts +4 -0
  120. package/dist/expressions.d.ts.map +1 -0
  121. package/dist/expressions.js +3 -0
  122. package/dist/expressions.js.map +1 -0
  123. package/documentation/administration.md +33 -0
  124. package/documentation/backend.md +117 -2
  125. package/documentation/data-authz.md +30 -0
  126. package/documentation/declarations-cheatsheet.md +2 -1
  127. package/documentation/development.md +7 -0
  128. package/documentation/field-components.md +44 -1
  129. package/documentation/getting-started.md +60 -7
  130. package/documentation/managed-concurrency-frontend.md +10 -4
  131. package/documentation/manifest.json +10 -10
  132. package/documentation/workflow-events.md +303 -9
  133. package/package.json +26 -21
  134. package/releases/2.55.5.json +30 -0
  135. package/releases/2.55.6.json +32 -0
  136. package/releases/2.57.1.json +31 -0
  137. package/releases/2.58.0.json +37 -0
  138. package/releases/2.58.1.json +31 -0
  139. package/releases/2.59.0.json +36 -0
  140. package/releases/2.59.1.json +37 -0
  141. package/releases/2.59.2.json +33 -0
  142. package/skills/manifest.json +1 -1
  143. package/skills/openxiangda-v2/SKILL.md +4 -4
  144. package/skills/openxiangda-v2/references/administration.md +33 -0
  145. package/skills/openxiangda-v2/references/backend.md +117 -2
  146. package/skills/openxiangda-v2/references/data-authz.md +30 -0
  147. package/skills/openxiangda-v2/references/declarations-cheatsheet.md +2 -1
  148. package/skills/openxiangda-v2/references/development.md +7 -0
  149. package/skills/openxiangda-v2/references/field-components.md +44 -1
  150. package/skills/openxiangda-v2/references/getting-started.md +60 -7
  151. package/skills/openxiangda-v2/references/managed-concurrency-frontend.md +10 -4
  152. package/skills/openxiangda-v2/references/workflow-events.md +303 -9
@@ -28,6 +28,36 @@ 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`。平台在环境
@@ -30,7 +30,7 @@
30
30
  | `labelField` 必须指向目标资源的 `text.short` / `text.long` 字段 | 不要用流水号/选项字段当 label |
31
31
  | 列表可排序列用视图级 `sortableFields` 表达(`defaultSort.field` 隐式可排序);平台审计列(如 `created_at`)同样合法 | `list: { sortableFields: ['capacity'], defaultSort: { field: 'name', order: 'asc' } }`;`defaultSort: { field: 'created_at', order: 'desc' }` |
32
32
  | 每个字段都必须带中文/业务 `label`(含子表外键与排序字段) | `{ code: 'requestId', type: 'uuid', label: '所属申请', required: true }` |
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', 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 |
34
34
  | 图片/附件的 `file` 限定数量与大小 | `file: { maxCount: 3, maxSizeMb: 10, accept: ['image/png', 'image/jpeg'] }` |
35
35
 
36
36
  ## 权限声明
@@ -39,6 +39,7 @@
39
39
  | --- | --- |
40
40
  | 数据策略是**白名单**语义:规则 `roleCodes` 之外的角色若不在 `unrestrictedRoleCodes` 中会被 RLS 全拒(报错只有 FIELD_ROW_FORBIDDEN) | `unrestrictedRoleCodes: ['admin']` 必须列出所有"不受限"角色 |
41
41
  | 基线角色(`authenticatedUserRoleCode`)进 `unrestrictedRoleCodes` = 策略对所有人失效(角色并集必含基线角色),编译器直接报错 | 把基线角色移出 unrestrictedRoleCodes,为其单独声明 rules |
42
+ | 登录公共字段与管理私有范围共存不能直接放开基线角色 | 只读策略显式 `publicRead: { fields: [...] }`,全部非公开字段及变更历史须拒绝基线,详见 data-authz;不支持公共子表 |
42
43
  | 匿名公开策略的 `ownRecordFields` 必须是 `fields` 的子集;`create` 必须配套 `draft`;`requiredFields` ⊆ `fields` | 先定 fields,再从中选 required/own |
43
44
  | workflow definition 必须显式 `launch`(编译器强制) | `definitions: [{ version: 1, definition, launch: { mode: 'standalone' } }]` |
44
45
  | option/user/department/resource-ref/cascade 字段投影进工作流事实是 { label, value } 对象,不能声明为标量;条件比较用 `<fact>.value` | `inputSchema.properties.urgency = { type: 'object', ... }` + `path: 'urgency.value'` |
@@ -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、生成契约和部署状态。新应用维护具体设计和评审,复杂度随业务展开;既有小变更沿用有效设计,仅修订受影响记录,无行为变化可引用已有记录。每轮先读取当前规则、澄清业务、评估架构、权限和性能,随后实施与验证,发布后更新当前规格及交接。测试部署前需要设计和验收计划,生产晋级前需要绑定测试运行及包摘要的实际验收报告。
@@ -130,6 +130,13 @@ import { AttachmentFileList } from 'openxiangda/field-kit';
130
130
  平台按来源资源的字段权限和 PostgreSQL RLS 查询并返回完整资源快照。来源记录改名或删除后,
131
131
  已经保存的 `{label,value,resourceCode,snapshot}` 仍可直接展示,不需要再次查询。
132
132
 
133
+ 过滤条件绑定其他表单字段时,可显式设置 `source.clearOnBindingChange: true`。
134
+ 用户改变绑定值后,标准表单、任务补填和同一子表行会清除对应旧选择:单选清空、
135
+ 多选变为空数组,依赖链中的可写关联字段也会清除。只比较引用的真实 `value`;
136
+ 同值重选、显示标签刷新、无关字段或其他子表行的修改不清除当前选择。
137
+ 默认缺省或 `false` 保留选择;程序预填、草稿与资料恢复不会触发这项用户事件联动。
138
+ 这项设置只管理当前输入,提交是否合法仍由平台事务与字段权限判断。
139
+
133
140
  成员和部门同样保存完整显示快照:
134
141
 
135
142
  ```ts
@@ -160,11 +167,24 @@ import { AttachmentFileList } from 'openxiangda/field-kit';
160
167
  ```
161
168
 
162
169
  职责和范围维度必须在同包声明。`pageSize` 为1–50,默认20;范围使用代码常量 `value`,
163
- 或同资源的 `text.short`、`uuid`、`option.single` 字段 `field`,两者互斥。
170
+ 或同资源的 `text.short`、`uuid`、`option.single`、`resource-ref.single` 字段 `field`,两者互斥。
164
171
  单选范围取稳定的 `.value`,不按显示标签决定身份。记录范围必须来自已授权、已保存的记录或当前任务,
165
172
  首版新建不接受非空的记录范围选人。修改范围须清空相依选择并保存,再按新范围重选。
166
173
  候选显示失败不能当作空名单;旧选择失效须保留显示快照并提示重选。
167
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
+
168
188
  流程使用 `{ provider: 'form_field_users', inputPath: 'leaders', candidateField: 'unitLeaders' }`,
169
189
  其中 `subject.factProjection.leaders` 必须精确指向 `unitLeaders`,范围字段也须有唯一事实投影。
170
190
  不能另写职责、范围或路由覆盖来源,不能用嵌套输入路径绕过候选字段。
@@ -189,8 +209,16 @@ import { AttachmentFileList } from 'openxiangda/field-kit';
189
209
  ```ts
190
210
  { code: 'reminderMinute', type: 'time', label: '提醒时间', timePrecision: 'minute' }
191
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' }
192
214
  ```
193
215
 
216
+ `datetime`和`datetime-range`也可声明`timePrecision`。分钟声明同时驱动PC/手机
217
+ 输入、筛选和只读显示;保存仍为ISO instant,秒及小数秒非零时服务端拒绝,
218
+ 不会自动截断原值。区间的精度应用于两端,闭/半开边界分别保留。直接组件已有
219
+ `minuteStep`时继续使用更严格步长;无需在每个页面重复设置步长。未声明或声明
220
+ `second`沿用既有日期时间保存行为。`date`与`date-range`不使用时间精度。
221
+
194
222
  定位只支持钉钉定位或浏览器 Geolocation 采集 WGS84 经纬度。组件没有地址输入、
195
223
  手工定位或地图选点;服务商返回的地址/POI 只能作为该坐标的只读显示快照。
196
224
 
@@ -303,3 +331,18 @@ ISO instant)与 `minuteStep`(1 到 60 且整除 60)。设置步长后只
303
331
 
304
332
  `rating` 需要支持该控件的编译器、前端包与服务端 Surface 校验组合;存储、查询和校验仍为
305
333
  整数。它不会修改已有 `number.integer` 字段的默认数值输入控件。
334
+
335
+ ### 子表提交行数
336
+
337
+ 单个子表 `maxRows` 最多500。同一模型下所有子表的声明上限合计默认最多500;
338
+ 历史快照加行程、多种材料等场景可在模型上显式声明 `ownedRowLimit: 550` 或
339
+ `ownedRowLimit: 1000`,最多1000。此限额随模型编译到Native资源,不由提交请求指定。
340
+ 扩展声明需要平台支持 `data.aggregate-owned-subtable-capacity`;旧平台在激活前拒绝。
341
+ 标准表单、任务补填、具名初建和级联删除共用该限额与原子事务。完整替换最多2016个
342
+ 操作,但一次事务/草稿/任务值仍限2MiB;超额或最后行版本冲突整笔失败,不自动裁剪或分批写。
343
+
344
+ `subtable.minRows`为可选整数,默认0,不能超过`maxRows`(默认20);恰好一行可用
345
+ `minRows: 1, maxRows: 1`。它约束父表提交的owned计划,独立子表写权限仍应关闭。
346
+ 普通新建即使省略表也检查;编辑只检查本次提交的表。任务草稿/保存允许不足,
347
+ 完成时对可见可写表检查最终行数,删除标记不算行。旧固定声明不隐式补造数据。
348
+ 标准PC/移动表单显示下限并保留字段校验;应用可提供初始空行,平台不生成可信资料。
@@ -68,10 +68,10 @@ MCP 服务随项目根包一起安装,AI 客户端的 stdio 连接仍需配置
68
68
  以下命令的版本占位符由随包资料替换为该根包的精确版本。网站源码阅读者应先确认要使用的发行版本。
69
69
 
70
70
  ```bash
71
- pnpm dlx openxiangda@2.55.1 skill install --force
72
- pnpm dlx openxiangda@2.55.1 auth status --base-url <平台地址> --json
73
- pnpm dlx openxiangda@2.55.1 login --cwd my-app --base-url https://platform.example.com
74
- pnpm dlx openxiangda@2.55.1 create my-app --base-url https://platform.example.com
71
+ pnpm dlx openxiangda@2.59.2 skill install --force
72
+ pnpm dlx openxiangda@2.59.2 auth status --base-url <平台地址> --json
73
+ pnpm dlx openxiangda@2.59.2 login --cwd my-app --base-url https://platform.example.com
74
+ pnpm dlx openxiangda@2.59.2 create my-app --base-url https://platform.example.com
75
75
  cd my-app
76
76
  pnpm openxiangda context --json
77
77
  pnpm openxiangda dev
@@ -121,6 +121,36 @@ AppSpec 随开发持续维护:测试发布前补齐总纲、关联变更与验
121
121
 
122
122
  前端启动使用根目录 `dev:web`。声明了后端的应用同时运行配置的 `backend.root` 包内的 `dev`,无需增加根目录 `dev:server`;纯前端应用只启动 Web 和代理。已有前端测试版本后,可以启用本地 Nest 联调,不必先构建或发布后端镜像。平台返回的活动应用版本和开发会话绑定本次联调,环境版本变化导致会话不一致时,停止后重新运行 `dev`。
123
123
 
124
+ 在已有测试环境的应用中,`dev` 先将当前完整资源、权限、具名操作和固定流程配置
125
+ 提交给平台。平台使用同源编译器校验配置与契约,保存真实配置版本和同步回执,
126
+ 选择该应用 test 的配置 Head,然后 CLI 重新读取环境并创建开发会话。这个过程
127
+ 不运行应用 `build`、打包或容器部署;代码继续在本机运行。相同配置与契约再次启动
128
+ 时复用当前版本;旧 Head 的开发会话失效,需要重新启动。新增模型和流程可以在
129
+ 同一批开发中联调,不需要每次冻结 SDK 和正式部署应用。
130
+
131
+ 完整开发配置要求平台提供 `application.development-configuration` 1.0.0,并且
132
+ 应用已有 test Native Head;当前尚不支持无测试基线的新应用直接同步。同步会改变
133
+ test 的配置选择,历史正式版本、数据和原运行保留。开发配置不能用于生产晋级、
134
+ 正式部署或回滚候选。
135
+
136
+ 声明后端的应用还要求 `application.development-backend-events` 1.0.0。CLI自动连接
137
+ 当前test开发版本,把平台已签名的后台事件和流程业务步骤投递到本机Nest源码,
138
+ 并复用平台的持久执行回执与失败恢复。应用运行凭据只进入本地Nest环境,不传入Web、
139
+ 页面或终端状态。开发连接关闭或失联时,事件保留在平台队列,不回退到旧后端制品;
140
+ 同一测试环境同时只能连接一个开发会话,环境版本变化后重新运行dev。
141
+ 临时运输故障会在20秒内恢复原连接;已执行处理器的回复只重发原响应,不重复执行业务。
142
+ 授权、环境版本或连接归属变化会立即停止;超过恢复窗口则保留平台原执行记录,重新运行dev继续。
143
+
144
+ 开发连接会启用当前后台事件订阅,保留手工暂停;正常关闭时暂停本连接开启的订阅。
145
+ Timer和DateTrigger继续暂停,日期提醒仍须确认测试副作用意图并完成专门验收。
146
+ 当前投递范围是标准后台事件与流程业务步骤;自定义审批人provider、managed-command
147
+ planner等调用仍须正式后端或后续能力。不要把本地开发者联调视为普通角色验收。
148
+
149
+ 同步失败保留原配置运行 ID;相同输入重试复用原回执与版本,并由平台锁和 Head
150
+ CAS 判断是否允许继续。并发请求返回进行中;服务重启释放锁后允许恢复原运行。
151
+ 不要修改环境 ID、直接写配置表或换随机键绕过错误。平台缺能力时更新配套平台,
152
+ 不通过重复打包应用规避开发能力缺口。
153
+
124
154
  纯 CRUD 修改优先使用标准模型、字段和页面;跨模型事务或外部副作用再选择后端。角色、行和字段权限在平台执行。详见[开发流程](development.md)、[模型与标准 CRUD](application-foundation.md)和[按需后端](backend.md)。
125
155
 
126
156
  ## 应用源码
@@ -174,9 +204,9 @@ MCP 的 `docs_read` 可以读取本说明,当前没有独立的源码操作 MC
174
204
  无需本地工作区,使用本 Skill 随包精确版本或已安装的对应 CLI:
175
205
 
176
206
  ```bash
177
- pnpm dlx openxiangda@2.55.1 auth status --base-url <平台> --json
178
- pnpm dlx openxiangda@2.55.1 source resolve <仓库URL> --base-url <平台> --json
179
- pnpm dlx openxiangda@2.55.1 source clone <仓库URL> <新目录> --base-url <平台> --json
207
+ pnpm dlx openxiangda@2.59.2 auth status --base-url <平台> --json
208
+ pnpm dlx openxiangda@2.59.2 source resolve <仓库URL> --base-url <平台> --json
209
+ pnpm dlx openxiangda@2.59.2 source clone <仓库URL> <新目录> --base-url <平台> --json
180
210
  ```
181
211
 
182
212
  登录缺失或站点不匹配时,先按该平台执行 login。resolve 根据平台已经登记的绑定返回
@@ -227,6 +257,29 @@ openxiangda link rebind --base-url https://platform-b.example.com # 显式换
227
257
  幂等初始化处暴露,随时可以再次 rebind 修正。详细决策记录见仓库
228
258
  `docs/architecture-decisions/workspace-platform-rebind.md`。
229
259
 
260
+ ### 普通角色与应用登录联调
261
+
262
+ `pnpm openxiangda dev --identity browser` 使用应用自身的登录入口验证普通用户;
263
+ 新模板已接入开发模式挂载插件。既有 Vite 应用在 `vite.config.ts` 中从
264
+ `openxiangda/config` 导入 `createConnectedDevelopmentVitePlugin`,加入 `plugins`。
265
+ 插件只在 CLI 的普通身份连接开发模式下提供标准运行时挂载信息;正式构建及
266
+ 默认开发者模式不受影响,登录、Cookie、CSRF 与实时角色仍由平台管理。
267
+ 退出后仍保持应用登录模式。默认的 `developer` 模式方便开发者联调,但已携带应用
268
+ 浏览器 cookie 或不同显式 Bearer 的请求保留原身份。失效 cookie 由平台拒绝,不会
269
+ 回退开发者身份。登录、退出和 CSRF 均由平台处理。
270
+
271
+ 普通用户的 Data API 和业务操作经过平台授权。预发布开发配置已激活、平台支持
272
+ `application.development-backend-invocations` 且当前 CLI 连接存活时,已声明的业务
273
+ operation 通过平台网关进入本地 Nest 源码;浏览器身份、CSRF 和原幂等键保持不变。
274
+ 平台在派发和 Nest 验证时重查身份、角色与当前版本,浏览器不会取得开发者凭据。
275
+
276
+ 这条联调路径支持有限缓冲 HTTP:请求最多 256 KiB,响应最多 1 MiB,每环境事件与
277
+ 业务调用共用 8 个运输槽,普通调用最多等待 30 秒;SSE 明确拒绝,托管文件使用平台
278
+ 文件接口。关闭或撤销连接、停止环境、切换 Head 都使旧调用失效。回执丢失沿原
279
+ 意图查询或恢复,不生成第二次业务提交。正式部署仍走已激活的正式后端。
280
+ 旧平台与事件专用连接不支持此路径;启用后端的 `--identity browser` 会提示配套升级。
281
+ 源码测试与批次正式构建、激活、普通角色验收分别记录。
282
+
230
283
  ## 检查与交付 {#delivery}
231
284
 
232
285
  只检查时运行 `pnpm openxiangda check`。需要部署测试环境时直接运行 `pnpm openxiangda deploy`,它已包含检查、测试和构建;无需再连续重复运行全部脚本。
@@ -49,9 +49,9 @@ export async function readOffer(
49
49
 
50
50
  将读取接入应用已有的异步查询状态:初次加载显示局部骨架,空数组显示无可展示内容,失败提供局部重试。组件卸载或资源变化时中止旧请求,迟到响应不能覆盖新资源。同页多个观察者可复用应用已有查询层,查询键包含 `client.scope`、读取 code 和规范化参数,身份变化时清除旧主体视图;当前没有内置的 `useManagedRead` hook。
51
51
 
52
- ### 只读预算繁忙恢复
52
+ ### 只读繁忙与断连恢复
53
53
 
54
- `read`、`mine`、`result`、`allocation` 共用有界恢复:单次调用默认含 HTTP 和等待的总预算 120 秒,最多 12 次总请求。应用可以通过 `budgetMs` 显式延长;超过 120 秒时最多 120 次总请求,预算上限为 30 分钟,超出上限按 30 分钟处理。只重试 HTTP 429 的 `CONCURRENCY_API_BUSY`、`CONCURRENCY_RESULT_BUSY`、`CONCURRENCY_RATE_LIMITED`、`CONCURRENCY_SOURCE_BUSY`;兼容旧平台的 HTTP 503 仅限前两个已知预算错误。明确 `retryable: false`、未知 429、权限拒绝、Redis/数据库/授权依赖失败和网络失败直接返回,不用繁忙重试掩盖。
54
+ `read`、`mine`、`result`、`allocation` 共用有界恢复:单次调用默认含 HTTP 和等待的总预算 120 秒,最多 12 次总请求。应用可以通过 `budgetMs` 显式延长;超过 120 秒时最多 120 次总请求,预算上限为 30 分钟,超出上限按 30 分钟处理。可恢复的预算响应为 HTTP 429 的 `CONCURRENCY_API_BUSY`、`CONCURRENCY_RESULT_BUSY`、`CONCURRENCY_RATE_LIMITED`、`CONCURRENCY_SOURCE_BUSY`;兼容旧平台的 HTTP 503 仅限前两个已知预算错误。认证传输层标记为 HTTP 503、`PLATFORM_TRANSPORT_UNAVAILABLE` 的连接中断也按原预算恢复。明确 `retryable: false`、未标记的网络错误、未知 429、权限拒绝、Redis/数据库/授权依赖失败直接返回;连接中断不证明请求已受理或业务失败。
55
55
 
56
56
  第一次失败后的基础等待为 2 秒,之后指数增加到最多 30 秒;取其与有效服务端提示的较大值,再加 0% 至 25% 随机抖动。提示优先使用合法 `Retry-After`(秒或 HTTP 日期),缺失时使用 `data.retryAfterMs`。若等待达到剩余预算,不提前查询,直接返回最后一次繁忙错误;请求次数用完也保留最后繁忙响应。正在进行的请求超过总预算则中止并返回 `CONCURRENCY_READ_RECOVERY_EXHAUSTED`,不以之前的繁忙响应掩盖悬挂请求。
57
57
 
@@ -236,10 +236,16 @@ hook 从 `openxiangda/react` 和 `openxiangda/mobile` 导出。state、initializ
236
236
 
237
237
  已受理申请的自动观察最多持续到首次明确提交后的 30 分钟,默认受理恢复仍为 120 秒,两者分别计算。自动观察的每次结果读取同时受单次 120 秒和原提交剩余时间限制;刷新和 resume 不重新获得观察时间。跨设备没有本地首次时间时,用原回执 acceptedAt 计算观察窗口,不能以页面挂载时间重新计时。达到窗口后保留原意图,状态为 recovering、isObserving 为 false,提示稍后核对;明确 refresh 仍可用有界初查预算查询迟到终态,但不重新启动已经到期的自动观察,也不自动提交。
238
238
 
239
- 正常待处理结果每次至少间隔 5 秒,遵守更长的服务端 retryAfterMs,再加随机抖动。单次只读恢复耗尽且仍是已知预算繁忙时,外层可在原观察窗口内指数退避继续。SDK 自身明确标记为 status=504、retryable=true 的 CONCURRENCY_READ_RECOVERY_EXHAUSTED 也只在已受理原结果观察中按退避恢复;它不代表服务端忙,不延长原三十分钟截止,也不触发再次提交。权限、依赖、普通网络错误、其他 504 或未标记可恢复的错误立即停止自动观察,显示 error 并保留原回执和请求键。终态停止。受理恢复中核对原结果同样只允许已知预算繁忙继续,读取依赖失败不能被外层重试隐藏。一个业务区域只挂载一个观察者。离开或关闭页面不撤销已受理请求,平台自动继续;新设备通过 mine 找到本人的原请求。position 为空时显示「已受理,稍后可查看」,不要显示虚假的精确人数或预计秒数。
239
+ 正常待处理结果每次至少间隔 5 秒,遵守更长的服务端 retryAfterMs,再加随机抖动。单次只读恢复耗尽且仍是已知预算繁忙或认证传输层标记的 `PLATFORM_TRANSPORT_UNAVAILABLE`/503 时,外层可在原观察窗口内指数退避继续。SDK 自身明确标记为 status=504、retryable=true 的 CONCURRENCY_READ_RECOVERY_EXHAUSTED 也只在已受理原结果观察中按退避恢复;它不代表服务端忙,不延长原三十分钟截止,也不触发再次提交。权限、依赖、未标记的网络错误、其他 504 或未标记可恢复的错误立即停止自动观察,显示 error 并保留原回执和请求键。终态停止。受理恢复中核对原结果的连接中断由同一有界只读层恢复,内层耗尽不触发 enqueue 重放,读取依赖失败不能被外层重试隐藏。一个业务区域只挂载一个观察者。离开或关闭页面不撤销已受理请求,平台自动继续;新设备通过 mine 找到本人的原请求。position 为空时显示「已受理,稍后可查看」,不要显示虚假的精确人数或预计秒数。
240
240
 
241
- refresh 有本地原键时先薄查询原 key;找到已受理非终态后不再 mine。没有本地意图或原申请已有终态时,mine 优先恢复新的进行中周期,避免本地历史 succeeded 遮蔽另一个设备的新申请。原键明确 404 后保留一次本人列表兜底;未确认的本地意图只能采用同原键回执。列表中只有别的活跃周期时显示 recovering / CONCURRENCY_ORIGINAL_REQUEST_REQUIRED,并保留原 key/input;没有匹配时显示 CONCURRENCY_ACCEPTANCE_UNCONFIRMED,提供「核对原申请」和「恢复原申请」动作。不能把无匹配解释为业务失败,也不丢弃可能迟到受理的原意图。已知读取繁忙耗尽显示 recovering,真实依赖、网络、权限或未知 400 显示 error;两种状态均保留原键、输入和已受理回执,读取失败不自动提交。
241
+ refresh 有本地原键时先薄查询原 key;找到已受理非终态后不再 mine。没有本地意图或原申请已有终态时,mine 优先恢复新的进行中周期,避免本地历史 succeeded 遮蔽另一个设备的新申请。原键明确 404 后保留一次本人列表兜底;未确认的本地意图只能采用同原键回执。列表中只有别的活跃周期时显示 recovering / CONCURRENCY_ORIGINAL_REQUEST_REQUIRED,并保留原 key/input;没有匹配时显示 CONCURRENCY_ACCEPTANCE_UNCONFIRMED,提供「核对原申请」和「恢复原申请」动作。不能把无匹配解释为业务失败,也不丢弃可能迟到受理的原意图。已知读取繁忙耗尽显示 recovering,认证传输层标记的断连先在原预算内恢复;真实依赖、未标记的网络错误、权限或未知 400 显示 error。两种状态均保留原键、输入和已受理回执,读取失败不自动提交。
242
242
 
243
243
  不要在 mount 发现历史 succeeded 时自动跳成功页或永久禁用提交。它可能已经被管理员取消,需结合当前业务记录展示。只有用户明确再次点击 submit,且原请求已有终态,SDK 才创建新的 requestKey;活跃请求或未知应答始终恢复原 key。平台明确返回未受理的参数错误(400 + CONCURRENCY_INPUT_INVALID 等约定错误)时,SDK 才清除被拒输入,允许修正后再提交;未知 400、409、429、5xx 和网络错误仍保留原意图。成功提示以 receipt.state==='succeeded' 和 receipt.result 为准,accepted/executing 只显示「已登记,处理中」。
244
244
 
245
245
  permit 的 ManagedCommandGate 仍只用于 admitted 短确认,不用于 durable。durable 不能套任意前端 onSubmit 冒充后台事务,真正业务必须由已声明的 backend-plan handler 返回受管计划。
246
+
247
+ ### 入口等待与身份加载连续性
248
+
249
+ 平台启用入口排队时,SDK 的当前用户读取只对明确的入口繁忙响应接续等待:HTTP 429、`CONCURRENCY_BOOTSTRAP_BUSY`、可重试以及有效的等待状态与 `remainingMs`。第一次有效回执固定等待截止,后续回执只能缩短,最长不超过首次读取开始后的三十分钟。查询至少间隔 2 秒,尊重更长的服务端提示,再加最多 20% 抖动;例如 60 秒提示实际等待 60–72 秒,不提前压成 15 秒。若提示达到剩余等待预算,保留最后响应并停止,不能提前查询或刷新截止。不会因普通繁忙或网络错误无限延长。普通身份读取仍使用五分钟恢复预算;权限拒绝、版本变化、入口过期和满额终止恢复。单次读取、投影和网络失败的限制保持独立。
250
+
251
+ 该行为只读取平台身份,不替应用发起或重放报名,也不改变已经受理命令的原始请求键与结果截止。上线容量需在使用该 SDK 的实际应用制品上重新验证。