openxiangda 2.18.8 → 2.19.0

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 (32) hide show
  1. package/dist/browser/components/resource/GeneratedResourceCrud.d.ts +5 -0
  2. package/dist/browser/components/resource/GeneratedResourceCrud.d.ts.map +1 -1
  3. package/dist/browser/components/resource/GeneratedResourceCrud.js +27 -3
  4. package/dist/browser/components/resource/GeneratedResourceCrud.js.map +1 -1
  5. package/dist/browser/components/todo/ApplicationTodoCenterPage.d.ts.map +1 -1
  6. package/dist/browser/components/todo/ApplicationTodoCenterPage.js +10 -10
  7. package/dist/browser/components/todo/ApplicationTodoCenterPage.js.map +1 -1
  8. package/dist/browser/components/workflow/StandardWorkflowPages.d.ts.map +1 -1
  9. package/dist/browser/components/workflow/StandardWorkflowPages.js +24 -13
  10. package/dist/browser/components/workflow/StandardWorkflowPages.js.map +1 -1
  11. package/dist/browser/record-detail.css +25 -12
  12. package/dist/browser/styles.css +86 -8
  13. package/documentation/application-foundation.md +7 -1
  14. package/documentation/backend.md +28 -0
  15. package/documentation/declarations-cheatsheet.md +8 -1
  16. package/documentation/delivery.md +1 -1
  17. package/documentation/frontend.md +41 -2
  18. package/documentation/getting-started.md +7 -7
  19. package/documentation/manifest.json +8 -8
  20. package/documentation/workflow-events.md +15 -1
  21. package/package.json +28 -21
  22. package/releases/2.19.0.json +38 -0
  23. package/skills/manifest.json +1 -1
  24. package/skills/openxiangda-v2/SKILL.md +4 -4
  25. package/skills/openxiangda-v2/references/application-foundation.md +7 -1
  26. package/skills/openxiangda-v2/references/backend.md +28 -0
  27. package/skills/openxiangda-v2/references/declarations-cheatsheet.md +8 -1
  28. package/skills/openxiangda-v2/references/delivery.md +1 -1
  29. package/skills/openxiangda-v2/references/frontend.md +41 -2
  30. package/skills/openxiangda-v2/references/getting-started.md +7 -7
  31. package/skills/openxiangda-v2/references/workflow-events.md +15 -1
  32. package/releases/2.18.8.json +0 -31
