openxiangda 2.0.0-alpha.99 → 2.0.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.
- package/LICENSE +21 -0
- package/README.md +23 -20
- package/bin/distribution/commands.js +55 -0
- package/bin/distribution/launcher.js +49 -0
- package/bin/distribution/migrate.js +60 -0
- package/bin/distribution/releases.js +52 -0
- package/bin/distribution/skills.js +80 -0
- package/bin/distribution/update.js +68 -0
- package/bin/distribution/workspace.js +85 -0
- package/bin/run.js +9 -11
- package/dist/browser/AuthoritativeSelector.d.ts +3 -2
- package/dist/browser/AuthoritativeSelector.d.ts.map +1 -1
- package/dist/browser/AuthoritativeSelector.js +39 -24
- package/dist/browser/AuthoritativeSelector.js.map +1 -1
- package/dist/browser/components/platform-fields/MobileFieldControls.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/MobileFieldControls.js +2 -2
- package/dist/browser/components/platform-fields/MobileFieldControls.js.map +1 -1
- package/dist/browser/components/platform-fields/ResourceReferenceField.d.ts +4 -2
- package/dist/browser/components/platform-fields/ResourceReferenceField.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/ResourceReferenceField.js +2 -2
- package/dist/browser/components/platform-fields/ResourceReferenceField.js.map +1 -1
- package/dist/browser/components/platform-fields/rich-text-value.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/rich-text-value.js +11 -1
- package/dist/browser/components/platform-fields/rich-text-value.js.map +1 -1
- package/dist/browser/components/resource/RecordDetailFrame.js +1 -1
- package/dist/browser/components/resource/RecordDetailFrame.js.map +1 -1
- package/dist/browser/components/resource/SurfaceFields.d.ts +3 -2
- package/dist/browser/components/resource/SurfaceFields.d.ts.map +1 -1
- package/dist/browser/components/resource/SurfaceFields.js +14 -7
- package/dist/browser/components/resource/SurfaceFields.js.map +1 -1
- package/dist/browser/components/resource/resource-import.d.ts +16 -1
- package/dist/browser/components/resource/resource-import.d.ts.map +1 -1
- package/dist/browser/components/resource/resource-import.js +58 -34
- package/dist/browser/components/resource/resource-import.js.map +1 -1
- package/dist/browser/components/resource/useResourceFormDrafts.d.ts.map +1 -1
- package/dist/browser/components/todo/ApplicationTodoCenterPage.d.ts.map +1 -1
- package/dist/browser/components/todo/ApplicationTodoCenterPage.js +1 -2
- package/dist/browser/components/todo/ApplicationTodoCenterPage.js.map +1 -1
- package/dist/browser/components/workflow/StandardWorkflowPages.d.ts.map +1 -1
- package/dist/browser/components/workflow/StandardWorkflowPages.js +54 -52
- package/dist/browser/components/workflow/StandardWorkflowPages.js.map +1 -1
- package/dist/browser/platform-client.d.ts +3 -2
- package/dist/browser/platform-client.d.ts.map +1 -1
- package/dist/browser/platform-client.js +69 -18
- package/dist/browser/platform-client.js.map +1 -1
- package/dist/browser/record-detail.css +3 -2
- package/dist/browser/runtime.d.ts.map +1 -1
- package/dist/browser/runtime.js +26 -2
- package/dist/browser/runtime.js.map +1 -1
- package/dist/browser/workflow-launch.d.ts +4 -1
- package/dist/browser/workflow-launch.d.ts.map +1 -1
- package/dist/browser/workflow-launch.js +32 -0
- package/dist/browser/workflow-launch.js.map +1 -1
- package/dist/core.d.ts +1 -1
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js.map +1 -1
- package/documentation/AGENTS.md +26 -0
- package/documentation/administration.md +27 -0
- package/documentation/application-foundation.md +162 -0
- package/documentation/appspec.md +152 -0
- package/documentation/backend.md +132 -0
- package/documentation/concepts.md +61 -0
- package/documentation/data-authz.md +62 -0
- package/documentation/delivery.md +110 -0
- package/documentation/development.md +32 -0
- package/documentation/field-components.md +236 -0
- package/documentation/frontend.md +269 -0
- package/documentation/getting-started.md +66 -0
- package/documentation/interaction-patterns.md +56 -0
- package/documentation/manifest.json +120 -0
- package/documentation/product-design.md +142 -0
- package/documentation/public-access.md +167 -0
- package/documentation/reference/cli.md +27 -0
- package/documentation/reference/mcp.md +649 -0
- package/documentation/testing.md +63 -0
- package/documentation/upgrading.md +39 -0
- package/documentation/workflow-events.md +181 -0
- package/launcher-skill/openxiangda/SKILL.md +24 -0
- package/package.json +72 -9
- package/releases/2.0.0.json +50 -0
- package/skills/manifest.json +2 -2
- package/skills/openxiangda-v2/SKILL.md +64 -51
- 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 +132 -47
- package/skills/openxiangda-v2/references/backend.md +101 -248
- package/skills/openxiangda-v2/references/cli.md +27 -0
- package/skills/openxiangda-v2/references/concepts.md +61 -0
- package/skills/openxiangda-v2/references/data-authz.md +36 -388
- package/skills/openxiangda-v2/references/delivery.md +110 -49
- package/skills/openxiangda-v2/references/development.md +32 -0
- package/skills/openxiangda-v2/references/field-components.md +236 -0
- package/skills/openxiangda-v2/references/frontend.md +254 -280
- package/skills/openxiangda-v2/references/getting-started.md +66 -0
- package/skills/openxiangda-v2/references/interaction-patterns.md +56 -0
- package/skills/openxiangda-v2/references/mcp.md +649 -0
- package/skills/openxiangda-v2/references/product-design.md +142 -0
- package/skills/openxiangda-v2/references/public-access.md +92 -84
- package/skills/openxiangda-v2/references/testing.md +45 -56
- package/skills/openxiangda-v2/references/upgrading.md +39 -0
- package/skills/openxiangda-v2/references/workflow-events.md +143 -285
- package/skills/openxiangda-v2/references/architecture.md +0 -9
- package/skills/openxiangda-v2/references/commands.md +0 -21
- package/skills/openxiangda-v2/references/discovery.md +0 -15
- package/skills/openxiangda-v2/references/workspace.md +0 -62
|
@@ -1,295 +1,269 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
Read [Data and authorization](data-authz.md) for every resource or permission
|
|
4
|
-
change and keep the generated [workspace contract](workspace.md) authoritative.
|
|
5
|
-
|
|
6
|
-
Use the official Vite + React Router + Refine Core + Ant Design template. Import the platform-owned runtime from `openxiangda/react`, field controls from `openxiangda/field-kit` and clients/types from `openxiangda/core`. Do not copy these implementations into application source and do not add per-resource function wrappers.
|
|
7
|
-
|
|
8
|
-
Generated desktop lists already own row selection, atomic batch update/delete,
|
|
9
|
-
CSV/XLS/XLSX preview import, export, filters, column settings and density. Keep
|
|
10
|
-
imports at 100 rows per transaction, use exact declared labels or field codes,
|
|
11
|
-
and leave attachment values to the platform managed-file component.
|
|
12
|
-
|
|
13
|
-
Declare searchable and filterable fields on the resource and let the standard
|
|
14
|
-
CRUD renderer compose one toolbar. Keyword search spans the declared searchable
|
|
15
|
-
fields; all declared filters open on demand in the platform modal. Business
|
|
16
|
-
columns are the default; audit columns and density are optional list settings.
|
|
17
|
-
Desktop create/edit opens a drawer over the retained list; existing full-page
|
|
18
|
-
routes use the same form lifecycle. The renderer retains values after failed
|
|
19
|
-
saves, prevents repeated submission and asks before discarding an edited form.
|
|
20
|
-
Declare shared form/detail groups in `crud[].sections` with `title` and `fields`.
|
|
21
|
-
Form/detail field selections remain exhaustive and ordered. Use lightweight
|
|
22
|
-
section headings, two ordinary columns on PC and one on mobile; small forms
|
|
23
|
-
need no artificial group. Do not copy a list/form renderer or add application
|
|
24
|
-
search toolbars, field ordering maps or authorization/debug explanations.
|
|
25
|
-
|
|
26
|
-
Read the current user, complete application-role union and capabilities from the platform runtime authorization endpoint. There is no application-selected active role or identity switch. The standard Shell owns the optional Perspective selector. Use `hasReadCapability` for navigation, list/detail visibility and readable fields; continue to use `hasCapability` for create/update/delete, workflows and custom actions. The standard client sends the selected Perspective automatically, and the server repeats the projection for rows, fields and RLS. Never implement resource-specific frontend filters for it. Strip unauthorized fields from create and update payloads and never treat a disabled input as server authorization. Verify with `pnpm openxiangda check`.
|
|
27
|
-
|
|
28
|
-
Use the standard `Shell` unchanged. It owns the authenticated user's display
|
|
29
|
-
name, account identifier, safe avatar upload, localized application-role names,
|
|
30
|
-
Perspective selection, collapsible menu groups and navigation scroll restoration. It
|
|
31
|
-
also owns directory field requests under the current logged-in user's role
|
|
32
|
-
union. Never fetch identity for the header, display role codes, add a second
|
|
33
|
-
identity selector, or copy Shell and
|
|
34
|
-
directory-client implementations into application source.
|
|
35
|
-
|
|
36
|
-
For a custom application role-management page, use only the typed functions in
|
|
37
|
-
`openxiangda/core`: `loadRoleManagementCatalog`, `listRoleMemberships`,
|
|
38
|
-
`searchRoleManagementUsers`, the membership mutations, and the
|
|
39
|
-
role-management-grant mutations. The catalog's `roleManagement` projection
|
|
40
|
-
drives button visibility, while the platform repeats the check for every
|
|
41
|
-
request. The “Custom role-management pages” section in
|
|
42
|
-
[Data and authorization](data-authz.md) defines the delegation and CAS
|
|
43
|
-
contract. Do not use the developer control-plane client in browser code.
|
|
44
|
-
|
|
45
|
-
The application owns the editable admin information architecture through the
|
|
46
|
-
typed `defineAdminNavigation`, `adminNavigationGroup`, `adminResourcePage`,
|
|
47
|
-
and `adminOperationPage` helpers in `openxiangda/config`. The compiler emits
|
|
48
|
-
all reachable `adminPages`, but the Shell renders only pages explicitly
|
|
49
|
-
referenced by generated `adminNavigation`, then applies current-user access as
|
|
50
|
-
a final filter. Page existence, route reachability and menu visibility are
|
|
51
|
-
separate: detail/new/edit/dynamic/handoff pages never become menu entries by
|
|
52
|
-
discovery, and permission logic cannot create entries. Read
|
|
53
|
-
`openxiangda://workspace/contracts` or call `contract_describe`, then copy
|
|
54
|
-
`data.adminNavigationAuthoring.suggestion.expression` once into
|
|
55
|
-
`frontend.admin.navigation` with the listed `openxiangda/config` imports. The
|
|
56
|
-
proposal is deterministic and editable; the compiler/runtime never invokes it
|
|
57
|
-
or appends newly added resources later.
|
|
58
|
-
|
|
59
|
-
Generated desktop resource CRUD routes use the compiler-owned
|
|
60
|
-
`/admin/resources/<resourceCode>...` namespace and always render inside the
|
|
61
|
-
platform's one Shell. Their independent mobile admin surface is projected from
|
|
62
|
-
the same generated route catalog under `/m/admin/resources/<resourceCode>...`.
|
|
63
|
-
Generated pages consume that catalog for every list/create/detail/edit/back
|
|
64
|
-
navigation; do not reconstruct root resource paths in application code. Root
|
|
65
|
-
and ordinary `/m/...` paths remain available to explicit user routes. The
|
|
66
|
-
compiler rejects an explicit route whose canonical path shape conflicts with
|
|
67
|
-
any explicit or platform-generated route, including dynamic routes that differ
|
|
68
|
-
only by parameter name. Do not add aliases, redirects or route-order branches
|
|
69
|
-
for earlier alpha paths.
|
|
70
|
-
|
|
71
|
-
Declare the application-wide admin boundary at `frontend.admin.access` with
|
|
72
|
-
`allOf` and/or `anyOf` capability arrays. Import generated `adminAccess` and
|
|
73
|
-
pass it to `OpenXiangdaApplication`; the runtime evaluates that same immutable
|
|
74
|
-
expression before `/admin/**`, `/m/admin/**`, the Shell, generated resources or
|
|
75
|
-
admin contribution pages mount. Portal shortcuts may use the exported pure
|
|
76
|
-
`isAdminAccessAllowed` predicate, while Data/App/Workflow APIs remain the
|
|
77
|
-
server-side authority.
|
|
78
|
-
|
|
79
|
-
Declare custom routes in `openxiangda.config.ts`, import the generated
|
|
80
|
-
`appRoutes`, and bind every route key to exactly one local React page with
|
|
81
|
-
`defineApplicationContributions` from `openxiangda/react`. Pass the result to
|
|
82
|
-
`OpenXiangdaApplication`. The runtime registers `surface: 'admin'` routes inside
|
|
83
|
-
the one platform Shell; do not wrap them in another Shell. It renders
|
|
84
|
-
`surface: 'user'` routes without the admin Shell so mobile/user experiences can
|
|
85
|
-
own their page layout without creating another router, identity provider or
|
|
86
|
-
permission store. Only static admin routes explicitly referenced by
|
|
87
|
-
`frontend.admin.navigation` enter the menu. Hidden routes retain the same
|
|
88
|
-
`capability` or `access.allOf/anyOf`, including ancestor constraints. Keep admin
|
|
89
|
-
operation pages under `/admin/operations`; parameterized routes remain
|
|
90
|
-
reachable but cannot be menu references. `defineAdminContributions` remains an
|
|
91
|
-
admin-only helper and intentionally rejects `user` routes.
|
|
92
|
-
|
|
93
|
-
When a Workflow Surface must link back to an application-owned business record,
|
|
94
|
-
declare `detailRouteCode: { desktop, mobile }` on that resource. Both codes must
|
|
95
|
-
reference explicit `surface: 'user'` routes that require the resource's read
|
|
96
|
-
capability. The desktop path must stay outside `/m`, the mobile path must start
|
|
97
|
-
with `/m/`, and each path must contain exactly one bounded dynamic record
|
|
98
|
-
parameter; its name may follow the application domain, such as
|
|
99
|
-
`:applicationId`. The compiler emits the pair in the resource Contract and in
|
|
100
|
-
`resourceDefinitions`; the platform substitutes the record id from the
|
|
101
|
-
authorized Workflow Surface. Never derive `/<resourceCode>/<recordId>`, add an
|
|
102
|
-
alias, or build the destination in the browser. Omitting the declaration means
|
|
103
|
-
there is no application business-record target; a broken published mapping
|
|
104
|
-
fails closed.
|
|
105
|
-
|
|
106
|
-
Wrap bespoke admin content in `OpenXiangdaAdminPage` and use Ant Design default
|
|
107
|
-
components. The platform UI provider supplies Chinese locale and contextual
|
|
108
|
-
feedback only. Do not generate appearance preferences, color settings or palette
|
|
109
|
-
registries. Keep component CSS scoped and verify real PC/mobile interactions,
|
|
110
|
-
including selectors, dialogs, form submission and failure recovery.
|
|
111
|
-
|
|
112
|
-
Declare application-owned login visuals with optional
|
|
113
|
-
`frontend.authentication`. The only supported account contract is
|
|
114
|
-
`existing-platform-users-only` with `registration.mode: 'reject'`; use exact
|
|
115
|
-
desktop `/login` and mobile `/m/login`, each pointing to a static protected user
|
|
116
|
-
default route. Import generated `authenticationSurfaces` and bind an exact
|
|
117
|
-
desktop/mobile renderer map alongside `appRoutes`:
|
|
1
|
+
# 前端架构
|
|
118
2
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
3
|
+
状态:Vite/Refine 已成为 OpenXiangda 2.0 唯一默认前端栈。决策与实测见
|
|
4
|
+
[核心架构](concepts.md)。
|
|
5
|
+
|
|
6
|
+
## 默认技术栈
|
|
7
|
+
|
|
8
|
+
- Vite 7:开发服务器与生产构建,只监听 `127.0.0.1`;
|
|
9
|
+
- React 19 + React Router:普通应用路由;
|
|
10
|
+
- Refine Core:资源查询、分页、排序和 mutation 状态;
|
|
11
|
+
- Ant Design 6:B 端页面组件。
|
|
12
|
+
|
|
13
|
+
不维护 Umi/Pro 双栈,也不在新模板中依赖已退休的前端框架包或旧身份 Provider。
|
|
14
|
+
|
|
15
|
+
## 数据和权限
|
|
16
|
+
|
|
17
|
+
`modules/` 中的业务模型由编译器派生 DataResource 契约,`openxiangda.config.ts` 声明页面
|
|
18
|
+
capability、应用角色和数据策略。前端只根据当前登录用户完整应用角色并集的
|
|
19
|
+
`capabilityCodes` 隐藏页面、按钮和只读字段;这些只是展示保护,平台 Data API
|
|
20
|
+
每次请求仍按同一角色并集做权威的行、字段和操作授权。
|
|
21
|
+
|
|
22
|
+
自定义角色管理页只调用 `openxiangda/core` 的角色管理 SDK。目录搜索使用
|
|
23
|
+
`searchRoleManagementUsers`,页面按钮按 `loadRoleManagementCatalog()` 返回的
|
|
24
|
+
`roleManagement` 投影显示,但前端显示不能替代服务端复核。不要在应用中复制角色表、
|
|
25
|
+
权限表或通过 NestJS 转发开发者凭据。
|
|
26
|
+
|
|
27
|
+
列表查询必须使用服务端过滤、排序和分页;新增、读取、更新、删除和文件上传都经过
|
|
28
|
+
可替换 Data API adapter。不要调用自定义 Nest CRUD、Function 或 Workflow 来绕过
|
|
29
|
+
Data API。只有真正需要事务或外部系统的动作才使用同源 `/api`。
|
|
30
|
+
|
|
31
|
+
默认仪器模块有 30 个字段,其中 `id/revision` 是 Data API 系统字段,28 个业务
|
|
32
|
+
字段由资源声明。新增、编辑和详情共用同一份字段元数据。五个边界字段使用五个独立
|
|
33
|
+
capability,不使用角色名或影子字段判断。
|
|
34
|
+
|
|
35
|
+
字段策略用 `create` / `update` 分别声明能力;显式空数组表示拒绝。学校管理员通过
|
|
36
|
+
`unrestrictedRoleCodes` 跳过行谓词,但仍受资源和字段能力
|
|
37
|
+
约束;学院管理员创建时可填写五个边界字段,更新时禁止修改 `collegeId`;仪器管理员
|
|
38
|
+
更新时禁止修改这五个字段。表单提交必须从 payload 删除无权字段。
|
|
39
|
+
|
|
40
|
+
DataQuery 使用有界 where 条件树,支持 and/or/not。标准列表的筛选、关键词、分页和导出共用已声明字段与同一查询条件,不在页面重写查询协议。
|
|
41
|
+
|
|
42
|
+
## 标准后台扩展
|
|
43
|
+
|
|
44
|
+
默认 CRUD、统一 Shell、current-user 权限和 Data Provider 都由 `openxiangda/react`
|
|
45
|
+
维护;应用拥有后台信息架构声明。页面实现、路由可达、菜单可见是三个不同合同:
|
|
46
|
+
|
|
47
|
+
- `resource.generated` 与 `frontend.routes` 决定有哪些标准页或 operation route;
|
|
48
|
+
- 编译器把全部可达页生成到 `adminPages`,detail/new/edit/handoff 可以存在但默认不进菜单;
|
|
49
|
+
- `frontend.admin.navigation` 是菜单的唯一权威声明,Shell 只渲染其中引用的页面,最后再按
|
|
50
|
+
current-user 权限过滤。权限不能发现或创建菜单项。
|
|
51
|
+
|
|
52
|
+
生成式资源后台固定使用 `/admin/resources/<resourceCode>` 命名空间,detail、create、
|
|
53
|
+
update 分别追加 `/:id`、`/new`、`/:id/edit`;独立移动后台面使用同一编译目录投影出的
|
|
54
|
+
`/m/admin/resources/<resourceCode>...`。所有桌面生成页由平台放进唯一 `Shell`,页面内部
|
|
55
|
+
跳转也只消费生成路径。普通 `/activities`、`/m/activities` 等产品路径留给 `user`
|
|
56
|
+
route。显式 route 与任何平台生成 route 的路径形状冲突时编译失败;即使动态参数名不同,
|
|
57
|
+
例如 `/:id` 与 `/:recordId`,也视为同一路径。不要添加旧根路径别名、重定向或通过注册顺序
|
|
58
|
+
解决冲突。
|
|
59
|
+
|
|
60
|
+
使用 typed helper 声明业务分组、用户名称、顺序、图标与页面引用,不维护 raw JSON:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import {
|
|
64
|
+
adminNavigationGroup,
|
|
65
|
+
adminOperationPage,
|
|
66
|
+
adminResourcePage,
|
|
67
|
+
defineAdminNavigation,
|
|
68
|
+
defineOpenXiangdaApp,
|
|
69
|
+
} from 'openxiangda/config';
|
|
70
|
+
|
|
71
|
+
export default defineOpenXiangdaApp({
|
|
72
|
+
// ...
|
|
73
|
+
frontend: {
|
|
74
|
+
root: 'apps/web',
|
|
75
|
+
routes: [{
|
|
76
|
+
code: 'instrument-import',
|
|
77
|
+
path: '/admin/operations/instrument-import',
|
|
78
|
+
label: '仪器导入',
|
|
79
|
+
surface: 'admin',
|
|
80
|
+
}],
|
|
81
|
+
user: { applicationTodoCenter: true },
|
|
82
|
+
admin: {
|
|
83
|
+
access: { anyOf: ['app:example:admin:view'] },
|
|
84
|
+
navigation: defineAdminNavigation([
|
|
85
|
+
adminNavigationGroup('instrument-center', '仪器管理', [
|
|
86
|
+
adminResourcePage('instruments'),
|
|
87
|
+
adminOperationPage('instrument-import'),
|
|
88
|
+
], { icon: 'database', order: 100 }),
|
|
89
|
+
]),
|
|
127
90
|
},
|
|
128
91
|
},
|
|
129
|
-
);
|
|
92
|
+
});
|
|
130
93
|
```
|
|
131
94
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
`
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
route and bind it through `frontend.publicAccess`. The policy must name one
|
|
145
|
-
resource, its writable/returnable fields and only the bounded operations needed
|
|
146
|
-
by the page (`draft.read`, `draft.update`, `validate`, `create`, `own.list`,
|
|
147
|
-
`own.read`). A public route must not also declare `capability` or `access`.
|
|
148
|
-
Pass generated `anonymousPublicAccess` to
|
|
149
|
-
`<OpenXiangdaApplication publicAccess={anonymousPublicAccess}>`, then use
|
|
150
|
-
`createAnonymousPublicClient({ routeCode })` from `openxiangda/react` inside
|
|
151
|
-
the page. This client owns bootstrap, current-draft CAS, named validation,
|
|
152
|
-
managed upload, idempotent submission and owner-scoped list/detail calls. Do
|
|
153
|
-
not call the general Native Data API, store an identity in local storage, or
|
|
154
|
-
derive ownership from IP, user-agent or a browser fingerprint. The HttpOnly
|
|
155
|
-
browser credential identifies only this browser profile; clearing it or using
|
|
156
|
-
another browser loses access by design.
|
|
157
|
-
|
|
158
|
-
This is also the whole-application composition contract: pass the resulting
|
|
159
|
-
`contributions` to `OpenXiangdaApplication` and let that component remain the
|
|
160
|
-
only owner of `BrowserRouter`, `RuntimeBoundary`, Refine, generated resource and
|
|
161
|
-
Workflow routes, and the admin Shell. A user page may render an independent PC
|
|
162
|
-
or mobile layout, but it must not add a nested router/Shell or copy generated
|
|
163
|
-
routes. Route parameters continue to come from React Router, and generated
|
|
164
|
-
capability plus ancestor access guards run before the component renders.
|
|
165
|
-
|
|
166
|
-
To expose the standard application-level todo center, declare
|
|
167
|
-
`frontend.user.applicationTodoCenter: true`. The compiler generates `/todos`;
|
|
168
|
-
the same runtime exposes the independent mobile `/m/todos` page. The page reads only the authenticated user's
|
|
169
|
-
Notification Hub recipient projection and deep-links to the platform-resolved
|
|
170
|
-
target. Do not query Notification Hub management endpoints or recreate a local
|
|
171
|
-
message state store.
|
|
172
|
-
|
|
173
|
-
When an application needs branded user-end composition, keep those generated
|
|
174
|
-
routes and contribute renderers from the application entry through the public
|
|
175
|
-
`openxiangda/react` contract:
|
|
95
|
+
AI 先读取 `openxiangda://workspace/contracts` 的有界索引,再调用
|
|
96
|
+
`contract_describe` 并传入 `{ "selector": "navigation" }`,从 `data.selection.adminNavigationAuthoring.suggestion` 取得确定性的首次建议:
|
|
97
|
+
`proposal` 是有界机器可读声明,`imports` 是 `openxiangda/config` 的 typed helper,
|
|
98
|
+
`expression` 可一次性写入
|
|
99
|
+
`frontend.admin.navigation`,然后由应用正常编辑。该结果明确标记
|
|
100
|
+
`applyMode: "copy-once"` 和 `automaticRuntimeDiscovery: false`;compiler 和 runtime
|
|
101
|
+
从不调用建议器,也不会在以后新增内部资源时偷偷扩展生产菜单。直接使用 compiler API 的
|
|
102
|
+
tooling 也可调用 `renderAdminNavigationSuggestion(config)` 获得同一 proposal。
|
|
103
|
+
|
|
104
|
+
用 `defineApplicationContributions` 将每个生成的 `appRoutes` route 精确绑定到一个本地
|
|
105
|
+
React page。`admin` page 由 runtime 放入唯一的 `Shell`,component 不再次嵌套;`user`
|
|
106
|
+
page 不套 admin Shell,可独立实现移动/用户端布局,但仍共享当前用户、权限和 Router:
|
|
176
107
|
|
|
177
108
|
```tsx
|
|
178
109
|
import {
|
|
179
110
|
defineApplicationContributions,
|
|
180
|
-
|
|
181
|
-
type StandardUserPageFrameProps,
|
|
182
|
-
type StandardUserSurfaceContributions,
|
|
111
|
+
OpenXiangdaApplication,
|
|
183
112
|
} from 'openxiangda/react';
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
113
|
+
import {
|
|
114
|
+
adminNavigation,
|
|
115
|
+
adminAccess,
|
|
116
|
+
adminPages,
|
|
117
|
+
appRoutes,
|
|
118
|
+
routeManifest,
|
|
119
|
+
} from '@app/contracts/generated';
|
|
120
|
+
import { InstrumentCalibrationPage } from './operations/InstrumentCalibrationPage';
|
|
121
|
+
|
|
122
|
+
const contributions = defineApplicationContributions(appRoutes, {
|
|
123
|
+
pages: {
|
|
124
|
+
instrumentCalibration: InstrumentCalibrationPage,
|
|
189
125
|
},
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
<OpenXiangdaApplication
|
|
129
|
+
adminNavigation={adminNavigation}
|
|
130
|
+
adminAccess={adminAccess}
|
|
131
|
+
adminPages={adminPages}
|
|
132
|
+
routeManifest={routeManifest}
|
|
133
|
+
contributions={contributions}
|
|
134
|
+
/>;
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
`pages` 的键必须与生成的 `appRoutes` 完全一致。隐藏 route 仍执行同一 `capability` 或
|
|
138
|
+
`access.allOf/anyOf`,子 route 同时继承全部祖先约束。页面代码随应用不可变前端制品构建,
|
|
139
|
+
不能从平台下载 component/module URL。admin operation page 固定使用
|
|
140
|
+
`/admin/operations` 或其子路径;带参数 route 只可直接访问,不能被导航引用。
|
|
141
|
+
`defineAdminContributions` 是保留的 admin-only helper,会主动拒绝 `user` routes。
|
|
142
|
+
|
|
143
|
+
应用登录使用可选 `frontend.authentication` 声明:仅允许现有平台用户、拒绝注册,桌面
|
|
144
|
+
固定 `/login`、移动固定 `/m/login`,并分别引用同设备的静态 user 默认 route。登录面由
|
|
145
|
+
编译器生成到独立 `authenticationSurfaces`,不进入受保护 `appRoutes`。应用通过
|
|
146
|
+
`defineApplicationContributions({ routes: appRoutes, authenticationSurfaces },
|
|
147
|
+
{ pages, authentication })` 绑定独立 PC/移动 renderer;renderer 只拥有品牌视觉和本地
|
|
148
|
+
展示状态,并调用 `ApplicationLoginSurfaceProps` 的平台回调。密码、租户 provider、一次性
|
|
149
|
+
OAuth state/callback、Secure HttpOnly 会话与 refresh family、当前身份和 AuthZ 始终由平台
|
|
150
|
+
唯一持有。禁止调用 v1 auth API、在浏览器保存 Token、把登录页塞入受保护路由或创建第二
|
|
151
|
+
Router/identity provider。生成的 `platformAuthManifest` 是独立登录 QA 清单,不改变用户路由
|
|
152
|
+
覆盖数。
|
|
153
|
+
|
|
154
|
+
## 匿名公开用户页
|
|
155
|
+
|
|
156
|
+
没有平台账号的外部用户不进入应用登录或角色并集。此类页面使用专门的
|
|
157
|
+
[`frontend.publicAccess` 匿名公开访问合同](public-access.md),由平台生成 HttpOnly 浏览器凭证,
|
|
158
|
+
并通过 `createAnonymousPublicClient` 提供草稿、附件、具名重复校验、幂等提交和同一浏览器的
|
|
159
|
+
本人列表/详情。不要创建 guest 账号、公开一般 Data API、保存本地身份或使用 IP/指纹判断所有权。
|
|
160
|
+
|
|
161
|
+
这也是完整应用的一等组合边界:`OpenXiangdaApplication` 始终唯一持有
|
|
162
|
+
`BrowserRouter`、`RuntimeBoundary`、Refine、generated resource/workflow routes
|
|
163
|
+
和后台 `Shell`。应用不要把它包在第二个 Router/Shell 中。桌面/移动用户端可以绑定不同
|
|
164
|
+
组件并拥有各自布局,但仍共享同一个 runtime identity 和 capability ancestor guard。
|
|
165
|
+
|
|
166
|
+
通用应用级待办中心通过用户 Surface 声明开启:
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
frontend: {
|
|
170
|
+
user: { applicationTodoCenter: true },
|
|
171
|
+
// ...
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
编译器生成 `/todos` 和 `/m/todos`。页面只读取当前登录用户的
|
|
176
|
+
Notification Hub 收件人投影;不调用 management API,不复制消息状态库。桌面端使用
|
|
177
|
+
无常驻详情的全宽列表,移动端使用独立卡片列表;`查看详情` 统一进入平台解析后的
|
|
178
|
+
Workflow/custom application route。
|
|
179
|
+
|
|
180
|
+
编译器同时生成必填的 `routeManifest`。它是 Workflow/Todo 标准页的唯一桌面/移动成对路由来源,
|
|
181
|
+
每个 entry 都携带稳定 `routeCode`、参数名、访问能力和 `requiresAuthentication: true`,顶层
|
|
182
|
+
`digest` 绑定完整 catalog。模板把该产物直接传给 `OpenXiangdaApplication`;runtime 在注册
|
|
183
|
+
Router 和页面前校验成对 user surface、参数与访问元数据。应用不得重新声明 `/todos`、
|
|
184
|
+
`/m/todos` 或标准 Workflow 路径,也不得添加别名、重定向或第二份
|
|
185
|
+
路由状态。digest 的计算与合同校验由 compiler/platform preflight 负责,浏览器只接受有效格式并
|
|
186
|
+
fail-closed 校验 entry/pair 元数据。
|
|
187
|
+
|
|
188
|
+
标准 Workflow 详情页直接渲染 Surface 的 `presentation.businessDetail`、`summary`、
|
|
189
|
+
typed timeline 和 operation descriptors。业务字段继续使用平台 `SurfaceFieldValue` 语义;
|
|
190
|
+
父子表、附件、富文本图片和签名不由应用另写 renderer 或拼接 Data API 文件 URL。
|
|
191
|
+
PC canonical 路径为 `/tasks/:taskId` 和 `/workflows/:instanceId`,使用独立全屏页面而不进入
|
|
192
|
+
后台 Shell;旧 admin 详情路径不存在。桌面和移动使用独立
|
|
193
|
+
renderer,但共享同一授权与命令生命周期。主决策操作固定在底部,
|
|
194
|
+
低频操作统一进入“更多操作”;意见输入延迟到动作确认层,页面不常驻空白意见表单。
|
|
195
|
+
页面只显示非系统业务字段与节点内操作,不展示 UUID、revision、事件序列或技术信息区;
|
|
196
|
+
`stale` 不产生常驻提示,真实命令冲突才显示刷新提示。
|
|
197
|
+
应用只有在业务交互确实不能由标准页表达时才声明成对的 custom detail route。
|
|
198
|
+
|
|
199
|
+
标准流程提交使用浏览器客户端的 `loadBusinessProcessReceipt(commandId)` 和
|
|
200
|
+
`pollBusinessProcessCommand(commandId, afterRevision)`(Nest 使用对应的
|
|
201
|
+
`OpenXiangdaBusinessProcessService.receipt/poll`)。首个回执可能是 `accepted`;按
|
|
202
|
+
`nextPoll` 继续读取直到 `terminal`,再消费 typed command/surface。不要把 accepted 当作提交失败,
|
|
203
|
+
也不要对平台端点发起未类型化的 `fetch`。
|
|
204
|
+
|
|
205
|
+
资源用 `mutationOwner: 'native' | 'action' | 'readonly' | 'workflow'` 声明 mutation owner,
|
|
206
|
+
并可用 `generated.list/detail/create/update/delete` 精确选择标准 surface。非 Native owner
|
|
207
|
+
不能生成或向应用角色授予 Native mutation;零可写业务字段不能开放 create/update。
|
|
208
|
+
Workflow definition 用 `launch.mode` 声明 `standalone`、`custom-page`、`hidden-handoff` 或
|
|
209
|
+
`work-center-only`;只有 `standalone` 可进入菜单,`hidden-handoff` 保留同一标准 PC/移动路由
|
|
210
|
+
但不进菜单。缺省 submission 使用 compiler 生成的标准 process operation。action-owned 资源
|
|
211
|
+
则在 `standalone`/`hidden-handoff` 上声明 `submission.kind: 'named-operation'`,把 create/existing
|
|
212
|
+
表单字段、平台幂等键、当前用户、subject id/revision 和响应结果显式绑定到原 named operation。
|
|
213
|
+
标准页仍使用 generated field components,但最终由应用服务端完成业务校验、原子写入并决定
|
|
214
|
+
是否返回 durable process command;缺少或返回 null command 表示本次无需审批。浏览器不提供
|
|
215
|
+
save callback,也不直接调用 prepare/start。`custom-page` 仍只能由 verified Named Action 注入
|
|
216
|
+
`OpenXiangdaBusinessProcessService` 发起。
|
|
217
|
+
|
|
218
|
+
标准资源页提供 `toolbar`、`row`、`detail` 三类 action slot。slot 声明稳定 code、label、
|
|
219
|
+
可选 order 和 capability/access,render 只获得当前 resource、已授权 record/selection 与
|
|
220
|
+
受控 `refresh()`:
|
|
221
|
+
|
|
222
|
+
```tsx
|
|
223
|
+
const contributions = defineApplicationContributions(appRoutes, {
|
|
224
|
+
pages: { instrumentCalibration: InstrumentCalibrationPage },
|
|
225
|
+
resources: {
|
|
226
|
+
instruments: {
|
|
227
|
+
row: [{
|
|
228
|
+
code: 'calibrate',
|
|
229
|
+
label: '校准',
|
|
230
|
+
capability: 'instrument.calibration.run',
|
|
231
|
+
render: ({ record, refresh }) => (
|
|
232
|
+
<CalibrationButton recordId={String(record.id)} onDone={refresh} />
|
|
233
|
+
),
|
|
234
|
+
}],
|
|
235
|
+
},
|
|
193
236
|
},
|
|
194
|
-
}
|
|
237
|
+
});
|
|
238
|
+
```
|
|
195
239
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
240
|
+
slot 只扩展动作区域,不接管查询、字段策略、revision、保存或审计。跨资源事务、外部副作用
|
|
241
|
+
和业务不变量仍调用有 `@OpenXiangdaOperation` 门禁的 Nest App Operation;普通 CRUD 继续
|
|
242
|
+
直接使用 Native Data API。UI 隐藏不是服务端授权。
|
|
243
|
+
|
|
244
|
+
学院是应用自有 `colleges` Native Resource,仪器 `collegeId` 保存该资源的系统 UUID。
|
|
245
|
+
人员和部门选择器调用平台 Directory 的分页 search,并用 exact resolve 恢复已选 ID;学院
|
|
246
|
+
选择器调用 membership-bound scope-values search/resolve。空结果和错误直接展示,不回退
|
|
247
|
+
静态人员、部门或学院。组织部门与学院属于不同 owner,不能互相推断。
|
|
248
|
+
|
|
249
|
+
发布态 app/environment 只读取平台为每个 index 注入的
|
|
250
|
+
`openxiangda-runtime-base`、`openxiangda-app-code` 和
|
|
251
|
+
`openxiangda-environment` meta;不得使用 Vite 构建变量或手填环境覆盖它。
|
|
252
|
+
当前用户使用同源 `openxiangda.runtime-authorization/v2` 合同,每个 Data API query/body
|
|
253
|
+
都显式携带 environmentKey。标准客户端读取当前用户角色并集,不保存 Token,也不持久化
|
|
254
|
+
授权结果。该角色并集合同未部署的平台版本
|
|
255
|
+
必须在应用写入前 fail closed。
|
|
256
|
+
|
|
257
|
+
## 本地与浏览器门禁
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
openxiangda dev
|
|
261
|
+
pnpm --filter @app/web check
|
|
262
|
+
pnpm --filter @app/web test
|
|
263
|
+
pnpm --filter @app/web test:e2e
|
|
264
|
+
pnpm --filter @app/web build
|
|
200
265
|
```
|
|
201
266
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
`StandardUserPageFrameProps` contains `pageKind`, `device`, `mobile`, rendered
|
|
207
|
-
`children`, safe `route` metadata, `canGoBack` and the platform-owned `back()`
|
|
208
|
-
callback. The frame wraps Todo and standard Workflow work-center, launch, task
|
|
209
|
-
and instance pages. It must not create a Router, resolve identity, redirect a
|
|
210
|
-
standard path or reinterpret route metadata as authorization.
|
|
211
|
-
|
|
212
|
-
`StandardApplicationTodoCenterProps` contains only the authenticated current
|
|
213
|
-
user's `items`, aggregate `counts`, `total`, `loading`, `loadingMore`, `error`,
|
|
214
|
-
immutable `query`, `hasMore`, and the bounded callbacks `setQuery`, `refresh`,
|
|
215
|
-
`loadMore`, `recordInteraction` and `openItem`. `setQuery` owns view, keyword,
|
|
216
|
-
unread and paged-offset changes; `loadMore` appends and de-duplicates the next
|
|
217
|
-
platform page; `openItem` records a click best-effort and uses the
|
|
218
|
-
platform-resolved desktop/mobile target. Render only these props. Never import
|
|
219
|
-
the private platform client, call Notification Hub endpoints, persist a Todo
|
|
220
|
-
copy, accept a user/token parameter, or navigate from an item object not
|
|
221
|
-
supplied by the current render. A renderer exception is contained by the
|
|
222
|
-
platform error boundary without replacing `RuntimeBoundary` or the Router.
|
|
223
|
-
|
|
224
|
-
The compiler also emits the required generated `routeManifest`. This is the
|
|
225
|
-
single desktop/mobile paired catalog for standard Workflow and Todo pages. Each
|
|
226
|
-
entry carries stable route codes, path parameters, access metadata and a
|
|
227
|
-
`requiresAuthentication: true` marker; the top-level digest binds the complete
|
|
228
|
-
catalog. Pass it directly to `OpenXiangdaApplication`. The runtime validates
|
|
229
|
-
user Surface pairs, parameter names and shared access metadata before registering
|
|
230
|
-
the Router. Applications must not recreate standard `/todos`, `/m/todos`, or
|
|
231
|
-
Workflow paths, add aliases/redirects, or maintain a second route state. The
|
|
232
|
-
compiler/platform preflight is the digest authority; the browser validates the
|
|
233
|
-
digest shape and fails closed on malformed or inconsistent entries.
|
|
234
|
-
|
|
235
|
-
For standard process submission, consume the typed browser helpers
|
|
236
|
-
`loadBusinessProcessReceipt(commandId)` and
|
|
237
|
-
`pollBusinessProcessCommand(commandId, afterRevision)` (or the matching Nest
|
|
238
|
-
`receipt`/`poll` methods). A first response may be `accepted`; follow
|
|
239
|
-
`nextPoll` until `terminal` instead of treating it as failure or issuing a
|
|
240
|
-
generic request to the platform endpoint.
|
|
241
|
-
|
|
242
|
-
For a small business action on a generated resource page, use the typed
|
|
243
|
-
`resources[resourceCode].toolbar`, `.row` or `.detail` slots accepted by
|
|
244
|
-
`defineApplicationContributions`. Declare a stable action code, label and
|
|
245
|
-
capability/access expression. The render context contains only the current
|
|
246
|
-
resource, already-authorized record or selection, and a bounded `refresh()`;
|
|
247
|
-
it does not own CRUD, revisions, fields or authorization. Invoke a guarded Nest
|
|
248
|
-
App Operation for cross-resource transactions, invariants or side effects and
|
|
249
|
-
leave ordinary CRUD on the Native Data API. Do not copy a generated page just
|
|
250
|
-
to insert a button.
|
|
251
|
-
|
|
252
|
-
Generated contracts intentionally emit each resource Surface once in
|
|
253
|
-
`resourceSurfaces`; `resourceDefinitions[code].surface` references that shared
|
|
254
|
-
object, while an explicit resource `detailRouteCode` is preserved beside it.
|
|
255
|
-
Import the generated runtime definitions normally. Do not serialize, inline or
|
|
256
|
-
duplicate Surface literals in application code.
|
|
257
|
-
|
|
258
|
-
The standard Workflow detail renderers consume only the authoritative Surface:
|
|
259
|
-
`presentation.businessDetail`, `presentation.summary`, the typed timeline and
|
|
260
|
-
operation descriptors. Continue to use `SurfaceFieldValue` for complete field
|
|
261
|
-
semantics and the Workflow-scoped file client for attachments, rich-text images
|
|
262
|
-
and signatures. Keep desktop and mobile renderers structurally independent;
|
|
263
|
-
place decision actions in the fixed primary group, all low-frequency actions in
|
|
264
|
-
the single more-actions entry, and collect comments in the action confirmation
|
|
265
|
-
layer. The canonical desktop paths are `/tasks/:taskId` and
|
|
266
|
-
`/workflows/:instanceId`; they render as standalone full-screen pages outside
|
|
267
|
-
the admin Shell, while the platform alone replace-redirects historical admin
|
|
268
|
-
detail URLs. Filter `system: true` and internal fields, omit empty sections,
|
|
269
|
-
merge operation actor/action/reason/time into its vertical node, and never show
|
|
270
|
-
UUIDs or revision/event diagnostics. Treat `stale` as metadata and show the
|
|
271
|
-
friendly refresh prompt only after a real command token/CAS conflict. Do not
|
|
272
|
-
copy the standard page into an application merely to show full business fields
|
|
273
|
-
or rearrange platform-owned operations.
|
|
274
|
-
|
|
275
|
-
## Foundation module and field selection
|
|
276
|
-
|
|
277
|
-
New applications plan task pages first and compose data models and selected CRUD
|
|
278
|
-
views through `defineApplicationModule`. Internal tables need no page. List, form
|
|
279
|
-
and detail selections are exhaustive; `hidden` controls presentation independently
|
|
280
|
-
of Data API permissions. Keep root configuration short by importing business modules.
|
|
281
|
-
|
|
282
|
-
Use platform Field Kit before custom input controls. PC input may use `antd`;
|
|
283
|
-
mobile input uses the scoped `openxiangda/mobile` Ant Design Mobile adapter, inside
|
|
284
|
-
`MobileSurface` with `openxiangda/mobile/styles.css` (already included in React styles).
|
|
285
|
-
Do not import the `antd-mobile` root, which resets global page styles.
|
|
286
|
-
Do not write raw business input/select/textarea or
|
|
287
|
-
contentEditable elements. Keep mobile entrypoints in src/mobile/, Mobile*.tsx or
|
|
288
|
-
*.mobile.tsx so the application check can inspect their static local imports.
|
|
289
|
-
Basic text/number/boolean/option/date controls have a mobile adapter; complex field
|
|
290
|
-
migration remains staged, and each field must pass actual interaction acceptance.
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
标准列表使用高级条件分组、显示列浮层、冻结和拖动列序、多排序。仅从页面声明的可读业务字段提供选择;导出与列表共用条件和排序。依赖所选记录的 toolbar contribution 声明 `requiresSelection: true`。显示列修改即时预览,显式保存个人偏好。
|
|
294
|
-
|
|
295
|
-
标准表单使用“暂存 / 提交”及平台草稿箱,不自行使用 localStorage、业务表或 Nest 保存草稿。PC 抽屉头部提供全屏、新开页面、关闭;新开页面由平台保存并交接草稿。移动端为分组字段行、简单标题和固定底部操作,草稿/恢复确认用移动底部弹层;不显示“返回列表”。草稿字段必须保持权限裁剪,编辑草稿不得用最新 revision 覆盖原编辑版本。
|
|
267
|
+
测试必须真实断言 Vite LAN 不可达、production 警示 DOM 常驻、Data/Directory/App API
|
|
268
|
+
使用同一当前用户角色并集、Perspective 读取投影协议,并约束源码文件数、LOC、构建
|
|
269
|
+
体积和 gzip 体积。
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# 安装与开始开发
|
|
2
|
+
|
|
3
|
+
OpenXiangda 2.0 默认生成 React 应用和共享契约。普通 CRUD、标准审批和通知使用远端平台能力;只有真实服务端业务动作才按需增加 NestJS。本地无需启动平台、Docker 或 PostgreSQL。
|
|
4
|
+
|
|
5
|
+
## 准备 {#prerequisites}
|
|
6
|
+
|
|
7
|
+
准备平台地址、具有应用开发权限的账号、Node.js 24 和 pnpm 10.15.1。向平台维护者取得已验证的 OpenXiangda 2.0 精确版本,并核对平台能力是否支持。`openxiangda@latest` 可能属于 1.x;不能用它选择 2.0。
|
|
8
|
+
|
|
9
|
+
## 安装与创建 {#create}
|
|
10
|
+
|
|
11
|
+
以下命令的版本占位符由随包资料替换为该根包的精确版本。网站源码阅读者应先确认要使用的发行版本。
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pnpm dlx openxiangda@2.0.0 skill install --force
|
|
15
|
+
pnpm dlx openxiangda@2.0.0 auth status --base-url <平台地址> --json
|
|
16
|
+
pnpm dlx openxiangda@2.0.0 login --base-url https://platform.example.com
|
|
17
|
+
pnpm dlx openxiangda@2.0.0 create my-app --base-url https://platform.example.com
|
|
18
|
+
cd my-app
|
|
19
|
+
pnpm openxiangda context --json
|
|
20
|
+
pnpm openxiangda dev
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
将两处示例平台地址替换为同一个目标地址。`create` 先核对目标与当前登录平台,再创建本地目录、安装依赖并初始化远端应用;新应用不会自动沿用文件中最后登录的站点。CI 使用原有成对的 `OPENXIANGDA_BASE_URL` 和 `OPENXIANGDA_TOKEN` 时,可以由该显式地址指定目标。
|
|
24
|
+
|
|
25
|
+
初始化中断后重试同一命令;已有目录会核对原平台绑定,不能通过 `create` 改绑到其他站点。地址不一致时先检查目标并登录正确的平台,不修改 link 文件绕过检查,也不要使用内部 provision 接口另建应用。创建操作应在用户要求创建应用的范围内执行。
|
|
26
|
+
|
|
27
|
+
进入项目后使用 `pnpm openxiangda`,由项目依赖和锁文件决定版本。查看使用资料运行 `pnpm openxiangda docs`;查看单一主题运行 `pnpm openxiangda docs frontend`。安装到其他 AI 工具时使用 `skill install --destination <Skill根目录>`。
|
|
28
|
+
|
|
29
|
+
## 项目结构 {#workspace}
|
|
30
|
+
|
|
31
|
+
```text
|
|
32
|
+
apps/web 页面与应用入口
|
|
33
|
+
packages/contracts 平台编译器生成的契约
|
|
34
|
+
modules 业务模型、页面选择和模块声明
|
|
35
|
+
openxiangda.config.ts 应用装配、导航、权限和按需能力
|
|
36
|
+
appspec 需求、架构、变更和验收记录
|
|
37
|
+
AGENTS.md 平台约定与项目自有说明
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
以实际模板输出为准。资源与页面通过模块声明组合,不创建 `platform/data`。`apps/server` 仅在启用后端时初始化;后续保留用户业务代码。
|
|
41
|
+
|
|
42
|
+
AppSpec 随开发持续维护:测试发布前补齐总纲、关联变更与验收计划,部署后记录真实业务结果,生产晋级核对该测试版本的验收报告。新应用业务实现前先完成[产品设计与确认基线](product-design.md);研究、示例原型和技术检查可用于逐步完善设计。具体步骤见[全流程记录](appspec.md)。
|
|
43
|
+
|
|
44
|
+
## 连接开发 {#connected-development}
|
|
45
|
+
|
|
46
|
+
`dev` 监听本机回环地址,页面通过同源代理访问平台测试数据。浏览器不持久化平台凭据。终端和页面显示当前环境;只有生产环境时会持续提示生产数据风险。开发数据写入仍是远端真实写入,按任务范围操作。
|
|
47
|
+
|
|
48
|
+
纯 CRUD 修改优先使用标准模型、字段和页面;跨模型事务或外部副作用再选择后端。角色、行和字段权限在平台执行。详见[开发流程](development.md)、[模型与标准 CRUD](application-foundation.md)和[按需后端](backend.md)。
|
|
49
|
+
|
|
50
|
+
## 检查与交付 {#delivery}
|
|
51
|
+
|
|
52
|
+
只检查时运行 `pnpm openxiangda check`。需要部署测试环境时直接运行 `pnpm openxiangda deploy`,它已包含检查、测试和构建;无需再连续重复运行全部脚本。
|
|
53
|
+
|
|
54
|
+
生产必须复用成功测试运行。部署状态、真实角色验收和回滚步骤见[应用交付](delivery.md)。纯前端发布不要求 Docker;启用后端后才需要官方镜像构建条件。
|
|
55
|
+
|
|
56
|
+
## 接入 MCP {#mcp}
|
|
57
|
+
|
|
58
|
+
MCP 使用相同的项目 CLI:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pnpm exec openxiangda --mcp-stdio --cwd <应用绝对路径>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
先调用 `workspace_context`,再按任务读取 `docs_read` 和当前契约。配置示例与工具参数见[MCP 参考](mcp.md)。登录、创建和长期 dev 进程继续由 CLI/终端管理。
|
|
65
|
+
|
|
66
|
+
指定站点授权可用 `auth status --base-url <平台地址> --json` 或 MCP `authorization_status` 只读核验,无需工作区。状态为 `authorized` 才证明当前 access 被平台接受;`missing`/`platform_mismatch`/`refresh_required` 需处理会话,`unauthorized` 表示平台拒绝,`unavailable` 表示暂时无法核验,不能当成过期。查询不刷新、不打开浏览器、不修改绑定;应用管理权限需另行核验。
|