@guandata/guanmetric 0.1.18 → 0.1.19

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.
Files changed (34) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +19 -3
  3. package/package.json +6 -6
  4. package/skills/guanmetric/SKILL.md +53 -8
  5. package/skills/guanmetric/evals/evals.json +117 -0
  6. package/skills/guanmetric/evals/fixtures/atomic-detail-read-model.json +18 -0
  7. package/skills/guanmetric/evals/fixtures/confirmed-template-summary.json +12 -0
  8. package/skills/guanmetric/evals/fixtures/create-result-unknown-state.json +13 -0
  9. package/skills/guanmetric/evals/forward-eval-2026-09-21.json +62 -0
  10. package/skills/guanmetric/references/metric-api-contract-examples.json +690 -0
  11. package/skills/guanmetric/references/metric-api-contract.schema.json +349 -0
  12. package/skills/guanmetric/references/metric-api-contracts.md +436 -0
  13. package/skills/guanmetric/references/metric-atomic-mutation.md +11 -0
  14. package/skills/guanmetric/references/metric-business-dictionary-api-contract-examples.json +53 -0
  15. package/skills/guanmetric/references/metric-business-dictionary-api-contract.schema.json +26 -0
  16. package/skills/guanmetric/references/metric-business-dictionary.md +4 -0
  17. package/skills/guanmetric/references/metric-composite-mutation.md +15 -17
  18. package/skills/guanmetric/references/metric-derived-mutation.md +14 -16
  19. package/skills/guanmetric/references/metric-excel-template.md +14 -4
  20. package/skills/guanmetric/references/metric-flow-generate-example.json +79 -0
  21. package/skills/guanmetric/references/metric-flow-generate.schema.json +93 -0
  22. package/skills/guanmetric/references/metric-flow.md +218 -0
  23. package/skills/guanmetric/references/metric-hierarchy-api-contract-examples.json +171 -0
  24. package/skills/guanmetric/references/metric-hierarchy-api-contract.schema.json +167 -0
  25. package/skills/guanmetric/references/metric-hierarchy-api-contracts.md +193 -0
  26. package/skills/guanmetric/references/metric-mutation.md +13 -9
  27. package/skills/guanmetric/references/metric-public-dimension-api-contract-examples.json +62 -0
  28. package/skills/guanmetric/references/metric-public-dimension-api-contract.schema.json +47 -0
  29. package/skills/guanmetric/references/metric-public-dimension.md +4 -0
  30. package/skills/guanmetric/references/metric-tree-api-contract-examples.json +277 -0
  31. package/skills/guanmetric/references/metric-tree-api-contract.schema.json +263 -0
  32. package/skills/guanmetric/references/metric-tree-api-contracts.md +53 -0
  33. package/skills/guanmetric/references/metric-tree-mutation.md +31 -3
  34. package/skills/guanmetric/references/metric-validation-ownership.md +74 -0
