@josephyan/qingflow-app-builder-mcp 1.1.30 → 1.1.33
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 +6 -4
- package/docs/local-agent-install.md +57 -6
- package/entry_point.py +1 -1
- package/npm/bin/qingflow-app-builder-mcp.mjs +1 -1
- package/npm/bin/qingflow-skills.mjs +5 -0
- package/npm/lib/runtime.mjs +20 -59
- package/npm/scripts/postinstall.mjs +1 -10
- package/package.json +3 -2
- package/pyproject.toml +1 -1
- package/skills/qingflow-app-builder/SKILL.md +111 -55
- package/skills/qingflow-app-builder/references/complete-system-development-guide.md +169 -0
- package/skills/qingflow-app-builder/references/create-app.md +31 -24
- package/skills/qingflow-app-builder/references/environments.md +1 -1
- package/skills/qingflow-app-builder/references/gotchas.md +40 -14
- package/skills/qingflow-app-builder/references/match-rules.md +196 -85
- package/skills/qingflow-app-builder/references/public-surface-sync.md +2 -2
- package/skills/qingflow-app-builder/references/single-app-development-guide.md +84 -0
- package/skills/qingflow-app-builder/references/solution-playbooks.md +10 -0
- package/skills/qingflow-app-builder/references/tool-selection.md +40 -25
- package/skills/qingflow-app-builder/references/update-flow.md +27 -52
- package/skills/qingflow-app-builder/references/update-schema.md +14 -0
- package/skills/qingflow-app-builder/references/update-views.md +101 -32
- package/skills/qingflow-app-builder/scripts/validate_system_build_summary.py +124 -0
- package/skills/qingflow-app-builder-code-integrations/SKILL.md +5 -3
- package/skills/qingflow-app-builder-code-integrations/references/code-block.md +1 -1
- package/skills/qingflow-app-builder-code-integrations/references/q-linker.md +1 -1
- package/skills/qingflow-mcp-setup/SKILL.md +13 -9
- package/skills/qingflow-mcp-setup/references/claude-desktop.md +1 -1
- package/skills/qingflow-mcp-setup/references/environments.md +2 -1
- package/skills/qingflow-mcp-setup/references/generic-stdio.md +6 -5
- package/skills/qingflow-workflow-builder/SKILL.md +9 -7
- package/skills/qingflow-workflow-builder/references/01-overview.md +4 -2
- package/skills/qingflow-workflow-builder/references/03-flow-patterns.md +2 -0
- package/skills/qingflow-workflow-builder/references/06-stage3-build-spec.md +59 -7
- package/skills/qingflow-workflow-builder/references/07-stage4-validate-spec.md +14 -5
- package/skills/qingflow-workflow-builder/references/08-stage5-apply-verify.md +19 -3
- package/skills/qingflow-workflow-builder/references/11-troubleshooting.md +2 -0
- package/src/qingflow_mcp/__main__.py +6 -2
- package/src/qingflow_mcp/builder_facade/models.py +473 -138
- package/src/qingflow_mcp/builder_facade/service.py +6356 -1866
- package/src/qingflow_mcp/cli/commands/builder.py +358 -355
- package/src/qingflow_mcp/cli/commands/chart.py +1 -1
- package/src/qingflow_mcp/cli/commands/common.py +12 -3
- package/src/qingflow_mcp/cli/commands/exports.py +2 -2
- package/src/qingflow_mcp/cli/commands/imports.py +3 -3
- package/src/qingflow_mcp/cli/commands/portal.py +2 -2
- package/src/qingflow_mcp/cli/commands/record.py +101 -27
- package/src/qingflow_mcp/cli/commands/task.py +28 -47
- package/src/qingflow_mcp/cli/commands/view.py +1 -1
- package/src/qingflow_mcp/cli/context.py +0 -3
- package/src/qingflow_mcp/cli/formatters.py +784 -16
- package/src/qingflow_mcp/cli/main.py +120 -41
- package/src/qingflow_mcp/errors.py +43 -2
- package/src/qingflow_mcp/public_surface.py +26 -17
- package/src/qingflow_mcp/response_trim.py +81 -17
- package/src/qingflow_mcp/server.py +14 -12
- package/src/qingflow_mcp/server_app_builder.py +83 -39
- package/src/qingflow_mcp/server_app_user.py +22 -16
- package/src/qingflow_mcp/session_store.py +11 -7
- package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +173 -0
- package/src/qingflow_mcp/solution/executor.py +114 -15
- package/src/qingflow_mcp/tools/ai_builder_tools.py +3571 -1473
- package/src/qingflow_mcp/tools/app_tools.py +184 -43
- package/src/qingflow_mcp/tools/approval_tools.py +197 -35
- package/src/qingflow_mcp/tools/auth_tools.py +92 -16
- package/src/qingflow_mcp/tools/code_block_tools.py +298 -40
- package/src/qingflow_mcp/tools/custom_button_tools.py +64 -10
- package/src/qingflow_mcp/tools/directory_tools.py +236 -72
- package/src/qingflow_mcp/tools/export_tools.py +244 -34
- package/src/qingflow_mcp/tools/feedback_tools.py +9 -0
- package/src/qingflow_mcp/tools/file_tools.py +9 -3
- package/src/qingflow_mcp/tools/import_tools.py +336 -49
- package/src/qingflow_mcp/tools/navigation_tools.py +91 -12
- package/src/qingflow_mcp/tools/package_tools.py +118 -6
- package/src/qingflow_mcp/tools/portal_tools.py +39 -3
- package/src/qingflow_mcp/tools/qingbi_report_tools.py +116 -7
- package/src/qingflow_mcp/tools/record_tools.py +1141 -356
- package/src/qingflow_mcp/tools/resource_read_tools.py +188 -39
- package/src/qingflow_mcp/tools/role_tools.py +80 -9
- package/src/qingflow_mcp/tools/solution_tools.py +57 -15
- package/src/qingflow_mcp/tools/task_context_tools.py +687 -159
- package/src/qingflow_mcp/tools/task_tools.py +113 -29
- package/src/qingflow_mcp/tools/view_tools.py +106 -3
- package/src/qingflow_mcp/tools/workflow_tools.py +17 -1
- package/src/qingflow_mcp/tools/workspace_tools.py +71 -3
- package/src/qingflow_mcp/version.py +0 -2
- package/skills/qingflow-app-builder/references/build-complete-system.md +0 -234
- package/skills/qingflow-app-builder/references/build-single-app.md +0 -138
|
@@ -6,16 +6,17 @@ This playbook follows the current public builder surface, not legacy package hel
|
|
|
6
6
|
Do not use this playbook when the user is really asking for a system/package with multiple forms or modules. In that case:
|
|
7
7
|
|
|
8
8
|
1. read or create the package through `package_get` / `package_apply`
|
|
9
|
-
2. create related apps
|
|
9
|
+
2. create the related apps in one `app_schema_apply(package_id=..., apps=[...])` call
|
|
10
10
|
3. keep package ownership on the public `package_id` path instead of a separate attach step
|
|
11
|
-
4. add relation fields
|
|
11
|
+
4. add same-call relation fields with `target_app_ref` when one new app references another new app; use `target_app_key` only after the target app already exists or readback confirms it
|
|
12
|
+
5. choose explicit non-template `icon + color` for each new package/app
|
|
12
13
|
|
|
13
14
|
Hierarchy reminder:
|
|
14
15
|
|
|
15
16
|
- package -> app -> field -> relation
|
|
16
17
|
- another business object is another app, not a text field
|
|
17
18
|
|
|
18
|
-
If creating a brand new package would help, ask the user to confirm package creation first. After confirmation, create it through `package_apply(
|
|
19
|
+
If creating a brand new package would help, ask the user to confirm package creation first. After confirmation, create it through `package_apply(package_name=..., icon=..., color=...)`.
|
|
19
20
|
|
|
20
21
|
## Minimal sequence
|
|
21
22
|
|
|
@@ -36,12 +37,25 @@ then do not treat that as one app.
|
|
|
36
37
|
|
|
37
38
|
Use this pattern instead:
|
|
38
39
|
|
|
39
|
-
1. `package_get` or `package_apply(
|
|
40
|
-
2. for a multi-app system, run one `app_schema_apply` with `apps[]`
|
|
40
|
+
1. `package_get` or `package_apply(package_name=..., icon=..., color=...)`
|
|
41
|
+
2. for a multi-app system, run one `app_schema_apply` with `package_id` and `apps[]`
|
|
41
42
|
3. use `apps[].client_key` plus relation field `target_app_ref` when one new app references another new app
|
|
42
43
|
|
|
44
|
+
If that multi-app call times out, returns `partial_success`, returns `write_executed=true`, has `safe_to_retry=false`, or has incomplete readback, do not decide that the create failed. Run `readback_before_retry`: read the package, resolve each intended app by package/name or returned app key, read fields, and retry only verified missing apps or fields. Do not rebuild the same complete system as separate single-app creates, and do not create `V2`, `测试`, timestamp, or random-suffix apps to bypass duplicate names.
|
|
45
|
+
|
|
43
46
|
## Example
|
|
44
47
|
|
|
48
|
+
When designing fields, do not add platform system fields such as `数据ID`, `编号`, `申请人`, `申请时间`, `创建人`, `创建时间`, `提交人`, `提交时间`, `更新时间`, `更新人`, `当前流程状态`, `当前处理人`, `当前处理节点`, or `流程标题`. Qingflow provides them automatically; create only business fields.
|
|
49
|
+
|
|
50
|
+
Field authoring rules:
|
|
51
|
+
|
|
52
|
+
- Use intuitive field types in drafts: `text`, `multiline`, `select`, `multi_select`, `number`, `amount`, `date`, `datetime`, `member`, `department`, `attachment`, `relation`.
|
|
53
|
+
- The tool normalizes aliases before writing: `multiline -> long_text`, `select -> single_select`, `checkbox -> multi_select`, `currency -> amount`, `mobile -> phone`. Readback may show canonical types; that is not a failed write.
|
|
54
|
+
- Every new app must have exactly one top-level `as_data_title: true` field. `as_data_cover: true` is optional and only valid on a top-level `attachment`.
|
|
55
|
+
- Select fields must define `options` during schema design. Options may be strings or objects such as `{"label": "进行中"}`; sample data must use those labels or ids.
|
|
56
|
+
- Relation fields must use `target_app_ref` for same-batch apps or `target_app_key` for existing apps, plus object selectors: `display_field: {"name": "..."}` and `visible_fields: [{"name": "..."}]`. Do not write bare strings for display/visible field selectors.
|
|
57
|
+
- Do not impose a one-relation-field-per-app limit. Model the real business links and let backend validation/readback decide.
|
|
58
|
+
|
|
45
59
|
Create a new package only after the user confirms package creation:
|
|
46
60
|
|
|
47
61
|
```json
|
|
@@ -50,7 +64,8 @@ Create a new package only after the user confirms package creation:
|
|
|
50
64
|
"arguments": {
|
|
51
65
|
"profile": "default",
|
|
52
66
|
"package_name": "研发项目管理",
|
|
53
|
-
"
|
|
67
|
+
"icon": "briefcase",
|
|
68
|
+
"color": "azure"
|
|
54
69
|
}
|
|
55
70
|
}
|
|
56
71
|
```
|
|
@@ -76,21 +91,16 @@ Apply schema for a new app:
|
|
|
76
91
|
"profile": "default",
|
|
77
92
|
"app_name": "客户订单",
|
|
78
93
|
"package_id": 1218950,
|
|
79
|
-
"
|
|
94
|
+
"icon": "delivery-box-1",
|
|
95
|
+
"color": "emerald",
|
|
80
96
|
"publish": true,
|
|
81
97
|
"add_fields": [
|
|
82
98
|
{"name": "订单编号", "type": "text", "required": true, "as_data_title": true},
|
|
83
99
|
{"name": "客户名称", "type": "text", "required": true},
|
|
84
100
|
{"name": "订单封面", "type": "attachment", "as_data_cover": true},
|
|
85
101
|
{"name": "订单金额", "type": "amount"},
|
|
86
|
-
{"name": "状态", "type": "
|
|
102
|
+
{"name": "状态", "type": "select", "options": [{"label": "草稿"}, {"label": "进行中"}, {"label": "已完成"}], "required": true}
|
|
87
103
|
],
|
|
88
|
-
"form": {
|
|
89
|
-
"sections": [
|
|
90
|
-
{"title": "基础信息", "rows": [["订单编号", "客户名称"], ["状态"]]},
|
|
91
|
-
{"title": "金额与附件", "rows": [["订单金额"], ["订单封面"]]}
|
|
92
|
-
]
|
|
93
|
-
},
|
|
94
104
|
"update_fields": [],
|
|
95
105
|
"remove_fields": []
|
|
96
106
|
}
|
|
@@ -105,24 +115,22 @@ Apply schema for multiple apps in one call:
|
|
|
105
115
|
"arguments": {
|
|
106
116
|
"profile": "default",
|
|
107
117
|
"package_id": 1218950,
|
|
108
|
-
"create_if_missing": true,
|
|
109
118
|
"publish": true,
|
|
110
119
|
"apps": [
|
|
111
120
|
{
|
|
112
121
|
"client_key": "customer",
|
|
113
122
|
"app_name": "客户",
|
|
114
|
-
"icon": "
|
|
115
|
-
"color": "
|
|
123
|
+
"icon": "business-personalcard",
|
|
124
|
+
"color": "emerald",
|
|
116
125
|
"add_fields": [
|
|
117
126
|
{"name": "客户名称", "type": "text", "required": true, "as_data_title": true}
|
|
118
|
-
]
|
|
119
|
-
"form": {"sections": [{"title": "基础信息", "rows": [["客户名称"]]}]}
|
|
127
|
+
]
|
|
120
128
|
},
|
|
121
129
|
{
|
|
122
130
|
"client_key": "order",
|
|
123
131
|
"app_name": "订单",
|
|
124
132
|
"icon": "delivery-box-1",
|
|
125
|
-
"color": "
|
|
133
|
+
"color": "blue",
|
|
126
134
|
"add_fields": [
|
|
127
135
|
{"name": "订单编号", "type": "text", "required": true, "as_data_title": true},
|
|
128
136
|
{
|
|
@@ -132,8 +140,7 @@ Apply schema for multiple apps in one call:
|
|
|
132
140
|
"display_field": {"name": "客户名称"},
|
|
133
141
|
"visible_fields": [{"name": "客户名称"}]
|
|
134
142
|
}
|
|
135
|
-
]
|
|
136
|
-
"form": {"sections": [{"title": "基础信息", "rows": [["订单编号", "关联客户"]]}]}
|
|
143
|
+
]
|
|
137
144
|
}
|
|
138
145
|
]
|
|
139
146
|
}
|
|
@@ -146,11 +153,11 @@ Data title is required: mark exactly one top-level field with `as_data_title: tr
|
|
|
146
153
|
|
|
147
154
|
### `APP_NOT_FOUND`
|
|
148
155
|
|
|
149
|
-
|
|
156
|
+
For new apps, submit `app_schema_apply` with `package_id + app_name + icon + color`. For existing apps, resolve and pass the real `app_key`.
|
|
150
157
|
|
|
151
158
|
### `CREATE_APP_ROUTE_NOT_FOUND`
|
|
152
159
|
|
|
153
|
-
The create route did not resolve in the current backend route context.
|
|
160
|
+
The create route did not resolve in the current backend route context. In Wingent Momo runtime, first retry the same `app_schema_apply` after confirming the injected session is still active. Only run `workspace_select` if a business tool explicitly reports a missing or wrong workspace.
|
|
154
161
|
|
|
155
162
|
### Hierarchy modeling mistake
|
|
156
163
|
|
|
@@ -16,7 +16,7 @@ If the user did not specify an environment, default to `prod`.
|
|
|
16
16
|
Use test for:
|
|
17
17
|
|
|
18
18
|
- first application of a new `SolutionSpec`
|
|
19
|
-
- trying `
|
|
19
|
+
- trying builder apply flows end-to-end with readback verification, or `solution_install` when the user is installing an existing packaged solution
|
|
20
20
|
- package initialization and schema evolution experiments
|
|
21
21
|
- mock data creation, with at least `5` records per relevant entity unless the user asks for fewer
|
|
22
22
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
## Auth and workspace
|
|
4
4
|
|
|
5
5
|
- `auth_*` success does not mean a workspace is selected
|
|
6
|
-
-
|
|
6
|
+
- In Wingent Momo runtime, do not run `workspace_select` before builder work. Re-run it only after an explicit auth/route recovery or when a business tool reports the workspace is missing.
|
|
7
7
|
|
|
8
8
|
## Package ownership
|
|
9
9
|
|
|
@@ -17,13 +17,14 @@
|
|
|
17
17
|
- Another app is not a field
|
|
18
18
|
- If the user names multiple forms/modules that relate to each other, create multiple apps and connect them with relation fields
|
|
19
19
|
- Do not use child app names like “项目/需求/任务/缺陷/团队” as plain text fields inside one app
|
|
20
|
+
- For a complete system, the main creation path is one multi-app `app_schema_apply(package_id=..., apps=[...])` with stable `apps[].client_key` values and same-call relation fields using `target_app_ref`
|
|
21
|
+
- Use `target_app_key` only for an app that already exists or has been confirmed by readback
|
|
20
22
|
|
|
21
|
-
##
|
|
23
|
+
## Auto publish
|
|
22
24
|
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
- `app_associated_resources_apply`
|
|
26
|
-
- `app_charts_apply` is immediate-live and has no publish step
|
|
25
|
+
- `app_schema_apply`, `app_layout_apply`, `app_flow_apply`, and `app_views_apply` publish by default
|
|
26
|
+
- For those four tools, pass `publish=false` only when the user explicitly wants to leave changes in draft
|
|
27
|
+
- `app_custom_buttons_apply` and `app_associated_resources_apply` publish after at least one write succeeds and do not accept `publish=false`
|
|
27
28
|
- `app_publish_verify` is for explicit final verification, not the default next step after every write
|
|
28
29
|
|
|
29
30
|
## BI Reports
|
|
@@ -32,18 +33,29 @@
|
|
|
32
33
|
- Use `app_associated_resources_apply` only when an existing BI report or view needs to appear in the Qingflow app associated-resource area or a specific view.
|
|
33
34
|
- `app_charts_apply` currently creates/updates app-source BI reports only (`dataSourceType=qingflow`); dataset BI reports can only be attached when they already exist.
|
|
34
35
|
- Creating a chart with `app_charts_apply` does not automatically show it in the Qingflow app UI; attach it separately if display is required.
|
|
36
|
+
- Main chart config should use semantic `metric`, `metrics`, `group_by`, and `where`; avoid raw `indicator_field_ids`, `selectedMetrics`, and QingBI filter matrices unless diagnosing or preserving existing raw config.
|
|
35
37
|
- `target` and `table` remain compatibility aliases for QingBI `indicator` and `detail`; use the real QingBI chart type when you need a specific type such as `summary`, `columnar`, `stacked_bar`, `scatter`, or `dualaxes`.
|
|
38
|
+
- Use `app_get_fields.chart_fields` as the source for dimensions, metrics, and filters. Record schema fields or normal form fields are not enough for chart apply.
|
|
39
|
+
- Use `target` / `indicator` for one metric card; do not use `summary` for a single KPI.
|
|
36
40
|
|
|
37
|
-
##
|
|
41
|
+
## Custom buttons
|
|
38
42
|
|
|
39
|
-
-
|
|
40
|
-
-
|
|
43
|
+
- For ordinary view-specific business buttons, use `app_views_apply` with `action_buttons`; do not use legacy `app_views_apply.buttons` unless you are maintaining an old full-replacement patch.
|
|
44
|
+
- Use `app_custom_buttons_apply` for advanced button creation/update/removal and view placement: custom style/icon, cross-view reuse, deleting button bodies, bulk binding reorder, or exact qRobot/wings configs.
|
|
45
|
+
- When changing one existing button parameter, use `patch_buttons` with `set/unset`. Do not send a partial `upsert_buttons` object and expect the backend to preserve hidden required fields.
|
|
46
|
+
- `addData` / `add_data` creates a related/downstream Qingflow record; use current-record `field_mappings` only on `detail` or `list`. `link` only opens a URL. `qRobot`/`wings` require user-provided exact config and must not be invented.
|
|
47
|
+
- For add-data buttons, prefer semantic `trigger_add_data_config.target_app_key`, `field_mappings`, and `default_values`.
|
|
41
48
|
- Do not handwrite raw `que_relation` unless you are preserving an existing backend config. If `field_mappings` and `que_relation` are mixed, the tool blocks the write.
|
|
42
49
|
- `field_mappings.source_field` can use source app fields and supported system fields such as `数据ID` (`field_id=-17`) and `编号` (`field_id=0`).
|
|
43
50
|
- To fill a target relation field with the current source record, map `{"source_field": "数据ID", "target_field": "目标引用字段"}`. Use `default_values` only for static constants.
|
|
51
|
+
- Do not put current-record `field_mappings` on a `header` button; `header` has no current row. Use `detail` or `list` for current-record add-data actions.
|
|
52
|
+
- Do not model approval, rejection, close-task, or status transition as a generic `link` button. Use workflow/task behavior, or `qRobot`/`wings` only when the user provides existing automation config.
|
|
44
53
|
- For field type compatibility, read `references/match-rules.md`.
|
|
45
|
-
-
|
|
54
|
+
- Use `header` for global actions with no current-row context, `detail` for safest current-record actions, and `list` for row/list actions.
|
|
55
|
+
- `view_configs[].buttons` is required in merge mode. Do not send a view config with only `view_key`; it is blocked to avoid no-op writes and accidental publish.
|
|
46
56
|
- Builder view configs use raw `view_key` from `app_get.views[].view_key`; do not prefix it with `custom:`. The `custom:<viewKey>` form is for record-data `view_id`.
|
|
57
|
+
- View button bindings merge by default. Use `view_configs[].mode="replace"` to replace the full set, or pass an explicit empty `buttons: []` when you intend to clear all custom button bindings for that view.
|
|
58
|
+
- Advanced view button bindings can include `button_limit`, `button_formula`, `button_formula_type`, and `print_tpls`, but keep ordinary buttons simple unless the user asks for conditional visibility or print templates.
|
|
47
59
|
- `placement=list` configures row/list buttons. The tool maps it to the backend `INSIDE` button position, not a raw `LIST` config type.
|
|
48
60
|
|
|
49
61
|
## Associated resources
|
|
@@ -64,11 +76,18 @@
|
|
|
64
76
|
|
|
65
77
|
## Partial update discipline
|
|
66
78
|
|
|
67
|
-
- Existing views, associated resources, and charts
|
|
79
|
+
- Existing views use `app_views_apply.views[]` with `operation="patch"` plus `set` and optional `unset`; custom buttons, associated resources, and charts use their `patch_*[].set` plus optional `patch_*[].unset`.
|
|
68
80
|
- The backend may still save a full payload. The MCP/CLI patch path is responsible for reading current config and preserving fields the user did not mention.
|
|
69
|
-
- Do not use `
|
|
81
|
+
- Do not use view `operation="upsert"`, `upsert_buttons`, `upsert_resources`, or `upsert_charts` for a tiny parameter replacement unless you are deliberately providing the full desired target config.
|
|
70
82
|
- `app_layout_apply(mode=merge)` is already a safe layout merge path; `mode=replace` is full layout replacement.
|
|
71
|
-
- `portal_apply` without `sections` is base-info-only. Supplying `sections` replaces the portal sections list.
|
|
83
|
+
- `portal_apply` without `sections` is base-info-only. Supplying `sections` replaces the portal sections list; use `patch_sections[]` for one-section updates.
|
|
84
|
+
- PC portal layout is 24-column. Group components by the same `y`: all components in that row must have the same `rows`, and their `cols` should sum to 24 unless the user explicitly wants blank space.
|
|
85
|
+
- Standard workbench heights: metric cards `rows=5`, BI charts `rows=7`, data views `rows=11`.
|
|
86
|
+
- Business-entry `grid` sections must include real `config.items[]`; an empty grid container is not a valid business entrance.
|
|
87
|
+
- Build portals only after referenced apps, raw `view_key`s, and chart ids/keys are known by readback. Intended names are not enough.
|
|
88
|
+
- Use standard order: business entry -> metric cards -> BI charts -> concrete data views.
|
|
89
|
+
- Do not use platform default views such as `全部数据` / `我的数据` as the main portal views.
|
|
90
|
+
- Do not use portal `source_type: "filter"` as the normal automation path; it is raw/unstable and not part of the unified filter DSL.
|
|
72
91
|
- `app_flow_apply` is intentionally replace-only for the public linear workflow graph.
|
|
73
92
|
|
|
74
93
|
## Workflow dependencies
|
|
@@ -85,15 +104,22 @@
|
|
|
85
104
|
## Retry discipline
|
|
86
105
|
|
|
87
106
|
- If a write returns `partial_success`, read back before retrying
|
|
107
|
+
- If multi-app schema apply times out, returns `write_executed=true`, returns `safe_to_retry=false`, or has incomplete readback, treat it as `write_may_have_succeeded`; the next action is `readback_before_retry`
|
|
108
|
+
- `readback_before_retry` means read package/app/fields first, classify which intended apps and relation fields actually exist, and retry only the verified missing slice
|
|
88
109
|
- Do not repeat create steps after `app_key` already exists
|
|
110
|
+
- Do not split a complete-system schema create into single-app rebuilds until readback proves exactly what is missing
|
|
111
|
+
- Do not bypass duplicate/conflict states by inventing `V2`, `测试`, timestamp, or random-suffix app names in a real business package
|
|
89
112
|
- For backend rejects, keep the retry narrow: retry only the failed tool, not the whole chain
|
|
90
113
|
- For `VALIDATION_ERROR`, do not keep guessing. Reuse `suggested_next_call`, `canonical_arguments`, `allowed_keys`, and `allowed_values` first.
|
|
114
|
+
- For `builder_tool_contract`, read the returned `json_paths` first. Successful contract data is under `$.contract`; `allowed_values` uses flat dotted keys such as `["field.type"]`, not nested objects. Do not read successful field enums from top-level `allowed_values`.
|
|
115
|
+
- For `workspace_icon_catalog_get`, read icon candidates from `$.icon_names` and colors from `$.icon_colors`.
|
|
116
|
+
- For builder apply responses, read returned `json_paths` first. Stable fields are `$.summary` and `$.resources[]`; use `resources[].id/key/name` before legacy top-level fields.
|
|
91
117
|
- For layout `VALIDATION_ERROR`, also inspect `section_allowed_keys`, `section_aliases`, and `minimal_section_example`. If the same layout-shape error repeats twice, stop free-form retries and re-read `builder_tool_contract(app_layout_apply)`.
|
|
92
118
|
- For flow work, do not replay internal keys from old logs or plan outputs. Public builder calls should stay on:
|
|
93
119
|
- `assignees.role_ids` / `assignees.member_uids` / `assignees.member_emails`
|
|
94
120
|
- `permissions.editable_fields`
|
|
95
121
|
- For view work, treat `columns` as the only canonical public key. `app_get_views` and `app_views_apply` should all be read and written in that shape.
|
|
96
|
-
- For existing view parameter changes, prefer `
|
|
122
|
+
- For existing view parameter changes, prefer `views[]` with `operation="patch"`. Example: to change only query-panel fields, set only `query_conditions`; the tool will preserve columns, filters, date config, card fields, buttons, and other backend-required fields.
|
|
97
123
|
- For layout work, treat `title + rows` as the only canonical public section shape. `fields`, `field_ids`, and `columns` may appear in legacy/internal shapes, but they are not the preferred public write shape.
|
|
98
124
|
- A created view is not enough to claim a filter succeeded. When `app_views_apply` returns `partial_success`, `views_verified=false`, or `details.filter_mismatches`, treat the view as present but the filter as unverified.
|
|
99
125
|
- If duplicate view names exist, do not retry by name. Read the exact `view_key` and target that one.
|
|
@@ -1,118 +1,229 @@
|
|
|
1
|
-
# Builder
|
|
1
|
+
# Builder 统一筛选 / 条件写法
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
本文适用于 Builder 侧所有给智能体公开的筛选和条件入口:
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
- 视图固定筛选:`builder views apply` 的 `filters`
|
|
6
|
+
- 视图动作按钮显示条件:`action_buttons[].visible_when`
|
|
7
|
+
- QingBI 图表筛选:`builder charts apply` 或 `portal apply sections[].chart.filters`
|
|
8
|
+
- 关联视图 / 关联报表匹配:`builder associated-resource apply` 的 `match_mappings`
|
|
9
|
+
- 新增下游记录传参:`field_mappings` / `default_values`
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
它不是 `record_access` 分析筛选 DSL。数据分析仍走 `record access` 的 `where` 规则。
|
|
12
|
+
流程条件属于 WorkflowSpec 路径:先读 `app_flow_get_schema` / `app_get_flow`,再按读回结构修改;不要把 raw workflow `autoJudges/judgeType` 混入视图、报表、关联资源的公共筛选 DSL。
|
|
8
13
|
|
|
9
|
-
|
|
10
|
-
- `app_views_apply.patch_views[].set.action_buttons[].field_mappings`
|
|
11
|
-
- `app_associated_resources_apply.upsert_resources[].match_mappings`
|
|
12
|
-
- `app_associated_resources_apply.patch_resources[].set.match_mappings`
|
|
14
|
+
公开写法按场景选择,智能体不要混用。**operator 语义完全一致,区别只在字段名键**:
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
- **固定筛选**:`field_name + operator + value/values`
|
|
17
|
+
- **关联资源上下文匹配**:`target_field + operator + source_field/value`
|
|
18
|
+
- **新增数据传参**:`source_field + target_field`;静态默认值写 `default_values`
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
不要直接写 `judgeType`、`judgeValues`、`matchRules`、`beforeAggregationFilterMatrix`。CLI 会按目标协议自动编译,并在读回时还原为业务语义。
|
|
17
21
|
|
|
18
|
-
|
|
22
|
+
最短判断:
|
|
19
23
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
| 你想表达 | 写法 | 示例 |
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| 当前视图/图表只显示某类数据 | `filters` | `{"field_name":"状态","operator":"eq","value":"进行中"}` |
|
|
27
|
+
| 关联报表/关联视图只显示“当前记录相关”的数据 | `match_mappings` + `source_field` | `{"target_field":"关联客户","operator":"eq","source_field":"数据ID"}` |
|
|
28
|
+
| 关联报表/关联视图再加一个固定条件 | `match_mappings` + `value/values` | `{"target_field":"状态","operator":"eq","value":"有效"}` |
|
|
29
|
+
| 从当前记录创建下游记录并带值 | `field_mappings` | `{"source_field":"数据ID","target_field":"关联工单"}` |
|
|
24
30
|
|
|
25
|
-
|
|
31
|
+
---
|
|
26
32
|
|
|
27
|
-
##
|
|
33
|
+
## 1. `operator` / `value` 统一规则
|
|
28
34
|
|
|
29
|
-
|
|
35
|
+
| `operator` | 含义 | `value/values` |
|
|
36
|
+
| --- | --- | --- |
|
|
37
|
+
| `eq` | 等于 | 单值用 `value` |
|
|
38
|
+
| `neq` | 不等于 | 单值用 `value` |
|
|
39
|
+
| `in` | 任一匹配 | 多值用 `values` |
|
|
40
|
+
| `contains` | 包含 / 模糊包含 | 单值用 `value` |
|
|
41
|
+
| `gte` | 大于等于 | 单值用 `value` |
|
|
42
|
+
| `lte` | 小于等于 | 单值用 `value` |
|
|
43
|
+
| `is_empty` | 为空 | 不写 `value/values` |
|
|
44
|
+
| `not_empty` | 不为空 | 不写 `value/values` |
|
|
45
|
+
|
|
46
|
+
`operator` 省略时按 `eq` 处理,但主示例必须显式写 `operator`。`value` 是单值主写法;`values` 是多值主写法。CLI 兼容 `value` 传数组、`values` 传单个标量,但不要把兼容形态当主示例。
|
|
47
|
+
|
|
48
|
+
兼容别名:`equal`、`equals`、`=`、`==`、`!=`、`not_equal`、`any_of`、`one_of`、`include`、`like`、`empty`、`is null`、`not empty`、`not null`。主示例只写上表 canonical operator。
|
|
49
|
+
|
|
50
|
+
### 1.1 不同字段类型的值写法
|
|
51
|
+
|
|
52
|
+
默认优先写业务可读值,但要区分字段类型。选项字段(单选/多选/是否)在视图筛选、QingBI 筛选、关联资源静态筛选中均支持选项文本或 option id,CLI 会按目标协议自动转成 id 或文本。成员、部门、关联记录这类实体字段在固定筛选里优先写唯一 id 或 `{id,value}`;只有新增数据默认值、record 写入、候选解析类路径才先写名称,解析失败后再按候选改成 id。
|
|
53
|
+
|
|
54
|
+
| 字段类型 | 推荐值写法 | 示例 |
|
|
55
|
+
| --- | --- | --- |
|
|
56
|
+
| 文本 / 长文本 / 手机 / 邮箱 | 字符串;模糊匹配用 `contains` | `{"field_name":"客户名称","operator":"contains","value":"上海"}` |
|
|
57
|
+
| 数字 / 金额 | JSON 数字;范围用 `gte` / `lte` | `{"field_name":"金额","operator":"gte","value":10000}` |
|
|
58
|
+
| 日期 / 日期时间 | 字符串;优先 `YYYY-MM-DD` 或 `YYYY-MM-DD HH:mm:ss` | `{"field_name":"计划日期","operator":"lte","value":"2026-06-30"}` |
|
|
59
|
+
| 单选 | 选项文本或 option id;优先写文本;对象可写 `{id,value}` / `{optId,optValue}` | `{"field_name":"状态","operator":"eq","value":"进行中"}` 或 `{"field_name":"状态","operator":"eq","value":"160712876"}` |
|
|
60
|
+
| 多选 | 多值用 `values`;每一项可写选项文本、option id 或选项对象 | `{"field_name":"标签","operator":"in","values":["重点","续约"]}` |
|
|
61
|
+
| 布尔 / 是否 | 按字段实际选项文本写,通常是 `是` / `否` | `{"field_name":"是否逾期","operator":"eq","value":"是"}` |
|
|
62
|
+
| 成员 / 部门 | 固定筛选写唯一 id 或 `{id,value}`;候选解析类写入路径可先写名称 | `{"field_name":"负责人","operator":"eq","value":{"id":123,"value":"沈嘉慧"}}` |
|
|
63
|
+
| 关联记录 / relation | 固定筛选写目标记录真实 `record_id/apply_id`;当前记录跨应用匹配用 `source_field:"数据ID"` | `{"field_name":"关联客户","operator":"eq","value":"535734615263924225"}` |
|
|
64
|
+
| 引用 / 数据填充字段 | 按读回展示类型写值;若本质来自选项字段,仍优先写展示文本 | `{"field_name":"客户等级","operator":"eq","value":"A"}` |
|
|
65
|
+
|
|
66
|
+
字段值选择原则:
|
|
67
|
+
|
|
68
|
+
- 选项字段:优先写选项文本,例如 `"正常"`;如果文本不唯一或来自读回,也可写 option id,例如 `"160712876"`。
|
|
69
|
+
- 成员/部门:固定筛选优先写 id 或 `{id,value}`;record 写入、默认值等候选解析路径可先写名称,若返回 `needs_confirmation` 再按候选改成 id。
|
|
70
|
+
- 关联/relation:固定筛选写目标记录真实 `record_id/apply_id`;跨应用当前记录匹配写 `source_field:"数据ID"`,不要写前端编号。
|
|
71
|
+
- 引用/数据填充字段:按前端展示的业务值写;如果引用来源是选项字段,仍优先写选项文本。
|
|
72
|
+
- 读回口径:`builder view/chart/associated-resource get` 优先返回业务文本和 canonical `operator`,不把后端数字 `judgeType`、option id、`matchRules` 作为智能体主输出。raw `config` 只用于诊断。
|
|
73
|
+
|
|
74
|
+
空值判断示例:
|
|
30
75
|
|
|
31
76
|
```json
|
|
32
|
-
{
|
|
33
|
-
"target_app_key": "WORKLOG_APP",
|
|
34
|
-
"field_mappings": [
|
|
35
|
-
{"source_field": "数据ID", "target_field": "关联员工"},
|
|
36
|
-
{"source_field": "员工名称", "target_field": "员工姓名"}
|
|
37
|
-
],
|
|
38
|
-
"default_values": {
|
|
39
|
-
"状态": "待提交"
|
|
40
|
-
}
|
|
41
|
-
}
|
|
77
|
+
{"field_name": "完工日期", "operator": "is_empty"}
|
|
42
78
|
```
|
|
43
79
|
|
|
44
|
-
|
|
80
|
+
读回示例:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{"field_name":"使用状态","operator":"eq","value":"正常"}
|
|
84
|
+
{"target_field":"状态","operator":"in","values":["有效","待提交"]}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 2. 当前记录上下文匹配
|
|
45
90
|
|
|
46
|
-
|
|
91
|
+
优先使用语义化映射,不手写后端 raw `que_relation` / `match_rules`。
|
|
92
|
+
|
|
93
|
+
心智模型:**同一个 operator,同一套 value 规则;只是当前记录匹配要把 `field_name` 改成 `target_field`,并用 `source_field` 表示当前记录字段。**
|
|
94
|
+
|
|
95
|
+
- 固定筛选当前资源自己的数据:`field_name + operator + value/values`
|
|
96
|
+
- 用当前记录过滤另一个资源:`target_field + operator + source_field`
|
|
97
|
+
- 给另一个资源加静态筛选:`target_field + operator + value/values`
|
|
98
|
+
- 从当前记录创建下游记录时传值:`source_field + target_field`,不写 `operator`
|
|
99
|
+
|
|
100
|
+
`operator` 和 `value/values` 的含义与 §1 完全一致。`operator` 省略时默认为 `eq`,但为了可读性,主配置仍推荐显式写出。
|
|
101
|
+
不要把跨应用“当前记录匹配”写成 `filters`:`filters` 只筛当前视图/报表自己的数据;`match_mappings` 才表示“拿当前记录的某个字段去匹配另一个资源”。
|
|
102
|
+
|
|
103
|
+
### 2.1 新增数据按钮
|
|
47
104
|
|
|
48
105
|
```json
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
"
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
106
|
+
[
|
|
107
|
+
{
|
|
108
|
+
"client_key": "add_worklog",
|
|
109
|
+
"button_text": "快捷添加工时",
|
|
110
|
+
"trigger_action": "addData",
|
|
111
|
+
"trigger_add_data_config": {
|
|
112
|
+
"target_app_key": "WORKLOG_APP",
|
|
113
|
+
"field_mappings": [
|
|
114
|
+
{"source_field": "数据ID", "target_field": "关联员工"},
|
|
115
|
+
{"source_field": "员工名称", "target_field": "员工姓名"}
|
|
116
|
+
],
|
|
117
|
+
"default_values": {
|
|
118
|
+
"状态": "待提交"
|
|
63
119
|
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
]
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
`field_mappings` 表示从当前记录动态带值,不需要 `operator`;`default_values` 只表示静态默认值。
|
|
126
|
+
|
|
127
|
+
### 2.2 关联视图 / 报表
|
|
128
|
+
|
|
129
|
+
跨应用关联必须显式传 `target_app_key`。若关联的是当前应用自己的视图或报表,可以省略 `target_app_key`,CLI 会默认使用命令里的 `--app-key`。
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
[
|
|
133
|
+
{
|
|
134
|
+
"client_key": "employee_worklogs",
|
|
135
|
+
"graph_type": "view",
|
|
136
|
+
"target_app_key": "WORKLOG_APP",
|
|
137
|
+
"view_key": "WORKLOG_VIEW",
|
|
138
|
+
"match_mappings": [
|
|
139
|
+
{"target_field": "关联员工", "source_field": "数据ID"},
|
|
140
|
+
{"target_field": "状态", "value": "待提交"}
|
|
64
141
|
]
|
|
65
142
|
}
|
|
66
|
-
|
|
143
|
+
]
|
|
67
144
|
```
|
|
68
145
|
|
|
69
|
-
|
|
146
|
+
动态条件用 `source_field`;静态条件用 `value/values`。如果一个条件写了 `source_field`,就不要再写 `value/values`。
|
|
147
|
+
|
|
148
|
+
`field_name` / `field` 可作为 `target_field` 别名;静态单值写 `value`,多值写 `values`,空值类 operator 不写值。
|
|
70
149
|
|
|
71
|
-
|
|
150
|
+
跨应用 relation 最常见写法是把当前记录的数据 ID 匹配到目标应用的引用字段:
|
|
72
151
|
|
|
73
152
|
```json
|
|
74
|
-
{
|
|
75
|
-
"graph_type": "view",
|
|
76
|
-
"target_app_key": "WORKLOG_APP",
|
|
77
|
-
"view_key": "WORKLOG_VIEW",
|
|
78
|
-
"match_mappings": [
|
|
79
|
-
{"target_field": "关联员工", "source_field": "数据ID"},
|
|
80
|
-
{"target_field": "状态", "value": "待提交"}
|
|
81
|
-
]
|
|
82
|
-
}
|
|
153
|
+
{"target_field": "关联客户", "operator": "eq", "source_field": "数据ID"}
|
|
83
154
|
```
|
|
84
155
|
|
|
85
|
-
|
|
156
|
+
这里 `target_field` 是被关联资源所在应用里的字段,`source_field` 是当前详情页这条记录里的字段。不要把它写成视图/报表 `filters`,也不要手写 `matchRules`。
|
|
86
157
|
|
|
87
|
-
|
|
158
|
+
如果 `target_field` 是目标应用中的引用 / relation 字段,最稳妥的当前记录匹配值是 `source_field: "数据ID"`,因为它表示当前记录真实 `record_id/apply_id`。不要用前端可见 `编号` 代替,除非目标字段本身就是文本/编号字段。
|
|
159
|
+
|
|
160
|
+
示例:
|
|
88
161
|
|
|
89
162
|
```json
|
|
90
|
-
{
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
163
|
+
{"target_field": "客户ID", "operator": "eq", "source_field": "数据ID"}
|
|
164
|
+
{"target_field": "状态", "operator": "eq", "value": "有效"}
|
|
165
|
+
{"target_field": "状态", "operator": "in", "values": ["有效", "待提交"]}
|
|
166
|
+
{"target_field": "归档说明", "operator": "is_empty"}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## 3. 系统字段
|
|
172
|
+
|
|
173
|
+
系统字段可以参与匹配:
|
|
174
|
+
|
|
175
|
+
| 写法 | field_id | 含义 |
|
|
176
|
+
| --- | --- | --- |
|
|
177
|
+
| `数据ID` / `row_record_id` / `apply_id` / `_id` | `-17` | 当前记录真实 record/apply ID |
|
|
178
|
+
| `编号` / `数据编号` / `record_number` | `0` | 前端可见数据编号,可能是自定义编号 |
|
|
179
|
+
|
|
180
|
+
也可以显式写:
|
|
181
|
+
|
|
182
|
+
```json
|
|
183
|
+
{"source_field": {"field_id": -17}, "target_field": "关联员工"}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
注意:`数据ID` 和 `编号` 不是同一个东西。要把当前记录填入目标引用字段时,用 `数据ID`。
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 4. 类型兼容规则
|
|
191
|
+
|
|
192
|
+
| 目标 / 源字段类型 | 可匹配对象 |
|
|
193
|
+
| --- | --- |
|
|
194
|
+
| 引用字段 | 同目标应用的引用字段,或当前源应用记录的 `数据ID(-17)` |
|
|
195
|
+
| `数据ID(-17)` | 指向当前源应用的目标引用字段;也可匹配 ID 兼容的文本/数字字段 |
|
|
196
|
+
| `编号(0)` | 文本、长文本、数字、金额、编号类字段 |
|
|
197
|
+
| 成员字段 | 成员字段 |
|
|
198
|
+
| 部门字段 | 部门字段 |
|
|
199
|
+
| 单选 / 多选 / 布尔 | 选项类字段或静态选项值 |
|
|
200
|
+
| 日期 / 日期时间 | 日期类字段互通 |
|
|
201
|
+
| 文本 / 长文本 / 电话 / 邮箱 | 文本类字段互通 |
|
|
202
|
+
| 数字 / 金额 | 数值类字段互通 |
|
|
203
|
+
|
|
204
|
+
附件、子表、代码块、Q-Linker、地址字段默认不作为匹配字段。
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## 5. 常见错误处理
|
|
209
|
+
|
|
210
|
+
| 错误场景 | 下一步 |
|
|
211
|
+
| --- | --- |
|
|
212
|
+
| 字段不存在 | 重新 `builder app get --app-key APP_KEY fields` / `builder app get --app-key APP_KEY`,用准确字段标题或 `field_id` |
|
|
213
|
+
| 类型不兼容 | 按上表换兼容的源字段 / 目标字段 |
|
|
214
|
+
| 引用来源不一致 | 目标引用字段指向了别的应用;换成指向当前源应用的引用字段 |
|
|
215
|
+
| 同时传 semantic 与 raw | 同一项里只能二选一:`field_mappings/match_mappings` 或 raw `que_relation/match_rules` |
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## 6. 关联资源 ID 口径
|
|
220
|
+
|
|
221
|
+
`associated_item_id` 是应用级关联资源池里的 `form_asos_chart.id`,最终口径来自:
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
qingflow --json builder app get --app-key APP_KEY
|
|
98
225
|
```
|
|
99
226
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
- Record ID `数据ID(-17)`: can match relation fields that point to the current source app, or ID-compatible text/number fields.
|
|
104
|
-
- Record number `编号(0)`: can match text, long text, number, amount, or another record-number field.
|
|
105
|
-
- Member fields: only match member fields.
|
|
106
|
-
- Department fields: only match department fields.
|
|
107
|
-
- Option fields: single select, multi select, and boolean can match option-family fields or static option values.
|
|
108
|
-
- Date fields: date and datetime can match each other.
|
|
109
|
-
- Text fields: text, long text, phone, and email can match each other.
|
|
110
|
-
- Number fields: number and amount can match each other.
|
|
111
|
-
- Attachment, subtable, code block, Q-Linker, and address fields are not default match fields.
|
|
112
|
-
|
|
113
|
-
## Error Interpretation
|
|
114
|
-
|
|
115
|
-
- Field not found: re-read `app_get` or `app_get_fields` and retry with an exact title or `field_id`.
|
|
116
|
-
- Type mismatch: choose a compatible source/target pair from the matrix above.
|
|
117
|
-
- Reference source mismatch: the target relation field points to a different app; choose a relation field that points back to the current source app, or match a non-relation field.
|
|
118
|
-
- Mixed raw and semantic modes: use either semantic `field_mappings/match_mappings` or raw `que_relation/match_rules`, never both in the same item.
|
|
227
|
+
或同等 `app_get.associated_resources[].associated_item_id`。
|
|
228
|
+
|
|
229
|
+
它不是 `chart_id`、`chart_key`、`view_key`。但新版 `builder associated-resource apply` 在部分入口可接受 `chart_id` / `chart_key` / `view_key` 作为 selector,并自动解析成后端需要的 `associated_item_id`;写 view config 或排障时仍以读回的 `associated_item_id` 为准。
|
|
@@ -39,14 +39,14 @@ It is not a user-facing product spec. It exists to prevent skill drift.
|
|
|
39
39
|
- `app_layout_apply`
|
|
40
40
|
- `app_flow_apply`
|
|
41
41
|
- `app_views_apply`
|
|
42
|
+
- `app_custom_buttons_apply`
|
|
42
43
|
- `app_associated_resources_apply`
|
|
43
44
|
- `app_charts_apply`
|
|
44
45
|
- `portal_apply`
|
|
45
46
|
- `app_publish_verify`
|
|
46
47
|
- `portal_apply` edit mode may omit `sections` for base-info-only updates
|
|
47
48
|
- `app_charts_apply.visibility` is a public capability and should be treated as a base-only visibility update
|
|
48
|
-
-
|
|
49
|
-
- Existing object parameter replacement should use `patch_views`, `patch_resources`, and `patch_charts`; `upsert_*` is for creation or full target config
|
|
49
|
+
- Existing view parameter replacement should use `app_views_apply.views[]` with `operation="patch"`; existing buttons, resources, and charts should use `patch_buttons`, `patch_resources`, and `patch_charts`; `upsert_*` is for creation or full target config
|
|
50
50
|
- `app_get.editability` uses:
|
|
51
51
|
- `can_edit_app_base`
|
|
52
52
|
- `can_edit_form`
|