openxiangda-skill-kit 2.0.0-alpha.19 → 2.0.0-alpha.22
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/docs/architecture/admin-shell-v2.md +479 -71
- package/docs/architecture/authorization-consistency-v2.md +419 -0
- package/docs/architecture/environment-configuration-kernel-v2.md +288 -0
- package/docs/architecture/implementation-roadmap.md +77 -0
- package/docs/architecture/local-development-v2.md +134 -0
- package/docs/architecture/native-configuration-projection-v2.md +488 -0
- package/docs/architecture/native-kernel-inventory-v2.md +196 -0
- package/docs/architecture/repository-and-release.md +1 -0
- package/docs/architecture/tenant-public-origin-implementation-blueprint.md +484 -0
- package/docs/architecture/tenant-public-origin-v2.md +236 -0
- package/docs/architecture/verification-orchestration-v2.md +24 -0
- package/docs/backend.md +16 -7
- package/docs/data-authz.md +27 -2
- package/docs/delivery.md +2 -2
- package/docs/design/admin-shell-dashboard-v2.png +0 -0
- package/docs/design/admin-standard-pages-v2.png +0 -0
- package/docs/frontend.md +32 -11
- package/docs/getting-started.md +20 -14
- package/docs/index.md +2 -0
- package/docs/llms.txt +7 -0
- package/docs/reference/cli.md +17 -2
- package/docs/reference/mcp.md +1 -0
- package/docs/school-contact-relations.md +117 -0
- package/docs/workflow-events.md +23 -1
- package/package.json +2 -2
- package/skills/manifest.json +6 -6
- package/skills/openxiangda-v2/SKILL.md +13 -0
- package/skills/openxiangda-v2-backend/SKILL.md +7 -1
- package/skills/openxiangda-v2-data-authz/SKILL.md +7 -1
- package/skills/openxiangda-v2-frontend/SKILL.md +39 -3
- package/skills/openxiangda-v2-workflow-events/SKILL.md +22 -5
package/docs/getting-started.md
CHANGED
|
@@ -22,7 +22,7 @@ openxiangda app create ../my-local-validation \
|
|
|
22
22
|
--install
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
带 `--install` 时,创建器先写依赖映射并安装,再执行确定性契约生成;新应用第一次执行 `generate --check` 就应通过。省略 `--install` 时结果会标记 `generationDeferred: true`,需要先运行 `pnpm install`,再运行 `openxiangda generate`。`--local-sdk`
|
|
25
|
+
带 `--install` 时,创建器先写依赖映射并安装,再执行确定性契约生成;新应用第一次执行 `generate --check` 就应通过。省略 `--install` 时结果会标记 `generationDeferred: true`,需要先运行 `pnpm install`,再运行 `openxiangda generate`。`--local-sdk` 会先把本地 2.0 SDK 构建为 `.openxiangda/local-sdk-artifacts/` 下的 npm tarball,再写入机器相关的 pnpm `file:` overrides;它只用于可丢弃的本地验收应用。tarball 与正式发包采用同一依赖归一化规则,避免源码符号链接把第二份 React/NestJS 运行时带入应用进程。
|
|
26
26
|
|
|
27
27
|
应用始终调用工作区本地 `openxiangda-cli`;本地依赖未安装时直接失败,不存在 1.x 回退。`skill install` 会同时安装领域 Skills 与其引用的 2.0 参考文档。
|
|
28
28
|
|
|
@@ -40,14 +40,20 @@ openxiangda.config.ts 应用级平台声明
|
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
42
|
openxiangda dev
|
|
43
|
+
openxiangda dev status
|
|
43
44
|
openxiangda generate
|
|
44
45
|
openxiangda check
|
|
45
46
|
openxiangda test
|
|
46
|
-
pnpm dev
|
|
47
47
|
pnpm test:e2e
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
需要使用钉钉家校监护关系的应用,应先阅读[家校通讯录关系](./school-contact-relations.md)。2.0 尚未正式投产,当前生产应用继续使用 1.0 SDK;2.0 应用必须通过 NestJS App API 和当前 RoleSession 读取,不能复制 1.0 页面 SDK 代码。
|
|
51
|
+
|
|
52
|
+
`openxiangda dev` 是唯一受监督的日常入口:它启动完整 Admin、相互隔离的 React/Vite 与 NestJS 进程、独立 loopback 本地平台,以及工作区隔离的 PostgreSQL。开发者**不需要安装 PostgreSQL**,只需要 Docker Desktop 或兼容容器运行时;CLI 自动下载摘要固定的镜像、创建数据库、选择端口并限制容器资源。关闭前台命令或执行 `openxiangda dev stop` 时只停止进程和容器并保留项目专属 volume,因此数据在重启后仍存在。`openxiangda dev status` 查看当前/上次会话;只有显式执行 `openxiangda dev reset --data` 才会在校验工作区、容器、数据卷和凭据归属后删除本地数据库与凭据。`openxiangda dev --reset` 是“安全重置后立即启动”的快捷形式。工作区内部 `pnpm dev` 只供 CLI 编排,不负责平台进程、数据库、会话锁和清理,不作为公开开发命令。local 不是远程环境,不要求 provision 或远程 OAuth/Secret。`generate` 根据配置生成 Data、AuthZ、Event 与 Workflow 类型。`check` 必须是确定性的:同一提交、同一依赖锁、同一配置产生同一结果。完整本地模型见 [本地开发内核](./architecture/local-development-v2.md)。
|
|
53
|
+
|
|
54
|
+
默认 `pnpm test:e2e` 会自行启动隔离的 UI-only 快速回归。需要把同一套 Chromium 场景作为完整本地集成证据时,先保持 `openxiangda dev --no-open` 运行,再执行 `OPENXIANGDA_E2E_BASE_URL=http://127.0.0.1:<web-port> pnpm test:e2e`。此时 Playwright 不创建第二个服务器,而是验证浏览器、独立本地平台、NestJS 与项目专属 PostgreSQL 的同一受监督会话;`<web-port>` 以 `openxiangda dev status` 为准。外部会话模式不会隐式重置开发数据,针对确定性种子数据的整套回归只能指向一次性验收应用,或由开发者先明确停止并执行 `openxiangda dev --reset`;不得在测试配置中绕过 CLI 所有权校验直接清理容器或 volume。
|
|
55
|
+
|
|
56
|
+
完整模式下,浏览器对 App API 的请求先进入本地平台网关:网关验证当前稳定 RoleSession,丢弃浏览器自带的 Authorization,再用仅限 loopback 的短期平台身份转发给 NestJS。CLI 另外创建一个 workspace runtime OAuth client,只把原始 Secret 注入 `dev:server`,供 Worker/Scheduler/后台业务调用 Data API;Vite 进程拿不到该 Secret。数据库连接、OAuth 凭据和其他本地状态位于 Git 忽略的 `.openxiangda/local/state/`,权限为仅当前用户可读写,并且不会进入 AppPackage。
|
|
51
57
|
|
|
52
58
|
开发 2.0 工具链本身时,每一轮可用一个命令完成发布前同等级的本地验收:
|
|
53
59
|
|
|
@@ -55,7 +61,7 @@ pnpm test:e2e
|
|
|
55
61
|
pnpm verify:local
|
|
56
62
|
```
|
|
57
63
|
|
|
58
|
-
它会用本地 tarball
|
|
64
|
+
它会用本地 tarball 创建并销毁一个独立新应用,覆盖脚手架、安装、生成、单测、生产构建、Skill 和文档;Chromium 只运行一次,并在该临时应用经过显式安全重置后的完整受监督会话中同时验证 React、独立本地平台、NestJS 与真实 PostgreSQL。相同生命周期还验证工作区隔离、资源限制、重启持久化、事务幂等回放和显式重置。它不会执行 npm 发布、Git 提交或平台部署。
|
|
59
65
|
|
|
60
66
|
准备发包时,先从干净且已同步远端的 `master` 物化已经评审的 Changesets,
|
|
61
67
|
检查生成的包版本、内部依赖与模板 BOM,提交并推送该版本提交,然后查看机器生成的影响计划:
|
|
@@ -67,7 +73,7 @@ pnpm release:plan
|
|
|
67
73
|
pnpm release:publish
|
|
68
74
|
```
|
|
69
75
|
|
|
70
|
-
`release:version` 不提交、不发包,只把 Changesets 确定的候选版本写入 Git 工作树;未完成这一步时,后续所有发布命令会在构建前失败。`release:plan` 会完成 npm 不可变性检查并比较候选包与上一发布版本的真实 tarball。`release:publish` 冻结一批带摘要的候选 tarball
|
|
76
|
+
`release:version` 不提交、不发包,只把 Changesets 确定的候选版本写入 Git 工作树;未完成这一步时,后续所有发布命令会在构建前失败。`release:plan` 会完成 npm 不可变性检查并比较候选包与上一发布版本的真实 tarball。`release:publish` 冻结一批带摘要的候选 tarball,只针对这批工件执行一次正式增量门禁,成功后再发布同一批字节;不会在发包前后重复跑同一测试。真实 PostgreSQL 生命周期门禁也只在本地平台、开发生命周期或相关模板发生变化时运行。需要提前做一次不写 registry 的演练时单独运行 `pnpm verify:release`,它不是正式发布的必选重复步骤。无法分类的新包或变化自动升级为全量验证,周期审计使用 `pnpm verify:release:full`。
|
|
71
77
|
|
|
72
78
|
## OAuth2 应用身份
|
|
73
79
|
|
|
@@ -75,7 +81,7 @@ pnpm release:publish
|
|
|
75
81
|
|
|
76
82
|
```bash
|
|
77
83
|
openxiangda oauth client create --name erp-sync \
|
|
78
|
-
--environment
|
|
84
|
+
--environment preproduction \
|
|
79
85
|
--scope app:invoke \
|
|
80
86
|
--scope data:read
|
|
81
87
|
openxiangda oauth client list
|
|
@@ -88,8 +94,8 @@ NestJS App API 使用 `@RequireCapability` 验证服务身份 scope;Workflow
|
|
|
88
94
|
应用后端自己的 workload client 由平台托管,不向开发者显示 Secret。查询状态或主动轮换时使用专门命令:
|
|
89
95
|
|
|
90
96
|
```bash
|
|
91
|
-
openxiangda oauth runtime status --environment
|
|
92
|
-
openxiangda oauth runtime rotate --environment
|
|
97
|
+
openxiangda oauth runtime status --environment preproduction
|
|
98
|
+
openxiangda oauth runtime rotate --environment preproduction \
|
|
93
99
|
--grace-period-seconds 600 \
|
|
94
100
|
--idempotency-key runtime-rotation-20260812
|
|
95
101
|
```
|
|
@@ -101,14 +107,14 @@ openxiangda oauth runtime rotate --environment development \
|
|
|
101
107
|
`openxiangda.config.ts` 只声明后端需要的 Secret 名称和注入环境变量,值不会进入源码或 AppPackage。可先在本地/测试环境配置,再部署应用:
|
|
102
108
|
|
|
103
109
|
```bash
|
|
104
|
-
APP_SECRET='
|
|
110
|
+
APP_SECRET='preproduction-only-value' \
|
|
105
111
|
openxiangda secret create dingtalk-client-secret \
|
|
106
|
-
--environment
|
|
112
|
+
--environment preproduction \
|
|
107
113
|
--from-env APP_SECRET
|
|
108
114
|
|
|
109
115
|
openxiangda event subscription list
|
|
110
116
|
openxiangda event delivery list
|
|
111
|
-
openxiangda workflow provider list --environment
|
|
117
|
+
openxiangda workflow provider list --environment preproduction
|
|
112
118
|
```
|
|
113
119
|
|
|
114
120
|
事件死信通过 `event delivery replay` 显式重放;Workflow Provider 密钥轮换要在下一次成功部署后才激活。
|
|
@@ -119,13 +125,13 @@ openxiangda workflow provider list --environment development
|
|
|
119
125
|
|
|
120
126
|
```bash
|
|
121
127
|
openxiangda build --backend-image registry.example.com/apps/my-app@sha256:...
|
|
122
|
-
openxiangda deploy
|
|
128
|
+
openxiangda deploy preproduction --backend-image registry.example.com/apps/my-app@sha256:...
|
|
123
129
|
openxiangda status <deployment-id>
|
|
124
130
|
```
|
|
125
131
|
|
|
126
|
-
CLI 上传应用包并创建 DeploymentRun;部署、重试、健康检查和激活都由平台执行。CLI
|
|
132
|
+
CLI 上传应用包并创建 DeploymentRun;部署、重试、健康检查和激活都由平台执行。CLI 退出不影响发布继续进行。生产只晋级预发已验证的同一不可变 AppVersion,不重新构建。
|
|
127
133
|
|
|
128
|
-
`app provision` 只用于首次创建平台中的稳定 2.0
|
|
134
|
+
`app provision` 只用于首次创建平台中的稳定 2.0 应用身份,并在同一事务中补齐稳定的 `preproduction`、`production` 原生环境;命令可安全重试,且需要平台管理员身份。日常 CI 使用该应用的发布权限即可,不需要平台管理员。
|
|
129
135
|
|
|
130
136
|
## AI 入口
|
|
131
137
|
|
package/docs/index.md
CHANGED
|
@@ -21,3 +21,5 @@ features:
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
23
|
OpenXiangda 2.0 保留平台统一数据与治理能力,同时把应用开发恢复成成熟的前后端工程。本工具链只面向 2.0 应用;旧应用由独立的 1.x 产品线维护。
|
|
24
|
+
|
|
25
|
+
当前能力的完成证据、真实缺口和实施顺序见[实施路线图与证据矩阵](/architecture/implementation-roadmap)。实现前先阅读[环境配置内核](/architecture/environment-configuration-kernel-v2)、[Alpha 退役与 Native 切换前置审计](/architecture/native-kernel-inventory-v2)、[原生配置投影蓝图](/architecture/native-configuration-projection-v2)与[授权一致性内核](/architecture/authorization-consistency-v2),Admin 页面协议建立在这些可验证的运行时事实之上。
|
package/docs/llms.txt
CHANGED
|
@@ -7,6 +7,13 @@
|
|
|
7
7
|
- /data-authz.md: RBAC plus contextual data and field authorization
|
|
8
8
|
- /workflow-events.md: Workflow Kernel v2, providers, actions, durable events
|
|
9
9
|
- /delivery.md: immutable AppPackage and platform-owned DeploymentRun
|
|
10
|
+
- /architecture/implementation-roadmap.md: evidence-backed capability status, dependencies, and delivery order
|
|
11
|
+
- /architecture/environment-configuration-kernel-v2.md: native environment registry, immutable projections, Head activation, gateway delegation, and runtime gates
|
|
12
|
+
- /architecture/native-kernel-inventory-v2.md: read-only database, data-volume, and Kubernetes evidence; redaction, ambiguity classification, deterministic digests, and migration-plan validation
|
|
13
|
+
- /architecture/authorization-consistency-v2.md: environment-native RBAC, role subjects, contextual scope, concurrency, cache, and cutover invariants
|
|
14
|
+
- /architecture/admin-shell-v2.md: complete Admin framework contracts and staged implementation gates
|
|
10
15
|
- /architecture/repository-and-release.md: standalone 2.0 repository and release boundaries
|
|
16
|
+
- /architecture/tenant-public-origin-v2.md: canonical tenant origin registry, migration, cookie boundary, and gateway contract
|
|
17
|
+
- /architecture/tenant-public-origin-implementation-blueprint.md: file-level B0-O schema, API, CLI, deployment, and verification contract
|
|
11
18
|
- /reference/cli.md: generated CLI commands
|
|
12
19
|
- /reference/mcp.md: generated MCP resources and tools
|
package/docs/reference/cli.md
CHANGED
|
@@ -9,8 +9,19 @@
|
|
|
9
9
|
| `auth logout` | write-local | 删除当前登录会话 |
|
|
10
10
|
| `app create` | write-local | 从官方模板创建 2.0 应用 |
|
|
11
11
|
| `app link` | write-local | 绑定平台地址和应用环境 |
|
|
12
|
-
| `app provision` | deploy | 在平台幂等创建 2.0
|
|
12
|
+
| `app provision` | deploy | 在平台幂等创建 2.0 应用身份和预发/生产环境 |
|
|
13
13
|
| `app info` | read | 读取应用工作区上下文 |
|
|
14
|
+
| `authz membership list` | read | 查询 Native 应用角色成员 |
|
|
15
|
+
| `authz membership grant` | deploy | 授予 Native 应用业务角色 |
|
|
16
|
+
| `authz membership update` | deploy | 更新 Native 角色成员范围 |
|
|
17
|
+
| `authz membership revoke` | deploy | 撤销 Native 应用角色成员 |
|
|
18
|
+
| `authz relationship list` | read | 查询 Native 资源关系授权 |
|
|
19
|
+
| `authz relationship grant` | deploy | 创建 Native 资源关系授权 |
|
|
20
|
+
| `authz relationship update` | deploy | 更新 Native 资源关系授权 |
|
|
21
|
+
| `authz relationship revoke` | deploy | 撤销 Native 资源关系授权 |
|
|
22
|
+
| `authz super-admin list` | read | 查询 Native 应用超级管理员 |
|
|
23
|
+
| `authz super-admin grant` | deploy | 授予 Native 应用超级管理员 |
|
|
24
|
+
| `authz super-admin revoke` | deploy | 撤销 Native 应用超级管理员 |
|
|
14
25
|
| `oauth client list` | read | 查询应用 OAuth2 客户端 |
|
|
15
26
|
| `oauth client create` | deploy | 创建环境绑定的 OAuth2 客户端 |
|
|
16
27
|
| `oauth client update` | deploy | 更新 OAuth2 客户端 |
|
|
@@ -32,11 +43,15 @@
|
|
|
32
43
|
| `event delivery replay` | deploy | 幂等回放历史事件投递 |
|
|
33
44
|
| `event timer list` | read | 查询定时事件 |
|
|
34
45
|
| `event timer status` | deploy | 暂停或恢复定时事件 |
|
|
46
|
+
| `event timer fire` | write-local | 在完整本地开发会话中触发下一次定时事件 |
|
|
35
47
|
| `workflow provider list` | read | 查询 Workflow Assignee Provider |
|
|
36
48
|
| `workflow provider rotate` | deploy | 轮换 Workflow Provider 签名密钥 |
|
|
37
49
|
| `skill install` | write-local | 安装 OpenXiangda 2.0 AI Skills |
|
|
38
50
|
| `skill validate` | read | 验证 OpenXiangda 2.0 AI Skills |
|
|
39
|
-
| `dev` | write-local |
|
|
51
|
+
| `dev` | write-local | 启动受监督的完整本地应用 |
|
|
52
|
+
| `dev status` | read | 查看当前工作区本地开发会话 |
|
|
53
|
+
| `dev stop` | write-local | 停止当前工作区本地开发会话并保留数据 |
|
|
54
|
+
| `dev reset` | write-local | 删除当前工作区本地数据库和开发状态 |
|
|
40
55
|
| `generate` | write-local | 生成 Data/App/Workflow/Event 类型契约 |
|
|
41
56
|
| `check` | read | 确定性检查完整应用 |
|
|
42
57
|
| `test` | read | 运行应用测试 |
|
package/docs/reference/mcp.md
CHANGED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# 家校通讯录关系
|
|
2
|
+
|
|
3
|
+
状态:2.0 尚未正式投产。本页定义已经实现的后端读取合同和应用接入方式;当前生产应用仍按 1.0 文档接入,不能混用两代 SDK。
|
|
4
|
+
|
|
5
|
+
## 数据合同
|
|
6
|
+
|
|
7
|
+
平台同步钉钉家校通讯录后,以只读关系返回监护人、学生和班级。关系两端都包含:
|
|
8
|
+
|
|
9
|
+
- `userId`:平台用户 ID,业务数据应保存这个稳定标识;
|
|
10
|
+
- `dingtalkUserId`:钉钉 `userid`,用于钉钉侧联动和排查;
|
|
11
|
+
- `name`:平台用户姓名;
|
|
12
|
+
- `mobile`:平台已有手机号,可能为 `null`。
|
|
13
|
+
|
|
14
|
+
关系还包含 `relationCode`、`relationName`、班级信息、同步时间和同步状态。未能安全绑定到平台用户、或角色方向不一致的数据不会出现在应用查询结果中。
|
|
15
|
+
|
|
16
|
+
## 权限与默认范围
|
|
17
|
+
|
|
18
|
+
应用在 `openxiangda.config.ts` 声明需要的能力,并把其中一种能力授予角色:
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
authz: {
|
|
22
|
+
capabilities: [
|
|
23
|
+
{
|
|
24
|
+
code: 'app:school-service:school-contact:read',
|
|
25
|
+
kind: 'backend',
|
|
26
|
+
name: '读取全部家校关系',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
code: 'app:school-service:school-contact:self:read',
|
|
30
|
+
kind: 'backend',
|
|
31
|
+
name: '读取本人家校关系',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
code: 'app:school-service:school-contact:class:read',
|
|
35
|
+
kind: 'backend',
|
|
36
|
+
name: '读取任教班级家校关系',
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
roles: [
|
|
40
|
+
{
|
|
41
|
+
code: 'user',
|
|
42
|
+
name: '普通用户',
|
|
43
|
+
capabilities: ['app:school-service:school-contact:read'],
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
应用自己的查询接口也要进入不可变 App API 合同,并复用同一个能力:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
backend: {
|
|
53
|
+
operations: [
|
|
54
|
+
{
|
|
55
|
+
code: 'family.mine',
|
|
56
|
+
method: 'GET',
|
|
57
|
+
path: '/api/family/mine',
|
|
58
|
+
capability: 'app:school-service:school-contact:read',
|
|
59
|
+
requestSchema: { type: 'object', additionalProperties: false },
|
|
60
|
+
responseSchema: { type: 'object' },
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
默认配置使用 `school-contact:read`,数据范围是 `all`,即不限制,可以查看全部已同步关系。只有业务明确需要最小化可见范围时,才把角色改为 `self:read` 或 `class:read`。同一角色同时获得多个能力时按 `all > class > self` 取最宽范围,避免前后端对范围产生不同解释。
|
|
67
|
+
|
|
68
|
+
## NestJS App API
|
|
69
|
+
|
|
70
|
+
浏览器不能直接调用平台关系接口。应用后端使用 `OpenXiangdaPlatformClient`,透传 SDK 已验证的 authorization 和当前 RoleSession,再通过应用自己的 App API 返回业务需要的字段:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import {
|
|
74
|
+
OpenXiangdaHttpRequest,
|
|
75
|
+
OpenXiangdaOperation,
|
|
76
|
+
OpenXiangdaPlatformClient,
|
|
77
|
+
} from 'openxiangda-nest';
|
|
78
|
+
import { Controller, Get, Req } from '@nestjs/common';
|
|
79
|
+
import { appOperations } from '@app/contracts';
|
|
80
|
+
|
|
81
|
+
@Controller('/api/family')
|
|
82
|
+
export class FamilyController {
|
|
83
|
+
constructor(private readonly platform: OpenXiangdaPlatformClient) {}
|
|
84
|
+
|
|
85
|
+
@Get('/mine')
|
|
86
|
+
@OpenXiangdaOperation(appOperations.familyMine)
|
|
87
|
+
async mine(@Req() request: OpenXiangdaHttpRequest) {
|
|
88
|
+
const context = request.openxiangda!;
|
|
89
|
+
return await this.platform.mySchoolContactFamily(
|
|
90
|
+
context.authorization,
|
|
91
|
+
context.roleSessionId!,
|
|
92
|
+
{ page: 1, pageSize: 50 }
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
可用方法:
|
|
99
|
+
|
|
100
|
+
- `querySchoolContactRelations(authorization, roleSessionId, query)`:按平台用户 ID、手机号、钉钉 userid、姓名、班级或关系类型分页检索;
|
|
101
|
+
- `schoolContactChildren(..., userId, query)`:查询指定监护人的学生;
|
|
102
|
+
- `schoolContactGuardians(..., userId, query)`:查询指定学生的监护人;
|
|
103
|
+
- `mySchoolContactFamily(...)`:同时查询当前用户作为监护人和学生的两个方向。
|
|
104
|
+
|
|
105
|
+
应用前端用 `useOpenXiangdaAdmin().appApi()` 调用上面的 App API。不要把登录 token、RoleSession ID、平台 URL 或完整关系快照放入浏览器缓存;手机号只展示给确有业务需要的页面,日志不得记录手机号和完整返回体。
|
|
106
|
+
|
|
107
|
+
## 失效与降级
|
|
108
|
+
|
|
109
|
+
- `sync.state = disabled`:租户未开启后续同步,历史关系仍可能存在;
|
|
110
|
+
- `sync.state = not_synced`:已开启但尚无成功快照;
|
|
111
|
+
- `sync.state = current`:至少有一次成功快照,`lastSuccessfulSyncAt` 给出时间。
|
|
112
|
+
|
|
113
|
+
应用应显示同步状态,不要把“查不到关系”等同于“该用户没有家校关系”。平台只有在完整快照成功后才替换关系;钉钉分页失败时保留上次成功数据。
|
|
114
|
+
|
|
115
|
+
## 验证
|
|
116
|
+
|
|
117
|
+
至少覆盖:默认 `all`、`self`、任教班级 `class`、无权限 403、RoleSession 切换、手机号为空、同步关闭和空关系。完成后运行 `openxiangda generate --check`、`openxiangda check` 和 `openxiangda test`。
|
package/docs/workflow-events.md
CHANGED
|
@@ -6,11 +6,19 @@ Workflow Kernel v2 专注审批语义:版本化定义、条件分支、审批
|
|
|
6
6
|
|
|
7
7
|
业务字段始终由 Data API 或 App API 保存。流程内核仅保存定义、实例、节点、任务、动作、参与者快照、字段策略和关联业务记录 ID。
|
|
8
8
|
|
|
9
|
+
Native 本地运行与远端 Kernel 使用同一持久化边界:预览令牌只能消费一次;实例、当前任务、新任务、时间线和命令回执在一个 PostgreSQL 事务中提交;实例与任务版本同时参与 CAS。相同幂等键和相同请求跨重启返回原结果,相同键但不同请求明确冲突;两个运行实例并发处理同一任务时只有一个版本更新能够成功。`openxiangda dev --reset` 会清空这组本地工作流状态。本地内存适配器只用于 `--ui-only`,不提供重启或多实例保证。
|
|
10
|
+
|
|
9
11
|
标准任务页使用实例的 DataRef 加载业务记录,并按节点 `fieldPolicy` 控制字段。`edit` 与 `edit_required` 的变化在流程命令前先写入 Data API,使用记录 revision 防止覆盖他人修改;采用 App API 存储的应用注入等价 loader/saver。流程命令失败不会把业务数据偷偷写进 Kernel。
|
|
10
12
|
|
|
11
13
|
任务级操作包含同意、拒绝、退回、重新提交、转交、任务代理和前/后加签;实例级操作包含发起人撤回和应用管理员终止。一个正在审批的任务 Surface 可以同时返回任务级与实例级操作,例如应用管理员在任务仍活动时仍能终止实例。Admin 执行器按操作类型选择任务或实例命令,不以“当前页面有没有任务”猜测请求目标;撤回和终止也不会被当前审批节点的必填业务字段误拦截。
|
|
12
14
|
|
|
13
|
-
长期代理绑定委托人的当前 RoleAssignment,以及代理人的明确 RoleAssignment。平台提供代理目标身份查询,页面同时展示角色和 scope grant
|
|
15
|
+
长期代理绑定委托人的当前 RoleAssignment,以及代理人的明确 RoleAssignment。平台提供代理目标身份查询,页面同时展示角色和 scope grant;多角色用户不会因为只选择了人员而获得错误的数据范围。规则采用半开有效期 `[validFrom, validTo)`;同一委托身份下,全局规则与流程专属规则不能在时间上重叠,避免一次任务解析出两个代理人。应用最高管理员身份不能被代理转授,代理身份必须保持相同业务角色并覆盖委托身份的审批 scope,规则时间窗不能超出目标 RoleAssignment 自身的有效期。
|
|
16
|
+
|
|
17
|
+
长期代理是任务创建时的分派策略,不是读取待办时动态套用的过滤器。提交预览显示实际代理人;预览令牌同时绑定发起用户和活动 RoleAssignment,换人或切换身份后不能复用。正式创建任务时把原审批人标记为已代理,并把规则 ID、有效期和明确的代理 RoleAssignment 冻结为活动参与者。规则在预览后发生变化会让提交失败并要求重新预览;数据库事务再次锁定委托身份并核对整份参与者快照,防止创建任务与撤销规则并发时产生漂移。生效规则的目标身份若失去节点角色、有效期或业务 scope,预览/提交明确失败,不静默回退给原审批人。撤销只影响新任务,已创建任务继续按冻结快照处理;有效期届满后普通代理人不能继续操作遗留任务,应用管理员可根据审计链重新分派或接管。首期只允许单跳代理,不递归追踪代理人的其他代理规则。
|
|
18
|
+
|
|
19
|
+
任务内的参与者是一个持久化、有顺序、可审计的队列。原审批人、长期代理人、前/后加签人、转交人和任务代理人都记录 user、RoleAssignment、角色、来源参与者、状态与完成身份;长期代理参与者额外记录规则 ID 和冻结有效期。任务表的 `assignedRoleAssignmentId` 是当前活动参与者的索引投影:长期代理、转交或任务代理会切换待办归属;前加签先让加签人活动,后加签在原审批人通过后接棒;只有最后一个必需参与者通过,节点才继续流转。拒绝、退回、撤回和管理员终止会原子关闭剩余参与者,避免出现孤立待办。
|
|
20
|
+
|
|
21
|
+
任务级转交、代理和加签不能只提交 userId,必须提交从平台目标查询获得的具体 `roleAssignmentId`。Kernel 再校验其角色代码、审批操作权限和当前业务 scope;scope 值缺失时 fail-closed,主部门选择会规范化为实例的学院 scope。Admin 会按当前节点过滤可选身份,并展示完整参与者链。应用管理员仍可按既定规则绕过业务数据权限处理任务,但其操作会记录为真实完成身份,不会改写被代理人的身份。
|
|
14
22
|
|
|
15
23
|
## Provider 与自定义操作
|
|
16
24
|
|
|
@@ -25,6 +33,7 @@ Workflow Kernel v2 专注审批语义:版本化定义、条件分支、审批
|
|
|
25
33
|
- fieldPolicy;
|
|
26
34
|
- presentation;
|
|
27
35
|
- assignee/代理/加签上下文;
|
|
36
|
+
- 当前活动参与者与完整参与者链;
|
|
28
37
|
- 提交所需 concurrency token。
|
|
29
38
|
|
|
30
39
|
前端按协议展示,不需要复制内核状态机。协议允许扩展展示元数据,但内核始终校验动作是否合法。
|
|
@@ -44,6 +53,19 @@ openxiangda event delivery replay <delivery-id> \
|
|
|
44
53
|
|
|
45
54
|
应用管理员也可在标准“运行与诊断”页面暂停/启用事件订阅和定时事件,并对重试或死信执行重放。重放创建新 delivery,原记录保持不变,便于审计与关联排障。
|
|
46
55
|
|
|
56
|
+
定时声明使用明确的六段 Cron、IANA 时区和不超过 64 KiB 的 payload,最短间隔为 60 秒。平台持久化 `nextDueAt / lastFiredAt` 和每次 firing,并在同一事务中推进 schedule、写 firing、outbox 与匹配订阅的 delivery;多实例并发扫描或本地并发触发,同一 `timer + scheduledAt` 最多产生一个事件。停机恢复会把遗漏时段合并为一次 firing,避免恢复后形成历史洪峰;Cron 或时区改变时按新声明重算下一次执行。
|
|
57
|
+
|
|
58
|
+
本地开发不需要为了等待定时点临时修改 Cron。完整 `openxiangda dev` 会话中可执行:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
openxiangda event timer list
|
|
62
|
+
openxiangda event timer fire <timer-id>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
该命令触发当前计划中的下一次 firing,仍然写 PostgreSQL 并经过真实 outbox、签名、Nest handler 和 receipt;它不接受远端环境,也不能在 `--ui-only` 使用。
|
|
66
|
+
|
|
67
|
+
暂停是投递控制,不是丢弃开关:暂停生效后,新业务事件不为该订阅创建 delivery;并发边界上已经存在但尚未领取的 delivery 也不会被 Worker 领取,恢复后继续处理。Worker 的完成或失败更新必须匹配本次领取的 attempt/lease 代次,旧 Worker 超时返回不能覆盖接管后的结果。重放的唯一性范围是 `app + originalDeliveryId + idempotencyKey`,客户端重试同一个操作只返回原重放记录。
|
|
68
|
+
|
|
47
69
|
Nest SDK 默认使用平台托管的持久化 receipt store:它复用当前事件订阅密钥,对 `claim / complete / release` 命令做 HMAC 签名,并把消费状态保存在平台数据库,因此 Pod 重启、滚动部署或多副本运行都不会退化为进程内去重,也不要求应用自建数据库。只有显式注入 `InMemoryOpenXiangdaEventReceiptStore` 时才使用本地进程内实现。
|
|
48
70
|
|
|
49
71
|
处理器完成后才提交 receipt,异常会释放 claim 以便平台重试。仍在租约内处理的重复投递返回可重试错误;只有状态已经是 `succeeded` 的事件才返回成功重复。对于“外部副作用成功、回执提交前进程崩溃”的固有窗口,处理器仍应把 `event.id` 作为 Data API 受限事务的 `idempotencyKey`,或使用下游系统自己的幂等键;receipt 提供的是可靠的消费领取与完成记录,不虚构跨系统 exactly-once。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openxiangda-skill-kit",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.22",
|
|
4
4
|
"description": "Validation and deterministic packaging for OpenXiangda 2.0 AI skills.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"README.md"
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"openxiangda-devkit-core": "2.0.0-alpha.
|
|
24
|
+
"openxiangda-devkit-core": "2.0.0-alpha.19"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"tsx": "4.23.12",
|
package/skills/manifest.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
{
|
|
5
5
|
"name": "openxiangda-v2",
|
|
6
6
|
"description": "Build, inspect, validate, and deliver a complete OpenXiangda 2.0 application workspace. Use when a task spans the React frontend, NestJS backend, Data API, authorization, workflow, events, or whole-application delivery.",
|
|
7
|
-
"sha256": "
|
|
7
|
+
"sha256": "0c9e6ca500aeff46780c55c4711e170c36f6ce67f1d6397116e9f5be809541e6"
|
|
8
8
|
},
|
|
9
9
|
{
|
|
10
10
|
"name": "openxiangda-v2-architecture",
|
|
@@ -14,27 +14,27 @@
|
|
|
14
14
|
{
|
|
15
15
|
"name": "openxiangda-v2-backend",
|
|
16
16
|
"description": "Build the standard OpenXiangda 2.0 NestJS application backend. Use when implementing App APIs, Data API transactions, identity-aware business services, event consumers, health checks, or external integration endpoints.",
|
|
17
|
-
"sha256": "
|
|
17
|
+
"sha256": "d605a69807f79887f5962e24bc7a950f5e6bf9758b3af1fb63f7c062123ea4df"
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
"name": "openxiangda-v2-data-authz",
|
|
21
21
|
"description": "Design OpenXiangda 2.0 Data API and contextual authorization contracts. Use for RBAC, active-role behavior, department or record attributes, application-admin bypass, field policies, and restricted transactions.",
|
|
22
|
-
"sha256": "
|
|
22
|
+
"sha256": "01d90dcfa66eb61312fd8f2553e78f98e3cc2144de64563fde449a76c8ce25de"
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
25
|
"name": "openxiangda-v2-delivery",
|
|
26
26
|
"description": "Validate, build, deploy, observe, promote, retry, and roll back an OpenXiangda 2.0 application. Use when preparing an immutable AppPackage or changing a platform-managed environment.",
|
|
27
|
-
"sha256": "
|
|
27
|
+
"sha256": "c46927bbbe65352591cd08fbdc8797885bf60005967ae64dd3eb7987fbfc30a7"
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
"name": "openxiangda-v2-frontend",
|
|
31
31
|
"description": "Build OpenXiangda 2.0 React and Ant Design admin experiences. Use when implementing menus, routes, CRUD pages, role switching, workflow task pages, or application-defined action components.",
|
|
32
|
-
"sha256": "
|
|
32
|
+
"sha256": "a84c487b5a2d46f5a3c995c479c5aef5d4858d2df724d117275496b09d56946b"
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
"name": "openxiangda-v2-workflow-events",
|
|
36
36
|
"description": "Implement OpenXiangda Workflow Kernel v2 and durable application events. Use for approval definitions, assignee providers, task actions, delegation, add-sign, previews, data-change events, workflow events, or timers.",
|
|
37
|
-
"sha256": "
|
|
37
|
+
"sha256": "4290957767fd86664b66a3a0e394e6120c3b440d482f0ded0b56096f20cfa622"
|
|
38
38
|
}
|
|
39
39
|
]
|
|
40
40
|
}
|
|
@@ -22,6 +22,14 @@ Treat the repository as one typed application product. Work through package cont
|
|
|
22
22
|
|
|
23
23
|
For a new repository, link it to the target platform and let an authorized platform administrator run `openxiangda app provision` once. The command is idempotent and provisions only a native 2.0 application identity.
|
|
24
24
|
|
|
25
|
+
## Local Development Gate
|
|
26
|
+
|
|
27
|
+
- Use `openxiangda dev` as the only public full-stack development entrypoint. Do not ask the developer to install or administer PostgreSQL; full mode requires Docker Desktop (or a compatible daemon), and the CLI owns a digest-pinned, workspace-isolated PostgreSQL container and volume.
|
|
28
|
+
- Use `openxiangda dev status` to inspect the active or last session and `openxiangda dev stop` to stop it while preserving data. Ctrl+C has the same preservation rule.
|
|
29
|
+
- Delete local data only through the explicit `openxiangda dev reset --data` command. It must validate the exact workspace, session process identity, container labels, volume labels and credential binding before removal. Never substitute raw `docker rm`/`docker volume rm` or delete another workspace's resources.
|
|
30
|
+
- `openxiangda dev --reset` is the reset-then-start convenience. Use `--ui-only` only for visual work when Docker is unavailable; its in-memory evidence never satisfies integration or release verification.
|
|
31
|
+
- Local is a runtime mode, not a remote environment. Remote delivery accepts only `preproduction` and `production`.
|
|
32
|
+
|
|
25
33
|
## Boundaries
|
|
26
34
|
|
|
27
35
|
- Put browser code in `apps/web`, server code in `apps/server`, shared domain types in `packages/domain`, and generated declarations in `packages/contracts`.
|
|
@@ -30,9 +38,14 @@ For a new repository, link it to the target platform and let an authorized platf
|
|
|
30
38
|
- Use durable event consumers for side effects and idempotency keys for retries.
|
|
31
39
|
- Build one immutable application package; the platform owns deployment execution, health gates, promotion, and rollback.
|
|
32
40
|
- Reject any workspace that does not declare the native 2.0 application configuration.
|
|
41
|
+
- Read school-contact relationships only through a NestJS App API bound to the
|
|
42
|
+
active RoleSession. The default relation scope is unrestricted; narrower
|
|
43
|
+
self/class access must be an explicit authorization decision.
|
|
33
44
|
|
|
34
45
|
## Delivery Gate
|
|
35
46
|
|
|
36
47
|
Use `openxiangda build --backend-image <immutable-image>` only after checks pass. Use `openxiangda deploy`, `openxiangda status`, and `openxiangda logs` only when the user has authorized the environment change.
|
|
37
48
|
|
|
38
49
|
Read [Getting Started](../../docs/getting-started.md) for the complete development loop.
|
|
50
|
+
For guardian/student relationships, read
|
|
51
|
+
[School contact relations](../../docs/school-contact-relations.md).
|
|
@@ -20,6 +20,10 @@ Build a normal NestJS service in `apps/server`. The platform deploys one contain
|
|
|
20
20
|
the request RoleSession.
|
|
21
21
|
8. For attachments, initiate a platform-managed upload, upload to the signed
|
|
22
22
|
plan, complete verification, and persist only the returned `DataFileRef`.
|
|
23
|
+
9. For DingTalk school-contact relations, call the typed platform client from
|
|
24
|
+
the NestJS backend with the verified authorization and RoleSession. Expose
|
|
25
|
+
only an application App API to the browser; never call the platform relation
|
|
26
|
+
endpoint from React.
|
|
23
27
|
|
|
24
28
|
## Runtime Path
|
|
25
29
|
|
|
@@ -39,4 +43,6 @@ Build a normal NestJS service in `apps/server`. The platform deploys one contain
|
|
|
39
43
|
|
|
40
44
|
Use `openxiangda dev` for local orchestration. Run `openxiangda check`, `openxiangda test`, and `openxiangda build --backend-image <immutable-image>` before deployment.
|
|
41
45
|
|
|
42
|
-
Read [Backend](../../docs/backend.md) for the standard module layout.
|
|
46
|
+
Read [Backend](../../docs/backend.md) for the standard module layout. For
|
|
47
|
+
guardian, student, and class relationships, read
|
|
48
|
+
[School contact relations](../../docs/school-contact-relations.md).
|
|
@@ -27,6 +27,10 @@ Model permissions as capability checks plus contextual data predicates. A role g
|
|
|
27
27
|
- Require the application directory capability before using department or user
|
|
28
28
|
selectors. Store stable IDs and resolve display labels through Directory v2;
|
|
29
29
|
do not copy tenant contact data into application records.
|
|
30
|
+
- School-contact access defaults to the unrestricted `school-contact:read`
|
|
31
|
+
capability. Use `school-contact:self:read` or
|
|
32
|
+
`school-contact:class:read` only when the product explicitly requires a
|
|
33
|
+
narrower scope; rely on the platform query boundary, not browser filtering.
|
|
30
34
|
- Apply field policies consistently to queries, search controls, forms, CSV
|
|
31
35
|
transfer and restricted transactions.
|
|
32
36
|
- Use the bounded server-side aggregate endpoint for charts and summaries. Only
|
|
@@ -41,4 +45,6 @@ Model permissions as capability checks plus contextual data predicates. A role g
|
|
|
41
45
|
|
|
42
46
|
Run `openxiangda check` and `openxiangda test` after every policy or schema change.
|
|
43
47
|
|
|
44
|
-
Read [Data and Authorization](../../docs/data-authz.md) for policy examples
|
|
48
|
+
Read [Data and Authorization](../../docs/data-authz.md) for policy examples and
|
|
49
|
+
[School contact relations](../../docs/school-contact-relations.md) for the
|
|
50
|
+
guardian/student contract.
|
|
@@ -16,7 +16,11 @@ Build inside `apps/web` with `openxiangda-admin`. Preserve the standard shell, r
|
|
|
16
16
|
5. Render workflow actions and field policies from the backend protocol. Do not duplicate workflow transition rules in the browser.
|
|
17
17
|
6. Keep data calls in typed client modules rather than components.
|
|
18
18
|
7. Preserve the standard responsive layout, permission-filtered navigation,
|
|
19
|
-
|
|
19
|
+
bounded tabs, explicit `tabPersistence` / `keepAlive`, personal center and
|
|
20
|
+
stable role switcher. Static routes default to session-restored tabs without
|
|
21
|
+
mounted-page caching; only list/workbench routes should opt into memory
|
|
22
|
+
keep-alive. Dynamic detail, workflow task and edit routes stay non-persistent
|
|
23
|
+
and non-cached. Build management lists
|
|
20
24
|
with the standard search, pagination, sorting, density, column settings,
|
|
21
25
|
revision-aware editing and batch action surfaces before adding custom UI.
|
|
22
26
|
8. Use `department`, `user`, and `relation` search/form controls for persisted
|
|
@@ -32,8 +36,40 @@ Build inside `apps/web` with `openxiangda-admin`. Preserve the standard shell, r
|
|
|
32
36
|
for managed attachments and the aggregate chart components for summaries;
|
|
33
37
|
never expose storage URLs or aggregate complete result sets in-browser.
|
|
34
38
|
12. Import from the narrow `openxiangda-admin/core`, `/data`, `/dashboard`,
|
|
35
|
-
and `/workflow` entrypoints.
|
|
36
|
-
|
|
39
|
+
and `/workflow` entrypoints. Register optional personal-center domains with
|
|
40
|
+
`definePersonalCenterSections`; import Workflow delegation only from
|
|
41
|
+
`/workflow/personal-center`. Core must not import a domain module, and a
|
|
42
|
+
no-Workflow production build must not contain its delegation chunk. Keep
|
|
43
|
+
business route modules lazy and preserve the template's chunk-cycle and
|
|
44
|
+
size budgets.
|
|
45
|
+
13. Use `DataFormPage` / `DataRecordPage` for full-page CRUD and
|
|
46
|
+
`WorkflowSubmissionPage` for business-backed approval submission. Its
|
|
47
|
+
`saveBusiness` adapter must persist through Data API or NestJS App API and
|
|
48
|
+
return `businessKey`, revision-bound `dataRef`, and workflow `facts`.
|
|
49
|
+
Never hard-code a demo record reference or keep a preview valid after
|
|
50
|
+
business fields, department, or approver answers change.
|
|
51
|
+
14. Standard data and workflow forms already participate in the scoped
|
|
52
|
+
`DirtyStateRegistry`. Custom editors must call `useAdminDirtyState` instead
|
|
53
|
+
of adding their own `beforeunload` or router prompt. Use synchronous
|
|
54
|
+
`useAdminBeforeDispose` only to release subscriptions, workers, or object
|
|
55
|
+
URLs; it must not persist business data or veto identity/permission
|
|
56
|
+
invalidation.
|
|
57
|
+
15. Prefer `DataListPage` for ordinary resource management. Use
|
|
58
|
+
`useDataWorkbenchController` from `openxiangda-admin/data` only when a
|
|
59
|
+
business workbench genuinely needs a custom surface or composed view. Bind
|
|
60
|
+
it to stable `identityScope`, `identityEpoch`, `resourceCode`, and
|
|
61
|
+
`configVersion`; adapt reads through the existing typed Data API or App API
|
|
62
|
+
client, honor its `AbortSignal` when the client supports cancellation, and
|
|
63
|
+
keep the standard `DataQuery` contract. Do not fetch complete datasets for
|
|
64
|
+
browser filtering, add a second query DSL, or persist page results,
|
|
65
|
+
selection, errors, tokens, or authorization decisions. Do not synchronize
|
|
66
|
+
filters to the URL until each search field explicitly declares itself
|
|
67
|
+
shareable and the application enforces bounded values.
|
|
68
|
+
16. Use `WorkflowWorkCenterPage` for pending, completed, and created workflow
|
|
69
|
+
records. Treat `total`, `limit`, and `offset` as Kernel facts, keep the
|
|
70
|
+
standard 20-row server page, reset offset on category or identity changes,
|
|
71
|
+
and never derive a total, search result, or sort order from the current
|
|
72
|
+
browser page.
|
|
37
73
|
|
|
38
74
|
Run `openxiangda generate`, `openxiangda check`, and `openxiangda test` after changing contracts or pages. Run `pnpm test:e2e` for shell, navigation, role, data-page or recovery changes; preserve the desktop and mobile Chromium paths and use accessible role/label locators instead of Ant Design private DOM. Use accessible Ant Design patterns and run the repository's Ant Design lint when available.
|
|
39
75
|
|
|
@@ -11,18 +11,35 @@ The workflow kernel owns definitions, instances, tasks, transitions, delegation,
|
|
|
11
11
|
|
|
12
12
|
1. Declare approval and conditional nodes in `openxiangda.config.ts`.
|
|
13
13
|
2. Use provider contracts for application-data-dependent assignee resolution and custom action decisions.
|
|
14
|
-
3.
|
|
14
|
+
3. Use `WorkflowSubmissionPage` when the flow starts from a business form.
|
|
15
|
+
Persist the draft first through Data API/App API and return a revision-bound
|
|
16
|
+
snapshot; bind preview readiness to that snapshot plus all submission
|
|
17
|
+
answers. Reuse one idempotency key across a failed save retry and a separate
|
|
18
|
+
stable key across a failed start retry.
|
|
15
19
|
4. Return protocol `operations`, field policies, presentation hints, execution targets, and concurrency tokens from the backend. Task and instance operations may coexist on one Surface; dispatch them to their declared task/instance command scope.
|
|
16
|
-
5. Persist business changes through Data API or App API, then correlate them to
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
5. Persist business changes through Data API or App API, then correlate them to
|
|
21
|
+
the workflow action. The Kernel never stores business fields or silently
|
|
22
|
+
projects business status; use an App API or workflow event consumer for the
|
|
23
|
+
latter.
|
|
24
|
+
6. In full local development, persist preparation tokens, instances, tasks,
|
|
25
|
+
timelines, delegations, and command receipts in PostgreSQL. Commit instance
|
|
26
|
+
and task CAS updates atomically; scope idempotency to the command, request,
|
|
27
|
+
and RoleAssignment so restart replay cannot cross identities.
|
|
28
|
+
7. Test approve, reject, transfer, return, resubmit, delegation, add-sign, initiator withdrawal, admin termination, duplicate requests, stale revisions, restart replay, and concurrent commands.
|
|
29
|
+
8. Rotate application Provider signing keys with `workflow provider rotate`,
|
|
19
30
|
then deploy. During that deployment the Nest adapter must accept both current
|
|
20
31
|
and `_NEXT` secrets; the platform activates the next version after readiness.
|
|
21
32
|
|
|
22
33
|
## Events
|
|
23
34
|
|
|
24
35
|
- Subscribe to typed data and workflow events; implement idempotent consumers.
|
|
25
|
-
-
|
|
36
|
+
- Declare timers with an explicit six-field Cron expression, an IANA timezone,
|
|
37
|
+
and a bounded object payload. Use them as durable event producers rather than
|
|
38
|
+
adding an application-owned scheduler.
|
|
39
|
+
- In a full local `openxiangda dev` session, use
|
|
40
|
+
`openxiangda event timer fire <timer-id>` (or MCP `fire_local_timer`) to test
|
|
41
|
+
the next persisted occurrence without editing the schedule. Confirm the
|
|
42
|
+
resulting delivery with `event delivery list`; UI-only mode is not evidence.
|
|
26
43
|
- Verify signatures, propagate correlation IDs, and fail retryably for transient dependencies.
|
|
27
44
|
- Never assume event ordering unless the contract explicitly provides a partition key.
|
|
28
45
|
- Inspect dead letters with `event delivery list` and replay with a stable
|