@@ -109,6 +109,34 @@ try {
109
109
  ```
110
110
 
111
111
  事务守卫的 `errorCode` 必须匹配 `^OPENXIANGDA_[A-Z0-9_]{1,96}$`,例如 `OPENXIANGDA_REPAIR_REQUEST_NOT_PENDING`。
112
+
113
+ ## 在同一事务中引用前序 create 生成的 id {#transaction-references}
114
+
115
+ 一个事务内"先建主记录、再建引用它的子记录"不需要预先分配 id,也不需要两段式
116
+ 暂存。后续 create/update 的 `data` 字段值可以直接写
117
+ `{ operationIndex, field: 'id' }` 引用本事务中**之前的 create** 生成的主键,
118
+ 平台在提交前解析替换:
119
+
120
+ ```ts
121
+ await businessData.transaction({
122
+ schemaVersion: 'openxiangda.data-transaction-request/v2',
123
+ idempotencyKey: input.idempotencyKey,
124
+ operations: [
125
+ { operation: 'create', resourceCode: 'clubs', data: { name: input.name } },
126
+ { operation: 'create', resourceCode: 'club-memberships',
127
+ data: { clubId: { operationIndex: 0, field: 'id' }, userId: input.ownerId, role: 'owner' } },
128
+ { operation: 'create', resourceCode: 'club-memberships',
129
+ data: { clubId: { operationIndex: 0, field: 'id' }, userId: input.memberId, role: 'member' } },
130
+ ],
131
+ });
132
+ ```
133
+
134
+ 引用约束:引用对象只含 `operationIndex`(0..99 的整数)与 `field: 'id'` 两个键;
135
+ 只能指向索引更小的 create 操作;引用不得嵌套在数组或对象里。违反形状报
136
+ `OPENXIANGDA_NATIVE_DATA_TRANSACTION_REFERENCE_INVALID`,嵌套报
137
+ `..._NESTED`,目标不可解析报 `..._UNRESOLVED`。任一操作失败时整个事务回滚,
138
+ 不会留下无成员的 club。
139
+
112
140
  ## 业务动作与普通查询 {#business-action}
113
141
 
114
142
  `OpenXiangdaDataApiService` 按当前用户的普通资源、行和字段权限执行。具名业务动作使用 `OpenXiangdaBusinessDataApiService`:入口先检查该动作 capability,平台在精确应用和环境内以受信任后端执行,并保留发起人与动作审计。业务动作不能接受任意模型/字段/用户 ID 后不做业务校验;应用负责该动作的输入约束和业务不变量。
@@ -14,6 +14,7 @@
14
14
  | Workflow 详情接管的资源路由用模型级 `detailRouteCode` 表达(desktop/mobile 各引用一条 user surface 路由) | `defineDataModel({ code: 'x', detailRouteCode: { desktop: 'x-detail', mobile: 'x-detail-mobile' }, ... })` |
15
15
  | 迁移工具/验收脚本需要看模块投影结果时,用公共出口的 `materializeApplicationModules`,不要引用 devkit 的 dist 文件路径 | `import { defineApplicationModule, materializeApplicationModules } from 'openxiangda/config';` → `const { resources } = materializeApplicationModules([module])` |
16
16
  | system 字段(服务端赋值)可以进入查询与分组类选择(filterFields/searchableFields/sortableFields/defaultSort/sections.fields),不可进入展示与可写选择(list/form/detail.fields) | `filterFields: ['campaignId']`(system 外键筛选合法);hidden 字段任何选择都拒绝 |
17
+ | 平台审计列(created_at/updated_at/created_by/updated_by/id/revision)可直接作 `defaultSort`/`sortableFields`,无需声明;不可进入 filterFields/searchableFields/展示/可写选择 | `defaultSort: { field: 'created_at', order: 'desc' }`(按真实创建时间倒序,勿复制业务时间字段) |
17
18
 
18
19
  ## 字段声明
19
20
 
@@ -25,7 +26,7 @@
25
26
  | `audit.read` 可写 `true`(绑定本资源读能力)或能力数组 | `audit: { read: true }` |
26
27
  | `resource-ref.*` 必须带 `source` 来源协议 | `{ type: 'resource-ref.single', source: { kind: 'resource', resourceCode: 'repair-requests', labelField: 'title', searchFields: ['title'], pageSize: 20, loadMode: 'search' } }` |
27
28
  | `labelField` 必须指向目标资源的 `text.short` / `text.long` 字段 | 不要用流水号/选项字段当 label |
28
- | 列表可排序列用视图级 `sortableFields` 表达(`defaultSort.field` 隐式可排序) | `list: { sortableFields: ['capacity'], defaultSort: { field: 'name', order: 'asc' } }` |
29
+ | 列表可排序列用视图级 `sortableFields` 表达(`defaultSort.field` 隐式可排序);平台审计列(如 `created_at`)同样合法 | `list: { sortableFields: ['capacity'], defaultSort: { field: 'name', order: 'asc' } }`;`defaultSort: { field: 'created_at', order: 'desc' }` |
29
30
  | 每个字段都必须带中文/业务 `label`(含子表外键与排序字段) | `{ code: 'requestId', type: 'uuid', label: '所属申请', required: true }` |
30
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 }` |
31
32
  | 图片/附件的 `file` 限定数量与大小 | `file: { maxCount: 3, maxSizeMb: 10, accept: ['image/png', 'image/jpeg'] }` |
@@ -34,6 +35,12 @@
34
35
 
35
36
  | 规则 | 正确片段 |
36
37
  | --- | --- |
38
+ | 数据策略是**白名单**语义:规则 `roleCodes` 之外的角色若不在 `unrestrictedRoleCodes` 中会被 RLS 全拒(报错只有 FIELD_ROW_FORBIDDEN) | `unrestrictedRoleCodes: ['admin']` 必须列出所有"不受限"角色 |
39
+ | 基线角色(`authenticatedUserRoleCode`)进 `unrestrictedRoleCodes` = 策略对所有人失效(角色并集必含基线角色),编译器直接报错 | 把基线角色移出 unrestrictedRoleCodes,为其单独声明 rules |
40
+ | 匿名公开策略的 `ownRecordFields` 必须是 `fields` 的子集;`create` 必须配套 `draft`;`requiredFields` ⊆ `fields` | 先定 fields,再从中选 required/own |
41
+ | workflow definition 必须显式 `launch`(编译器强制) | `definitions: [{ version: 1, definition, launch: { mode: 'standalone' } }]` |
42
+ | option/user/department/resource-ref/cascade 字段投影进工作流事实是 { label, value } 对象,不能声明为标量;条件比较用 `<fact>.value` | `inputSchema.properties.urgency = { type: 'object', ... }` + `path: 'urgency.value'` |
43
+ | `cascade.*` 的写入/比较值形状是**数组路径** | `category: [{ label: '办公设备', value: 'office' }]` |
37
44
  | 平台保留能力(如 `app:<app>:directory:read`)**不能**在 `capabilities` 里重复声明,直接在角色中引用即可 | `const directoryRead = \`app:\${APP_CODE}:directory:read\`` → `roles: [{ code: 'admin', capabilities: [directoryRead] }]` |
38
45
  | 资源 CRUD 能力码用 `resourceCapabilityCodes(appCode, resourceCode)` 生成 | `const crud = resourceCapabilityCodes(APP_CODE, 'repair-requests')` → `capabilities: [crud.read, crud.create]` |
39
46
  | `authenticatedUserRoleCode` 是平台登录用户的基线角色 | `authz: { authenticatedUserRoleCode: 'app-user', ... }` |
@@ -102,7 +102,7 @@ MCP 的 check_app、deployment_plan、deploy_app 使用与 CLI 相同的环境
102
102
 
103
103
  ## 构建前运行配额
104
104
 
105
- `deploy --dry-run`(MCP `deployment_plan`)会只读查询目标 TEST 的运行配额,输出 `runtimeCapacity` 的核验时间、所需增量、各配额剩余量和缺口。`sufficient: false` 表示当前不足;`null` 表示无需新增或未核验,必须结合 `basis` 与 `capacity.checked` 阅读。专用命名空间未检查不能当成资源充足。
105
+ `deploy --dry-run`(MCP `deployment_plan`)会只读查询目标 TEST 的运行配额,输出 `runtimeCapacity` 的核验时间、所需增量、各配额剩余量和缺口。`sufficient: false` 表示当前不足;`null` 表示无需新增或未核验,必须结合 `basis` 与 `capacity.checked` 阅读。专用命名空间未检查不能当成资源充足。同一预检还会比对源码 `workflows.activations` 与环境 Head,输出 `workflowActivation` 诊断:版本回退(error,拒绝部署)、源码缺失已激活流程(warning,本次部署会停用)、目录不可读(error,拒绝盲部署),详见 [Workflow 事件](./workflow-events.md)。
106
106
 
107
107
  正式 deploy 在检查脚本和镜像构建前预检;平台缺少配套能力或无法核验时明确停止。配额快照不预留资源,实际执行再次检查。已有可验证密封候选会携带摘要和幂等键,平台识别 `existing-run` 时返回原运行,不把它当作新副本;观察或恢复原运行使用 status/retry。不要为绕过配额创建新包或切换目标环境。
108
108
 
@@ -90,12 +90,13 @@ import { resourceSurfaces } from '@app/contracts';
90
90
 
91
91
  const records = createNativeResourceClient('records', resourceSurfaces.records);
92
92
 
93
- // 服务端过滤、排序、分页;字段必须已声明,未声明字段直接报错
93
+ // 服务端过滤、排序、分页;where 字段必须已声明;排序字段用已声明字段或
94
+ // 平台审计列(created_at/updated_at/created_by/updated_by/id/revision)
94
95
  const page = await records.list({
95
96
  page: 1,
96
97
  pageSize: 20,
97
98
  where: { field: 'enabled', operator: 'eq', value: true },
98
- sort: { field: 'createdAt', order: 'desc' },
99
+ sort: { field: 'created_at', order: 'desc' },
99
100
  });
100
101
 
101
102
  const record = await records.get(id);
@@ -126,6 +127,44 @@ capability,不使用角色名或影子字段判断。
126
127
 
127
128
  DataQuery 使用有界 where 条件树,支持 and/or/not。标准列表的筛选、关键词、分页和导出共用已声明字段与同一查询条件,不在页面重写查询协议。
128
129
 
130
+ ## 自建待办与消息中心 UI {#self-hosted-centers}
131
+
132
+ 应用不满意默认待办中心/消息中心的呈现时,在自有 user 路由上用 `openxiangda/core`
133
+ 公开客户端自建 UI;数据和事实仍由平台唯一拥有:
134
+
135
+ ```tsx
136
+ import {
137
+ loadWorkflowWorkCenter,
138
+ loadApplicationTodos,
139
+ recordApplicationTodoInteraction,
140
+ } from 'openxiangda/core';
141
+
142
+ // 待办四视图:created / pending / handled / cc,counts 随每次查询内嵌返回
143
+ const work = await loadWorkflowWorkCenter({ view: 'pending', limit: 20, offset: 0 });
144
+ // 消息视图:all / pending / informational / completed,未读与回执由 Notification Hub 投影
145
+ const todos = await loadApplicationTodos({ view: 'all', unread: false, keyword: '', limit: 12, offset: 0 });
146
+ // read/click 回执幂等;失败不阻断目标页自身的读取与鉴权
147
+ await recordApplicationTodoInteraction(item.messageId, 'click');
148
+ ```
149
+
150
+ 边界(与默认标准页一致,`check` 与运行时都会强制):
151
+
152
+ - 不得注册、替换或重定向 `/todos`、`/m/todos`、`/work-center`、`/m/work-center`
153
+ 及任何 Workflow 路由;自建页面必须挂在应用自己声明的路由上。
154
+ - 收件箱只读当前用户:没有跨用户查询、没有批量审批;待办页不执行
155
+ Workflow approve/reject/return 命令,操作一律进入平台解析的
156
+ `detailNavigation.desktopPath/mobilePath`,`navigationUnavailable` 时禁用入口。
157
+ - 视图语义由服务端裁定(待办的 created/cc 是 Workflow 事实,不是消息搜索的
158
+ 客户端并集);合同没有的优先级、截止时间、排序与批量选择不得在浏览器伪造。
159
+ - 服务端集成使用 `openxiangda-nest` 的 `OpenXiangdaPlatformClient`:
160
+ `workflowWorkCenter` 支持 `view`(`created/handled/cc` 需要 view,
161
+ `status` 仅保留 pending/completed 兼容映射),`applicationTodos` 与回执
162
+ 访问同名可用。
163
+
164
+ 默认呈现的替换式定制仅限既有 contribution 面(用户面 frame、
165
+ `applicationTodoCenter` 渲染器);Workflow 待办中心目前没有渲染器替换钩子,
166
+ 需要完全不同的呈现时走本节的自建路由方案。
167
+
129
168
  ## 标准后台扩展
130
169
 
131
170
  ### 未保存内容的离开保护
@@ -68,10 +68,10 @@ MCP 服务随项目根包一起安装,AI 客户端的 stdio 连接仍需配置
68
68
  以下命令的版本占位符由随包资料替换为该根包的精确版本。网站源码阅读者应先确认要使用的发行版本。
69
69
 
70
70
  ```bash
71
- pnpm dlx openxiangda@2.18.8 skill install --force
72
- pnpm dlx openxiangda@2.18.8 auth status --base-url <平台地址> --json
73
- pnpm dlx openxiangda@2.18.8 login --cwd my-app --base-url https://platform.example.com
74
- pnpm dlx openxiangda@2.18.8 create my-app --base-url https://platform.example.com
71
+ pnpm dlx openxiangda@2.19.0 skill install --force
72
+ pnpm dlx openxiangda@2.19.0 auth status --base-url <平台地址> --json
73
+ pnpm dlx openxiangda@2.19.0 login --cwd my-app --base-url https://platform.example.com
74
+ pnpm dlx openxiangda@2.19.0 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
@@ -173,9 +173,9 @@ MCP 的 `docs_read` 可以读取本说明,当前没有独立的源码操作 MC
173
173
  无需本地工作区,使用本 Skill 随包精确版本或已安装的对应 CLI:
174
174
 
175
175
  ```bash
176
- pnpm dlx openxiangda@2.18.8 auth status --base-url <平台> --json
177
- pnpm dlx openxiangda@2.18.8 source resolve <仓库URL> --base-url <平台> --json
178
- pnpm dlx openxiangda@2.18.8 source clone <仓库URL> <新目录> --base-url <平台> --json
176
+ pnpm dlx openxiangda@2.19.0 auth status --base-url <平台> --json
177
+ pnpm dlx openxiangda@2.19.0 source resolve <仓库URL> --base-url <平台> --json
178
+ pnpm dlx openxiangda@2.19.0 source clone <仓库URL> <新目录> --base-url <平台> --json
179
179
  ```
180
180
 
181
181
  登录缺失或站点不匹配时,先按该平台执行 login。resolve 根据平台已经登记的绑定返回
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "schemaVersion": "openxiangda.documentation/v1",
3
- "version": "2.18.8",
3
+ "version": "2.19.0",
4
4
  "topics": [
5
5
  {
6
6
  "id": "getting-started",
7
7
  "title": "安装与开始开发",
8
8
  "file": "getting-started.md",
9
- "sha256": "276f39b5b84d041c3ccb7a9bcd023dfcb12e83f3131724aab5dd3fbaec897b3c"
9
+ "sha256": "49e80dcfa95999972fc30aa9003b593e622fbeca1c58f45ca5d86d304daf584d"
10
10
  },
11
11
  {
12
12
  "id": "product-design",
@@ -48,13 +48,13 @@
48
48
  "id": "declarations-cheatsheet",
49
49
  "title": "声明速查:一次写对 config",
50
50
  "file": "declarations-cheatsheet.md",
51
- "sha256": "5b4327eeead055b9d1f46a4122c6c2ac7052ca86e9ca2d586c8ce1b3df4d2bd2"
51
+ "sha256": "b7943a245f2a40599c90adc72cbc42280c65e22513b3df7cac6c1adaa8e6c48c"
52
52
  },
53
53
  {
54
54
  "id": "application-foundation",
55
55
  "title": "业务模型与标准 CRUD",
56
56
  "file": "application-foundation.md",
57
- "sha256": "dd28e08c6ebbcb2651a216649182c8c46b1ab62a2853a4cece9f041f5da2cd15"
57
+ "sha256": "7a315a0a5db5c2c60ccfaf2fdf9da903167821e8c5214bfae14e9674d894b68e"
58
58
  },
59
59
  {
60
60
  "id": "appspec",
@@ -72,7 +72,7 @@
72
72
  "id": "frontend",
73
73
  "title": "页面与标准组件扩展",
74
74
  "file": "frontend.md",
75
- "sha256": "30e30cde40a6c52ba6622770f0df73d717e395dca1fc916c198bca26756cb099"
75
+ "sha256": "e668ddfd81a8308e1f750e4d79d34eac316ba97e2d28ba27a72c166565ea5949"
76
76
  },
77
77
  {
78
78
  "id": "field-components",
@@ -96,13 +96,13 @@
96
96
  "id": "workflow-events",
97
97
  "title": "审批、事件与通知",
98
98
  "file": "workflow-events.md",
99
- "sha256": "9d25f32e7758888b2d051519bb3f260c1202a5908120d788ed1c997d358e1bdd"
99
+ "sha256": "9d78faf470638c33d4bf8b0f7b7540c9adb10e0661d4ec790779c304fc9a7bb6"
100
100
  },
101
101
  {
102
102
  "id": "backend",
103
103
  "title": "按需后端与业务动作",
104
104
  "file": "backend.md",
105
- "sha256": "75c8f9b83c37afe53b57d0283fa814a5153aa7d72a85efb2a1d9c4a9c1844e6a"
105
+ "sha256": "323d585d3069e0eb7f649eb2c5d0bf0f7344266ce446f539e872b4ec7bc0fbd9"
106
106
  },
107
107
  {
108
108
  "id": "administration",
@@ -120,7 +120,7 @@
120
120
  "id": "delivery",
121
121
  "title": "部署、生产晋级与恢复",
122
122
  "file": "delivery.md",
123
- "sha256": "32f07cfe6b946975bb3795e6ca3a01370e4d6bcc89f1b52b8df19085438e92c2"
123
+ "sha256": "69c94361f2c7e1038bb50be9875b34337d8138a923e1913d3f8ee3d5dfb2a57d"
124
124
  },
125
125
  {
126
126
  "id": "upgrading",
@@ -202,6 +202,15 @@ command 按固定版本完成,`cancel-on-deactivate` 在声明删除后取消
202
202
  默认 1/200,最大 200。
203
203
  需要按流程实例串行投递时只声明 `ordering: 'workflow-instance'`,不接受下划线别名。
204
204
 
205
+ 平台按 desired set 直接覆盖环境 Head,不做版本比较。因此 `openxiangda deploy`
206
+ 与 `deploy --dry-run` 会在构建前只读比对源码激活声明与环境 Head:
207
+ 源码 `definitionVersion` 低于当前已激活版本时以
208
+ `DEPLOY_WORKFLOW_ACTIVATION_VERSION_REGRESSION` 拒绝部署——把高版本定义与激活
209
+ 声明合入源码后再发,版本号与 digest 必须与已注册版本一致(同版本不同内容会被
210
+ 平台以 `WORKFLOW_V2_DEFINITION_VERSION_IMMUTABLE` 拒绝);Head 已激活而源码
211
+ 缺声明的流程给出 `DEPLOY_WORKFLOW_ACTIVATION_ABSENT` 警告(本次部署会停用它);
212
+ 目录查询不可用时以 `WORKFLOW_HEAD_PREFLIGHT_UNAVAILABLE` 拒绝盲部署。
213
+
205
214
  Notification Hub 消费事实:
206
215
 
207
216
  - `participant.activated` 创建待处理消息;
@@ -294,7 +303,12 @@ Workflow instance-scoped preview/content 路由,平台在每次文件读取时
294
303
 
295
304
  标准发起页使用独立的 `WorkflowLaunchSurface` 读取当前激活合同:桌面路径为
296
305
  `/workflows/:workflowCode/start`,移动路径为
297
- `/m/workflows/:workflowCode/start`。`standalone`/`hidden-handoff` 缺省使用同一个
306
+ `/m/workflows/:workflowCode/start`。definition 必须显式声明
307
+ `launch: { mode: 'standalone' | 'hidden-handoff' | ... }`,缺失会被编译器拒绝;
308
+ factProjection 把 option/user/department/resource-ref/cascade 字段投影为
309
+ `{ label, value }` 对象,对应 inputSchema 属性必须声明为 `type: 'object'`
310
+ (multiple 类字段为 array + object items),条件表达式用 `path: '<fact>.value'`
311
+ 比较;声明成标量会在运行时 INPUT_SCHEMA_MISMATCH 并无限重试,编译器现已拦截。`standalone`/`hidden-handoff` 缺省使用同一个
298
312
  compiler-owned `processOperationCode`、subject declaration 和标准 process commit;平台在一个
299
313
  事务中写业务数据和 durable command。action-owned 资源改为声明
300
314
  `launch.submission.kind: 'named-operation'`,显式绑定 create/existing 请求来源、响应 subject/
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openxiangda",
3
- "version": "2.18.8",
3
+ "version": "2.19.0",
4
4
  "description": "OpenXiangda 2.0 的统一命令、应用 SDK、MCP 与中文 AI 技能资料。",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -60,13 +60,13 @@
60
60
  "antd-mobile": "5.42.3",
61
61
  "dayjs": "1.11.18",
62
62
  "docx-preview": "0.3.7",
63
- "openxiangda-cli": "2.4.16",
64
- "openxiangda-contracts": "2.14.1",
65
- "openxiangda-devkit-core": "2.16.0",
63
+ "openxiangda-cli": "2.4.19",
64
+ "openxiangda-contracts": "2.15.0",
65
+ "openxiangda-devkit-core": "2.17.0",
66
66
  "openxiangda-legacy": "npm:openxiangda@1.0.269",
67
- "openxiangda-mcp": "2.0.25",
68
- "openxiangda-nest": "2.4.2",
69
- "openxiangda-skill-kit": "2.1.11",
67
+ "openxiangda-mcp": "2.0.26",
68
+ "openxiangda-nest": "2.4.4",
69
+ "openxiangda-skill-kit": "2.2.0",
70
70
  "xlsx": "https://github.com/1377385356/openxiangda/releases/download/vendor-mirror/xlsx-0.20.3.tgz"
71
71
  },
72
72
  "peerDependencies": {
@@ -132,34 +132,41 @@
132
132
  },
133
133
  "openxiangdaRelease": {
134
134
  "schemaVersion": "openxiangda.release-notes/v1",
135
- "version": "2.18.8",
135
+ "version": "2.19.0",
136
136
  "status": "reviewed",
137
- "title": "OpenXiangda 2.18.8:引擎钉漂移的恢复通道与确切指引",
138
- "summary": "update/version/changelog 在钉位漂移或依赖未安装时仍可执行(修复命令不再被自己要修复的问题拦住);PIN_MISMATCH 错误信息给出两步恢复路径;业务命令保持严格 fail-closed。",
139
- "newFeatures": [],
137
+ "title": "OpenXiangda 2.19.0:平台探针实测修复——编译期拦截三大易错声明与错误透明化",
138
+ "summary": "来自平台能力探针(platform-capability-probe)全流程实测的修复批:工作流 launch 缺失、快照字段标量投影、数据策略基线角色 unrestricted 三类错误从\"部署后白屏/无限重试/策略静默失效\"提前到编译期拦截;匿名公开策略校验拆分为带指针的独立诊断;发起页防白屏并透出流程命令 lastError;CLI create 支持会话向上继承;同步平台审计列排序与部署 Workflow Head 预检。",
139
+ "newFeatures": [
140
+ "编译器新增三项编译期拦截:workflow definition 必须显式声明 launch;unrestrictedRoleCodes 含基线角色(authenticatedUserRoleCode)直接报错(角色并集必命中,策略会静默失效);option/user/department/resource-ref/cascade 快照字段投影到标量 inputSchema 属性直接报错并给出对象形状与 `<fact>.value` 比较片段。",
141
+ "匿名公开策略校验拆分为带独立错误码与指针的分组诊断(route 绑定/operations/fields/requiredFields/ownRecordFields 子集/draft 规则/public 投影等),不再聚合为一条无指针报错。",
142
+ "工作流发起页:definition.launch 渲染期访问改为可选链,缺失时显示可诊断的 404 而不是白屏;提交后轮询透出 process command 的 lastError(不再无提示转圈)。",
143
+ "平台审计列排序(contracts DATA_SYSTEM_SORT_FIELD_CODES):列表 defaultSort/sortableFields 支持 created_at/updated_at/created_by/updated_by/id/revision,标准 Admin 列表内置创建/更新时间列可点击排序。",
144
+ "deploy 构建前只读比对 workflows.activations 与环境 Head:版本回退拒绝部署(DEPLOY_WORKFLOW_ACTIVATION_VERSION_REGRESSION),源码缺失已激活流程告警,防止盲部署停用流程。"
145
+ ],
140
146
  "fixes": [
141
- "统一入口对 update、version、changelog 启用宽松引擎解析:钉位漂移时可用漂移前的安装引擎执行诊断与修复;依赖未安装时回退启动器引擎,update install --target workspace 仍能完成安装并统一全部钉位。",
142
- "WORKSPACE_ENGINE_PIN_MISMATCH WORKSPACE_ENGINE_NOT_INSTALLED 的错误信息升级为可行动恢复指引(先 pnpm install,钉位不一致时 openxiangda update install --target workspace)。",
143
- "随包文档(安装与开始开发)补充升级后漂移的恢复路径与命令豁免范围说明。"
147
+ "openxiangda-cli create 在目标目录无登录态时按工作区发现规则向上继承会话(.git 边界停住),不再要求在不存在的目标目录里先登录。",
148
+ "openxiangda-skill-kit 打包技能/文档同步:声明速查表补数据策略白名单语义与基线角色陷阱、匿名公开字段子集约束、workflow launch 必填、快照对象事实、cascade 数组路径形状;workflow-events 补发起页与事实投影说明。"
144
149
  ],
145
150
  "affectedUsers": [
146
- "升级工具链或手改依赖后遇到引擎版本一致性校验失败的应用开发者与 AI 会话。"
151
+ "所有 OpenXiangda 2.0 应用开发者与 AI 开发会话;使用数据策略、工作流、匿名公开访问的应用需要关注新的编译期校验。"
147
152
  ],
148
153
  "upgradeSteps": [
149
- "应用精确依赖升级到 openxiangda 2.18.8 后重新运行 check 与部署。"
154
+ "应用把 openxiangda 精确钉扎到 2.19.0 并重跑 pnpm openxiangda check;此前能通过 check 的声明无需改动,此前靠运行时报错暴露的写法会在编译期给出带修复片段的明确报错。",
155
+ "工作流 definition 若未声明 launch,会在编译期被拒绝:按报错提示补 `launch: { mode: 'standalone' }` 等声明后重新部署。"
150
156
  ],
151
157
  "knownLimitations": [
152
- "check/deploy/dev 等业务命令仍严格要求钉位一致(fail-closed 不变);自动安装未实现,恢复仍需运行一条命令。"
158
+ "快照字段投影仅支持对象形状事实,标量投影不支持是契约决定而非缺陷;条件表达式需使用 `<fact>.value` 路径。",
159
+ "平台侧配套修复(auth 落地路由兼容、不变量 NULL 语义、匿名错误透传、验收票据时效、token TTL)在平台服务端发布列车中交付,本工具链列车不含。"
153
160
  ],
154
161
  "issues": [],
155
162
  "compatibility": {
156
163
  "node": ">=24",
157
164
  "workspaceGenerations": "v2",
158
- "platform": "无平台配合要求。",
159
- "v1": "V1 工作区同样受益于恢复命令豁免。"
165
+ "platform": "平台服务端需随下一平台列车更新到匹配的 openxiangda-contracts;未更新前 check 的目标平台预检会报校验器版本不一致(fail-closed,属预期)。",
166
+ "v1": "V1 工作区不受影响。"
160
167
  },
161
- "sha256": "6d756cf2e7f197c8c7654541a8b047309ee2e02e3060850ceefcf5f65186a9cb",
162
- "url": "https://github.com/1377385356/openxiangda/releases/tag/v2.18.8"
168
+ "sha256": "89940c302299258200c67215c2ddadbcee505642cc586eda90434541b3f81468",
169
+ "url": "https://github.com/1377385356/openxiangda/releases/tag/v2.19.0"
163
170
  },
164
171
  "scripts": {
165
172
  "build": "node ../../scripts/prune-package-dist.mjs && tsc -p tsconfig.json && node scripts/copy-assets.mjs",
@@ -0,0 +1,38 @@
1
+ {
2
+ "schemaVersion": "openxiangda.release-notes/v1",
3
+ "version": "2.19.0",
4
+ "status": "reviewed",
5
+ "title": "OpenXiangda 2.19.0:平台探针实测修复——编译期拦截三大易错声明与错误透明化",
6
+ "summary": "来自平台能力探针(platform-capability-probe)全流程实测的修复批:工作流 launch 缺失、快照字段标量投影、数据策略基线角色 unrestricted 三类错误从\"部署后白屏/无限重试/策略静默失效\"提前到编译期拦截;匿名公开策略校验拆分为带指针的独立诊断;发起页防白屏并透出流程命令 lastError;CLI create 支持会话向上继承;同步平台审计列排序与部署 Workflow Head 预检。",
7
+ "newFeatures": [
8
+ "编译器新增三项编译期拦截:workflow definition 必须显式声明 launch;unrestrictedRoleCodes 含基线角色(authenticatedUserRoleCode)直接报错(角色并集必命中,策略会静默失效);option/user/department/resource-ref/cascade 快照字段投影到标量 inputSchema 属性直接报错并给出对象形状与 `<fact>.value` 比较片段。",
9
+ "匿名公开策略校验拆分为带独立错误码与指针的分组诊断(route 绑定/operations/fields/requiredFields/ownRecordFields 子集/draft 规则/public 投影等),不再聚合为一条无指针报错。",
10
+ "工作流发起页:definition.launch 渲染期访问改为可选链,缺失时显示可诊断的 404 而不是白屏;提交后轮询透出 process command 的 lastError(不再无提示转圈)。",
11
+ "平台审计列排序(contracts DATA_SYSTEM_SORT_FIELD_CODES):列表 defaultSort/sortableFields 支持 created_at/updated_at/created_by/updated_by/id/revision,标准 Admin 列表内置创建/更新时间列可点击排序。",
12
+ "deploy 构建前只读比对 workflows.activations 与环境 Head:版本回退拒绝部署(DEPLOY_WORKFLOW_ACTIVATION_VERSION_REGRESSION),源码缺失已激活流程告警,防止盲部署停用流程。"
13
+ ],
14
+ "fixes": [
15
+ "openxiangda-cli create 在目标目录无登录态时按工作区发现规则向上继承会话(.git 边界停住),不再要求在不存在的目标目录里先登录。",
16
+ "openxiangda-skill-kit 打包技能/文档同步:声明速查表补数据策略白名单语义与基线角色陷阱、匿名公开字段子集约束、workflow launch 必填、快照对象事实、cascade 数组路径形状;workflow-events 补发起页与事实投影说明。"
17
+ ],
18
+ "affectedUsers": [
19
+ "所有 OpenXiangda 2.0 应用开发者与 AI 开发会话;使用数据策略、工作流、匿名公开访问的应用需要关注新的编译期校验。"
20
+ ],
21
+ "upgradeSteps": [
22
+ "应用把 openxiangda 精确钉扎到 2.19.0 并重跑 pnpm openxiangda check;此前能通过 check 的声明无需改动,此前靠运行时报错暴露的写法会在编译期给出带修复片段的明确报错。",
23
+ "工作流 definition 若未声明 launch,会在编译期被拒绝:按报错提示补 `launch: { mode: 'standalone' }` 等声明后重新部署。"
24
+ ],
25
+ "knownLimitations": [
26
+ "快照字段投影仅支持对象形状事实,标量投影不支持是契约决定而非缺陷;条件表达式需使用 `<fact>.value` 路径。",
27
+ "平台侧配套修复(auth 落地路由兼容、不变量 NULL 语义、匿名错误透传、验收票据时效、token TTL)在平台服务端发布列车中交付,本工具链列车不含。"
28
+ ],
29
+ "issues": [],
30
+ "compatibility": {
31
+ "node": ">=24",
32
+ "workspaceGenerations": "v2",
33
+ "platform": "平台服务端需随下一平台列车更新到匹配的 openxiangda-contracts;未更新前 check 的目标平台预检会报校验器版本不一致(fail-closed,属预期)。",
34
+ "v1": "V1 工作区不受影响。"
35
+ },
36
+ "sha256": "89940c302299258200c67215c2ddadbcee505642cc586eda90434541b3f81468",
37
+ "url": "https://github.com/1377385356/openxiangda/releases/tag/v2.19.0"
38
+ }
@@ -4,7 +4,7 @@
4
4
  {
5
5
  "name": "openxiangda-v2",
6
6
  "description": "使用 OpenXiangda 2.0 从模糊业务想法、已有资料或具体变更出发,通过对话发现模块、完成详细产品设计,由 AI 在工作区内调用 OpenDesign 原版 CLI/Skill/MCP 形成整体视觉与可运行原型,再开发、检查和交付应用。OpenDesign 客户端只作为可选预览器;维护 1.x 应用时使用对应的 1.x 技能。",
7
- "sha256": "b156d84ea0a5bc8c1709bf7ea831709c7396461781ac0439fbf0505eb4a0f4f5"
7
+ "sha256": "80a0a3ab4c92c6f5ee7495bea706f6d976015776a7790a447d43e379ae10e43f"
8
8
  }
9
9
  ]
10
10
  }
@@ -40,10 +40,10 @@ AI 接到新应用、页面或改版任务时,在同一个 OpenXiangda 工作
40
40
  未创建工作区时使用本 Skill 随根包发布的精确版本:
41
41
 
42
42
  ```bash
43
- pnpm dlx openxiangda@2.18.8 auth status --cwd <应用目录> --base-url <平台地址> --json
44
- pnpm dlx openxiangda@2.18.8 login --cwd <应用目录> --base-url <平台地址>
45
- pnpm dlx openxiangda@2.18.8 create <应用目录> --base-url <同一平台地址>
46
- pnpm dlx openxiangda@2.18.8 skill install --force
43
+ pnpm dlx openxiangda@2.19.0 auth status --cwd <应用目录> --base-url <平台地址> --json
44
+ pnpm dlx openxiangda@2.19.0 login --cwd <应用目录> --base-url <平台地址>
45
+ pnpm dlx openxiangda@2.19.0 create <应用目录> --base-url <同一平台地址>
46
+ pnpm dlx openxiangda@2.19.0 skill install --force
47
47
  ```
48
48
 
49
49
  创建前把产品要求的目标平台明确带入命令,不从旧登录态推断站点。已有工作区从原绑定恢复,平台不一致时先解决登录与目标,不改 link 文件跨站创建。
@@ -194,7 +194,13 @@ crud: [{
194
194
  }]
195
195
  ```
196
196
 
197
- 引用未声明字段按编译错误处理;低层 `data.resources[].fields[].sortable` 语义不变。
197
+ 排序字段可以是已声明字段,也可以是平台审计列(`created_at` / `updated_at` /
198
+ `created_by` / `updated_by` / `id` / `revision`)——它们由平台维护、所有记录必有值,
199
+ 不需要也无法在模型 `fields` 中声明。"按真实创建时间倒序"直接写
200
+ `defaultSort: { field: 'created_at', order: 'desc' }`,标准 Admin 列表的内置
201
+ "创建时间/更新时间"列同样可点击排序;不要为排序复制一份业务时间字段。
202
+ 引用其他未声明字段仍按编译错误处理;低层 `data.resources[].fields[].sortable`
203
+ 语义不变。`filterFields` / `searchableFields` 仍只接受已声明字段。
198
204
 
199
205
  ## 资源详情路由声明 {#detail-route-code}
200
206
 
@@ -109,6 +109,34 @@ try {
109
109
  ```
110
110
 
111
111
  事务守卫的 `errorCode` 必须匹配 `^OPENXIANGDA_[A-Z0-9_]{1,96}$`,例如 `OPENXIANGDA_REPAIR_REQUEST_NOT_PENDING`。
112
+
113
+ ## 在同一事务中引用前序 create 生成的 id {#transaction-references}
114
+
115
+ 一个事务内"先建主记录、再建引用它的子记录"不需要预先分配 id,也不需要两段式
116
+ 暂存。后续 create/update 的 `data` 字段值可以直接写
117
+ `{ operationIndex, field: 'id' }` 引用本事务中**之前的 create** 生成的主键,
118
+ 平台在提交前解析替换:
119
+
120
+ ```ts
121
+ await businessData.transaction({
122
+ schemaVersion: 'openxiangda.data-transaction-request/v2',
123
+ idempotencyKey: input.idempotencyKey,
124
+ operations: [
125
+ { operation: 'create', resourceCode: 'clubs', data: { name: input.name } },
126
+ { operation: 'create', resourceCode: 'club-memberships',
127
+ data: { clubId: { operationIndex: 0, field: 'id' }, userId: input.ownerId, role: 'owner' } },
128
+ { operation: 'create', resourceCode: 'club-memberships',
129
+ data: { clubId: { operationIndex: 0, field: 'id' }, userId: input.memberId, role: 'member' } },
130
+ ],
131
+ });
132
+ ```
133
+
134
+ 引用约束:引用对象只含 `operationIndex`(0..99 的整数)与 `field: 'id'` 两个键;
135
+ 只能指向索引更小的 create 操作;引用不得嵌套在数组或对象里。违反形状报
136
+ `OPENXIANGDA_NATIVE_DATA_TRANSACTION_REFERENCE_INVALID`,嵌套报
137
+ `..._NESTED`,目标不可解析报 `..._UNRESOLVED`。任一操作失败时整个事务回滚,
138
+ 不会留下无成员的 club。
139
+
112
140
  ## 业务动作与普通查询 {#business-action}
113
141
 
114
142
  `OpenXiangdaDataApiService` 按当前用户的普通资源、行和字段权限执行。具名业务动作使用 `OpenXiangdaBusinessDataApiService`:入口先检查该动作 capability,平台在精确应用和环境内以受信任后端执行,并保留发起人与动作审计。业务动作不能接受任意模型/字段/用户 ID 后不做业务校验;应用负责该动作的输入约束和业务不变量。
@@ -14,6 +14,7 @@
14
14
  | Workflow 详情接管的资源路由用模型级 `detailRouteCode` 表达(desktop/mobile 各引用一条 user surface 路由) | `defineDataModel({ code: 'x', detailRouteCode: { desktop: 'x-detail', mobile: 'x-detail-mobile' }, ... })` |
15
15
  | 迁移工具/验收脚本需要看模块投影结果时,用公共出口的 `materializeApplicationModules`,不要引用 devkit 的 dist 文件路径 | `import { defineApplicationModule, materializeApplicationModules } from 'openxiangda/config';` → `const { resources } = materializeApplicationModules([module])` |
16
16
  | system 字段(服务端赋值)可以进入查询与分组类选择(filterFields/searchableFields/sortableFields/defaultSort/sections.fields),不可进入展示与可写选择(list/form/detail.fields) | `filterFields: ['campaignId']`(system 外键筛选合法);hidden 字段任何选择都拒绝 |
17
+ | 平台审计列(created_at/updated_at/created_by/updated_by/id/revision)可直接作 `defaultSort`/`sortableFields`,无需声明;不可进入 filterFields/searchableFields/展示/可写选择 | `defaultSort: { field: 'created_at', order: 'desc' }`(按真实创建时间倒序,勿复制业务时间字段) |
17
18
 
18
19
  ## 字段声明
19
20
 
@@ -25,7 +26,7 @@
25
26
  | `audit.read` 可写 `true`(绑定本资源读能力)或能力数组 | `audit: { read: true }` |
26
27
  | `resource-ref.*` 必须带 `source` 来源协议 | `{ type: 'resource-ref.single', source: { kind: 'resource', resourceCode: 'repair-requests', labelField: 'title', searchFields: ['title'], pageSize: 20, loadMode: 'search' } }` |
27
28
  | `labelField` 必须指向目标资源的 `text.short` / `text.long` 字段 | 不要用流水号/选项字段当 label |
28
- | 列表可排序列用视图级 `sortableFields` 表达(`defaultSort.field` 隐式可排序) | `list: { sortableFields: ['capacity'], defaultSort: { field: 'name', order: 'asc' } }` |
29
+ | 列表可排序列用视图级 `sortableFields` 表达(`defaultSort.field` 隐式可排序);平台审计列(如 `created_at`)同样合法 | `list: { sortableFields: ['capacity'], defaultSort: { field: 'name', order: 'asc' } }`;`defaultSort: { field: 'created_at', order: 'desc' }` |
29
30
  | 每个字段都必须带中文/业务 `label`(含子表外键与排序字段) | `{ code: 'requestId', type: 'uuid', label: '所属申请', required: true }` |
30
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 }` |
31
32
  | 图片/附件的 `file` 限定数量与大小 | `file: { maxCount: 3, maxSizeMb: 10, accept: ['image/png', 'image/jpeg'] }` |
@@ -34,6 +35,12 @@
34
35
 
35
36
  | 规则 | 正确片段 |
36
37
  | --- | --- |
38
+ | 数据策略是**白名单**语义:规则 `roleCodes` 之外的角色若不在 `unrestrictedRoleCodes` 中会被 RLS 全拒(报错只有 FIELD_ROW_FORBIDDEN) | `unrestrictedRoleCodes: ['admin']` 必须列出所有"不受限"角色 |
39
+ | 基线角色(`authenticatedUserRoleCode`)进 `unrestrictedRoleCodes` = 策略对所有人失效(角色并集必含基线角色),编译器直接报错 | 把基线角色移出 unrestrictedRoleCodes,为其单独声明 rules |
40
+ | 匿名公开策略的 `ownRecordFields` 必须是 `fields` 的子集;`create` 必须配套 `draft`;`requiredFields` ⊆ `fields` | 先定 fields,再从中选 required/own |
41
+ | workflow definition 必须显式 `launch`(编译器强制) | `definitions: [{ version: 1, definition, launch: { mode: 'standalone' } }]` |
42
+ | option/user/department/resource-ref/cascade 字段投影进工作流事实是 { label, value } 对象,不能声明为标量;条件比较用 `<fact>.value` | `inputSchema.properties.urgency = { type: 'object', ... }` + `path: 'urgency.value'` |
43
+ | `cascade.*` 的写入/比较值形状是**数组路径** | `category: [{ label: '办公设备', value: 'office' }]` |
37
44
  | 平台保留能力(如 `app:<app>:directory:read`)**不能**在 `capabilities` 里重复声明,直接在角色中引用即可 | `const directoryRead = \`app:\${APP_CODE}:directory:read\`` → `roles: [{ code: 'admin', capabilities: [directoryRead] }]` |
38
45
  | 资源 CRUD 能力码用 `resourceCapabilityCodes(appCode, resourceCode)` 生成 | `const crud = resourceCapabilityCodes(APP_CODE, 'repair-requests')` → `capabilities: [crud.read, crud.create]` |
39
46
  | `authenticatedUserRoleCode` 是平台登录用户的基线角色 | `authz: { authenticatedUserRoleCode: 'app-user', ... }` |
@@ -102,7 +102,7 @@ MCP 的 check_app、deployment_plan、deploy_app 使用与 CLI 相同的环境
102
102
 
103
103
  ## 构建前运行配额
104
104
 
105
- `deploy --dry-run`(MCP `deployment_plan`)会只读查询目标 TEST 的运行配额,输出 `runtimeCapacity` 的核验时间、所需增量、各配额剩余量和缺口。`sufficient: false` 表示当前不足;`null` 表示无需新增或未核验,必须结合 `basis` 与 `capacity.checked` 阅读。专用命名空间未检查不能当成资源充足。
105
+ `deploy --dry-run`(MCP `deployment_plan`)会只读查询目标 TEST 的运行配额,输出 `runtimeCapacity` 的核验时间、所需增量、各配额剩余量和缺口。`sufficient: false` 表示当前不足;`null` 表示无需新增或未核验,必须结合 `basis` 与 `capacity.checked` 阅读。专用命名空间未检查不能当成资源充足。同一预检还会比对源码 `workflows.activations` 与环境 Head,输出 `workflowActivation` 诊断:版本回退(error,拒绝部署)、源码缺失已激活流程(warning,本次部署会停用)、目录不可读(error,拒绝盲部署),详见 [Workflow 事件](workflow-events.md)。
106
106
 
107
107
  正式 deploy 在检查脚本和镜像构建前预检;平台缺少配套能力或无法核验时明确停止。配额快照不预留资源,实际执行再次检查。已有可验证密封候选会携带摘要和幂等键,平台识别 `existing-run` 时返回原运行,不把它当作新副本;观察或恢复原运行使用 status/retry。不要为绕过配额创建新包或切换目标环境。
108
108
 
@@ -90,12 +90,13 @@ import { resourceSurfaces } from '@app/contracts';
90
90
 
91
91
  const records = createNativeResourceClient('records', resourceSurfaces.records);
92
92
 
93
- // 服务端过滤、排序、分页;字段必须已声明,未声明字段直接报错
93
+ // 服务端过滤、排序、分页;where 字段必须已声明;排序字段用已声明字段或
94
+ // 平台审计列(created_at/updated_at/created_by/updated_by/id/revision)
94
95
  const page = await records.list({
95
96
  page: 1,
96
97
  pageSize: 20,
97
98
  where: { field: 'enabled', operator: 'eq', value: true },
98
- sort: { field: 'createdAt', order: 'desc' },
99
+ sort: { field: 'created_at', order: 'desc' },
99
100
  });
100
101
 
101
102
  const record = await records.get(id);
@@ -126,6 +127,44 @@ capability,不使用角色名或影子字段判断。
126
127
 
127
128
  DataQuery 使用有界 where 条件树,支持 and/or/not。标准列表的筛选、关键词、分页和导出共用已声明字段与同一查询条件,不在页面重写查询协议。
128
129
 
130
+ ## 自建待办与消息中心 UI {#self-hosted-centers}
131
+
132
+ 应用不满意默认待办中心/消息中心的呈现时,在自有 user 路由上用 `openxiangda/core`
133
+ 公开客户端自建 UI;数据和事实仍由平台唯一拥有:
134
+
135
+ ```tsx
136
+ import {
137
+ loadWorkflowWorkCenter,
138
+ loadApplicationTodos,
139
+ recordApplicationTodoInteraction,
140
+ } from 'openxiangda/core';
141
+
142
+ // 待办四视图:created / pending / handled / cc,counts 随每次查询内嵌返回
143
+ const work = await loadWorkflowWorkCenter({ view: 'pending', limit: 20, offset: 0 });
144
+ // 消息视图:all / pending / informational / completed,未读与回执由 Notification Hub 投影
145
+ const todos = await loadApplicationTodos({ view: 'all', unread: false, keyword: '', limit: 12, offset: 0 });
146
+ // read/click 回执幂等;失败不阻断目标页自身的读取与鉴权
147
+ await recordApplicationTodoInteraction(item.messageId, 'click');
148
+ ```
149
+
150
+ 边界(与默认标准页一致,`check` 与运行时都会强制):
151
+
152
+ - 不得注册、替换或重定向 `/todos`、`/m/todos`、`/work-center`、`/m/work-center`
153
+ 及任何 Workflow 路由;自建页面必须挂在应用自己声明的路由上。
154
+ - 收件箱只读当前用户:没有跨用户查询、没有批量审批;待办页不执行
155
+ Workflow approve/reject/return 命令,操作一律进入平台解析的
156
+ `detailNavigation.desktopPath/mobilePath`,`navigationUnavailable` 时禁用入口。
157
+ - 视图语义由服务端裁定(待办的 created/cc 是 Workflow 事实,不是消息搜索的
158
+ 客户端并集);合同没有的优先级、截止时间、排序与批量选择不得在浏览器伪造。
159
+ - 服务端集成使用 `openxiangda-nest` 的 `OpenXiangdaPlatformClient`:
160
+ `workflowWorkCenter` 支持 `view`(`created/handled/cc` 需要 view,
161
+ `status` 仅保留 pending/completed 兼容映射),`applicationTodos` 与回执
162
+ 访问同名可用。
163
+
164
+ 默认呈现的替换式定制仅限既有 contribution 面(用户面 frame、
165
+ `applicationTodoCenter` 渲染器);Workflow 待办中心目前没有渲染器替换钩子,
166
+ 需要完全不同的呈现时走本节的自建路由方案。
167
+
129
168
  ## 标准后台扩展
130
169
 
131
170
  ### 未保存内容的离开保护
@@ -68,10 +68,10 @@ MCP 服务随项目根包一起安装,AI 客户端的 stdio 连接仍需配置
68
68
  以下命令的版本占位符由随包资料替换为该根包的精确版本。网站源码阅读者应先确认要使用的发行版本。
69
69
 
70
70
  ```bash
71
- pnpm dlx openxiangda@2.18.8 skill install --force
72
- pnpm dlx openxiangda@2.18.8 auth status --base-url <平台地址> --json
73
- pnpm dlx openxiangda@2.18.8 login --cwd my-app --base-url https://platform.example.com
74
- pnpm dlx openxiangda@2.18.8 create my-app --base-url https://platform.example.com
71
+ pnpm dlx openxiangda@2.19.0 skill install --force
72
+ pnpm dlx openxiangda@2.19.0 auth status --base-url <平台地址> --json
73
+ pnpm dlx openxiangda@2.19.0 login --cwd my-app --base-url https://platform.example.com
74
+ pnpm dlx openxiangda@2.19.0 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
@@ -173,9 +173,9 @@ MCP 的 `docs_read` 可以读取本说明,当前没有独立的源码操作 MC
173
173
  无需本地工作区,使用本 Skill 随包精确版本或已安装的对应 CLI:
174
174
 
175
175
  ```bash
176
- pnpm dlx openxiangda@2.18.8 auth status --base-url <平台> --json
177
- pnpm dlx openxiangda@2.18.8 source resolve <仓库URL> --base-url <平台> --json
178
- pnpm dlx openxiangda@2.18.8 source clone <仓库URL> <新目录> --base-url <平台> --json
176
+ pnpm dlx openxiangda@2.19.0 auth status --base-url <平台> --json
177
+ pnpm dlx openxiangda@2.19.0 source resolve <仓库URL> --base-url <平台> --json
178
+ pnpm dlx openxiangda@2.19.0 source clone <仓库URL> <新目录> --base-url <平台> --json
179
179
  ```
180
180
 
181
181
  登录缺失或站点不匹配时,先按该平台执行 login。resolve 根据平台已经登记的绑定返回