@josephyan/qingflow-app-builder-mcp 1.0.8 → 1.1.1
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 +4 -2
- package/npm/bin/qingflow-app-builder-mcp.mjs +31 -2
- package/npm/lib/runtime.mjs +43 -2
- package/package.json +1 -1
- package/pyproject.toml +2 -1
- package/skills/qingflow-app-builder/SKILL.md +135 -14
- package/skills/qingflow-app-builder/references/build-complete-system.md +428 -0
- package/skills/qingflow-app-builder/references/build-single-app.md +530 -0
- package/skills/qingflow-app-builder/references/create-app.md +43 -3
- package/skills/qingflow-app-builder/references/gotchas.md +47 -3
- package/skills/qingflow-app-builder/references/match-rules.md +114 -0
- package/skills/qingflow-app-builder/references/public-surface-sync.md +75 -0
- package/skills/qingflow-app-builder/references/tool-selection.md +25 -10
- package/skills/qingflow-app-builder/references/update-flow.md +29 -1
- package/skills/qingflow-app-builder/references/update-schema.md +6 -2
- package/skills/qingflow-app-builder/references/update-views.md +135 -6
- package/skills/qingflow-mcp-setup/SKILL.md +111 -0
- package/skills/qingflow-mcp-setup/agents/openai.yaml +4 -0
- package/skills/qingflow-mcp-setup/references/claude-desktop.md +34 -0
- package/skills/qingflow-mcp-setup/references/environments.md +61 -0
- package/skills/qingflow-mcp-setup/references/generic-stdio.md +31 -0
- package/skills/qingflow-mcp-setup/scripts/check_local_server.sh +38 -0
- package/skills/qingflow-workflow-builder/SKILL.md +96 -0
- package/skills/qingflow-workflow-builder/manifest.yaml +8 -0
- package/skills/qingflow-workflow-builder/references/01-overview.md +45 -0
- package/skills/qingflow-workflow-builder/references/02-update-mode.md +53 -0
- package/skills/qingflow-workflow-builder/references/03-flow-patterns.md +57 -0
- package/skills/qingflow-workflow-builder/references/04-stage1-business-modeling.md +131 -0
- package/skills/qingflow-workflow-builder/references/05-stage2-members-roles.md +29 -0
- package/skills/qingflow-workflow-builder/references/06-stage3-build-spec.md +165 -0
- package/skills/qingflow-workflow-builder/references/07-stage4-validate-spec.md +33 -0
- package/skills/qingflow-workflow-builder/references/08-stage5-apply-verify.md +51 -0
- package/skills/qingflow-workflow-builder/references/09-stage6-summary.md +88 -0
- package/skills/qingflow-workflow-builder/references/10-node-config-reference.md +93 -0
- package/skills/qingflow-workflow-builder/references/11-troubleshooting.md +15 -0
- package/skills/qingflow-workflow-builder/scripts/diff_flow_spec.py +275 -0
- package/skills/qingflow-workflow-builder/scripts/validate_flow_spec.py +605 -0
- package/src/qingflow_mcp/__init__.py +1 -1
- package/src/qingflow_mcp/backend_client.py +55 -1
- package/src/qingflow_mcp/builder_facade/models.py +532 -48
- package/src/qingflow_mcp/builder_facade/service.py +9194 -2384
- package/src/qingflow_mcp/builder_facade/workflow_spec.py +111 -0
- package/src/qingflow_mcp/cli/commands/app.py +3 -16
- package/src/qingflow_mcp/cli/commands/builder.py +354 -56
- package/src/qingflow_mcp/cli/commands/record.py +112 -6
- package/src/qingflow_mcp/cli/formatters.py +133 -2
- package/src/qingflow_mcp/cli/main.py +204 -3
- package/src/qingflow_mcp/public_surface.py +12 -9
- package/src/qingflow_mcp/response_trim.py +288 -22
- package/src/qingflow_mcp/server.py +29 -20
- package/src/qingflow_mcp/server_app_builder.py +108 -30
- package/src/qingflow_mcp/server_app_user.py +29 -23
- package/src/qingflow_mcp/solution/compiler/__init__.py +1 -3
- package/src/qingflow_mcp/solution/compiler/icon_utils.py +294 -0
- package/src/qingflow_mcp/solution/executor.py +3 -133
- package/src/qingflow_mcp/tools/ai_builder_tools.py +2617 -440
- package/src/qingflow_mcp/tools/app_tools.py +53 -8
- package/src/qingflow_mcp/tools/package_tools.py +16 -2
- package/src/qingflow_mcp/tools/record_tools.py +14451 -9110
- package/src/qingflow_mcp/tools/resource_read_tools.py +3 -0
- package/src/qingflow_mcp/tools/solution_tools.py +30 -2
- package/src/qingflow_mcp/tools/workflow_tools.py +3 -31
- package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +0 -173
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
# Build Single App(单应用完整搭建)
|
|
2
|
+
|
|
3
|
+
Use this when the user wants to set up one Qingflow app end-to-end: a rich field schema, grouped layout, approval flow, multiple view types, custom action buttons, in-app charts, associated reports on views, and sample data.
|
|
4
|
+
|
|
5
|
+
**Signal phrases**: "创建一个应用"、"帮我搭一个XX管理"、"从零开始建一个XX表单"、"我需要一个管理XX的应用"
|
|
6
|
+
|
|
7
|
+
For a multi-app system with cross-app relations and a portal dashboard, use [build-complete-system.md](./build-complete-system.md) instead.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Execution order (never reorder)
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
Phase 0 → Phase 1 → Phase 2 → Phase 3 → Phase 4 → Phase 5 → Phase 6 → Phase 7 → Phase 8 → Phase 9
|
|
15
|
+
Package Schema Layout Flow Views Buttons Charts Assoc. Data Verify
|
|
16
|
+
Res.
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
- Phase 4 (views) must complete before Phase 7 (associated resources) — `view_key` values must be known first
|
|
20
|
+
- Phase 6 (charts) must complete before Phase 7 (associated resources) — `chart_id`/`chart_key` values must be known first
|
|
21
|
+
- Phase 8 (data) runs after all config phases — fields, flow, and views must be live
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Phase 0 — Scan workspace packages
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{"tool_name": "package_list", "arguments": {"profile": "default"}}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- **Package name exists in workspace** → tell the user, wait for explicit confirmation before adding the app into it
|
|
32
|
+
- **Package name not in workspace** → create immediately, no confirmation needed:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"tool_name": "package_apply",
|
|
37
|
+
"arguments": {
|
|
38
|
+
"profile": "default",
|
|
39
|
+
"package_name": "合同管理",
|
|
40
|
+
"create_if_missing": true
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Record the returned `package_id`. All subsequent phases use it.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Phase 1 — Schema (15–20 fields)
|
|
50
|
+
|
|
51
|
+
> **Read first**: [update-schema.md](./update-schema.md)
|
|
52
|
+
|
|
53
|
+
### Field type distribution
|
|
54
|
+
|
|
55
|
+
| Type | Count | Examples |
|
|
56
|
+
|------|-------|---------|
|
|
57
|
+
| `text` | 2–3 | 名称、编号、联系人 |
|
|
58
|
+
| `long_text` | 1–2 | 描述、摘要、备注 |
|
|
59
|
+
| `single_select` | 2–3 | 状态、类型、优先级 |
|
|
60
|
+
| `multi_select` | 1–2 | 标签、关联业务线 |
|
|
61
|
+
| `date` / `datetime` | 2–3 | 签署日期、生效日期、到期日期 |
|
|
62
|
+
| `amount` | 1–2 | 合同金额、已付金额 |
|
|
63
|
+
| `number` | 1–2 | 期限(月)、完成率(%) |
|
|
64
|
+
| `member` | 2 | 负责人、审核人 |
|
|
65
|
+
| `department` | 0–1 | 所属部门 |
|
|
66
|
+
| `phone` | 0–1 | 联系电话 |
|
|
67
|
+
| `attachment` | 1 | 附件(`as_data_cover: true` for cover display) |
|
|
68
|
+
|
|
69
|
+
### Hard rules
|
|
70
|
+
|
|
71
|
+
- Exactly one field must have `as_data_title: true`
|
|
72
|
+
- `as_data_cover: true` requires `type: attachment`
|
|
73
|
+
- No `relation` fields in a single-app build — use [build-complete-system.md](./build-complete-system.md) if cross-app links are needed
|
|
74
|
+
- `single_select`/`multi_select` fields must include an `options` array
|
|
75
|
+
|
|
76
|
+
### Example — 合同管理
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"tool_name": "app_schema_apply",
|
|
81
|
+
"arguments": {
|
|
82
|
+
"profile": "default",
|
|
83
|
+
"package_id": 1218950,
|
|
84
|
+
"create_if_missing": true,
|
|
85
|
+
"publish": true,
|
|
86
|
+
"apps": [
|
|
87
|
+
{
|
|
88
|
+
"client_key": "contract",
|
|
89
|
+
"app_name": "合同",
|
|
90
|
+
"add_fields": [
|
|
91
|
+
{"name": "合同名称", "type": "text", "required": true, "as_data_title": true},
|
|
92
|
+
{"name": "合同编号", "type": "text"},
|
|
93
|
+
{"name": "合同类型", "type": "single_select", "options": ["服务合同", "采购合同", "劳务合同", "保密协议", "其他"]},
|
|
94
|
+
{"name": "合同状态", "type": "single_select", "options": ["草稿", "审批中", "已生效", "已到期", "已终止"]},
|
|
95
|
+
{"name": "优先级", "type": "single_select", "options": ["高", "中", "低"]},
|
|
96
|
+
{"name": "合同标签", "type": "multi_select", "options": ["重点客户", "续签", "新签", "框架协议"]},
|
|
97
|
+
{"name": "签署日期", "type": "date"},
|
|
98
|
+
{"name": "生效日期", "type": "date"},
|
|
99
|
+
{"name": "到期日期", "type": "date"},
|
|
100
|
+
{"name": "合同金额", "type": "amount"},
|
|
101
|
+
{"name": "已付金额", "type": "amount"},
|
|
102
|
+
{"name": "付款比例", "type": "number"},
|
|
103
|
+
{"name": "合同期限(月)", "type": "number"},
|
|
104
|
+
{"name": "负责人", "type": "member"},
|
|
105
|
+
{"name": "法务审核人", "type": "member"},
|
|
106
|
+
{"name": "所属部门", "type": "department"},
|
|
107
|
+
{"name": "甲方联系人", "type": "text"},
|
|
108
|
+
{"name": "甲方联系电话", "type": "phone"},
|
|
109
|
+
{"name": "合同内容摘要", "type": "long_text"},
|
|
110
|
+
{"name": "合同附件", "type": "attachment", "as_data_cover": true}
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Record the returned `app_key`. All subsequent phases use it.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Phase 2 — Layout
|
|
123
|
+
|
|
124
|
+
> **Read first**: [update-layout.md](./update-layout.md)
|
|
125
|
+
|
|
126
|
+
Group fields into 3–4 logical sections with 2–3 fields per row.
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"tool_name": "app_layout_apply",
|
|
131
|
+
"arguments": {
|
|
132
|
+
"profile": "default",
|
|
133
|
+
"app_key": "APP_KEY",
|
|
134
|
+
"mode": "merge",
|
|
135
|
+
"publish": true,
|
|
136
|
+
"sections": [
|
|
137
|
+
{
|
|
138
|
+
"title": "基础信息",
|
|
139
|
+
"rows": [
|
|
140
|
+
["合同名称", "合同编号"],
|
|
141
|
+
["合同类型", "合同状态"],
|
|
142
|
+
["优先级", "合同标签"]
|
|
143
|
+
]
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"title": "时间与金额",
|
|
147
|
+
"rows": [
|
|
148
|
+
["签署日期", "生效日期", "到期日期"],
|
|
149
|
+
["合同金额", "已付金额"],
|
|
150
|
+
["付款比例", "合同期限(月)"]
|
|
151
|
+
]
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"title": "责任人",
|
|
155
|
+
"rows": [
|
|
156
|
+
["负责人", "法务审核人"],
|
|
157
|
+
["所属部门"]
|
|
158
|
+
]
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"title": "对方信息与附件",
|
|
162
|
+
"rows": [
|
|
163
|
+
["甲方联系人", "甲方联系电话"],
|
|
164
|
+
["合同内容摘要"],
|
|
165
|
+
["合同附件"]
|
|
166
|
+
]
|
|
167
|
+
}
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Phase 3 — Flow
|
|
176
|
+
|
|
177
|
+
> **Read first**: [update-flow.md](./update-flow.md) and [flow-actors-and-permissions.md](./flow-actors-and-permissions.md)
|
|
178
|
+
|
|
179
|
+
Search for roles first; create only if none fits:
|
|
180
|
+
|
|
181
|
+
```json
|
|
182
|
+
{"tool_name": "role_search", "arguments": {"profile": "default", "query": "法务"}}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
```json
|
|
186
|
+
{
|
|
187
|
+
"tool_name": "app_flow_apply",
|
|
188
|
+
"arguments": {
|
|
189
|
+
"profile": "default",
|
|
190
|
+
"app_key": "APP_KEY",
|
|
191
|
+
"preset": "basic_approval",
|
|
192
|
+
"publish": true,
|
|
193
|
+
"nodes": [
|
|
194
|
+
{
|
|
195
|
+
"id": "approve_1",
|
|
196
|
+
"type": "approve",
|
|
197
|
+
"name": "法务审核",
|
|
198
|
+
"assignees": {"role_names": ["法务"]},
|
|
199
|
+
"permissions": {"editable_fields": ["合同状态", "合同内容摘要"]}
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"id": "approve_2",
|
|
203
|
+
"type": "approve",
|
|
204
|
+
"name": "负责人确认",
|
|
205
|
+
"assignees": {"role_names": ["部门主管"]},
|
|
206
|
+
"permissions": {"editable_fields": ["合同状态"]}
|
|
207
|
+
}
|
|
208
|
+
]
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Phase 4 — Views (multiple types)
|
|
216
|
+
|
|
217
|
+
> **Read first**: [update-views.md](./update-views.md)
|
|
218
|
+
|
|
219
|
+
Build all applicable view types in one call. All views require `query_conditions` with `enabled: true`.
|
|
220
|
+
|
|
221
|
+
| Type | Build condition | Key config |
|
|
222
|
+
|------|----------------|------------|
|
|
223
|
+
| **table** | Always — build first | `columns` covering title/status/date/amount/member |
|
|
224
|
+
| **board** | App has a `single_select` status or stage field | `group_by` = that field name |
|
|
225
|
+
| **gantt** | App has 2+ date fields | `start_field` + `end_field` |
|
|
226
|
+
| **card** | App has `attachment` with `as_data_cover: true` | Visual browsing |
|
|
227
|
+
| **calendar** | App has a key due/expiry date field | `date_field` = that field name |
|
|
228
|
+
|
|
229
|
+
```json
|
|
230
|
+
{
|
|
231
|
+
"tool_name": "app_views_apply",
|
|
232
|
+
"arguments": {
|
|
233
|
+
"profile": "default",
|
|
234
|
+
"app_key": "APP_KEY",
|
|
235
|
+
"publish": true,
|
|
236
|
+
"upsert_views": [
|
|
237
|
+
{
|
|
238
|
+
"name": "全部合同",
|
|
239
|
+
"type": "table",
|
|
240
|
+
"columns": ["合同名称", "合同编号", "合同类型", "合同状态", "合同金额", "负责人", "签署日期", "到期日期"],
|
|
241
|
+
"query_conditions": {
|
|
242
|
+
"enabled": true,
|
|
243
|
+
"exact": false,
|
|
244
|
+
"hide_before_query": false,
|
|
245
|
+
"rows": [["合同名称", "合同类型"], ["合同状态", "负责人"], ["签署日期", "到期日期"]]
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
"name": "合同看板",
|
|
250
|
+
"type": "board",
|
|
251
|
+
"columns": ["合同名称", "合同类型", "合同金额", "负责人", "到期日期"],
|
|
252
|
+
"group_by": "合同状态",
|
|
253
|
+
"query_conditions": {
|
|
254
|
+
"enabled": true,
|
|
255
|
+
"exact": false,
|
|
256
|
+
"hide_before_query": false,
|
|
257
|
+
"rows": [["合同名称", "负责人"]]
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
"name": "合同甘特图",
|
|
262
|
+
"type": "gantt",
|
|
263
|
+
"columns": ["合同名称", "合同状态", "负责人", "合同金额"],
|
|
264
|
+
"start_field": "生效日期",
|
|
265
|
+
"end_field": "到期日期",
|
|
266
|
+
"query_conditions": {
|
|
267
|
+
"enabled": true,
|
|
268
|
+
"exact": false,
|
|
269
|
+
"hide_before_query": false,
|
|
270
|
+
"rows": [["合同名称", "合同状态"]]
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
"name": "合同卡片",
|
|
275
|
+
"type": "card",
|
|
276
|
+
"columns": ["合同名称", "合同类型", "合同状态", "合同金额", "到期日期"],
|
|
277
|
+
"query_conditions": {
|
|
278
|
+
"enabled": true,
|
|
279
|
+
"exact": false,
|
|
280
|
+
"hide_before_query": false,
|
|
281
|
+
"rows": [["合同名称", "合同状态"]]
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
"name": "到期日历",
|
|
286
|
+
"type": "calendar",
|
|
287
|
+
"columns": ["合同名称", "合同类型", "合同金额", "负责人"],
|
|
288
|
+
"date_field": "到期日期",
|
|
289
|
+
"query_conditions": {
|
|
290
|
+
"enabled": true,
|
|
291
|
+
"exact": false,
|
|
292
|
+
"hide_before_query": false,
|
|
293
|
+
"rows": [["合同名称", "合同状态"]]
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
]
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Record all `view_key` values before Phase 7.
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## Phase 5 — Custom Buttons
|
|
306
|
+
|
|
307
|
+
> Call `builder_tool_contract(tool="app_custom_buttons_apply")` if the exact button schema is unclear.
|
|
308
|
+
> `app_custom_buttons_apply` publishes automatically — do **not** pass `publish`.
|
|
309
|
+
|
|
310
|
+
Build 2–3 buttons. Common patterns for a single app:
|
|
311
|
+
|
|
312
|
+
| Button | Trigger type | Placement | When to use |
|
|
313
|
+
|--------|-------------|-----------|-------------|
|
|
314
|
+
| 快捷创建子记录 | `add_data` | header, detail | When a related app exists in the same package |
|
|
315
|
+
| 外部跳转 | `link` | header, list | Always applicable — jump to external URL or doc |
|
|
316
|
+
| 列表行操作 | `add_data` / `link` | list | Row-level quick action in table view |
|
|
317
|
+
|
|
318
|
+
**Example — link button (always applicable) + add-data button (requires a related app):**
|
|
319
|
+
|
|
320
|
+
```json
|
|
321
|
+
{
|
|
322
|
+
"tool_name": "app_custom_buttons_apply",
|
|
323
|
+
"arguments": {
|
|
324
|
+
"profile": "default",
|
|
325
|
+
"app_key": "APP_KEY",
|
|
326
|
+
"upsert_buttons": [
|
|
327
|
+
{
|
|
328
|
+
"name": "查看合同模板",
|
|
329
|
+
"trigger_type": "link",
|
|
330
|
+
"style": "default",
|
|
331
|
+
"placements": ["header", "detail"],
|
|
332
|
+
"trigger_link_config": {
|
|
333
|
+
"url": "https://your-template-url"
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
"name": "发起变更申请",
|
|
338
|
+
"trigger_type": "add_data",
|
|
339
|
+
"style": "primary",
|
|
340
|
+
"placements": ["header", "detail", "list"],
|
|
341
|
+
"trigger_add_data_config": {
|
|
342
|
+
"target_app_key": "CHANGE_REQUEST_APP_KEY",
|
|
343
|
+
"field_mappings": [
|
|
344
|
+
{"source_field": "数据ID", "target_field": "关联合同"},
|
|
345
|
+
{"source_field": "合同名称", "target_field": "合同标题"},
|
|
346
|
+
{"source_field": "负责人", "target_field": "申请人"}
|
|
347
|
+
]
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
],
|
|
351
|
+
"view_configs": [
|
|
352
|
+
{
|
|
353
|
+
"view_key": "TABLE_VIEW_KEY",
|
|
354
|
+
"mode": "merge",
|
|
355
|
+
"buttons": ["发起变更申请", "查看合同模板"]
|
|
356
|
+
}
|
|
357
|
+
]
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**Notes:**
|
|
363
|
+
- `placements: ["list"]` maps to the backend row-level `INSIDE` position
|
|
364
|
+
- `view_configs[].buttons` is required in merge mode — do not send a view config with only `view_key`
|
|
365
|
+
- `source_field: "数据ID"` passes the current record's ID to the target relation field
|
|
366
|
+
- If this app has no related app, skip the add-data button and use the link button only
|
|
367
|
+
- Use raw `view_key` from `app_get.views[].view_key`; do not prefix with `custom:`
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
## Phase 6 — Charts
|
|
372
|
+
|
|
373
|
+
> `app_charts_apply` is immediate-live — no publish step. Record all returned `chart_id`/`chart_key` values before Phase 7.
|
|
374
|
+
|
|
375
|
+
Build 2–4 charts: 2 indicator cards + 1 distribution chart + 1 trend chart.
|
|
376
|
+
|
|
377
|
+
```json
|
|
378
|
+
{
|
|
379
|
+
"tool_name": "app_charts_apply",
|
|
380
|
+
"arguments": {
|
|
381
|
+
"profile": "default",
|
|
382
|
+
"app_key": "APP_KEY",
|
|
383
|
+
"upsert_charts": [
|
|
384
|
+
{
|
|
385
|
+
"name": "合同总金额",
|
|
386
|
+
"chart_type": "target",
|
|
387
|
+
"config": {
|
|
388
|
+
"measure_field": "合同金额",
|
|
389
|
+
"aggregate": "SUM"
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
"name": "有效合同数",
|
|
394
|
+
"chart_type": "target",
|
|
395
|
+
"config": {
|
|
396
|
+
"filter": {"合同状态": ["已生效"]},
|
|
397
|
+
"aggregate": "COUNT"
|
|
398
|
+
}
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
"name": "合同状态分布",
|
|
402
|
+
"chart_type": "columnar",
|
|
403
|
+
"config": {
|
|
404
|
+
"dimension_field": "合同状态",
|
|
405
|
+
"measure_field": "合同金额",
|
|
406
|
+
"aggregate": "SUM"
|
|
407
|
+
}
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
"name": "月度签约趋势",
|
|
411
|
+
"chart_type": "area",
|
|
412
|
+
"config": {
|
|
413
|
+
"dimension_field": "签署日期",
|
|
414
|
+
"time_granularity": "month",
|
|
415
|
+
"measure_field": "合同金额",
|
|
416
|
+
"aggregate": "SUM"
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
]
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## Phase 7 — Associated Resources
|
|
427
|
+
|
|
428
|
+
Attach charts to the app's view area so users can see them inline without leaving the app.
|
|
429
|
+
|
|
430
|
+
Before running `upsert_resources`, check existing resources with the dedicated read tool:
|
|
431
|
+
|
|
432
|
+
```json
|
|
433
|
+
{"tool_name": "app_get_associated_resources", "arguments": {"profile": "default", "app_key": "APP_KEY"}}
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
If the result already contains the target chart, use `patch_resources` with its `associated_item_id` instead of re-upserting.
|
|
437
|
+
|
|
438
|
+
```json
|
|
439
|
+
{
|
|
440
|
+
"tool_name": "app_associated_resources_apply",
|
|
441
|
+
"arguments": {
|
|
442
|
+
"profile": "default",
|
|
443
|
+
"app_key": "APP_KEY",
|
|
444
|
+
"upsert_resources": [
|
|
445
|
+
{
|
|
446
|
+
"client_key": "res_status_chart",
|
|
447
|
+
"resource_type": "chart",
|
|
448
|
+
"chart_key": "CHART_KEY_FOR_STATUS_DISTRIBUTION",
|
|
449
|
+
"display_name": "合同状态分布"
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
"client_key": "res_trend_chart",
|
|
453
|
+
"resource_type": "chart",
|
|
454
|
+
"chart_key": "CHART_KEY_FOR_TREND",
|
|
455
|
+
"display_name": "月度签约趋势"
|
|
456
|
+
}
|
|
457
|
+
],
|
|
458
|
+
"view_configs": [
|
|
459
|
+
{
|
|
460
|
+
"view_key": "TABLE_VIEW_KEY",
|
|
461
|
+
"associated_item_refs": ["res_status_chart", "res_trend_chart"]
|
|
462
|
+
}
|
|
463
|
+
]
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
**Notes:**
|
|
469
|
+
- `app_associated_resources_apply` publishes automatically — do **not** pass `publish`
|
|
470
|
+
- `client_key` is a same-call alias only; repeated `upsert_resources` without `associated_item_id` creates duplicates
|
|
471
|
+
- On subsequent edits, use `patch_resources` with `associated_item_id` instead
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
## Phase 8 — Sample Data
|
|
476
|
+
|
|
477
|
+
> **Hand off to `qingflow-record-insert` skill**. Read the record-insert skill docs before inserting.
|
|
478
|
+
|
|
479
|
+
Insert **5–8 records** covering all status values and realistic amounts. Call `record_insert_schema_get` first.
|
|
480
|
+
|
|
481
|
+
```json
|
|
482
|
+
{"tool_name": "record_insert_schema_get", "arguments": {"profile": "default", "app_key": "APP_KEY"}}
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
```json
|
|
486
|
+
{
|
|
487
|
+
"tool_name": "record_insert",
|
|
488
|
+
"arguments": {
|
|
489
|
+
"profile": "default",
|
|
490
|
+
"app_key": "APP_KEY",
|
|
491
|
+
"items": [
|
|
492
|
+
{"合同名称": "上海科技服务协议", "合同编号": "HT-2024-001", "合同类型": "服务合同", "合同状态": "已生效", "合同金额": 580000, "已付金额": 290000, "负责人": "张三", "签署日期": "2024-01-15", "生效日期": "2024-02-01", "到期日期": "2025-01-31", "优先级": "高", "合同期限(月)": 12},
|
|
493
|
+
{"合同名称": "北京采购框架合同", "合同编号": "HT-2024-002", "合同类型": "采购合同", "合同状态": "审批中", "合同金额": 1200000, "已付金额": 0, "负责人": "李四", "签署日期": "2024-03-10", "生效日期": "2024-04-01", "到期日期": "2025-03-31", "优先级": "高", "合同期限(月)": 12},
|
|
494
|
+
{"合同名称": "广州运维服务合同", "合同编号": "HT-2024-003", "合同类型": "服务合同", "合同状态": "已生效", "合同金额": 240000, "已付金额": 120000, "负责人": "王五", "签署日期": "2024-02-20", "生效日期": "2024-03-01", "到期日期": "2024-12-31", "优先级": "中", "合同期限(月)": 10},
|
|
495
|
+
{"合同名称": "深圳保密协议", "合同编号": "HT-2024-004", "合同类型": "保密协议", "合同状态": "已生效", "合同金额": 0, "已付金额": 0, "负责人": "张三", "签署日期": "2024-04-05", "生效日期": "2024-04-05", "到期日期": "2027-04-04", "优先级": "中", "合同期限(月)": 36},
|
|
496
|
+
{"合同名称": "杭州合作开发合同", "合同编号": "HT-2024-005", "合同类型": "服务合同", "合同状态": "草稿", "合同金额": 850000, "已付金额": 0, "负责人": "李四", "签署日期": "2024-05-01", "生效日期": "2024-06-01", "到期日期": "2025-05-31", "优先级": "高", "合同期限(月)": 12},
|
|
497
|
+
{"合同名称": "成都劳务外包合同", "合同编号": "HT-2023-006", "合同类型": "劳务合同", "合同状态": "已到期", "合同金额": 360000, "已付金额": 360000, "负责人": "王五", "签署日期": "2023-01-01", "生效日期": "2023-01-01", "到期日期": "2023-12-31", "优先级": "低", "合同期限(月)": 12}
|
|
498
|
+
]
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
Member and department fields accept natural language values — do not look up IDs manually.
|
|
504
|
+
|
|
505
|
+
---
|
|
506
|
+
|
|
507
|
+
## Phase 9 — Publish Verify
|
|
508
|
+
|
|
509
|
+
```json
|
|
510
|
+
{"tool_name": "app_publish_verify", "arguments": {"profile": "default", "app_key": "APP_KEY"}}
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
Confirm `publish_status` is live and `unplaced_fields` is empty. If `unplaced_fields` is non-empty, run `app_layout_apply` to place them before reporting completion.
|
|
514
|
+
|
|
515
|
+
---
|
|
516
|
+
|
|
517
|
+
## Common failures
|
|
518
|
+
|
|
519
|
+
| Error | Phase | Fix |
|
|
520
|
+
|-------|-------|-----|
|
|
521
|
+
| `VALIDATION_ERROR` on select field | 1 | `single_select`/`multi_select` must include `options` array |
|
|
522
|
+
| `UNKNOWN_LAYOUT_FIELD` | 2 | Re-read with `app_get_fields`; field name in `rows` must match exactly |
|
|
523
|
+
| `FLOW_ASSIGNEE_REQUIRED` | 3 | Run `role_search` first; every approve/fill node must have at least one assignee |
|
|
524
|
+
| View `partial_success` | 4 | Check `verification.view_query_conditions_verified`; read `views_diff.failed` |
|
|
525
|
+
| `calendar` view rejected | 4 | Build calendar only when a date field exists; verify field type |
|
|
526
|
+
| Button `view_configs` blocked | 5 | `buttons` array is required in merge mode; do not send a view config with only `view_key` |
|
|
527
|
+
| Button add-data fails — no related app | 5 | Skip add-data button; use link button only |
|
|
528
|
+
| Chart config rejected | 6 | Call `builder_tool_contract(tool="app_charts_apply")` for exact field/aggregate schema |
|
|
529
|
+
| Associated resource duplicate | 7 | Check `app_get.associated_resources` first; use `patch_resources` with `associated_item_id` if already exists |
|
|
530
|
+
| `unplaced_fields` non-empty on verify | 9 | Run `app_layout_apply` to place the missing fields, then re-verify |
|
|
@@ -37,8 +37,8 @@ then do not treat that as one app.
|
|
|
37
37
|
Use this pattern instead:
|
|
38
38
|
|
|
39
39
|
1. `package_get` or `package_apply(create_if_missing=true, package_name=...)`
|
|
40
|
-
2. for
|
|
41
|
-
3.
|
|
40
|
+
2. for a multi-app system, run one `app_schema_apply` with `apps[]`
|
|
41
|
+
3. use `apps[].client_key` plus relation field `target_app_ref` when one new app references another new app
|
|
42
42
|
|
|
43
43
|
## Example
|
|
44
44
|
|
|
@@ -79,8 +79,9 @@ Apply schema for a new app:
|
|
|
79
79
|
"create_if_missing": true,
|
|
80
80
|
"publish": true,
|
|
81
81
|
"add_fields": [
|
|
82
|
-
{"name": "订单编号", "type": "text", "required": true},
|
|
82
|
+
{"name": "订单编号", "type": "text", "required": true, "as_data_title": true},
|
|
83
83
|
{"name": "客户名称", "type": "text", "required": true},
|
|
84
|
+
{"name": "订单封面", "type": "attachment", "as_data_cover": true},
|
|
84
85
|
{"name": "订单金额", "type": "amount"},
|
|
85
86
|
{"name": "状态", "type": "single_select", "options": ["草稿", "进行中", "已完成"], "required": true}
|
|
86
87
|
],
|
|
@@ -90,6 +91,45 @@ Apply schema for a new app:
|
|
|
90
91
|
}
|
|
91
92
|
```
|
|
92
93
|
|
|
94
|
+
Apply schema for multiple apps in one call:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"tool_name": "app_schema_apply",
|
|
99
|
+
"arguments": {
|
|
100
|
+
"profile": "default",
|
|
101
|
+
"package_id": 1218950,
|
|
102
|
+
"create_if_missing": true,
|
|
103
|
+
"publish": true,
|
|
104
|
+
"apps": [
|
|
105
|
+
{
|
|
106
|
+
"client_key": "customer",
|
|
107
|
+
"app_name": "客户",
|
|
108
|
+
"add_fields": [
|
|
109
|
+
{"name": "客户名称", "type": "text", "required": true, "as_data_title": true}
|
|
110
|
+
]
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"client_key": "order",
|
|
114
|
+
"app_name": "订单",
|
|
115
|
+
"add_fields": [
|
|
116
|
+
{"name": "订单编号", "type": "text", "required": true, "as_data_title": true},
|
|
117
|
+
{
|
|
118
|
+
"name": "关联客户",
|
|
119
|
+
"type": "relation",
|
|
120
|
+
"target_app_ref": "customer",
|
|
121
|
+
"display_field": {"name": "客户名称"},
|
|
122
|
+
"visible_fields": [{"name": "客户名称"}]
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Data title is required: mark exactly one top-level field with `as_data_title: true`. Data cover is optional and only valid on a top-level `attachment` field.
|
|
132
|
+
|
|
93
133
|
## Common failures
|
|
94
134
|
|
|
95
135
|
### `APP_NOT_FOUND`
|
|
@@ -18,12 +18,46 @@
|
|
|
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
20
|
|
|
21
|
-
##
|
|
21
|
+
## Publish
|
|
22
22
|
|
|
23
|
-
- `app_schema_apply`, `app_layout_apply`, `app_flow_apply`, and `
|
|
24
|
-
- Pass `publish
|
|
23
|
+
- Always pass `publish: true` explicitly on `app_schema_apply`, `app_layout_apply`, `app_flow_apply`, `app_views_apply`, and `portal_apply` — do not rely on the default
|
|
24
|
+
- Pass `publish: false` on those five tools only when the user explicitly wants to leave changes in draft
|
|
25
|
+
- `app_custom_buttons_apply` and `app_associated_resources_apply` publish after at least one write succeeds and do not accept a `publish` parameter
|
|
26
|
+
- `app_charts_apply` is immediate-live and has no publish step
|
|
25
27
|
- `app_publish_verify` is for explicit final verification, not the default next step after every write
|
|
26
28
|
|
|
29
|
+
## BI Reports
|
|
30
|
+
|
|
31
|
+
- Use `app_charts_apply` for QingBI report body/config creation or updates.
|
|
32
|
+
- 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
|
+
- `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
|
+
- Creating a chart with `app_charts_apply` does not automatically show it in the Qingflow app UI; attach it separately if display is required.
|
|
35
|
+
- `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`.
|
|
36
|
+
|
|
37
|
+
## Custom buttons
|
|
38
|
+
|
|
39
|
+
- Use `app_custom_buttons_apply` for button creation/update/removal and view placement; do not split placement into `app_views_apply.buttons` unless you are maintaining a legacy patch.
|
|
40
|
+
- 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.
|
|
41
|
+
- For add-data buttons, prefer semantic `trigger_add_data_config.target_app_key`, `field_mappings`, and `default_values`.
|
|
42
|
+
- 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.
|
|
43
|
+
- `field_mappings.source_field` can use source app fields and supported system fields such as `数据ID` (`field_id=-17`) and `编号` (`field_id=0`).
|
|
44
|
+
- To fill a target relation field with the current source record, map `{"source_field": "数据ID", "target_field": "目标引用字段"}`. Use `default_values` only for static constants.
|
|
45
|
+
- For field type compatibility, read `references/match-rules.md`.
|
|
46
|
+
- Default button placements are `header` and `detail`; these map to the frontend's header and detail button areas.
|
|
47
|
+
- `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.
|
|
48
|
+
- 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`.
|
|
49
|
+
- 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.
|
|
50
|
+
- 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.
|
|
51
|
+
- `placement=list` configures row/list buttons. The tool maps it to the backend `INSIDE` button position, not a raw `LIST` config type.
|
|
52
|
+
|
|
53
|
+
## Associated resources
|
|
54
|
+
|
|
55
|
+
- Before creating an associated view/report, check `app_get.associated_resources` for the same `target_app_key + view_key/chart_key`.
|
|
56
|
+
- If the resource already exists, use `patch_resources` with its `associated_item_id`; do not call `upsert_resources` again.
|
|
57
|
+
- For per-view display, remove, and reorder, existing associated reports/views may be referenced by `associated_item_id`, `chart_id`/`chart_key`, or `view_key`; the tool resolves these to the internal id before writing.
|
|
58
|
+
- `client_key` is only a same-call alias for `view_configs[].associated_item_refs`. It is not stored by Qingflow and cannot prevent duplicates in later calls.
|
|
59
|
+
- Repeated `upsert_resources` without `associated_item_id` can create multiple app-level associated items pointing to the same view/report.
|
|
60
|
+
|
|
27
61
|
## Readback scope
|
|
28
62
|
|
|
29
63
|
- Prefer summary reads over large raw payloads
|
|
@@ -32,6 +66,15 @@
|
|
|
32
66
|
- Use `app_get_flow` before workflow work
|
|
33
67
|
- Use `app_get_views` before view work
|
|
34
68
|
|
|
69
|
+
## Partial update discipline
|
|
70
|
+
|
|
71
|
+
- Existing views, custom buttons, associated resources, and charts support the same public partial pattern: `patch_*[].set` plus optional `patch_*[].unset`.
|
|
72
|
+
- 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.
|
|
73
|
+
- Do not use `upsert_views`, `upsert_buttons`, `upsert_resources`, or `upsert_charts` for a tiny parameter replacement unless you are deliberately providing the full desired target config.
|
|
74
|
+
- `app_layout_apply(mode=merge)` is already a safe layout merge path; `mode=replace` is full layout replacement.
|
|
75
|
+
- `portal_apply` without `sections` is base-info-only. Supplying `sections` replaces the portal sections list.
|
|
76
|
+
- `app_flow_apply` is intentionally replace-only for the public linear workflow graph.
|
|
77
|
+
|
|
35
78
|
## Workflow dependencies
|
|
36
79
|
|
|
37
80
|
- Approval-style flows usually require an explicit status field
|
|
@@ -54,6 +97,7 @@
|
|
|
54
97
|
- `assignees.role_ids` / `assignees.member_uids` / `assignees.member_emails`
|
|
55
98
|
- `permissions.editable_fields`
|
|
56
99
|
- 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.
|
|
100
|
+
- For existing view parameter changes, prefer `patch_views`. 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.
|
|
57
101
|
- 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.
|
|
58
102
|
- 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.
|
|
59
103
|
- If duplicate view names exist, do not retry by name. Read the exact `view_key` and target that one.
|