@@ -0,0 +1,47 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://guandata.example/schemas/metric-public-dimension-api-contract.schema.json",
4
+ "title": "GuanData metric public dimension API contracts",
5
+ "$defs": {
6
+ "nonEmptyString": {"type": "string", "minLength": 1},
7
+ "user": {
8
+ "type": "object",
9
+ "required": ["uId", "name", "isDel"],
10
+ "properties": {"uId": {"$ref": "#/$defs/nonEmptyString"}, "name": {"type": "string"}, "email": {"type": "string"}, "avatar": {"type": "string"}, "isDel": {"type": "boolean"}},
11
+ "additionalProperties": true
12
+ },
13
+ "relatedFieldWrite": {
14
+ "type": "object",
15
+ "required": ["dsId", "fdId"],
16
+ "properties": {"dsId": {"$ref": "#/$defs/nonEmptyString"}, "fdId": {"$ref": "#/$defs/nonEmptyString"}},
17
+ "additionalProperties": false
18
+ },
19
+ "writeRequest": {
20
+ "type": "object",
21
+ "required": ["name", "businessOwner", "relatedFields"],
22
+ "properties": {"name": {"$ref": "#/$defs/nonEmptyString"}, "businessOwner": {"$ref": "#/$defs/nonEmptyString"}, "relatedFields": {"type": "array", "minItems": 1, "items": {"$ref": "#/$defs/relatedFieldWrite"}}},
23
+ "additionalProperties": false
24
+ },
25
+ "mutationResponse": {
26
+ "type": "object",
27
+ "required": ["result", "response"],
28
+ "properties": {"result": {"const": "ok"}, "response": {"type": "object", "required": ["id"], "properties": {"id": {"$ref": "#/$defs/nonEmptyString"}}, "additionalProperties": true}},
29
+ "additionalProperties": true
30
+ },
31
+ "detailResponse": {
32
+ "type": "object",
33
+ "required": ["result", "response"],
34
+ "properties": {"result": {"const": "ok"}, "response": {"type": "object", "required": ["id", "domId", "name", "businessOwner", "relatedFields", "creator", "ctime", "utime"], "properties": {"id": {"type": "string"}, "domId": {"type": "string"}, "name": {"type": "string"}, "businessOwner": {"$ref": "#/$defs/user"}, "relatedFields": {"type": "array"}, "creator": {"$ref": "#/$defs/user"}, "ctime": {"type": "string"}, "utime": {"type": "string"}}, "additionalProperties": true}},
35
+ "additionalProperties": true
36
+ },
37
+ "listResponse": {
38
+ "type": "object",
39
+ "required": ["result", "response"],
40
+ "properties": {"result": {"const": "ok"}, "response": {"type": "object", "required": ["contents", "count", "limit", "offset"], "properties": {"contents": {"type": "array"}, "count": {"type": "number"}, "limit": {"type": "number"}, "offset": {"type": "number"}}, "additionalProperties": true}},
41
+ "additionalProperties": true
42
+ },
43
+ "fieldMapResponse": {"type": "object", "required": ["result", "response"], "properties": {"result": {"const": "ok"}, "response": {"type": "object"}}, "additionalProperties": true},
44
+ "dependCheckResponse": {"type": "object", "required": ["result", "response"], "properties": {"result": {"const": "ok"}, "response": {"type": "object", "required": ["isDepended"], "properties": {"isDepended": {"type": "boolean"}}, "additionalProperties": true}}, "additionalProperties": true},
45
+ "deleteResponse": {"type": "object", "required": ["result", "response"], "properties": {"result": {"const": "ok"}, "response": {"type": "string"}}, "additionalProperties": true}
46
+ }
47
+ }
@@ -2,6 +2,8 @@
2
2
 
3
3
  公共维度用于把多个数据集中的同一业务维度字段关联起来,让跨指标、跨数据集的适用维度能够按同一逻辑维度对齐。
4
4
 
5
+ 构造或解析请求和响应前先读取 `metric-public-dimension-api-contract-examples.json` 与 `metric-public-dimension-api-contract.schema.json`。样例于 2026-09-21 在 test153 使用隔离临时公共维度和账号密码认证完成 create、detail/list、edit、depend-check、delete 后脱敏;PAT 尚未验证。仓库测试会按 Schema 校验这些真实快照的必需字段和类型,后端新增可选字段不会误报,但刷新快照时若 CLI 依赖字段缺失或变型会失败。
6
+
5
7
  ## 命令入口
6
8
 
