openxiangda 2.0.0-alpha.105 → 2.0.0-alpha.106
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/README.md +23 -20
- package/bin/run.js +1 -0
- package/documentation/AGENTS.md +23 -0
- package/documentation/administration.md +27 -0
- package/documentation/application-foundation.md +162 -0
- package/documentation/appspec.md +92 -0
- package/documentation/backend.md +85 -0
- package/documentation/concepts.md +61 -0
- package/documentation/data-authz.md +58 -0
- package/documentation/delivery.md +72 -0
- package/documentation/development.md +28 -0
- package/documentation/field-components.md +204 -0
- package/documentation/frontend.md +269 -0
- package/documentation/getting-started.md +59 -0
- package/documentation/manifest.json +108 -0
- package/documentation/public-access.md +151 -0
- package/documentation/reference/cli.md +26 -0
- package/documentation/reference/mcp.md +548 -0
- package/documentation/testing.md +51 -0
- package/documentation/upgrading.md +19 -0
- package/documentation/workflow-events.md +181 -0
- package/package.json +9 -8
- package/skills/manifest.json +2 -2
- package/skills/openxiangda-v2/SKILL.md +39 -52
- package/skills/openxiangda-v2/agents/openai.yaml +2 -2
- package/skills/openxiangda-v2/references/administration.md +27 -0
- package/skills/openxiangda-v2/references/application-foundation.md +162 -0
- package/skills/openxiangda-v2/references/appspec.md +71 -46
- package/skills/openxiangda-v2/references/architecture.md +57 -5
- package/skills/openxiangda-v2/references/backend.md +58 -252
- package/skills/openxiangda-v2/references/commands.md +23 -19
- package/skills/openxiangda-v2/references/data-authz.md +33 -389
- package/skills/openxiangda-v2/references/delivery.md +72 -49
- package/skills/openxiangda-v2/references/discovery.md +24 -11
- package/skills/openxiangda-v2/references/field-components.md +204 -0
- package/skills/openxiangda-v2/references/frontend.md +254 -280
- package/skills/openxiangda-v2/references/getting-started.md +59 -0
- package/skills/openxiangda-v2/references/mcp.md +548 -0
- package/skills/openxiangda-v2/references/public-access.md +76 -84
- package/skills/openxiangda-v2/references/testing.md +33 -56
- package/skills/openxiangda-v2/references/upgrading.md +19 -0
- package/skills/openxiangda-v2/references/workflow-events.md +143 -300
- package/skills/openxiangda-v2/references/workspace.md +0 -64
package/README.md
CHANGED
|
@@ -1,26 +1,29 @@
|
|
|
1
|
-
#
|
|
1
|
+
# OpenXiangda 2.0
|
|
2
2
|
|
|
3
|
-
`openxiangda`
|
|
4
|
-
stable subpaths instead of depending on physical implementation packages:
|
|
3
|
+
`openxiangda` 是应用开发统一安装的根包,提供 CLI、MCP、中文使用资料及同版本的 `openxiangda-v2` Skill。已有项目使用锁定版本;新项目使用明确的 2.0 版本。不要用未指定版本的全局命令判断项目行为。
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
```bash
|
|
6
|
+
pnpm openxiangda context --json
|
|
7
|
+
pnpm openxiangda docs
|
|
8
|
+
pnpm openxiangda docs getting-started
|
|
9
|
+
pnpm openxiangda skill install --workspace . --force
|
|
10
|
+
pnpm openxiangda dev
|
|
11
|
+
```
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
`openxiangda-v2` AI Skill distribution. OpenXiangda 1.x remains on the 1.x
|
|
14
|
-
version line and is not a compatibility target for this package.
|
|
13
|
+
应用导入统一子路径:
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
| 子路径 | 用途 |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| `openxiangda/config` | 模型、任务页、权限与应用声明 |
|
|
18
|
+
| `openxiangda/core` | 数据客户端与契约 |
|
|
19
|
+
| `openxiangda/react` | PC 页面、管理入口与标准组件 |
|
|
20
|
+
| `openxiangda/mobile` | 手机端组件 |
|
|
21
|
+
| `openxiangda/field-kit` | 字段、表单与详情 |
|
|
22
|
+
| `openxiangda/nest` | 按需启用的业务后端 |
|
|
23
|
+
| `openxiangda/testing` | 权限与业务测试辅助 |
|
|
17
24
|
|
|
18
|
-
`
|
|
19
|
-
locale and contextual message/notification support. Standalone component consumers
|
|
20
|
-
can wrap their content in `OpenXiangdaUiProvider`. Custom admin pages use
|
|
21
|
-
`OpenXiangdaAdminPage`; business fields use `openxiangda/field-kit`.
|
|
25
|
+
默认在本地运行 React,连接远端测试平台;标准 CRUD、审批和通知无需自建后端。`check` 是统一校验入口;`deploy` 已包含校验。生产通过 `deploy --environment production --from <test-deployment-id>` 复用成功测试版本。
|
|
22
26
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
stylesheet; do not import the upstream mobile root entry's document reset.
|
|
27
|
+
MCP 使用 `pnpm exec openxiangda --mcp-stdio --cwd <工作区绝对路径>`。先读取 workspace_context,再使用 docs_read 查询同版本中文正文。完整参数可运行 `pnpm openxiangda docs mcp`。
|
|
28
|
+
|
|
29
|
+
`OpenXiangdaApplication` 包含默认 Ant Design 样式、中文语言和消息上下文;独立组件可使用 `OpenXiangdaUiProvider`。管理页面使用 `OpenXiangdaAdminPage`,字段使用 Field Kit。自定义样式限制在组件内,应用负责全局重置;手机端只导入本包的局部样式,不引入上游移动库的全局重置。
|
package/bin/run.js
CHANGED
|
@@ -9,6 +9,7 @@ const packageManifest = JSON.parse(
|
|
|
9
9
|
);
|
|
10
10
|
process.env.OPENXIANGDA_DISTRIBUTION_NAME = packageManifest.name;
|
|
11
11
|
process.env.OPENXIANGDA_DISTRIBUTION_VERSION = packageManifest.version;
|
|
12
|
+
process.env.OPENXIANGDA_DOCUMENTATION_ROOT = join(packageRoot, 'documentation');
|
|
12
13
|
const packagedSkills = join(packageRoot, 'skills');
|
|
13
14
|
if (existsSync(packagedSkills)) {
|
|
14
15
|
process.env.OPENXIANGDA_SKILLS_ROOT ||= packagedSkills;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# 应用开发约定
|
|
2
|
+
|
|
3
|
+
<!-- OPENXIANGDA:BEGIN -->
|
|
4
|
+
## 平台约定
|
|
5
|
+
|
|
6
|
+
本项目使用 OpenXiangda 2.0。进入项目后以本地精确依赖和锁文件为准,使用 `pnpm openxiangda`;先运行 `context --json` 确认版本和绑定,使用 `docs` 按任务读取当前中文资料。
|
|
7
|
+
|
|
8
|
+
- 模型、页面、导航和权限由应用声明一次;编译器生成契约。业务代码不改生成结果、不创建 platform/data、不复制平台 Router、字段组件、客户端或权限状态。
|
|
9
|
+
- 当前用户、角色并集、数据授权和部署状态归平台;应用不保存凭据或授权快照。普通 CRUD 走 Data API,真实业务动作才按需启用 Nest。
|
|
10
|
+
- 标准业务字段使用 `openxiangda/field-kit`;PC 补充控件使用 antd,移动使用有作用域的 `openxiangda/mobile` 和 MobileSurface,不引入上游全局重置。
|
|
11
|
+
- 无账号表单读取 `docs public-access`,使用 frontend.publicAccess 和专用客户端;标准审批、通知和后端均按需启用。
|
|
12
|
+
- 日常使用 dev 和聚焦测试。只验证时使用 check;授权部署时直接 deploy,它已包含检查、测试和构建。生产必须指定成功测试运行并复用同一版本。
|
|
13
|
+
- 根据变化风险记录业务意图。无行为变化不新建 AppSpec;已有授权和已确认意图不重复向用户请求机械确认。真实角色和浏览器验收与本地测试分别记录。
|
|
14
|
+
- 失败保留错误码、指针和原候选;查询平台状态后使用允许的恢复操作,不自动重放未知结果。
|
|
15
|
+
|
|
16
|
+
MCP 使用同一项目 CLI:`pnpm exec openxiangda --mcp-stdio --cwd <workspace>`。先读取 workspace_context,再按任务读取 docs_read 和当前契约。登录、创建及长期 dev 使用 CLI/终端。
|
|
17
|
+
|
|
18
|
+
详细用法:`pnpm openxiangda docs development`、`docs frontend`、`docs data-authz`、`docs administration`、`docs testing`、`docs delivery`。按需加载,无需每次通读全部资料。
|
|
19
|
+
<!-- OPENXIANGDA:END -->
|
|
20
|
+
|
|
21
|
+
## 项目自有约定
|
|
22
|
+
|
|
23
|
+
在此补充本项目的业务范围和团队要求;平台资料刷新保留本节内容。
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# 应用管理与有效配置
|
|
2
|
+
|
|
3
|
+
平台的应用管理控制台维护应用成员、角色授权和流程运行参数。应用自身声明的 `/admin` 业务菜单展示业务页面,两者职责不同。可见入口和可执行操作以当前用户与目标环境返回结果为准。
|
|
4
|
+
|
|
5
|
+
## 发现当前入口 {#context}
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm openxiangda admin context --environment test --json
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
MCP 对应 `administration_context`。先检查返回的管理能力与入口,再进入平台标准管理页面。普通开发者不因拥有源码就自动获得成员管理或流程配置权限;拒绝时联系有权管理员,不伪造用户、租户或权限头。
|
|
12
|
+
|
|
13
|
+
## 查看流程节点配置 {#workflow}
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm openxiangda admin workflow <workflowCode> --environment test --json
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
MCP 对应 `workflow_node_configurations`。workflowCode 来自当前应用声明。管理员运行配置可能已经覆盖开发默认值;不要只看本地文件推断线上处理人。已创建任务保留其冻结配置,后续节点进入采用适用的新运行配置,具体版本以接口返回为准。
|
|
20
|
+
|
|
21
|
+
生产读取必须显式指定 production。两个命令均为只读发现,成员/角色和流程参数修改通过已授权的标准管理入口执行。
|
|
22
|
+
|
|
23
|
+
## 业务页面中的角色管理 {#role-management}
|
|
24
|
+
|
|
25
|
+
确有业务需要时,使用 `openxiangda/core` 的角色管理 SDK。目录提供可管理角色、动作与授权范围;业务角色只能维护管理员已委托的范围。进一步委托要求 management.delegate,并受已有目标角色及动作子集限制。
|
|
26
|
+
|
|
27
|
+
成员和委托修改带 UUID operationId、原因,更新/撤销带最新 expectedRevision;冲突后重新读取。应用不另建授权表、选择 actor 或自行保存权限快照。SDK 和当前用户数据边界见[权限](./data-authz.md)。
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# 业务模块与标准 CRUD 基础
|
|
2
|
+
|
|
3
|
+
这是 2026-09-05 平台重构的首批能力。数据存储、页面选择和角色授权独立定义,仍编译到平台现有 Data API、Surface 和权限引擎。
|
|
4
|
+
|
|
5
|
+
## 从业务任务到模块
|
|
6
|
+
|
|
7
|
+
先确定用户要完成的任务,再选择页面。辅助数据模型不需要独立页面;复杂任务页可组合多个模型。简单应用显式选择标准 CRUD 即可。
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// modules/records/models.ts
|
|
11
|
+
import { defineDataModel } from 'openxiangda/config';
|
|
12
|
+
|
|
13
|
+
export const records = defineDataModel({
|
|
14
|
+
code: 'records', name: '记录',
|
|
15
|
+
fields: [
|
|
16
|
+
{ code: 'title', label: '名称', type: 'text.short', required: true },
|
|
17
|
+
{ code: 'enabled', label: '启用', type: 'boolean' },
|
|
18
|
+
{ code: 'source_key', label: '来源标识', type: 'text.short', hidden: true },
|
|
19
|
+
],
|
|
20
|
+
});
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
// modules/records/index.ts
|
|
25
|
+
import { defineApplicationModule, defineResourceForm, defineResourceList } from 'openxiangda/config';
|
|
26
|
+
import { records } from './models';
|
|
27
|
+
|
|
28
|
+
export const recordsModule = defineApplicationModule({
|
|
29
|
+
code: 'records', models: [records],
|
|
30
|
+
crud: [{
|
|
31
|
+
model: records.code,
|
|
32
|
+
list: defineResourceList(records, { fields: ['title', 'enabled'], filterFields: ['enabled'] }),
|
|
33
|
+
form: defineResourceForm(records, { fields: ['title', 'enabled'] }),
|
|
34
|
+
}],
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
不写 `crud` 时仅注册数据模型;`crud: [{ model: records.code }]` 使用标准页面默认字段。列表默认列、表单、详情的字段选择均保持给定顺序。一个模型可以声明多套命名视图,各自配置字段、分组和操作入口,共用同一份数据和权限。
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
// openxiangda.config.ts
|
|
42
|
+
import { defineOpenXiangdaApp, resourceRoleCapabilities } from 'openxiangda/config';
|
|
43
|
+
import { recordsModule } from './modules/records';
|
|
44
|
+
|
|
45
|
+
const appCode = 'my-app';
|
|
46
|
+
export default defineOpenXiangdaApp({
|
|
47
|
+
app: { code: appCode, name: '我的应用' },
|
|
48
|
+
modules: [recordsModule],
|
|
49
|
+
frontend: { admin: { navigation: [] } },
|
|
50
|
+
authz: { capabilities: [], roles: [
|
|
51
|
+
{ code: 'reader', name: '查阅成员', capabilities: resourceRoleCapabilities(appCode, 'records', 'read') },
|
|
52
|
+
{ code: 'manager', name: '管理成员', capabilities: resourceRoleCapabilities(appCode, 'records', 'manage') },
|
|
53
|
+
] },
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
菜单单独规划;可使用现有 `suggestAdminNavigation` 提案后选择需要的条目。`read` 仅授予查看,`manage` 明确包含增删改查,也可传 `['read', 'create']`。页面生成不会改变角色权限。
|
|
58
|
+
|
|
59
|
+
## 同一模型的多套页面
|
|
60
|
+
|
|
61
|
+
例如简要登记只填写名称,完整管理填写名称和启用状态:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
crud: [
|
|
65
|
+
{
|
|
66
|
+
model: records.code, code: 'quick', name: '简要登记',
|
|
67
|
+
list: defineResourceList(records, { fields: ['title'] }),
|
|
68
|
+
form: defineResourceForm(records, { fields: ['title'] }),
|
|
69
|
+
detail: defineResourceForm(records, { fields: ['title'] }),
|
|
70
|
+
sections: [{ title: '登记信息', fields: ['title'] }],
|
|
71
|
+
generated: { delete: false },
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
model: records.code, code: 'complete', name: '完整管理',
|
|
75
|
+
form: defineResourceForm(records, { fields: ['title', 'enabled'] }),
|
|
76
|
+
sections: [{ title: '基本信息', fields: ['title'] }, { title: '管理设置', fields: ['enabled'] }],
|
|
77
|
+
},
|
|
78
|
+
]
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
使用 `adminResourcePage('records', { viewCode: 'quick' })` 绑定菜单。平台生成
|
|
82
|
+
`/admin/resources/records/views/quick`、`/new`、`/:id`、`/:id/edit` 和对应移动地址;
|
|
83
|
+
抽屉全屏、新开页面及提交后的返回地址都保留当前视图。每个模型最多 20 个命名视图,
|
|
84
|
+
`code` 必须唯一且为小写短横线格式。省略 `code` 的一套视图保留原地址;只声明命名视图时不额外生成默认页面。
|
|
85
|
+
|
|
86
|
+
命名新建表单必须包含模型中可写的必填字段。仅用于局部编辑的表单可声明
|
|
87
|
+
`generated: { create: false }`。`mobile: { enabled: false }` 关闭该视图的移动页面。
|
|
88
|
+
视图不能重定义字段类型、权限或写入归属,也不能用隐藏字段代替授权。
|
|
89
|
+
个人显示列设置和草稿按视图隔离;列设置仍可主动选取允许展示的其它字段。
|
|
90
|
+
此能力要求匹配的服务端校验和 `AddFormDraftViewScope` SQL 迁移。
|
|
91
|
+
|
|
92
|
+
## 字段与控件
|
|
93
|
+
|
|
94
|
+
标准 PC 管理页沿用一行工具栏和可折叠菜单。新增、编辑默认在抽屉中进行,保存后刷新原列表并保留当前筛选和页码;也可使用已有整页录入地址。筛选、显示列、排序按需打开。默认列来自选定的业务字段,创建、更新时间需主动选择。列选择、拖动顺序与冻结立即预览,点击工具栏“保存”后记住个人配置;多排序按规则顺序生效。
|
|
95
|
+
|
|
96
|
+
在 `crud` 视图上声明共享的表单/详情分组,不向存储模型添加布局:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
crud: [{
|
|
100
|
+
model: records.code,
|
|
101
|
+
form: defineResourceForm(records, { fields: ['title', 'enabled'] }),
|
|
102
|
+
sections: [
|
|
103
|
+
{ title: '基本信息', fields: ['title'] },
|
|
104
|
+
{ title: '使用设置', fields: ['enabled'] },
|
|
105
|
+
],
|
|
106
|
+
}]
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
分组只标记字段所属区域;表单/详情的 `fields` 仍决定展示集合及顺序,不会追加组内其它字段。普通小表单可省略分组。PC 每行最多两个普通字段,长文本、附件等复杂字段占整行;移动端使用单列。失败时保留输入并显示错误,未保存退出时提示确认。筛选可嵌套“满足全部/满足任一”,按字段类型提供运算符;查询、分页和导出使用同一条件树及多排序。批量扩展动作声明 `requiresSelection: true`,选择记录后才显示。
|
|
110
|
+
|
|
111
|
+
`hidden` 仅控制展示。`system` 表示由服务端维护,默认隐藏;业务需要展示的流水号、状态可显式 `hidden: false`。隐藏不会撤销 Data API 的读写授权;授权仍用现有字段 `access` 与行策略。普通必填字段不能从可新增表单中漏掉;内部必填值应有清晰的服务端赋值责任,不能靠隐藏字段绕过数据约束。
|
|
112
|
+
|
|
113
|
+
业务组件优先使用 `openxiangda/field-kit`,PC 补充使用 `antd`,移动端使用 `openxiangda/mobile` 封装的 Ant Design Mobile 控件。移动控件已覆盖文本、长文本、数字、布尔、静态选项、日期时间,以及人员/部门目录、动态资源引用和级联选择。选择弹层支持逐层浏览、搜索、翻页和已选项管理,点击确定才写回表单,关闭放弃本次修改。附件、图片、地址、子表和签名已提供移动交互,富文本在手机使用纯文本编辑并保留未修改 HTML;能力边界见[字段组件](./field-components.md)。共享值协议和表单控制器,不共享桌面弹层交互。
|
|
114
|
+
|
|
115
|
+
```tsx
|
|
116
|
+
import { MobileSurface, Input, Button } from 'openxiangda/mobile';
|
|
117
|
+
import 'openxiangda/mobile/styles.css';
|
|
118
|
+
|
|
119
|
+
// 在移动页面的最外层使用;标准 MobileSurfaceFieldControl 自带字段样式范围。
|
|
120
|
+
<MobileSurface>
|
|
121
|
+
<Input value={title} onChange={setTitle} aria-label="名称" />
|
|
122
|
+
<Button color="primary" onClick={save}>保存</Button>
|
|
123
|
+
</MobileSurface>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
平台按需加载移动组件,并在构建时限定上游基础样式的作用范围。此入口的 `Popup`、`Picker`、`DatePicker` 默认保留在当前页面中,保留组件样式作用范围。已有 `openxiangda/react/styles.css` 包含移动字段样式,不必重复导入。不要直接引入 `antd-mobile` 根入口,它会重置全页字体和链接。平台统一使用组件库默认外观,不再提供配色配置或外观偏好。
|
|
127
|
+
|
|
128
|
+
`openxiangda check` 检查应用前端 `src/` 中的原生录入元素。移动入口使用 `src/mobile/`、`Mobile*.tsx` 或 `*.mobile.tsx`,并检查其本地静态依赖;这是明确的源码约定,不是运行时授权或对动态代码的安全证明。平台组件内部的原生 DOM 不受应用规则限制。
|
|
129
|
+
|
|
130
|
+
## 开发与验收
|
|
131
|
+
|
|
132
|
+
普通 CRUD 可以省略 `backend`、`platform` 配置,`pnpm dev` 通过现有 connected development 连接平台。默认模板不包含后端源码;显式启用或声明需要应用代码执行的后端能力后,`pnpm openxiangda check` 或 `pnpm dev` 按需初始化源码与依赖,再启动 Nest。标准流程定义和激活由平台执行,不要求应用后端。
|
|
133
|
+
|
|
134
|
+
在现有 `appspec/app.md` 保留需求、任务页面、权限矩阵及验收记录。业务角色与权限由用户确认;技术 schema、接口和存储计划由平台产出。简单应用只维护这份短文档,复杂模块再拆分能力记录。
|
|
135
|
+
|
|
136
|
+
先读取 MCP 契约索引,再调用 `contract_describe` 并传入 `{ "selector": "permissions" }`,读取
|
|
137
|
+
`data.selection.permissionReview`。该产物使用 `openxiangda.permission-review/v2`,
|
|
138
|
+
`authority` 为 `declaration-projection`,并始终保留
|
|
139
|
+
`runtimeAuthorizationRequired: true`;`configDigest`、`contractDigest` 和
|
|
140
|
+
自身 `digest` 对应当前编译结果,便于在 appspec 中关联审核证据。
|
|
141
|
+
|
|
142
|
+
角色的 `capabilityCodes` 是编译后声明的能力集合,可通过能力代码关联页面、
|
|
143
|
+
资源操作和字段要求。运行时仍按当前用户的应用角色并集授权;
|
|
144
|
+
`deniedCapabilities` 只在编译时扣除该角色的 grant,不是跨角色的全局拒绝。
|
|
145
|
+
命名视图通过 `resourceCode` / `viewCode` 引用同一资源,字段策略只保存一次。
|
|
146
|
+
空字段策略显示为 `deny`,隐藏字段只代表展示选择。原始行谓词、scope 来源和
|
|
147
|
+
流程参与人绑定保留为待运行时求值的条件;静态能力匹配不代表真实请求允许。
|
|
148
|
+
该产物供审核使用,不写入角色、授权或另一份审批状态。
|
|
149
|
+
|
|
150
|
+
单元测试覆盖复杂业务规则、值转换和权限边界;接口测试覆盖存储、事务与策略;浏览器验收必须实际点击 PC/移动端的新增、选择、清空、保存、编辑和回显,并检查页面错误。组件模拟测试不等于已在远端真实业务环境验收。
|
|
151
|
+
|
|
152
|
+
## Alpha 应用迁移
|
|
153
|
+
|
|
154
|
+
依赖旧版“读权限自动附带写权限”的角色必须改成明确的 `manage` 或操作列表。原有 `data.resources` 可继续作为同一编译器的低层输入,按模块逐步拆分;不增加第二套资源存储。新增 `surface.fields.*.hidden` 与 `surface.list.fieldOrder` 需要配套平台版本,发布时必须固定匹配的服务端与工具链提交。
|
|
155
|
+
|
|
156
|
+
## 标准表单暂存
|
|
157
|
+
|
|
158
|
+
标准表单底部为“暂存 / 提交”。暂存允许必填项未完成,不写业务表、不启动流程;草稿箱可继续编辑或删除。草稿由平台当前用户、应用、环境和资源隔离,最多 20 份、90 天未更新过期。恢复编辑草稿保留原记录版本,提交仍检查冲突;正式提交与消耗草稿在同一 Data API 事务内完成。
|
|
159
|
+
|
|
160
|
+
PC 抽屉提供“全屏 / 新开页面 / 关闭”。全屏保留当前表单;新开页面先暂存,再通过草稿 ID 恢复,内容不放入 URL。移动录入使用平台移动字段的分组行式布局、简单标题和底部操作,不放“返回列表”或桌面输入控件;草稿箱和恢复确认使用底部弹层。
|
|
161
|
+
|
|
162
|
+
自定义表单可从 `openxiangda/react` 使用 `createResourceFormDraftClient(resourceCode, mode, recordId?, viewCode?)`,提供 `list/save/remove/submit`。命名视图只能恢复和提交属于当前视图的草稿;所有视图仍共用每人每个模型 20 份的上限。`save` 使用草稿 ID、expectedRevision 和可编辑字段值;`submit` 消费现有 DataTransactionOperation,不另建 CRUD 后端。此能力需要平台的 authenticated-form-drafts SQL 迁移及对应服务端版本,平台未升级时界面会明确显示暂存失败并保留输入。
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# AppSpec:轻量业务活规格
|
|
2
|
+
|
|
3
|
+
AppSpec 是 OpenXiangda 2.0 应用的可选辅助层:把当前业务目标、稳定需求、验收场景和本次变化
|
|
4
|
+
放在 Git 中,让人和 AI 都能先理解意图,再修改实现。它不参与 AppPackage,不改变平台协议,
|
|
5
|
+
也不会成为 `dev/check/deploy` 的发布门禁。
|
|
6
|
+
|
|
7
|
+
AppSpec 仅面向 2.0。工具不会读取、识别、导入或迁移 1.x 的 `openspec/`、SDD、表单、页面、
|
|
8
|
+
函数或发布记录。
|
|
9
|
+
|
|
10
|
+
## 最小结构
|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
appspec/
|
|
14
|
+
app.md
|
|
15
|
+
capabilities/ # 按需
|
|
16
|
+
changes/active/ # 按需
|
|
17
|
+
changes/history/ # close 时生成
|
|
18
|
+
decisions/ # 只有架构决定才需要
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
新应用默认只有一份简短 `app.md`。普通的小改动不需要补齐多份 proposal、design、tasks 和 evidence。
|
|
22
|
+
|
|
23
|
+
启用 AppSpec 后,按变化风险选择需要保留的记录:
|
|
24
|
+
|
|
25
|
+
| 风险 | 维护方式 |
|
|
26
|
+
| --- | --- |
|
|
27
|
+
| L0:没有行为变化 | 不创建记录 |
|
|
28
|
+
| L1:局部行为变化 | 一份短 ChangeSpec |
|
|
29
|
+
| L2:跨资源、权限或状态变化 | 增加正反验收、数据影响和回滚 |
|
|
30
|
+
| L3:身份、迁移、并发或外部副作用 | 再增加失败/幂等、资源边界和 ADR |
|
|
31
|
+
|
|
32
|
+
## 命令
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# 在旧的 2.0 应用中按需启用;新模板已经包含 app.md
|
|
36
|
+
pnpm openxiangda spec init
|
|
37
|
+
|
|
38
|
+
# 长期能力与稳定需求
|
|
39
|
+
pnpm openxiangda spec add-capability CAP-BOOKING \
|
|
40
|
+
--title "预约管理" --resources bookings
|
|
41
|
+
|
|
42
|
+
# 本次变化,默认 L1
|
|
43
|
+
pnpm openxiangda spec new booking-window \
|
|
44
|
+
--title "限制可预约时段" \
|
|
45
|
+
--capabilities CAP-BOOKING \
|
|
46
|
+
--resources bookings
|
|
47
|
+
|
|
48
|
+
# 给人或 AI 读取相关的当前上下文
|
|
49
|
+
pnpm openxiangda spec context booking-window --json
|
|
50
|
+
|
|
51
|
+
# 主动执行严格文档检查;普通应用 check 仍不被 AppSpec 阻断
|
|
52
|
+
pnpm openxiangda spec check
|
|
53
|
+
|
|
54
|
+
# 完成后归档;根据已确认业务意图记录长期内容已合入当前规格,平台发布状态仍由 DeploymentRun 负责
|
|
55
|
+
pnpm openxiangda spec close booking-window \
|
|
56
|
+
--current-spec merged \
|
|
57
|
+
--summary "已通过真实角色验收"
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
AI-native 客户端可以读取 `openxiangda://workspace/appspec` 或调用 `appspec_context`。AppSpec
|
|
61
|
+
有格式或引用问题时,这两个入口返回 advisory;只有显式 `spec check` 把确定性结构问题作为失败。
|
|
62
|
+
|
|
63
|
+
不传 selector 时,context v2 只返回应用总纲正文与能力、活跃变更、ADR、历史变更的有界索引;AI
|
|
64
|
+
再用稳定 capability/change/ADR ID 读取相关正文。历史变更 ID 也可直接选择。相关正文最多返回 256 KiB,
|
|
65
|
+
超出预算的文档仍保留在索引并给出 warning。`workspaceDigest` 标识全部 AppSpec 与实时合同,
|
|
66
|
+
`selectionDigest` 只标识应用总纲、当前 selector 的相关正文和实时合同。
|
|
67
|
+
|
|
68
|
+
每份新 ChangeSpec 都以 `currentSpec: pending` 开始。关闭前根据已确认的业务意图与实际完成情况记录:
|
|
69
|
+
|
|
70
|
+
- `merged`:仍然有效的 ADDED/MODIFIED/REMOVED 结果已经进入 `app.md` 或 CapabilitySpec;
|
|
71
|
+
- `not-applicable`:本次变化不改变长期业务规格。
|
|
72
|
+
|
|
73
|
+
AI 可在既有授权范围内整理和归档;业务意图不明确时先澄清。`spec close` 只约束 AppSpec 归档;它不会成为普通
|
|
74
|
+
`check/dev/deploy` 门禁。L2/L3 的必需章节如果为空或仍是默认占位内容,显式 `spec check`/`spec close`
|
|
75
|
+
失败,普通应用检查仍只显示 warning。
|
|
76
|
+
|
|
77
|
+
## 事实边界
|
|
78
|
+
|
|
79
|
+
- AppSpec:业务意图、当前有效需求、可观察验收和变更原因。
|
|
80
|
+
- `openxiangda.config.ts`:资源、字段、页面、权限、动作和模块声明。
|
|
81
|
+
- 编译合同与代码:实际技术行为。
|
|
82
|
+
- 测试和验收证据:实现是否真的符合需求。
|
|
83
|
+
- 平台:版本、部署、环境和运行状态。
|
|
84
|
+
|
|
85
|
+
如果 AppSpec 与实时合同冲突,工具会指出冲突,但不会让普通构建失败。先核对已确认的业务意图,再
|
|
86
|
+
修改 AppSpec 或实现;不要让 AI 静默选择其中一边。
|
|
87
|
+
|
|
88
|
+
## 能否只凭最终文档重建应用
|
|
89
|
+
|
|
90
|
+
可以较高程度复现业务规则和页面流程,但不能保证像素、性能、外部系统细节和历史缺陷完全一致。
|
|
91
|
+
最可靠的“可重建包”是:当前 AppSpec + `openxiangda.config.ts` + 必要自定义动作 + 测试 + 外部接口
|
|
92
|
+
合同。关闭后的历史 ChangeSpec 主要解释演进原因,新项目通常只需当前规格。
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# NestJS 后端
|
|
2
|
+
|
|
3
|
+
默认模板只包含 Web 和共享契约。只有需要执行服务端业务动作时才增加 NestJS。记录列表、详情、新增、编辑和删除直接由浏览器调用平台 Data API,不在 controller 中重写一遍。
|
|
4
|
+
|
|
5
|
+
平台网关验证当前用户完整的应用角色并集,并把经平台重验的角色、capability 与可选 Perspective 交给 Nest SDK。业务 controller 使用生成的 operation 合同和 capability 装饰器;平台仍是身份与授权的唯一所有者。请求作用域 `OpenXiangdaDataApiService` 自动继承 Perspective 读取投影;绕过 Data API 的自定义读取才使用 `@CurrentPerspective()` 显式投影。应用代码不替换身份、不保存平台凭据,也不建立第二套用户或权限状态。
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm openxiangda dev
|
|
9
|
+
pnpm openxiangda check
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
在 `openxiangda.config.ts` 声明 `backend: { enabled: true }`,或添加需要执行应用代码的
|
|
13
|
+
operation、事件消费者、人员提供器,然后运行 `pnpm openxiangda check` 或 `pnpm dev`。
|
|
14
|
+
工具从当前版本的内置模板初始化后端源码并安装依赖;后续不会覆盖业务代码。
|
|
15
|
+
标准表单、流程定义/激活和平台待办通知使用平台运行时,不会隐式启用 Nest。
|
|
16
|
+
|
|
17
|
+
依赖安装失败会保留新源码并报告 `OPENXIANGDA_BACKEND_INSTALL_FAILED`;重试相同命令
|
|
18
|
+
即可继续。关闭 backend 不自动删除用户源码。仅删除已经确认不用的后端目录和其依赖。
|
|
19
|
+
本地 `/api` 经过 connected proxy 进入 Nest;发布态由同源应用网关转发。
|
|
20
|
+
|
|
21
|
+
| 需求 | 使用的 SDK | 权威边界 |
|
|
22
|
+
| --- | --- | --- |
|
|
23
|
+
| 当前用户与角色并集 | `@CurrentUser()` | 网关验证结果,业务不管理凭据 |
|
|
24
|
+
| 当前用户范围的数据 | `OpenXiangdaDataApiService` | 平台行/字段权限和读取 Perspective |
|
|
25
|
+
| 已授权业务动作的跨模型读写 | `OpenXiangdaBusinessDataApiService` | 声明的 operation;平台保留发起人审计 |
|
|
26
|
+
| 原子写入与幂等回执 | `.transaction(idempotentTransaction(...))` | 同一平台事务,不读后再写 |
|
|
27
|
+
| 托管文件 | Data SDK 的 `initiateFileUpload` / `completeFileUpload` / `copyManagedFile` | 平台文件归属和操作授权 |
|
|
28
|
+
| 标准流程 | `OpenXiangdaWorkflowService`;带业务提交用 `OpenXiangdaBusinessProcessService` | 平台命令 token、版本和回执 |
|
|
29
|
+
| 当前用户待办 | `OpenXiangdaTodoService` | 平台投影,不另建待办表 |
|
|
30
|
+
| 通知 | `OpenXiangdaBusinessNotificationService` | 平台收件人、通道、投递和幂等 |
|
|
31
|
+
| 域事件 | 事务 `emitEvent` / `@OpenXiangdaEventHandler` | 平台 outbox 与消费回执 |
|
|
32
|
+
| 请求和动作日志 | `OpenXiangdaLoggerService`、`OpenXiangdaPlatformError.request` | Nest 日志输出和平台请求关联 |
|
|
33
|
+
|
|
34
|
+
下方代码是接入片段,模型与角色需要在应用中显式声明。独立的完整示例由工具链维护者在新建应用中做打包验收。
|
|
35
|
+
|
|
36
|
+
自定义 operation 的 capability 必须先在 `authz.capabilities` 以
|
|
37
|
+
`kind: 'backend'` 声明,再由 operation 和允许调用它的角色共同引用。普通资源 CRUD
|
|
38
|
+
能力仍由编译器生成,不写入显式 capability catalog。
|
|
39
|
+
|
|
40
|
+
访客重复预约统一使用 `OpenXiangdaStandardOperations.createVisitorReservation`。
|
|
41
|
+
`duplicateMatch` 是字段代码到本次提交值的非空对象,不是字段名数组;它与 `data`
|
|
42
|
+
必须来自同一个不可变请求,并连同 `idempotencyKey` 一次提交给平台事务。应用不先查
|
|
43
|
+
重、不自行加锁、不在重试时重新生成业务时间。
|
|
44
|
+
|
|
45
|
+
只读前置条件使用 `record-exists` 或 `record-match`,它们不要求同记录 mutation,
|
|
46
|
+
但仍执行 read capability、字段权限与行级授权。需要与数据库当前时间比较时使用
|
|
47
|
+
`databaseNowAssertion('publishAt', 'lte')`;平台用一次 PostgreSQL transaction time
|
|
48
|
+
完成所有断言,并把该时间作为 `evaluatedAt` 存入幂等回执。相同幂等键重放不会重新
|
|
49
|
+
读取当前时间。不得把 `Date.now()`、SQL 表达式、时区偏移或调用方时钟塞入断言。
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
## 业务动作与普通查询 {#business-action}
|
|
53
|
+
|
|
54
|
+
`OpenXiangdaDataApiService` 按当前用户的普通资源、行和字段权限执行。具名业务动作使用 `OpenXiangdaBusinessDataApiService`:入口先检查该动作 capability,平台在精确应用和环境内以受信任后端执行,并保留发起人与动作审计。业务动作不能接受任意模型/字段/用户 ID 后不做业务校验;应用负责该动作的输入约束和业务不变量。
|
|
55
|
+
|
|
56
|
+
同一业务变更用一次受限事务表达。断言、派生计数、写入和事件保持原子性;遇到可重试响应时复用不可变 payload 和 idempotencyKey,不先读取可变状态再决定写入。
|
|
57
|
+
|
|
58
|
+
## 启动与依赖注入 {#bootstrap}
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import 'reflect-metadata';
|
|
62
|
+
import { bootstrapOpenXiangdaApplication } from 'openxiangda/nest';
|
|
63
|
+
import { AppModule } from './app.module.js';
|
|
64
|
+
await bootstrapOpenXiangdaApplication(AppModule);
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
使用标准启动器保留原始请求体校验、代理信任和关闭处理。可注入依赖使用明确的 Nest 注入 token/装饰器,遵循生成后端的现有模式;不另建网关身份验证或自行转发授权 JSON。请求关联使用平台传入的 request ID。
|
|
68
|
+
|
|
69
|
+
## 通知与事件 {#notifications}
|
|
70
|
+
|
|
71
|
+
具名用户动作发送通知使用 `OpenXiangdaBusinessNotificationService.send()`,携带稳定 eventId、messageKey、sourceSequence 和 idempotencyKey。重放同一事件返回已有消息;同一 messageKey 的更高序列用于收敛状态。通知目标使用声明的 PC/移动路由代码及参数,不拼接环境域名或身份凭据。
|
|
72
|
+
|
|
73
|
+
签名事件处理器使用 `sendFromEvent()`,在声明中指定事件 data 内的收件人与文案路径,由平台验证不可变事件后解析。普通业务动作不需要平台通知管理权限。需要高级钉钉卡片时才使用已授权的管理服务和已启用通道,不能把它设为普通审批的默认依赖。
|
|
74
|
+
|
|
75
|
+
通知协议常量也从同一个公开入口导入:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import {
|
|
79
|
+
OpenXiangdaBusinessNotificationService,
|
|
80
|
+
OPENXIANGDA_NOTIFICATION_BUSINESS_SEND_V2,
|
|
81
|
+
OPENXIANGDA_NOTIFICATION_EVENT_SEND_V2,
|
|
82
|
+
} from 'openxiangda/nest';
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
用户动作 send 的 schemaVersion 使用 OPENXIANGDA_NOTIFICATION_BUSINESS_SEND_V2;事件处理 sendFromEvent 使用 OPENXIANGDA_NOTIFICATION_EVENT_SEND_V2。二者的调用上下文和收件人来源不同,不能混用。
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# 核心架构
|
|
2
|
+
|
|
3
|
+
```mermaid
|
|
4
|
+
flowchart LR
|
|
5
|
+
Repo["应用 Git 仓库"] --> CI["项目 CLI / MCP"]
|
|
6
|
+
CI --> Package["不可变 AppPackage"]
|
|
7
|
+
Package --> Control["平台控制面"]
|
|
8
|
+
Control --> Deploy["DeploymentRun"]
|
|
9
|
+
Deploy --> Web["前端静态包"]
|
|
10
|
+
Deploy --> Backend["按需启用的 NestJS 容器"]
|
|
11
|
+
Deploy --> Config["Data/AuthZ/Workflow/Event 配置版本"]
|
|
12
|
+
Backend --> Data["统一 Data API"]
|
|
13
|
+
Backend --> Kernel["Workflow Kernel v2"]
|
|
14
|
+
Backend --> Events["事件投递服务"]
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 工程边界
|
|
18
|
+
|
|
19
|
+
- Git 仓库是应用源码与声明的事实来源。
|
|
20
|
+
- AppPackage 是交付边界,包含前端摘要、后端镜像摘要、配置包摘要和契约版本。
|
|
21
|
+
- 平台是运行状态的事实来源,持久保存应用版本、部署运行、检查点与环境激活状态。
|
|
22
|
+
- AI、CLI、MCP 都是控制面客户端,不负责持有发布状态。
|
|
23
|
+
|
|
24
|
+
## 运行档位
|
|
25
|
+
|
|
26
|
+
纯 CRUD 和标准审批无需应用后端。需要后端时使用平台可控的运行方式:每应用独立容器,共享 Kubernetes 集群、节点池、网关和可观测基础设施。后续可以用资源配额形成共享档与独享档,但不建设多应用共用 Node 进程。
|
|
27
|
+
|
|
28
|
+
## 数据边界
|
|
29
|
+
|
|
30
|
+
首期不为应用创建独立数据库。业务后端通过统一 Data API 访问平台数据;Data API 提供资源化查询、字段策略、行级授权、并发修订和受限事务批处理。这样保留统一治理,又不限制应用后端表达业务逻辑。
|
|
31
|
+
|
|
32
|
+
应用后端声明具名 Operation 时,不应重新手写用户、部门、资源引用和文件字段协议。`openxiangda/config` 提供 `resourceRecordSchema`、`schemaRef`、`composeJsonSchema` 和 `composeAppOperationSchemas`:它们从同一 Resource declaration 和公共 `FIELD_VALUE_SCHEMAS` 投影请求/响应 JSON Schema,只允许有界的本地 `$defs`/`$ref`,不会改变 Data API、权限或业务事务 owner。
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import {
|
|
36
|
+
composeAppOperationSchemas,
|
|
37
|
+
resourceRecordSchema,
|
|
38
|
+
schemaRef,
|
|
39
|
+
} from 'openxiangda/config';
|
|
40
|
+
|
|
41
|
+
const schemas = composeAppOperationSchemas({
|
|
42
|
+
request: {
|
|
43
|
+
type: 'object',
|
|
44
|
+
additionalProperties: false,
|
|
45
|
+
required: ['record'],
|
|
46
|
+
properties: { record: schemaRef('InstrumentRecord') },
|
|
47
|
+
},
|
|
48
|
+
response: schemaRef('InstrumentRecord'),
|
|
49
|
+
definitions: {
|
|
50
|
+
InstrumentRecord: resourceRecordSchema(instruments, {
|
|
51
|
+
fields: ['name', 'owner'],
|
|
52
|
+
}),
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## 版本列车
|
|
58
|
+
|
|
59
|
+
OpenXiangda 2.0 使用兼容版本列车,而不是要求所有 npm 包共享同一个版本号。各包按职责独立递增;应用只直接安装精确版本的 `openxiangda` 根包并提交锁文件,内部物理依赖由根包确定,不能使用范围或 `latest`。AppPackage 记录 AppPackage、configuration bundle、contract bundle 和 compiler contract 的原子兼容四元组;平台通过唯一的 `capabilities.configurationCompatibility` 契约声明完整可接受组合、验证端点与 validator 能力版本。CLI 必须把真实生成的 configuration/contract bundle 交给目标平台只读预检,并在应用生产构建、后端镜像构建和制品上传前拒绝不兼容组合;平台部署准备阶段继续权威复验,不允许删字段或向下协商。
|
|
60
|
+
|
|
61
|
+
AppPackage 的 `compatibility.requiredPlatformCapabilities` 也是 compiler 输出:每项固定包含 `code`、`contractVersion` 和只覆盖该能力相关规范化声明的 `usageDigest`。平台 `features[code]` 必须处于 `available` 且 `contractVersion` 精确相等;`preview`、缺失或版本不同都不能部署。应用配置没有 `platform.requiredCapabilities`,构建 API 也没有追加入口;不得手改 AppPackage 或用字符串能力名绕过 compiler。摘要不包含运行期业务数据或 secret 值,平台部署准备仍须根据原始 config/contract bytes 权威重算。CLI、MCP、Skills 和文档随相关包变更发布,不因无关包升级而强制全量重发。
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Data API 与权限
|
|
2
|
+
|
|
3
|
+
授权由四层组成:页面/操作 capability、行谓词、字段 read,以及字段 create/update。前端只消费平台返回的最终访问结果来隐藏按钮、只读输入和剔除 payload;平台每次请求重新执行权威校验。
|
|
4
|
+
|
|
5
|
+
以下仅以仪器管理应用举例,不是平台默认模型或角色。该示例的行规则是:学校管理员不受行谓词限制;学院管理员按记录 `collegeId` 匹配;仪器管理员按 `instrumentAdminIds` 包含当前用户匹配。不要增加影子范围字段。
|
|
6
|
+
|
|
7
|
+
`collegeId` 是应用 `colleges` Native Resource 的记录 UUID。学院 scope dimension 通过
|
|
8
|
+
`valueSource.kind=native_resource` 绑定同一资源,选择器只展示平台按当前 membership 与
|
|
9
|
+
create/update 闭包返回的值。人员和部门保存平台目录真实 ID;部门不等于学院,也不能作为
|
|
10
|
+
学院范围的隐式来源。
|
|
11
|
+
|
|
12
|
+
字段策略支持 `read`、`create`、`update` 和 `mask`。显式空数组拒绝,能力数组采用 all-of。无权更新字段不仅 disabled,还必须从更新 payload 删除。
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pnpm openxiangda check
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
角色成员、维度授权和平台管理员由平台管理面维护,不属于应用开发 CLI。
|
|
19
|
+
|
|
20
|
+
自定义 PC/移动页面需要维护当前应用角色时,使用
|
|
21
|
+
`openxiangda/core` 的 `loadRoleManagementCatalog`、
|
|
22
|
+
`listRoleMemberships`、`searchRoleManagementUsers`、成员 mutation 与
|
|
23
|
+
role-management-grant mutation。应用/平台超级管理员可以把全部角色或明确的
|
|
24
|
+
目标角色集合委托给一个业务角色;普通业务管理者只有同时具备
|
|
25
|
+
`management.delegate` 时,才能把自己已有的目标角色和动作子集继续委托。
|
|
26
|
+
平台按当前用户角色并集重算,接口不接受 actor、tenant、active role 或
|
|
27
|
+
impersonation token。mutation 必须携带 UUID `operationId`、`reason`,更新/撤销还必须
|
|
28
|
+
携带最新 `expectedRevision`;409 后重新加载,不能猜 revision。使用前读取当前角色管理目录,详见[管理入口](./administration.md)。
|
|
29
|
+
|
|
30
|
+
匿名外部访问不属于 RBAC 角色或 current-user 行策略。公开表单、续填、附件、重复校验和同一
|
|
31
|
+
浏览器的本人记录访问只通过[`frontend.publicAccess` 专用合同](./public-access.md)开放;平台继续在
|
|
32
|
+
专用端点和 PostgreSQL/RLS 中强制匿名主体、字段、策略及提交回执边界。
|
|
33
|
+
|
|
34
|
+
数值边界直接声明在字段上,`min`/`max` 为闭区间,并且只允许用于
|
|
35
|
+
`number.integer` 和 `number.decimal`。跨字段约束声明在资源的
|
|
36
|
+
`invariants` 中;每条约束只能比较同一记录的两个已声明字段,最多 20 条,
|
|
37
|
+
由平台在 create/update/increment 的最终候选记录上统一执行。
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
{
|
|
41
|
+
code: 'sessions',
|
|
42
|
+
name: '场次',
|
|
43
|
+
fields: [
|
|
44
|
+
{ code: 'startAt', type: 'datetime', label: '开始', required: true },
|
|
45
|
+
{ code: 'endAt', type: 'datetime', label: '结束', required: true },
|
|
46
|
+
{ code: 'capacity', type: 'number.integer', label: '容量', min: 0 },
|
|
47
|
+
{ code: 'occupied', type: 'number.integer', label: '已占用', min: 0 },
|
|
48
|
+
],
|
|
49
|
+
invariants: [
|
|
50
|
+
{ code: 'time-order', expression: { leftField: 'startAt', operator: 'lt', rightField: 'endAt' } },
|
|
51
|
+
{ code: 'capacity-not-exceeded', expression: { leftField: 'capacity', operator: 'gte', rightField: 'occupied' } },
|
|
52
|
+
],
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`date-range` 与 `datetime-range` 必须显式声明 `rangeBoundary`,取值为 closed 或 half-open。选择半开区间 `[start, end)` 时相邻时间段不冲突;闭区间端点相接可能重叠。
|
|
57
|
+
|
|
58
|
+
业务 uuid 字段与系统 id 不同:可选业务 UUID 省略时为空,必填字段需调用方提供合法值,平台不会替业务 UUID 自动生成默认值。
|