openxiangda 1.0.77 → 1.0.79
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 +3 -1
- package/lib/cli.js +330 -11
- package/openxiangda-skills/SKILL.md +11 -9
- package/openxiangda-skills/references/automation-v3.md +17 -1
- package/openxiangda-skills/references/connector-resources.md +4 -1
- package/openxiangda-skills/references/data-views.md +23 -9
- package/openxiangda-skills/references/pages/page-sdk.md +15 -0
- package/openxiangda-skills/references/resource-manifest-cheatsheet.md +92 -19
- package/openxiangda-skills/references/workflow-v3.md +17 -1
- package/openxiangda-skills/skills/openxiangda-app/SKILL.md +7 -5
- package/openxiangda-skills/skills/openxiangda-core/SKILL.md +7 -4
- package/openxiangda-skills/skills/openxiangda-form/SKILL.md +9 -9
- package/openxiangda-skills/skills/openxiangda-inspect/SKILL.md +2 -2
- package/openxiangda-skills/skills/openxiangda-page/SKILL.md +19 -16
- package/openxiangda-skills/skills/openxiangda-permission-settings/SKILL.md +4 -4
- package/openxiangda-skills/skills/openxiangda-workflow-automation/SKILL.md +27 -8
- package/package.json +1 -1
- package/packages/sdk/dist/runtime/index.cjs +20 -0
- package/packages/sdk/dist/runtime/index.cjs.map +1 -1
- package/packages/sdk/dist/runtime/index.d.mts +18 -1
- package/packages/sdk/dist/runtime/index.d.ts +18 -1
- package/packages/sdk/dist/runtime/index.mjs +20 -0
- package/packages/sdk/dist/runtime/index.mjs.map +1 -1
- package/templates/sy-lowcode-app-workspace/scripts/build-js-code.mjs +8 -2
- package/templates/sy-lowcode-app-workspace/tsconfig.js-code-nodes.json +5 -1
|
@@ -26,10 +26,11 @@ OpenXiangda supports two workspace modes. Classic `sy-lowcode-app-workspace` pub
|
|
|
26
26
|
| 创建 / 修改自定义代码页 / portal / dashboard | `openxiangda-page` | edit `src/pages/<code>/` → `workspace publish --page <code>` |
|
|
27
27
|
| 审批流程 / workflow / 流程节点 / JS_CODE | `openxiangda-workflow-automation` | `openxiangda workflow validate / create / publish` |
|
|
28
28
|
| 自动化 / 定时任务 / 提交触发 / cron | `openxiangda-workflow-automation` | `openxiangda automation validate / create / publish / enable` |
|
|
29
|
+
| App Function / function_call / 可复用后端逻辑 | `openxiangda-workflow-automation` | declare `src/resources/functions/<code>.json` + `src/functions/<code>/index.ts` |
|
|
29
30
|
| 角色 / 权限组 / 字段权限 / 数据范围 / 公开访问 | `openxiangda-permission-settings` | `openxiangda permission ...` / `openxiangda settings ...` |
|
|
30
31
|
| 看应用结构 / 快照 / 对比 / 诊断 / 排查 / 报错 | `openxiangda-inspect` | `openxiangda app snapshot <APP_XXX> --profile <name> --json` |
|
|
31
32
|
| 登录 / 切换平台 / profile / token / whoami | `openxiangda-core` | `openxiangda env --profile <name>` / `openxiangda auth status` |
|
|
32
|
-
| 多表只读联表 / 固定口径统计 / 看板指标 | `openxiangda-form` (data view) | declare `src/resources/data-views/<code>.json` → `resource publish` |
|
|
33
|
+
| 多表只读联表 / 固定口径统计 / 强实时复杂查询 / 看板指标 | `openxiangda-form` (data view) | declare `src/resources/data-views/<code>.json` with `storageMode` → `resource publish` |
|
|
33
34
|
| 调外部 / 第三方 API / 钉钉 / 自建系统 | `openxiangda-page` (connector) | declare `src/resources/connectors/<code>.json` → `sdk.connector.invoke` |
|
|
34
35
|
|
|
35
36
|
### Hard rules — always
|
|
@@ -133,14 +134,15 @@ When the user provides a root domain such as `https://yida.wisejob.cn/`, use it
|
|
|
133
134
|
- All visible copy in forms and pages must be written for end users. Do not put implementation notes, developer explanations, schema descriptions, or "this area is generated by..." text into page sections, cards, labels, tips, or empty states.
|
|
134
135
|
- Use logical resource codes in local files. Platform-specific IDs such as `formUuid`, `pageId`, `workflowId`, and `automationId` must be isolated by profile.
|
|
135
136
|
- Put engineering-managed resources in `src/resources/` and use `openxiangda resource validate|plan|publish|pull`. `workspace publish` publishes workspace forms/pages first, then runs non-destructive resource upsert. Only pass `--prune` when the user explicitly wants local manifests to delete platform-side extras.
|
|
136
|
-
- For repeated read-only multi-form queries or predefined dashboard metrics, create a data view manifest in `src/resources/data-views/`. Use row views plus `sdk.dataView.query` for joined lists/lookups; use `viewType: "aggregate"` plus `sdk.dataView.stats` for count/sum/avg/min/max statistics.
|
|
137
|
+
- For repeated read-only multi-form queries or predefined dashboard metrics, create a data view manifest in `src/resources/data-views/`. Use `storageMode: "materialized"` for refreshed lists/reports that tolerate delay; use `storageMode: "live"` for bounded real-time joins where source changes must appear immediately. Use row views plus `sdk.dataView.query` for joined lists/lookups; use `viewType: "aggregate"` plus `sdk.dataView.stats` for count/sum/avg/min/max statistics. Add `indexes` only for materialized views. Do not use data views for single-form CRUD, simple linkedForm selects, writes, write-back, unbounded realtime joins, or ad-hoc BI. Read `references/data-views.md` before designing one.
|
|
137
138
|
- For external APIs, create a connector manifest in `src/resources/connectors/` and call it from pages through `sdk.connector`; never put third-party API keys in page source.
|
|
139
|
+
- For reusable backend logic shared by pages, automations, and workflows, create an App Function in `src/resources/functions/<functionCode>.json` plus `src/functions/<functionCode>/index.ts`. Call it from pages with `sdk.function.invoke`, from automation/workflow graphs with `function_call`, or from the runtime endpoint when the caller has app automation management permission. Current App Function MVP exposes controlled helpers such as `ctx.resources`, `ctx.form`, `ctx.dataView`, `ctx.connector`, `ctx.notification`, and `ctx.platform.api`; it does not expose raw SQL or Redis.
|
|
138
140
|
- Before scaffolding a real app, complex page, data management page, portal shell, status lifecycle, role governance, or automation, read `references/best-practices.md` and pick the architecture first. Prefer copying the relevant pattern from `examples/best-practices/` into `src/` instead of generating a single large page file.
|
|
139
141
|
- Before publishing to another platform, verify the workspace is bound for that profile. Resource IDs from one profile must not be reused for another profile.
|
|
140
142
|
- Use `openxiangda app snapshot <APP_XXX> --profile <name> --json` for diagnosis before changing an existing app.
|
|
141
143
|
- Run write commands that update `.openxiangda/state.json` sequentially within the same workspace. Read-only commands can run in parallel.
|
|
142
144
|
- JS_CODE is backend-executed workflow/automation logic, not frontend page code. Use it when logic must run after a backend trigger such as fixed cron schedules, form date-field schedules, form submit/update/delete/field-change events, or workflow approval/process events.
|
|
143
|
-
- Use JS_CODE for cross-form data queries, create/update/batch update operations, process termination, platform API calls, external HTTP calls, and
|
|
145
|
+
- Use JS_CODE for node-local cross-form data queries, create/update/batch update operations, process termination, platform API calls, external HTTP calls, and backend trigger orchestration. For logic that pages, automations, and workflows should reuse through a stable backend entry, prefer App Function. Do not use JS_CODE for simple UI interactions, ordinary form validation, or display-only page behavior.
|
|
144
146
|
- For workflow/automation JS_CODE nodes, prefer V2 `runtimeMode: "trusted_node"`. AI-authored source must be TypeScript under `sy-lowcode-app-workspace/src/js-code-nodes/<scriptCode>/index.ts`. `pnpm build-js-code --script <scriptCode>` runs TypeScript validation before bundling, and `sourceFile.localPath` should point to the TS source; the CLI builds, uploads, and replaces it with snapshot metadata during validate/create.
|
|
145
147
|
|
|
146
148
|
## Subskills
|
|
@@ -169,9 +171,9 @@ Core CLI / state:
|
|
|
169
171
|
|
|
170
172
|
- `references/openxiangda-api.md` — `/openxiangda-api/v1` request and response fields.
|
|
171
173
|
- `references/workspace-state.md` — `.openxiangda/state.json` shape and profile isolation rules.
|
|
172
|
-
- `references/connector-resources.md` — `src/resources` manifests, connector schema, and
|
|
173
|
-
- `references/resource-manifest-cheatsheet.md` — 复制即用的 connector / data-view / notification / workflow / automation / JS_CODE / role / permission group / settings / menu manifest 骨架与运行时调用示例。在创建任何 `src/resources/` 资源前先看这份。
|
|
174
|
-
- `references/data-views.md` — `src/resources/data-views` materialized view resources, DSL, permissions, refresh, CLI commands, and runtime SDK usage.
|
|
174
|
+
- `references/connector-resources.md` — `src/resources` manifests, connector schema, App Function boundary, and platform runtime calls.
|
|
175
|
+
- `references/resource-manifest-cheatsheet.md` — 复制即用的 connector / data-view / notification / App Function / workflow / automation / JS_CODE / role / permission group / settings / menu manifest 骨架与运行时调用示例。在创建任何 `src/resources/` 资源前先看这份。
|
|
176
|
+
- `references/data-views.md` — `src/resources/data-views` materialized/live data view resources, DSL, permissions, refresh, CLI commands, and runtime SDK usage.
|
|
175
177
|
- `references/notifications.md` — `src/resources/notifications`, notification templates/type bindings, and `sdk.notification` / `ctx.notification`.
|
|
176
178
|
- `references/best-practices.md` — initialized examples for modular pages, state lifecycles, role governance, permission isolation, high-performance queries, portal shells, workflow boundaries, and automation patterns.
|
|
177
179
|
|
|
@@ -184,13 +186,13 @@ Form authoring:
|
|
|
184
186
|
Page authoring:
|
|
185
187
|
|
|
186
188
|
- `references/pages/workspace-structure.md` — `src/pages/<pageCode>/` layout and config.
|
|
187
|
-
- `references/pages/page-sdk.md` — `openxiangda/runtime` data and
|
|
189
|
+
- `references/pages/page-sdk.md` — `openxiangda/runtime` data, connector, data view, notification, and App Function APIs.
|
|
188
190
|
- `references/pages/publish-flow.md` — workspace publish steps for code pages.
|
|
189
191
|
|
|
190
192
|
Workflow / automation / permissions:
|
|
191
193
|
|
|
192
|
-
- `references/workflow-v3.md` — workflow v3 definitions, JS_CODE nodes, trusted_node mode.
|
|
193
|
-
- `references/automation-v3.md` — automation triggers, conditions, and publishing.
|
|
194
|
+
- `references/workflow-v3.md` — workflow v3 definitions, JS_CODE nodes, App Function `function_call`, and trusted_node mode.
|
|
195
|
+
- `references/automation-v3.md` — automation triggers, conditions, App Function `function_call`, and publishing.
|
|
194
196
|
- `references/permissions-settings.md` — roles, page/form permission groups, settings.
|
|
195
197
|
|
|
196
198
|
Platform domain knowledge (read these first when generating forms or pages so the output matches the live platform behavior):
|
|
@@ -254,6 +254,22 @@ Supported node types:
|
|
|
254
254
|
|
|
255
255
|
Use trusted Node JS_CODE nodes for AI/admin automation logic that runs after an automation trigger. Typical cases include scheduled data cleanup, date-field reminders, cross-form synchronization after submit/update/delete, workflow-completed follow-up writes, calling internal platform APIs, calling external HTTP services, and other backend-only orchestration.
|
|
256
256
|
|
|
257
|
+
For reusable backend logic that should be shared by pages, multiple automations, and workflows, prefer an App Function under `src/functions/<functionCode>/index.ts` plus `src/resources/functions/<functionCode>.json`. Automation graphs can call it with a `function_call` node:
|
|
258
|
+
|
|
259
|
+
```json
|
|
260
|
+
{
|
|
261
|
+
"id": "call_summary",
|
|
262
|
+
"type": "function_call",
|
|
263
|
+
"data": {
|
|
264
|
+
"functionCode": "reservation_reminder_summary",
|
|
265
|
+
"input": { "scope": "today" },
|
|
266
|
+
"saveResponseTo": "summary"
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Use JS_CODE V2 when the script is local to one automation graph node.
|
|
272
|
+
|
|
257
273
|
```json
|
|
258
274
|
{
|
|
259
275
|
"id": "sync_customer",
|
|
@@ -275,7 +291,7 @@ Author source in `sy-lowcode-app-workspace/src/js-code-nodes/<scriptCode>/index.
|
|
|
275
291
|
|
|
276
292
|
The backend runs the snapshot in the trusted Node runtime, applies the node timeout (`30000` ms by default), stores execution logs, and writes the returned value to the node output and `variables.node_<nodeId>`. Scripts may use `export default async function (ctx) {}`, `module.exports = async (ctx) => {}`, `require`, `process`, `Buffer`, arbitrary HTTP, and `platform.api` for `/openxiangda-api/v1`.
|
|
277
293
|
|
|
278
|
-
Runtime context includes `ctx.triggerEvent`, `ctx.formData`, `ctx.workflowData`, `ctx.operator`, `ctx.app`, `ctx.variables`, and `ctx.node`.
|
|
294
|
+
Runtime context includes `ctx.triggerEvent`, `ctx.formData`, `ctx.workflowData`, `ctx.operator`, `ctx.app`, `ctx.variables`, and `ctx.node`. Prefer the higher-level resource helpers when available: `ctx.resources.resolveForm/resolveDataView/resolveConnector`, `ctx.form.queryMany/createOne/updateOne/updateById`, `ctx.dataView.query/stats`, `ctx.connector.call/invoke`, `ctx.notification.*`, and `ctx.platform.api.*`. Legacy data/process bridge methods remain available as `ctx.methods.queryOneData`, `queryManyData`, `updateOneData`, `updateDataByFormInstanceId`, `updateManyData`, `createOneData`, `terminateProcess`, and `getAllParentDepartments`.
|
|
279
295
|
|
|
280
296
|
Code automation also exposes `ctx.logger.debug/info/warn/error(message, data?)`. AI-authored code should log input parsing, query conditions, external calls, writes, branch decisions, and caught errors. Logs are stored as full raw execution data by default. Use CLI diagnosis commands:
|
|
281
297
|
|
|
@@ -11,6 +11,7 @@ Common folders:
|
|
|
11
11
|
- `workflows`
|
|
12
12
|
- `automations`
|
|
13
13
|
- `data-views`
|
|
14
|
+
- `functions`
|
|
14
15
|
- `permissions/page-groups`
|
|
15
16
|
- `permissions/form-groups`
|
|
16
17
|
- `settings/forms`
|
|
@@ -28,7 +29,9 @@ Connector manifests use stable `code` values. The platform maps connector `code`
|
|
|
28
29
|
|
|
29
30
|
Notification manifests live under `src/resources/notifications/` and contain `templates` plus `typeConfigs`. See `notifications.md` before generating reminders or message templates.
|
|
30
31
|
|
|
31
|
-
Data view manifests live under `src/resources/data-views/` and define read-only materialized
|
|
32
|
+
Data view manifests live under `src/resources/data-views/` and define read-only joined or aggregate query resources. Use `storageMode: "materialized"` for refreshed lists/reports where lag is acceptable, and `storageMode: "live"` for bounded real-time query shapes. Use row views with `sdk.dataView.query` and aggregate views with `sdk.dataView.stats`. Before generating one, confirm freshness tolerance, query bounds, and indexes for materialized filters/sort fields/dimensions/date buckets. Do not use them for single-form CRUD, simple linkedForm selects, writes, write-back, or ad-hoc BI. See `data-views.md` before generating one.
|
|
33
|
+
|
|
34
|
+
App Function manifests live under `src/resources/functions/`, with source in `src/functions/<functionCode>/index.ts`. Use them for reusable server-side logic that pages, automations, and workflows can share through `sdk.function.invoke` or `function_call` nodes. App Functions expose controlled runtime helpers such as `ctx.resources`, `ctx.form`, `ctx.dataView`, `ctx.connector`, `ctx.notification`, and `ctx.platform.api`; they do not expose raw SQL or Redis in the current MVP. Use JS_CODE V2 only for node-local workflow/automation scripts.
|
|
32
35
|
|
|
33
36
|
```json
|
|
34
37
|
{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Data View Resources
|
|
2
2
|
|
|
3
|
-
Data views are OpenXiangda-managed read-only PostgreSQL materialized views.
|
|
3
|
+
Data views are OpenXiangda-managed read-only query resources under `src/resources/data-views/`. They can run as PostgreSQL materialized views (`storageMode: "materialized"`, the default) or as live logical views (`storageMode: "live"`). Use them to publish repeated multi-form joins and predefined aggregate statistics as reusable app resources.
|
|
4
4
|
|
|
5
5
|
Use a data view when the app needs read-only joined data from multiple forms, such as:
|
|
6
6
|
|
|
@@ -10,13 +10,14 @@ Use a data view when the app needs read-only joined data from multiple forms, su
|
|
|
10
10
|
- Dashboard statistics such as monthly ticket count, order amount by customer, or task count by status.
|
|
11
11
|
- Reusable lookup or report data consumed by several pages or automations.
|
|
12
12
|
- Large list pages where repeated client-side cross-form joins would be slow or inconsistent.
|
|
13
|
+
- Real-time multi-form reads where the query shape is fixed and the source data volume is bounded (`storageMode: "live"`).
|
|
13
14
|
|
|
14
15
|
Do not use a data view for:
|
|
15
16
|
|
|
16
17
|
- Single-form CRUD. Use `sdk.form.advancedSearch`, form pages, or `DataManagementList`.
|
|
17
18
|
- Simple one-form dropdown options. Use `SelectField` with `optionSource.type: "linkedForm"`.
|
|
18
19
|
- Writes or write-back. Data views are read-only.
|
|
19
|
-
-
|
|
20
|
+
- Heavy real-time joins that cannot be paginated, indexed, filtered, or otherwise bounded.
|
|
20
21
|
- Raw SQL, incremental refresh, source-table trigger refresh, ad-hoc BI/pivot/window analysis, or write-heavy realtime dashboards.
|
|
21
22
|
|
|
22
23
|
## Authoring
|
|
@@ -25,8 +26,13 @@ Place manifests in `src/resources/data-views/*.json`. Use logical `formCode` val
|
|
|
25
26
|
|
|
26
27
|
Two view types are supported:
|
|
27
28
|
|
|
28
|
-
- `viewType: "row"` or omitted: row-level joined
|
|
29
|
-
- `viewType: "aggregate"`: grouped statistics
|
|
29
|
+
- `viewType: "row"` or omitted: row-level joined view using `select`.
|
|
30
|
+
- `viewType: "aggregate"`: grouped statistics view using `dimensions` and `measures`; query it with `stats`.
|
|
31
|
+
|
|
32
|
+
Two storage modes are supported:
|
|
33
|
+
|
|
34
|
+
- `storageMode: "materialized"` or omitted: create a PostgreSQL materialized view. Results may be stale until manual or scheduled refresh. Use `indexes` for common filters, sort fields, aggregate dimensions, and date buckets.
|
|
35
|
+
- `storageMode: "live"`: do not create a materialized view. Every query is compiled and executed against source forms in real time. `indexes` are ignored and refresh APIs do not apply. Use it only for bounded real-time query shapes.
|
|
30
36
|
|
|
31
37
|
Row view example:
|
|
32
38
|
|
|
@@ -34,6 +40,7 @@ Row view example:
|
|
|
34
40
|
{
|
|
35
41
|
"code": "ticket_with_customer",
|
|
36
42
|
"name": "Ticket With Customer",
|
|
43
|
+
"storageMode": "materialized",
|
|
37
44
|
"base": { "formCode": "service_ticket", "alias": "ticket" },
|
|
38
45
|
"joins": [
|
|
39
46
|
{
|
|
@@ -74,6 +81,7 @@ Aggregate statistics example:
|
|
|
74
81
|
"code": "ticket_stats_by_customer",
|
|
75
82
|
"name": "Ticket Stats By Customer",
|
|
76
83
|
"viewType": "aggregate",
|
|
84
|
+
"storageMode": "materialized",
|
|
77
85
|
"base": { "formCode": "service_ticket", "alias": "ticket" },
|
|
78
86
|
"joins": [
|
|
79
87
|
{
|
|
@@ -144,9 +152,11 @@ Filters:
|
|
|
144
152
|
|
|
145
153
|
Refresh:
|
|
146
154
|
|
|
155
|
+
- Refresh applies only to materialized data views.
|
|
147
156
|
- `manual` means refresh only when an administrator runs refresh or the resource is recreated.
|
|
148
157
|
- `scheduled` uses cron, for example `0 */10 * * * *`.
|
|
149
|
-
-
|
|
158
|
+
- Materialized query results may be stale. Show or inspect `lastRefreshedAt` when freshness matters.
|
|
159
|
+
- Live data views have no refresh state; `lastRefreshedAt` is `null` and refresh requests should be rejected.
|
|
150
160
|
- Do not choose a high-frequency schedule by default. Ask or infer how stale the data may be before setting `scheduled`.
|
|
151
161
|
|
|
152
162
|
Indexes:
|
|
@@ -159,11 +169,12 @@ Indexes:
|
|
|
159
169
|
|
|
160
170
|
## Performance And Freshness
|
|
161
171
|
|
|
162
|
-
|
|
172
|
+
Materialized data views move expensive joins and aggregations from page runtime to refresh time. Live data views keep results current by executing the same declared query shape on each request. Both modes reduce repeated page code complexity only when the view shape, data scope, and query bounds are chosen deliberately.
|
|
163
173
|
|
|
164
174
|
Before creating a data view, confirm these points:
|
|
165
175
|
|
|
166
176
|
- **Freshness tolerance**: ask whether users need near-real-time data, 10-30 minute freshness, hourly/daily reports, or manual snapshots.
|
|
177
|
+
- **Storage mode**: use `materialized` for read-heavy reports that tolerate refresh lag; use `live` for bounded real-time joins where source-table changes must appear immediately.
|
|
167
178
|
- **Query shape**: list the fields users will filter, sort, group, or drill down by. These should become output aliases and usually indexes.
|
|
168
179
|
- **Data scope**: if the business only needs active, recent, or in-scope records, put that rule in definition `where` so old/source-irrelevant rows are filtered before materialization.
|
|
169
180
|
- **Visible fields**: output only fields the page or permission rules need. Use hidden scope aliases for data permissions when needed, but do not build one huge catch-all view.
|
|
@@ -174,11 +185,12 @@ Refresh cadence guidance:
|
|
|
174
185
|
- Use `scheduled` every 10-30 minutes for normal dashboards, joined report lists, and recurring management views.
|
|
175
186
|
- Use hourly or daily schedules for leadership reports, historical statistics, and large aggregate views.
|
|
176
187
|
- Avoid intervals below 5 minutes unless the user explicitly confirms the time sensitivity and expected source-table volume. High-frequency refreshes can pressure both source tables and the materialized view.
|
|
177
|
-
- For strong real-time behavior after each form save,
|
|
188
|
+
- For strong real-time behavior after each form save, use `storageMode: "live"` only when the query is bounded. If the logic includes writes, side effects, raw platform orchestration, or expensive unbounded joins, use source-form queries, App Functions, or a different backend workflow instead.
|
|
178
189
|
|
|
179
190
|
Index guidance:
|
|
180
191
|
|
|
181
|
-
-
|
|
192
|
+
- For materialized mode, index only output aliases, not source references such as `customer.name`.
|
|
193
|
+
- Live data views ignore `indexes`; keep their runtime filters and page size conservative.
|
|
182
194
|
- For row views, index IDs used in drill-down (`ticketId`, `customerId`) and common filters/order fields (`statusValue`, `ownerId`, `createdAt`).
|
|
183
195
|
- For aggregate views, index the dimensions/time buckets used in runtime `filters`, `having` drill-downs, and `order` (`customerId`, `statusValue`, `createdMonth`).
|
|
184
196
|
- Keep compound indexes aligned with common query prefixes. For example, dashboard filters by customer then month should use `["customerId", "createdMonth"]`.
|
|
@@ -219,7 +231,7 @@ Diagnostic commands:
|
|
|
219
231
|
```bash
|
|
220
232
|
openxiangda data-view list --profile dev
|
|
221
233
|
openxiangda data-view status ticket_with_customer --profile dev
|
|
222
|
-
openxiangda data-view refresh ticket_with_customer --profile dev
|
|
234
|
+
openxiangda data-view refresh ticket_with_customer --profile dev # materialized only
|
|
223
235
|
openxiangda data-view query ticket_with_customer --profile dev --fields ticketId,customerName
|
|
224
236
|
openxiangda data-view query ticket_with_customer --profile dev --query-json query.json
|
|
225
237
|
openxiangda data-view stats ticket_stats_by_customer --profile dev --fields customerName,ticketCount
|
|
@@ -228,6 +240,8 @@ openxiangda data-view stats ticket_stats_by_customer --profile dev --query-json
|
|
|
228
240
|
|
|
229
241
|
## Runtime SDK
|
|
230
242
|
|
|
243
|
+
`sdk.dataView.query` and `sdk.dataView.stats` work for both materialized and live data views. Responses include `storageMode`; materialized responses may include `lastRefreshedAt`, while live responses return current data and `lastRefreshedAt: null`.
|
|
244
|
+
|
|
231
245
|
Direct query:
|
|
232
246
|
|
|
233
247
|
```ts
|
|
@@ -7,9 +7,11 @@ Guidelines:
|
|
|
7
7
|
- Do not hardcode `/openxiangda-api` calls inside end-user page components unless the page is explicitly an admin tool.
|
|
8
8
|
- Prefer SDK modules for form data, user context, permissions, and platform navigation.
|
|
9
9
|
- Use `sdk.dataView.query` for published read-only multi-form row data views. Use `sdk.dataView.stats` for aggregate data views declared with `viewType: "aggregate"`.
|
|
10
|
+
- Data views can be `storageMode: "materialized"` for refreshed report/list data or `storageMode: "live"` for bounded real-time joins. Page code calls the same SDK methods for both modes and should inspect `response.storageMode` / `response.lastRefreshedAt` when freshness is visible to users.
|
|
10
11
|
- Data view runtime queries can filter, sort, paginate, and select only output aliases.
|
|
11
12
|
- Keep data view page calls paginated and field-scoped. Runtime filters/order should use aliases that the data view indexes, especially for aggregate dimensions and date buckets.
|
|
12
13
|
- Use `sdk.dataSource.run()` with a page data source descriptor when the page config should own the data view code, default fields, or default filters.
|
|
14
|
+
- Use `sdk.function.invoke(code, { input })` for reusable backend business logic declared under `src/resources/functions/` and `src/functions/`. Do not implement multi-form orchestration, connector fan-out, notification orchestration, or permission-sensitive backend rules directly in a page component.
|
|
13
15
|
- Use `sdk.connector.invoke`, `sdk.connector.call("connector.api")`, or `sdk.connector.download` for external services. The SDK calls the platform runtime connector endpoint; it must not call third-party domains directly.
|
|
14
16
|
- Use `sdk.notification.sendByType` and `batchSendByType` for reusable business messages. Custom notification types must be declared in `src/resources/notifications/` and published with `openxiangda resource publish`.
|
|
15
17
|
- For the current user's department hierarchy, use `sdk.department.getCurrentUserParentDepartments()`; do not hardcode `GET /department/:id/parentDepartments` in page code.
|
|
@@ -87,6 +89,19 @@ const response = await sdk.dataSource.run("tickets", {
|
|
|
87
89
|
|
|
88
90
|
Data view filters, having, and fields use output aliases such as `customerName` or `ticketCount`, not source references such as `customer.name`. If the page only needs one form, prefer `sdk.form.advancedSearch`. If the page only needs a simple one-form dropdown, prefer linkedForm options.
|
|
89
91
|
|
|
92
|
+
App Function invocation:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
const result = await sdk.function.invoke("reservation_reminder_summary", {
|
|
96
|
+
input: {
|
|
97
|
+
scope: "today",
|
|
98
|
+
keyword,
|
|
99
|
+
},
|
|
100
|
+
})
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Use App Functions when the logic must run server-side and be reusable by pages, automations, or workflows. Current runtime invocation requires the caller to have app automation management permission; ordinary page users should normally consume function-backed data through a permission-aware page or a narrower backend resource.
|
|
104
|
+
|
|
90
105
|
Logout and current-user role switching:
|
|
91
106
|
|
|
92
107
|
```ts
|
|
@@ -66,13 +66,15 @@ const data = await sdk.connector.call("crm.getCustomer", { body: { keyword } });
|
|
|
66
66
|
- 多表只读联表列表 / lookup / 报表明细:用行级 data view,页面调用 `sdk.dataView.query`。
|
|
67
67
|
- 固定口径统计 / 看板指标 / 图表数据源:用 `viewType: "aggregate"`,页面调用 `sdk.dataView.stats`。
|
|
68
68
|
- ECharts 或自定义 dashboard 只负责展示;统计口径稳定时,数据源优先沉淀成 aggregate data view。
|
|
69
|
-
-
|
|
70
|
-
-
|
|
69
|
+
- 默认 `storageMode: "materialized"`,适合读多写少和可接受刷新延迟的列表/报表;发布前为常用筛选、排序、维度和时间桶声明 `indexes`。
|
|
70
|
+
- `storageMode: "live"` 每次查询实时执行,适合强实时但数据量可控的固定复杂查询;live 模式忽略 `indexes` 且不能 refresh。
|
|
71
|
+
- 不用于单表 CRUD、简单 `linkedForm` 下拉、写回、无边界重查询或临时 BI 查询。
|
|
71
72
|
|
|
72
73
|
```json
|
|
73
74
|
{
|
|
74
75
|
"code": "ticket_with_customer",
|
|
75
76
|
"name": "Ticket With Customer",
|
|
77
|
+
"storageMode": "materialized",
|
|
76
78
|
"base": { "formCode": "service_ticket", "alias": "ticket" },
|
|
77
79
|
"joins": [
|
|
78
80
|
{
|
|
@@ -137,7 +139,7 @@ const stats = await sdk.dataView.stats("ticket_stats_by_customer", {
|
|
|
137
139
|
});
|
|
138
140
|
```
|
|
139
141
|
|
|
140
|
-
性能要点:索引只能引用输出 alias;行级视图索引常用 filter/order 字段;聚合视图索引 dimensions/date buckets;`countDistinct` 和高基数维度刷新成本较高;低于 5 分钟的 scheduled refresh
|
|
142
|
+
性能要点:索引只能引用输出 alias;行级视图索引常用 filter/order 字段;聚合视图索引 dimensions/date buckets;`countDistinct` 和高基数维度刷新成本较高;低于 5 分钟的 scheduled refresh 需要用户明确确认时间敏感度。live 视图不刷新、不建索引,必须控制字段、过滤和分页。完整规则见 [`data-views.md`](data-views.md)。
|
|
141
143
|
|
|
142
144
|
## 3. Notification — `src/resources/notifications/<code>.json`
|
|
143
145
|
|
|
@@ -178,7 +180,73 @@ await sdk.notification.sendByType({
|
|
|
178
180
|
|
|
179
181
|
JS_CODE 调用:`ctx.notification.sendByType({ ... })`。允许的 channels:`inapp` / `email` / `dingding` / `wechat` / `thirdparty_todo`。完整规则见 [`notifications.md`](notifications.md)。
|
|
180
182
|
|
|
181
|
-
## 4.
|
|
183
|
+
## 4. App Function — `src/resources/functions/<functionCode>.json` + `src/functions/<functionCode>/index.ts`
|
|
184
|
+
|
|
185
|
+
```json
|
|
186
|
+
{
|
|
187
|
+
"code": "reservation_reminder_summary",
|
|
188
|
+
"name": "Reservation Reminder Summary",
|
|
189
|
+
"resources": {
|
|
190
|
+
"forms": ["reservation_order"],
|
|
191
|
+
"dataViews": ["reservation_order_overview"],
|
|
192
|
+
"connectors": ["crm"]
|
|
193
|
+
},
|
|
194
|
+
"definitionJson": {
|
|
195
|
+
"runtimeMode": "trusted_node",
|
|
196
|
+
"timeout": 30000,
|
|
197
|
+
"sourceFile": {
|
|
198
|
+
"localPath": "src/functions/reservation_reminder_summary/index.ts"
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
// src/functions/reservation_reminder_summary/index.ts
|
|
206
|
+
export default async function reservationReminderSummary(ctx, input) {
|
|
207
|
+
const orders = await ctx.form.queryMany({
|
|
208
|
+
formCode: "reservation_order",
|
|
209
|
+
filters: [{ field: "status", operator: "=", value: "pending" }],
|
|
210
|
+
pageSize: 50,
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
const overview = await ctx.dataView.query("reservation_order_overview", {
|
|
214
|
+
pageSize: 20,
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
pendingCount: orders.totalCount || orders.data?.length || 0,
|
|
219
|
+
overview: overview.data || [],
|
|
220
|
+
input,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
调用方式:
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
const result = await sdk.function.invoke("reservation_reminder_summary", {
|
|
229
|
+
input: { scope: "today" },
|
|
230
|
+
});
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
自动化 / 流程图节点调用:
|
|
234
|
+
|
|
235
|
+
```json
|
|
236
|
+
{
|
|
237
|
+
"id": "call_summary",
|
|
238
|
+
"type": "function_call",
|
|
239
|
+
"data": {
|
|
240
|
+
"functionCode": "reservation_reminder_summary",
|
|
241
|
+
"input": { "scope": "today" },
|
|
242
|
+
"saveResponseTo": "summary"
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
适用边界:可复用后端业务逻辑、跨页面/自动化/流程共享的查询编排、连接器调用、通知编排、受控平台 API 调用。当前 MVP 不暴露原始 SQL/Redis;运行时接口需要应用自动化管理权限,自动化/流程内部调用走服务端上下文。
|
|
248
|
+
|
|
249
|
+
## 5. Workflow — `src/resources/workflows/<code>/workflow.json`(manifest)+ `src/workflows/<code>/workflow.ts`(代码优先)
|
|
182
250
|
|
|
183
251
|
```jsonc
|
|
184
252
|
// src/resources/workflows/customer_approval/workflow.json
|
|
@@ -208,7 +276,7 @@ export default defineWorkflow({
|
|
|
208
276
|
|
|
209
277
|
CLI 编译为 `definition.v3.json` + `preview.json`,平台运行时仍走标准工作流引擎。完整规则见 [`workflow-v3.md`](workflow-v3.md)。
|
|
210
278
|
|
|
211
|
-
##
|
|
279
|
+
## 6. Automation — `src/resources/automations/<code>/{definition.code.json,preview.json}` + `src/automations/<code>/index.ts`
|
|
212
280
|
|
|
213
281
|
```jsonc
|
|
214
282
|
// src/resources/automations/notify_on_submit/definition.code.json
|
|
@@ -242,17 +310,18 @@ export default async function (ctx) {
|
|
|
242
310
|
|
|
243
311
|
`trigger_v2` 事件源:`form_data` / `form_field` / `workflow_task` / `workflow_process` / `mode: "scheduled"`(fixed_time / form_date_field)。完整规则见 [`automation-v3.md`](automation-v3.md)。
|
|
244
312
|
|
|
245
|
-
##
|
|
313
|
+
## 7. JS_CODE V2 — `src/js-code-nodes/<scriptCode>/index.ts`
|
|
314
|
+
|
|
315
|
+
JS_CODE V2 适合自动化/流程图里的节点级脚本。跨页面、跨自动化、需要一个稳定后端入口的可复用逻辑优先写 App Function,再用 `function_call` 节点或 `sdk.function.invoke` 调用。
|
|
246
316
|
|
|
247
317
|
```ts
|
|
248
318
|
export default async function (ctx) {
|
|
249
|
-
const { formData, operator,
|
|
250
|
-
const result = await
|
|
319
|
+
const { formData, operator, form, dataView, connector, notification, platform, utils, console } = ctx;
|
|
320
|
+
const result = await form.queryMany({
|
|
251
321
|
formCode: "customer",
|
|
252
|
-
|
|
253
|
-
searchCondition: [/* 查询条件 */],
|
|
322
|
+
filters: [/* 查询条件 */],
|
|
254
323
|
});
|
|
255
|
-
return { count: result.length };
|
|
324
|
+
return { count: result.totalCount || result.data?.length || 0 };
|
|
256
325
|
}
|
|
257
326
|
```
|
|
258
327
|
|
|
@@ -275,7 +344,9 @@ export default async function (ctx) {
|
|
|
275
344
|
|
|
276
345
|
构建:`pnpm build-js-code --script sync_customer`(先 `tsc` 再打包到 `dist/js-code-nodes/<code>/index.cjs`)。CLI validate/create/publish 时会上传快照、用 `{ bucketName, objectName, sha256 }` 替换 `sourceFile.localPath`。
|
|
277
346
|
|
|
278
|
-
|
|
347
|
+
`ctx.methods.*` 仍可用于兼容旧脚本;新脚本优先使用 `ctx.resources`、`ctx.form`、`ctx.dataView`、`ctx.connector`、`ctx.notification` 和 `ctx.platform.api`。
|
|
348
|
+
|
|
349
|
+
## 8. Role — `src/resources/roles/<code>.json`
|
|
279
350
|
|
|
280
351
|
```json
|
|
281
352
|
{
|
|
@@ -284,7 +355,7 @@ export default async function (ctx) {
|
|
|
284
355
|
}
|
|
285
356
|
```
|
|
286
357
|
|
|
287
|
-
##
|
|
358
|
+
## 9. Page Permission Group — `src/resources/permissions/page-groups/<code>.json`
|
|
288
359
|
|
|
289
360
|
```json
|
|
290
361
|
{
|
|
@@ -298,7 +369,7 @@ export default async function (ctx) {
|
|
|
298
369
|
|
|
299
370
|
`formCodes` / `pageCodes` / `menuCodes` 留空表示对匹配角色全部可见。
|
|
300
371
|
|
|
301
|
-
##
|
|
372
|
+
## 10. Form Permission Group — `src/resources/permissions/form-groups/<formCode>/<groupCode>.json`
|
|
302
373
|
|
|
303
374
|
```json
|
|
304
375
|
{
|
|
@@ -321,7 +392,7 @@ export default async function (ctx) {
|
|
|
321
392
|
}
|
|
322
393
|
```
|
|
323
394
|
|
|
324
|
-
##
|
|
395
|
+
## 11. Form Settings — `src/resources/settings/forms/<formCode>.json`
|
|
325
396
|
|
|
326
397
|
```json
|
|
327
398
|
{
|
|
@@ -339,7 +410,7 @@ export default async function (ctx) {
|
|
|
339
410
|
}
|
|
340
411
|
```
|
|
341
412
|
|
|
342
|
-
##
|
|
413
|
+
## 12. Menu — `src/resources/menus/<code>.json`
|
|
343
414
|
|
|
344
415
|
```json
|
|
345
416
|
{
|
|
@@ -359,16 +430,17 @@ export default async function (ctx) {
|
|
|
359
430
|
```text
|
|
360
431
|
需要展示数据?
|
|
361
432
|
├─ 单表 CRUD → 表单页 + DataManagementList(不要 data view)
|
|
362
|
-
├─ 多表只读联表 → src/resources/data-views
|
|
433
|
+
├─ 多表只读联表 → src/resources/data-views/(materialized 或 live)
|
|
363
434
|
├─ 表单字段下拉 → SelectField + optionSource.type: "linkedForm"(不要 data view)
|
|
364
435
|
└─ 大屏 / 报表 → 原生报表 → ECharts page
|
|
365
436
|
|
|
366
437
|
需要后端逻辑?
|
|
367
438
|
├─ 真有审批 → workflow(src/workflows/<code>/workflow.ts)
|
|
368
439
|
├─ 状态流转 → 表单 status 字段 + 状态机 + automation
|
|
440
|
+
├─ 可复用服务逻辑 → App Function(src/functions/<code>/index.ts + function_call / sdk.function.invoke)
|
|
369
441
|
├─ 提交/字段触发 → automation(trigger_v2 + src/automations/<code>/index.ts)
|
|
370
442
|
├─ 定时任务 → automation(mode: "scheduled")
|
|
371
|
-
└─
|
|
443
|
+
└─ 流程/自动化节点内脚本 → JS_CODE V2 trusted_node(src/js-code-nodes/<code>/index.ts)
|
|
372
444
|
|
|
373
445
|
需要外部数据?
|
|
374
446
|
├─ 第三方 HTTP → src/resources/connectors/ + sdk.connector.call
|
|
@@ -380,5 +452,6 @@ export default async function (ctx) {
|
|
|
380
452
|
- ❌ 把 `formUuid` / `pageId` 等平台 ID 写进 manifest。**用 code,CLI 自动解析。**
|
|
381
453
|
- ❌ 把 API key、token、密码写进 manifest。**用占位符,平台后台填真实值。**
|
|
382
454
|
- ❌ 同时在 manifest 与平台后台编辑同一个资源(漂移源)。**统一以 manifest 为单一来源**,需要看平台版本就 `resource pull`。
|
|
383
|
-
- ❌ 用 data view 代替 `linkedForm` 下拉、单表 CRUD 或写回。**data view
|
|
455
|
+
- ❌ 用 data view 代替 `linkedForm` 下拉、单表 CRUD 或写回。**data view 是只读;materialized 有刷新延迟,live 要控制查询边界。**
|
|
456
|
+
- ❌ 把跨页面/跨流程复用的后端逻辑都塞进 JS_CODE。**优先 App Function,JS_CODE 只做节点内脚本。**
|
|
384
457
|
- ❌ 在 page 源码里 hardcode `/api/notification-config/*` 或 `/connectors/actions/invoke`。**用 `sdk.notification` / `sdk.connector`。**
|
|
@@ -135,7 +135,23 @@ File snapshot:
|
|
|
135
135
|
|
|
136
136
|
AI-authored JS_CODE source must be TypeScript under `sy-lowcode-app-workspace/src/js-code-nodes/<scriptCode>/index.ts`. When validating or creating, the CLI runs `pnpm build-js-code --script <scriptCode>`, which runs TypeScript validation first, bundles to `dist/js-code-nodes/<scriptCode>/index.cjs`, uploads the bundle, and replaces `sourceFile.localPath` with immutable snapshot metadata. The backend verifies snapshot `sha256`, runs it in the trusted Node runtime, applies the node timeout (`30000` ms by default), stores execution logs, and writes the returned value to the node output and `variables.node_<nodeId>`.
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
For reusable backend logic that should be shared by pages, automations, and workflows, prefer an App Function under `src/functions/<functionCode>/index.ts` plus `src/resources/functions/<functionCode>.json`. Workflow graphs that support App Function nodes can call it with:
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
{
|
|
142
|
+
"id": "call_summary",
|
|
143
|
+
"type": "function_call",
|
|
144
|
+
"data": {
|
|
145
|
+
"functionCode": "reservation_reminder_summary",
|
|
146
|
+
"input": { "scope": "process" },
|
|
147
|
+
"saveResponseTo": "summary"
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Use JS_CODE V2 when the script is local to one workflow node.
|
|
153
|
+
|
|
154
|
+
Scripts can export `export default async function (ctx) {}` or `module.exports = async (ctx) => {}`. The runtime exposes `ctx.triggerEvent`, `ctx.formData`, `ctx.workflowData`, `ctx.operator`, `ctx.app`, `ctx.variables`, `ctx.resources`, `ctx.form`, `ctx.dataView`, `ctx.connector`, `ctx.notification`, `ctx.platform.api.*`, `ctx.utils`, `require`, `process`, and `Buffer`. Prefer `ctx.resources.resolveForm/resolveDataView/resolveConnector`, `ctx.form.queryMany/createOne/updateOne/updateById`, `ctx.dataView.query/stats`, and `ctx.connector.call/invoke` for platform-side work. Legacy data/process bridge methods remain available as `ctx.methods.queryOneData/queryManyData/updateOneData/updateDataByFormInstanceId/updateManyData/createOneData/terminateProcess/getAllParentDepartments`.
|
|
139
155
|
|
|
140
156
|
Example `src/js-code-nodes/sync_customer/index.ts`:
|
|
141
157
|
|
|
@@ -99,7 +99,7 @@ openxiangda workspace bind --profile <name> --app-type APP_XXX
|
|
|
99
99
|
- Do not search platform apps or reuse similar app names unless the user explicitly asks to reuse an existing app or gives an `appType`.
|
|
100
100
|
- Store platform-specific IDs only in `.openxiangda/state.json`.
|
|
101
101
|
- Use logical local codes for forms, pages, workflows, automations, and menus.
|
|
102
|
-
- Before scaffolding a new business app, read
|
|
102
|
+
- Before scaffolding a new business app, read `references/best-practices.md` and pick an architecture from the initialized `examples/best-practices/` catalog. Do not generate a large single-file app page when a template pattern already covers the scenario.
|
|
103
103
|
- For Phase 6 React SPA apps, use `--runtime react-spa`. The generated app owns routing/layouts/menus with React Router and Tailwind CSS; platform permissions still come from backend runtime bootstrap and route checks.
|
|
104
104
|
- React SPA form publish is schema-only by default. Do not add OSS credentials or old embedded form bundles unless explicitly maintaining legacy compatibility with `--legacy-form-bundle`.
|
|
105
105
|
- When publishing after app edits, prefer targeted commands (`workspace publish --changed --dry-run`, then `--changed`, `--page`, `--form`, or `--only`). Do not publish all forms/pages just because one page changed.
|
|
@@ -107,10 +107,12 @@ openxiangda workspace bind --profile <name> --app-type APP_XXX
|
|
|
107
107
|
|
|
108
108
|
## Resource State
|
|
109
109
|
|
|
110
|
-
Read
|
|
110
|
+
Read `references/workspace-state.md` when changing `.openxiangda/state.json`.
|
|
111
111
|
|
|
112
|
-
Read
|
|
112
|
+
Read `references/openxiangda-api.md` when exact endpoint fields are needed.
|
|
113
113
|
|
|
114
|
-
Read
|
|
114
|
+
Read `references/resource-manifest-cheatsheet.md` before creating shared resources such as data views, connectors, notifications, App Functions, workflows, automations, permissions, settings, or menus.
|
|
115
115
|
|
|
116
|
-
Read
|
|
116
|
+
Read `references/architecture-patterns.md` to understand the overall app structure (how forms, pages, menus, workflows, and permissions compose into an app, and the recommended `src/forms` / `src/pages` layout) before scaffolding or restructuring an app workspace.
|
|
117
|
+
|
|
118
|
+
Read `references/best-practices.md` before implementing app-level patterns such as status lifecycles, role governance, PC/mobile portals, high-performance data management pages, workflow boundaries, and automation.
|
|
@@ -287,7 +287,10 @@ It is responsible for:
|
|
|
287
287
|
|
|
288
288
|
## References
|
|
289
289
|
|
|
290
|
-
-
|
|
291
|
-
-
|
|
292
|
-
-
|
|
293
|
-
-
|
|
290
|
+
- `references/openxiangda-api.md` — exact endpoint contracts.
|
|
291
|
+
- `references/workspace-state.md` — `.openxiangda/state.json` shape and profile-scoped resource maps.
|
|
292
|
+
- `references/resource-manifest-cheatsheet.md` — quick templates for connectors, data views, App Functions, workflows, automations, permissions, settings, and menus.
|
|
293
|
+
- `references/data-views.md` — materialized/live data view authoring, refresh behavior, permissions, indexes, and runtime SDK usage.
|
|
294
|
+
- `references/connector-resources.md` — engineering resource folders, connector usage, App Function boundary, and platform runtime calls.
|
|
295
|
+
- `references/architecture-patterns.md` — overall architecture of an OpenXiangda app workspace (CRUD data flow, page/form layering, recommended directory organization). Read this when you need to understand how forms, pages, workflows, and platform state fit together end-to-end.
|
|
296
|
+
- `references/best-practices.md` — initialized best-practice templates and rules for modular pages, status lifecycles, role governance, data isolation, query performance, and workflow boundaries.
|
|
@@ -110,12 +110,12 @@ Do not use `openxiangda form create` as the normal way to generate a user-facing
|
|
|
110
110
|
|
|
111
111
|
Read these references only when writing or reviewing schema:
|
|
112
112
|
|
|
113
|
-
-
|
|
114
|
-
-
|
|
115
|
-
-
|
|
116
|
-
-
|
|
117
|
-
-
|
|
118
|
-
-
|
|
113
|
+
- `references/forms/form-schema.md`
|
|
114
|
+
- `references/forms/component-registry.md`
|
|
115
|
+
- `references/forms/layout-and-rules.md`
|
|
116
|
+
- `references/platform-data-model.md` — how each field type is persisted (JSONB, `{label, value}` for option fields, attachment shape). Consult before designing schema or wiring values.
|
|
117
|
+
- `references/component-guide.md` — platform component first, `antd` / `antd-mobile` fallback, and native-control ban for AI-authored app code.
|
|
118
|
+
- `references/best-practices.md` — status lifecycle fields, ownership redundancy, role-governance fields, and the boundary between normal forms and workflow forms.
|
|
119
119
|
|
|
120
120
|
## Rules
|
|
121
121
|
|
|
@@ -133,13 +133,13 @@ Read these references only when writing or reviewing schema:
|
|
|
133
133
|
- Do not copy `formUuid` from dev to prod unless the target platform explicitly already uses that ID.
|
|
134
134
|
- Keep `schema.ts` and `page.tsx` as the source for fields/layout/rules and presentation; generated build output is not the source of truth.
|
|
135
135
|
- In `schema.ts`, import `defineFormSchema` from `openxiangda` and default-export the schema.
|
|
136
|
-
- Treat `schema.ts` as the field/component contract. Prefer platform field components listed in
|
|
136
|
+
- Treat `schema.ts` as the field/component contract. Prefer platform field components listed in `references/forms/component-registry.md`; do not replace them with raw JSX controls in `page.tsx`.
|
|
137
137
|
- Keep `page.tsx` presentation-only. It may customize layout, wrappers, sections, or routing, but should render a complete OpenXiangda standard form/runtime rather than assembling isolated raw controls.
|
|
138
138
|
- If a platform field is missing for a real business need, submit feedback with `openxiangda feedback submit --yes` and then use an `antd` / `antd-mobile` wrapper as a local workaround. Report the workaround and fingerprint to the user.
|
|
139
139
|
- Put validation on field-level `rules`; never generate old top-level validation arrays under `schema.rules`. Top-level `rules` is only for `FormEffect[]` with `when` and `then`.
|
|
140
|
-
- Always provide `options` for option components. `SelectField`, `MultiSelectField`, `RadioField`, `CheckboxField`, and `CascadeSelectField` must not be emitted with `options` undefined. See
|
|
140
|
+
- Always provide `options` for option components. `SelectField`, `MultiSelectField`, `RadioField`, `CheckboxField`, and `CascadeSelectField` must not be emitted with `options` undefined. See `references/component-guide.md` for the full list and `references/platform-data-model.md` for the `{label, value}` storage contract.
|
|
141
141
|
- Do not emit raw native form controls in app/workspace source. For basic entry use `TextField`, `TextAreaField`, `NumberField`, `DateField`, `SelectField`, `RadioField`, etc.; for platform-specific entry use `UserSelectField`, `DepartmentSelectField`, `AttachmentField`, `ImageField`, `EditorField`, `DigitalSignatureField`, and `LocationField`.
|
|
142
142
|
- Workflow form pages use the same workspace form structure plus workflow v3 configuration. In legacy workspaces, publish the form page bundle through workspace publish before treating it as complete. In React SPA workspaces, `workspace publish --form` syncs schema only, and the SPA default process pages render through `runtime deploy`.
|
|
143
143
|
- After editing one form, use `workspace publish --form <formCode>` or preview `--changed --dry-run`; do not run full workspace publish by default.
|
|
144
144
|
- Use `openxiangda form pull` or app snapshot before overwriting an existing form.
|
|
145
|
-
- Before assuming a value shape (e.g. dates, attachments, member fields, option fields), verify against
|
|
145
|
+
- Before assuming a value shape (e.g. dates, attachments, member fields, option fields), verify against `references/platform-data-model.md` instead of guessing.
|
|
@@ -59,6 +59,6 @@ Use logical local codes first. If a code is missing from `.openxiangda/state.jso
|
|
|
59
59
|
|
|
60
60
|
## References
|
|
61
61
|
|
|
62
|
-
-
|
|
63
|
-
-
|
|
62
|
+
- `references/platform-data-model.md` — how each field type is persisted on the platform (JSONB, `{label, value}` for option fields, attachment shape, etc.). Consult this when a snapshot value looks unexpected so you can tell broken data from normal storage format.
|
|
63
|
+
- `references/troubleshooting.md` — catalog of known failure modes (missing styles, `options` runtime errors, mismatched option labels, etc.). Cross-check inspection findings against this list before reporting an issue or proposing a fix.
|
|
64
64
|
|