7
9
  ```bash
@@ -47,6 +49,8 @@ guanmetric public-dim fd-map <ds_id>
47
49
 
48
50
  `fd-map` 返回 `fdId -> { id, name }`,用于新建/编辑公共维度时避免选择已被其它公共维度使用的字段。
49
51
 
52
+ 真实返回的外层统一为 `{ "result": "ok", "response": ... }`:列表 `response` 包含 `contents/count/limit/offset`;详情中的 `businessOwner/creator` 是用户对象,`relatedFields` 是 `{dsInfo,fdInfo}` 数组;创建和编辑成功的 `response` 包含 `id`;依赖检查使用 `response.isDepended`;删除成功的 `response` 是 `"delete success."`。详情是读模型,不能把 `dsInfo/fdInfo`、用户对象、`domId/creator/ctime/utime` 原样回写。
53
+
50
54
  ## 新建/编辑入参
51
55
 
52
56
  | 字段 | 中文 | 说明 |
@@ -0,0 +1,277 @@
1
+ {
2
+ "schemaVersion": "1.0",
3
+ "source": {
4
+ "environment": "test71",
5
+ "capturedAt": "2026-09-21",
6
+ "authentication": "account-password",
7
+ "note": "由隔离临时指标树真实请求采集后脱敏;示例 ID、名称和日期不可直接用于调用。PAT 未验证。"
8
+ },
9
+ "createRequest": {
10
+ "metricId": "metric_root_example",
11
+ "name": "销售额指标树",
12
+ "parentDirId": "metric_tree_dir_root",
13
+ "config": {
14
+ "timeComparisonSetting": {
15
+ "advType": "COMPARATIVE",
16
+ "advValue": {
17
+ "advType": "COMPARATIVE",
18
+ "dateFdId": "fd_order_date",
19
+ "valueType": "RAWDATA",
20
+ "offset": 1,
21
+ "offsetType": "DAY",
22
+ "granularity": "DAY",
23
+ "window": { "period": ["2026-09-21"], "withMacro": false },
24
+ "mode": "NORMAL"
25
+ }
26
+ },
27
+ "comparisonEnabled": true,
28
+ "contributionCalcEnabled": true,
29
+ "dimensionDecompositionContent": {
30
+ "decomposableDimensionIds": [],
31
+ "multipleDimensionEnabled": false,
32
+ "multipleDimensionList": [],
33
+ "nodeNum": 5,
34
+ "orderBy": "valueDesc",
35
+ "drillDownLevels": []
36
+ },
37
+ "metricDecompositionContent": {
38
+ "metricRelationTree": [
39
+ { "operation": "", "metricId": "metric_root_example", "decomposeMode": "calculation" }
40
+ ]
41
+ }
42
+ }
43
+ },
44
+ "createResponse": {
45
+ "result": "ok",
46
+ "response": {
47
+ "success": true,
48
+ "message": "指标树创建成功",
49
+ "metricTreeId": "metric_tree_example"
50
+ }
51
+ },
52
+ "renameRequest": { "name": "销售经营分析指标树" },
53
+ "renameResponse": {
54
+ "result": "ok",
55
+ "response": {
56
+ "success": true,
57
+ "message": "指标树名称更新成功",
58
+ "data": {
59
+ "domId": "example_domain",
60
+ "metricId": "metric_root_example",
61
+ "metricTreeId": "metric_tree_example",
62
+ "name": "销售经营分析指标树",
63
+ "config": {},
64
+ "parentDirId": "metric_tree_dir_root",
65
+ "uId": "user_example",
66
+ "ctime": "2026-09-21 11:18:16+0800",
67
+ "utime": "2026-09-21 11:19:01+0800",
68
+ "isDel": false
69
+ }
70
+ }
71
+ },
72
+ "moveRequest": { "newParentDirId": "metric_tree_dir_sales" },
73
+ "moveResponse": {
74
+ "result": "ok",
75
+ "response": { "success": true, "message": "指标树移动成功" }
76
+ },
77
+ "updateConfigRequest": {
78
+ "config": {
79
+ "comparisonEnabled": true,
80
+ "contributionCalcEnabled": true,
81
+ "dimensionDecompositionContent": {
82
+ "decomposableDimensionIds": [],
83
+ "multipleDimensionEnabled": false,
84
+ "multipleDimensionList": [],
85
+ "nodeNum": 5,
86
+ "orderBy": "valueDesc",
87
+ "drillDownLevels": []
88
+ },
89
+ "metricDecompositionContent": {
90
+ "metricRelationTree": [
91
+ { "operation": "", "metricId": "metric_root_example", "decomposeMode": "calculation" }
92
+ ]
93
+ }
94
+ }
95
+ },
96
+ "updateConfigResponse": {
97
+ "result": "ok",
98
+ "response": {
99
+ "success": true,
100
+ "message": "指标树配置更新成功",
101
+ "data": {
102
+ "domId": "example_domain",
103
+ "metricId": "metric_root_example",
104
+ "metricTreeId": "metric_tree_example",
105
+ "name": "销售经营分析指标树",
106
+ "config": {},
107
+ "parentDirId": "metric_tree_dir_root",
108
+ "uId": "user_example",
109
+ "ctime": "2026-09-21 11:18:16+0800",
110
+ "utime": "2026-09-21 11:19:43+0800",
111
+ "isDel": false
112
+ }
113
+ }
114
+ },
115
+ "detailResponse": {
116
+ "result": "ok",
117
+ "response": {
118
+ "domId": "example_domain",
119
+ "metricTreeId": "metric_tree_example",
120
+ "metricTreeName": "销售经营分析指标树",
121
+ "config": {},
122
+ "parentDirId": "metric_tree_dir_root",
123
+ "ctime": "2026-09-21 11:18:16",
124
+ "utime": "2026-09-21 11:19:43",
125
+ "isDel": false,
126
+ "metricId": "metric_root_example",
127
+ "metricName": "销售额",
128
+ "projectId": "project_example",
129
+ "projectName": "经营指标",
130
+ "creatorId": "user_example",
131
+ "creatorName": "示例用户",
132
+ "canUse": true,
133
+ "canManage": true,
134
+ "dirPath": [
135
+ { "dirId": "metric_tree_dir_root", "dirName": "根目录" }
136
+ ]
137
+ }
138
+ },
139
+ "listByParentResponse": {
140
+ "result": "ok",
141
+ "response": {
142
+ "success": true,
143
+ "data": [
144
+ {
145
+ "domId": "example_domain",
146
+ "metricId": "metric_root_example",
147
+ "metricTreeId": "metric_tree_example",
148
+ "name": "销售经营分析指标树",
149
+ "config": {},
150
+ "parentDirId": "metric_tree_dir_root",
151
+ "uId": "user_example",
152
+ "ctime": "2026-09-21 11:18:16+0800",
153
+ "utime": "2026-09-21 11:19:43+0800",
154
+ "isDel": false
155
+ }
156
+ ],
157
+ "total": 1
158
+ }
159
+ },
160
+ "searchResponse": {
161
+ "result": "ok",
162
+ "response": {
163
+ "success": true,
164
+ "data": [
165
+ {
166
+ "metricTreeId": "metric_tree_example",
167
+ "metricTreeName": "销售经营分析指标树",
168
+ "metricId": "metric_root_example",
169
+ "metricName": "销售额",
170
+ "projectId": "project_example",
171
+ "projectName": "经营指标",
172
+ "creatorId": "user_example",
173
+ "creatorName": "示例用户",
174
+ "parentDirId": "metric_tree_dir_root",
175
+ "canUse": true,
176
+ "canManage": true,
177
+ "dirPath": [
178
+ { "dirId": "metric_tree_dir_root", "dirName": "根目录" }
179
+ ]
180
+ }
181
+ ],
182
+ "total": 1
183
+ }
184
+ },
185
+ "deleteResponse": {
186
+ "result": "ok",
187
+ "response": { "success": true, "message": "指标树删除成功" }
188
+ },
189
+ "directory": {
190
+ "createRequest": {
191
+ "name": "经营分析",
192
+ "parentDirId": "metric_tree_dir_root",
193
+ "dirType": "METRIC_TREE"
194
+ },
195
+ "createResponse": {
196
+ "result": "ok",
197
+ "response": {
198
+ "dirId": "metric_tree_dir_sales",
199
+ "dirName": "经营分析",
200
+ "dirType": "METRIC_TREE",
201
+ "parentDirId": "metric_tree_dir_root",
202
+ "parentDirName": "根目录",
203
+ "dirPath": [
204
+ { "dirId": "metric_tree_dir_root", "dirName": "根目录" },
205
+ { "dirId": "metric_tree_dir_sales", "dirName": "经营分析" }
206
+ ]
207
+ }
208
+ },
209
+ "updateRequest": {
210
+ "name": "销售经营分析",
211
+ "parentDirId": "metric_tree_dir_root",
212
+ "dirType": "METRIC_TREE"
213
+ },
214
+ "updateResponse": {
215
+ "result": "ok",
216
+ "response": {
217
+ "dirId": "metric_tree_dir_sales",
218
+ "dirName": "销售经营分析",
219
+ "dirType": "METRIC_TREE",
220
+ "parentDirId": "metric_tree_dir_root",
221
+ "parentDirName": "根目录",
222
+ "dirPath": [
223
+ { "dirId": "metric_tree_dir_root", "dirName": "根目录" },
224
+ { "dirId": "metric_tree_dir_sales", "dirName": "销售经营分析" }
225
+ ]
226
+ }
227
+ },
228
+ "detailResponse": {
229
+ "result": "ok",
230
+ "response": {
231
+ "count": 0,
232
+ "parentDirId": "metric_tree_dir_root",
233
+ "parentDirName": "根目录",
234
+ "dirType": "METRIC_TREE",
235
+ "dirId": "metric_tree_dir_sales",
236
+ "dirName": "销售经营分析",
237
+ "canManage": true,
238
+ "canUse": true,
239
+ "contents": [],
240
+ "dirPath": [
241
+ { "dirId": "metric_tree_dir_root", "dirName": "根目录" },
242
+ { "dirId": "metric_tree_dir_sales", "dirName": "销售经营分析" }
243
+ ],
244
+ "hasChildDir": false
245
+ }
246
+ },
247
+ "treeResponse": {
248
+ "result": "ok",
249
+ "response": {
250
+ "id": "metric_tree_dir_root",
251
+ "parentDirId": "",
252
+ "name": "根目录",
253
+ "type": "DIRECTORY",
254
+ "contents": [
255
+ {
256
+ "id": "metric_tree_dir_sales",
257
+ "parentDirId": "metric_tree_dir_root",
258
+ "name": "销售经营分析",
259
+ "type": "DIRECTORY",
260
+ "canManage": true,
261
+ "canUse": true,
262
+ "ctime": "2026-09-21T11:31:51.00Z",
263
+ "utime": "2026-09-21T11:32:55.00Z"
264
+ }
265
+ ],
266
+ "canManage": true,
267
+ "canUse": true,
268
+ "ctime": "2025-12-25T17:02:08.00Z",
269
+ "utime": "2026-09-21T11:32:55.00Z"
270
+ }
271
+ },
272
+ "deleteResponse": {
273
+ "result": "ok",
274
+ "response": "Directory deleted"
275
+ }
276
+ }
277
+ }
@@ -0,0 +1,263 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://guandata.dev/schemas/guanmetric/metric-tree-api-contract-1.0.json",
4
+ "title": "GuanData metric tree API contract",
5
+ "description": "用于 Agent 构造指标树写请求并解析真实后端响应。响应允许后端新增字段。",
6
+ "oneOf": [
7
+ { "$ref": "#/$defs/createRequest" },
8
+ { "$ref": "#/$defs/renameRequest" },
9
+ { "$ref": "#/$defs/moveRequest" },
10
+ { "$ref": "#/$defs/updateConfigRequest" },
11
+ { "$ref": "#/$defs/createResponse" },
12
+ { "$ref": "#/$defs/mutationResponse" },
13
+ { "$ref": "#/$defs/detailResponse" },
14
+ { "$ref": "#/$defs/listResponse" },
15
+ { "$ref": "#/$defs/searchResponse" },
16
+ { "$ref": "#/$defs/deleteResponse" },
17
+ { "$ref": "#/$defs/directoryWriteRequest" },
18
+ { "$ref": "#/$defs/directoryMutationResponse" },
19
+ { "$ref": "#/$defs/directoryDetailResponse" },
20
+ { "$ref": "#/$defs/directoryTreeResponse" },
21
+ { "$ref": "#/$defs/directoryDeleteResponse" }
22
+ ],
23
+ "$defs": {
24
+ "nonEmptyString": { "type": "string", "minLength": 1 },
25
+ "config": { "type": "object", "additionalProperties": true },
26
+ "createRequest": {
27
+ "type": "object",
28
+ "required": ["metricId", "name", "parentDirId"],
29
+ "properties": {
30
+ "metricId": { "$ref": "#/$defs/nonEmptyString" },
31
+ "name": { "$ref": "#/$defs/nonEmptyString" },
32
+ "parentDirId": { "$ref": "#/$defs/nonEmptyString" },
33
+ "config": { "$ref": "#/$defs/config" }
34
+ },
35
+ "additionalProperties": false
36
+ },
37
+ "renameRequest": {
38
+ "type": "object",
39
+ "required": ["name"],
40
+ "properties": { "name": { "$ref": "#/$defs/nonEmptyString" } },
41
+ "additionalProperties": false
42
+ },
43
+ "moveRequest": {
44
+ "type": "object",
45
+ "required": ["newParentDirId"],
46
+ "properties": { "newParentDirId": { "$ref": "#/$defs/nonEmptyString" } },
47
+ "additionalProperties": false
48
+ },
49
+ "updateConfigRequest": {
50
+ "type": "object",
51
+ "required": ["config"],
52
+ "properties": { "config": { "$ref": "#/$defs/config" } },
53
+ "additionalProperties": false
54
+ },
55
+ "pathItem": {
56
+ "type": "object",
57
+ "required": ["dirId", "dirName"],
58
+ "properties": {
59
+ "dirId": { "$ref": "#/$defs/nonEmptyString" },
60
+ "dirName": { "type": "string" }
61
+ },
62
+ "additionalProperties": true
63
+ },
64
+ "listItem": {
65
+ "type": "object",
66
+ "required": ["domId", "metricId", "metricTreeId", "name", "parentDirId", "isDel"],
67
+ "properties": {
68
+ "domId": { "$ref": "#/$defs/nonEmptyString" },
69
+ "metricId": { "$ref": "#/$defs/nonEmptyString" },
70
+ "metricTreeId": { "$ref": "#/$defs/nonEmptyString" },
71
+ "name": { "$ref": "#/$defs/nonEmptyString" },
72
+ "config": { "$ref": "#/$defs/config" },
73
+ "parentDirId": { "$ref": "#/$defs/nonEmptyString" },
74
+ "uId": { "type": "string" },
75
+ "ctime": { "type": "string" },
76
+ "utime": { "type": "string" },
77
+ "isDel": { "type": "boolean" }
78
+ },
79
+ "additionalProperties": true
80
+ },
81
+ "detail": {
82
+ "type": "object",
83
+ "required": ["metricTreeId", "metricTreeName", "metricId", "parentDirId", "canUse", "canManage"],
84
+ "properties": {
85
+ "metricTreeId": { "$ref": "#/$defs/nonEmptyString" },
86
+ "metricTreeName": { "$ref": "#/$defs/nonEmptyString" },
87
+ "metricId": { "$ref": "#/$defs/nonEmptyString" },
88
+ "metricName": { "type": "string" },
89
+ "parentDirId": { "$ref": "#/$defs/nonEmptyString" },
90
+ "config": { "$ref": "#/$defs/config" },
91
+ "canUse": { "type": "boolean" },
92
+ "canManage": { "type": "boolean" },
93
+ "dirPath": { "type": "array", "items": { "$ref": "#/$defs/pathItem" } }
94
+ },
95
+ "additionalProperties": true
96
+ },
97
+ "successPayload": {
98
+ "type": "object",
99
+ "required": ["success", "message"],
100
+ "properties": {
101
+ "success": { "const": true },
102
+ "message": { "$ref": "#/$defs/nonEmptyString" },
103
+ "data": { "$ref": "#/$defs/listItem" }
104
+ },
105
+ "additionalProperties": true
106
+ },
107
+ "envelope": {
108
+ "type": "object",
109
+ "required": ["result", "response"],
110
+ "properties": { "result": { "const": "ok" } },
111
+ "additionalProperties": true
112
+ },
113
+ "createResponse": {
114
+ "allOf": [
115
+ { "$ref": "#/$defs/envelope" },
116
+ {
117
+ "properties": {
118
+ "response": {
119
+ "allOf": [
120
+ { "$ref": "#/$defs/successPayload" },
121
+ { "required": ["metricTreeId"], "properties": { "metricTreeId": { "$ref": "#/$defs/nonEmptyString" } } }
122
+ ]
123
+ }
124
+ }
125
+ }
126
+ ]
127
+ },
128
+ "mutationResponse": {
129
+ "allOf": [
130
+ { "$ref": "#/$defs/envelope" },
131
+ { "properties": { "response": { "$ref": "#/$defs/successPayload" } } }
132
+ ]
133
+ },
134
+ "detailResponse": {
135
+ "allOf": [
136
+ { "$ref": "#/$defs/envelope" },
137
+ { "properties": { "response": { "$ref": "#/$defs/detail" } } }
138
+ ]
139
+ },
140
+ "pagedListPayload": {
141
+ "type": "object",
142
+ "required": ["success", "data", "total"],
143
+ "properties": {
144
+ "success": { "const": true },
145
+ "data": { "type": "array", "items": { "$ref": "#/$defs/listItem" } },
146
+ "total": { "type": "integer", "minimum": 0 }
147
+ },
148
+ "additionalProperties": true
149
+ },
150
+ "listResponse": {
151
+ "allOf": [
152
+ { "$ref": "#/$defs/envelope" },
153
+ { "properties": { "response": { "$ref": "#/$defs/pagedListPayload" } } }
154
+ ]
155
+ },
156
+ "searchResponse": {
157
+ "allOf": [
158
+ { "$ref": "#/$defs/envelope" },
159
+ {
160
+ "properties": {
161
+ "response": {
162
+ "type": "object",
163
+ "required": ["success", "data", "total"],
164
+ "properties": {
165
+ "success": { "const": true },
166
+ "data": { "type": "array", "items": { "$ref": "#/$defs/detail" } },
167
+ "total": { "type": "integer", "minimum": 0 }
168
+ },
169
+ "additionalProperties": true
170
+ }
171
+ }
172
+ }
173
+ ]
174
+ },
175
+ "deleteResponse": {
176
+ "allOf": [
177
+ { "$ref": "#/$defs/envelope" },
178
+ { "properties": { "response": { "$ref": "#/$defs/successPayload" } } }
179
+ ]
180
+ },
181
+ "directoryWriteRequest": {
182
+ "type": "object",
183
+ "required": ["name", "parentDirId", "dirType"],
184
+ "properties": {
185
+ "name": { "$ref": "#/$defs/nonEmptyString" },
186
+ "parentDirId": { "$ref": "#/$defs/nonEmptyString" },
187
+ "dirType": { "const": "METRIC_TREE" }
188
+ },
189
+ "additionalProperties": false
190
+ },
191
+ "directoryMutationPayload": {
192
+ "type": "object",
193
+ "required": ["dirId", "dirName", "dirType", "parentDirId", "parentDirName", "dirPath"],
194
+ "properties": {
195
+ "dirId": { "$ref": "#/$defs/nonEmptyString" },
196
+ "dirName": { "$ref": "#/$defs/nonEmptyString" },
197
+ "dirType": { "const": "METRIC_TREE" },
198
+ "parentDirId": { "$ref": "#/$defs/nonEmptyString" },
199
+ "parentDirName": { "type": "string" },
200
+ "dirPath": { "type": "array", "items": { "$ref": "#/$defs/pathItem" } }
201
+ },
202
+ "additionalProperties": true
203
+ },
204
+ "directoryMutationResponse": {
205
+ "allOf": [
206
+ { "$ref": "#/$defs/envelope" },
207
+ { "properties": { "response": { "$ref": "#/$defs/directoryMutationPayload" } } }
208
+ ]
209
+ },
210
+ "directoryDetail": {
211
+ "type": "object",
212
+ "required": ["count", "parentDirId", "dirType", "dirId", "dirName", "canManage", "canUse", "contents", "dirPath", "hasChildDir"],
213
+ "properties": {
214
+ "count": { "type": "integer", "minimum": 0 },
215
+ "parentDirId": { "type": "string" },
216
+ "parentDirName": { "type": ["string", "null"] },
217
+ "dirType": { "const": "METRIC_TREE" },
218
+ "dirId": { "$ref": "#/$defs/nonEmptyString" },
219
+ "dirName": { "type": "string" },
220
+ "canManage": { "type": "boolean" },
221
+ "canUse": { "type": "boolean" },
222
+ "contents": { "type": "array" },
223
+ "dirPath": { "type": "array", "items": { "$ref": "#/$defs/pathItem" } },
224
+ "hasChildDir": { "type": "boolean" }
225
+ },
226
+ "additionalProperties": true
227
+ },
228
+ "directoryDetailResponse": {
229
+ "allOf": [
230
+ { "$ref": "#/$defs/envelope" },
231
+ { "properties": { "response": { "$ref": "#/$defs/directoryDetail" } } }
232
+ ]
233
+ },
234
+ "directoryTreeNode": {
235
+ "type": "object",
236
+ "required": ["id", "parentDirId", "name", "type"],
237
+ "properties": {
238
+ "id": { "$ref": "#/$defs/nonEmptyString" },
239
+ "parentDirId": { "type": "string" },
240
+ "name": { "type": "string" },
241
+ "type": { "const": "DIRECTORY" },
242
+ "contents": { "type": "array", "items": { "$ref": "#/$defs/directoryTreeNode" } },
243
+ "canManage": { "type": "boolean" },
244
+ "canUse": { "type": "boolean" },
245
+ "ctime": { "type": "string" },
246
+ "utime": { "type": "string" }
247
+ },
248
+ "additionalProperties": true
249
+ },
250
+ "directoryTreeResponse": {
251
+ "allOf": [
252
+ { "$ref": "#/$defs/envelope" },
253
+ { "properties": { "response": { "$ref": "#/$defs/directoryTreeNode" } } }
254
+ ]
255
+ },
256
+ "directoryDeleteResponse": {
257
+ "allOf": [
258
+ { "$ref": "#/$defs/envelope" },
259
+ { "properties": { "response": { "type": "string" } } }
260
+ ]
261
+ }
262
+ }
263
+ }
@@ -0,0 +1,53 @@
1
+ # 指标树 API 真实契约
2
+
3
+ 本文记录指标树及其 `METRIC_TREE` 目录的创建、原地编辑、详情、列表和删除接口真实形态,供 Agent 构造请求和解析返回。完整脱敏样例见 `metric-tree-api-contract-examples.json`,JSON Schema 见 `metric-tree-api-contract.schema.json`。
4
+
5
+ 样例于 2026-09-21 使用 test71 隔离临时指标树和账号密码认证实测。PAT 尚未验证,不能据此声明这些接口已完成 PAT 兼容验证。
6
+
7
+ ## 接口矩阵
8
+
9
+ | 操作 | Method / Path | 请求体 | 关键响应 |
10
+ | --- | --- | --- | --- |
11
+ | 创建 | `POST /api/metric-platform/metric-tree/add` | `metricId/name/parentDirId`,可选 `config` | `success/message/metricTreeId` |
12
+ | 详情 | `GET /api/metric-platform/metric-tree/{id}` | 无 | 详情读模型,名称字段为 `metricTreeName` |
13
+ | 父目录列表 | `GET /api/metric-platform/metric-tree/by-parent/{parentDirId}` | 无 | `{success,data,total}`;列表项名称字段为 `name` |
14
+ | 搜索 | `GET /api/metric-platform/metric-tree/search?nameLike=...` | 无 | `{success,data,total}`;搜索项更接近详情模型,名称字段为 `metricTreeName` |
15
+ | 改名 | `POST /api/metric-platform/metric-tree/{id}/rename` | 仅 `{name}` | `success/message/data`,`data` 是列表态对象 |
16
+ | 移动 | `POST /api/metric-platform/metric-tree/{id}/move` | 仅 `{newParentDirId}` | `success/message`;移到当前目录会返回业务码 `1012` |
17
+ | 更新配置 | `POST /api/metric-platform/metric-tree/{id}/update-config` | 仅 `{config}` | `success/message/data`,`data` 是列表态对象 |
18
+ | 删除 | `POST /api/metric-platform/metric-tree/{id}/delete` | 无 | `{success:true,message:"指标树删除成功"}` |
19
+
20
+ ### METRIC_TREE 目录接口
21
+
22
+ | 操作 | Method / Path | 请求体 | 关键响应 |
23
+ | --- | --- | --- | --- |
24
+ | 目录树 | `GET /api/directory/METRIC_TREE/authorized-tree` | 无 | 递归目录节点,字段为 `id/name/type/contents` |
25
+ | 目录详情 | `GET /api/directory/METRIC_TREE?dirId=...&dirType=METRIC_TREE&folderOnly=true&offset=0&limit=0` | 无 | 详情字段为 `dirId/dirName/dirPath/hasChildDir/count` |
26
+ | 创建目录 | `POST /api/metric-platform/directory/create` | `{name,parentDirId,dirType:"METRIC_TREE"}` | 目录路径对象 |
27
+ | 编辑目录 | `POST /api/metric-platform/directory/{id}/update` | 完整 `{name,parentDirId,dirType:"METRIC_TREE"}` | 目录路径对象 |
28
+ | 删除目录 | `POST /api/metric-platform/directory/{id}/delete` | 无 | 字符串 `Directory deleted` |
29
+
30
+ Spring Controller 已确认上述路由真实存在:目录树和详情要求 `BASE.READ`;创建、编辑、删除分别要求 `METRIC_PLATFORM.CREATE`、`METRIC_PLATFORM.UPDATE`、`METRIC_PLATFORM.DELETE`。这是服务端最终权限判断,CLI 不在本地复制权限规则。PAT 默认授权及有权/无权对照尚未实测。
31
+
32
+ ## 读写模型必须分离
33
+
34
+ - 详情响应的 `metricTreeName`、`metricName`、`projectName`、`creatorName`、`canUse`、`canManage`、`dirPath`、`ctime`、`utime` 和 `isDel` 都是读模型字段,不能把详情整体提交给任一写接口。
35
+ - 父目录列表、rename 和 update-config 返回的对象用 `name`,详情与搜索用 `metricTreeName`。解析器不能假设二者同名。
36
+ - 改名只提交 `{name}`;移动只提交 `{newParentDirId}`;配置编辑只提交 `{config}`。不要用详情对象 merge 后整体回写。
37
+ - 创建的最小写模型是 `{metricId,name,parentDirId}`。CLI 会读取根指标并补齐默认配置;根指标没有时间维度时会拒绝创建。
38
+ - 指标树目录写模型必须固定 `dirType=METRIC_TREE`。目录树节点的 `id/name` 与详情/写响应的 `dirId/dirName` 是两套读模型字段,不能整体回写。
39
+ - 目录 edit 即使只改名称,也要先读详情并提交完整 `{name,parentDirId,dirType}`;根目录不能编辑或删除,目录不能移动到自身或后代。
40
+
41
+ ## 删除安全语义
42
+
43
+ `guanmetric metric-tree delete <id>` 默认先读取详情,展示根指标、项目、目录路径和配置,不真实删除。只有明确追加 `--confirm` 才调用删除接口;`--confirm --dry-run` 只展示 GET + POST 计划。删除由 BI 服务端最终校验权限,当前后端权限项为 `METRIC_PLATFORM.DELETE`。
44
+
45
+ 删除会使原指标树 ID、归因入口和外部链接失效,不可用“删除 + 同名创建”模拟编辑。改名、移动和配置变化必须使用对应原地编辑命令。
46
+
47
+ `guanmetric metric-tree directory delete <dir_id>` 同样默认只展示目录详情;`--confirm` 才删除。前端明确要求先清空目录,目录非空时由后端拒绝。
48
+
49
+ ## 验证边界
50
+
51
+ - 本轮账号密码实测覆盖:指标树创建、详情、父目录列表、搜索、改名、移动、更新配置、删除;以及指标树目录 tree、detail、create、rename、move、delete 和写后回读。
52
+ - PAT 未实测;在完成同用户同 Domain 的有权、无权、资源不存在及写后回读对照前,PAT 状态必须标记为“未验证”。
53
+ - JSON Schema 对请求体使用严格白名单;响应允许服务端新增字段,以降低只增加返回字段造成的漂移风险。