spec-lite 1.1.5 → 1.1.7
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/bin/cli.js +4 -0
- package/package.json +4 -2
- package/references/accessibility-checklist.md +160 -0
- package/references/orchestration-patterns.md +370 -0
- package/references/performance-checklist.md +153 -0
- package/references/security-checklist.md +134 -0
- package/references/testing-patterns.md +236 -0
- package/skills/ado-config/SKILL.md +349 -0
- package/skills/ado-create/SKILL.md +319 -0
- package/skills/ado-update/SKILL.md +295 -0
- package/skills/spec-new/SKILL.md +10 -1
- package/skills-overview.md +443 -0
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ado-config
|
|
3
|
+
description: Tạo hoặc cập nhật .claude/ado.yaml — lưu thông tin Azure DevOps project (org, project, team members, epic ticket). Dùng khi bắt đầu làm việc với một ADO project hoặc khi cần cập nhật thông tin team.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ado-config
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Tạo hoặc cập nhật `.claude/ado.yaml` — file config ADO project dùng chung cho tất cả các skill `/ado-*`.
|
|
11
|
+
|
|
12
|
+
## When to Use
|
|
13
|
+
|
|
14
|
+
- Lần đầu setup ADO cho project
|
|
15
|
+
- Cần cập nhật thông tin project, thành viên team, hoặc Epic ticket
|
|
16
|
+
|
|
17
|
+
## When NOT to Use
|
|
18
|
+
|
|
19
|
+
- Đã có `.claude/ado.yaml` và không cần thay đổi gì → dùng trực tiếp các skill `/ado-*` khác
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Process
|
|
24
|
+
|
|
25
|
+
### Bước 1: Kiểm tra file hiện tại
|
|
26
|
+
|
|
27
|
+
Kiểm tra xem `.claude/ado.yaml` đã tồn tại chưa.
|
|
28
|
+
|
|
29
|
+
**Nếu chưa tồn tại** → tiến hành collect toàn bộ từ Bước 2.
|
|
30
|
+
|
|
31
|
+
**Nếu đã tồn tại** → đọc file, hiển thị tóm tắt nội dung hiện tại:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
.claude/ado.yaml đã tồn tại:
|
|
35
|
+
|
|
36
|
+
organization: torus-engineering
|
|
37
|
+
project_name: Galaxy GCC (project_code: GAL-GCC)
|
|
38
|
+
team: PE: 1 người | SE: 2 người | DE: 1 người
|
|
39
|
+
epic: [42] [GAL-GCC] Spec Lite Kit
|
|
40
|
+
https://dev.azure.com/torus-engineering/Galaxy GCC/_workitems/edit/42
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Sau đó **bắt buộc** gọi `AskUserQuestion`:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
question: "Bạn muốn cập nhật phần nào?"
|
|
47
|
+
options:
|
|
48
|
+
- label: "Toàn bộ từ đầu"
|
|
49
|
+
description: "Chạy lại tất cả các bước — project, team, epic, environments"
|
|
50
|
+
- label: "Thông tin project"
|
|
51
|
+
description: "Cập nhật organization, project, project_id, project_code"
|
|
52
|
+
- label: "Team members"
|
|
53
|
+
description: "Cập nhật danh sách PE / SE / DE"
|
|
54
|
+
- label: "Epic ticket"
|
|
55
|
+
description: "Tạo mới hoặc thay Epic ticket đang được lưu"
|
|
56
|
+
- label: "Môi trường"
|
|
57
|
+
description: "Cập nhật danh sách environments (dev / stag / prod)"
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Tuỳ theo lựa chọn:
|
|
61
|
+
- **"Toàn bộ từ đầu"** → chạy Bước 2 → 3 → 4 → 5 → 6 → 7
|
|
62
|
+
- **"Thông tin project"** → chỉ chạy Bước 2, bỏ qua Bước 3, 4, 5, nhảy thẳng đến Bước 6 → 7 (giữ nguyên `team`, `epic`, `environments` từ file cũ)
|
|
63
|
+
- **"Team members"** → chỉ chạy Bước 3, bỏ qua Bước 2, 4, 5, nhảy thẳng đến Bước 6 → 7 (giữ nguyên `organization/project`, `epic`, `environments` từ file cũ)
|
|
64
|
+
- **"Epic ticket"** → chỉ chạy Bước 4, bỏ qua Bước 2, 3, 5, nhảy thẳng đến Bước 6 → 7 (giữ nguyên `organization/project`, `team`, `environments` từ file cũ)
|
|
65
|
+
- **"Môi trường"** → chỉ chạy Bước 5, bỏ qua Bước 2, 3, 4, nhảy thẳng đến Bước 6 → 7 (giữ nguyên tất cả từ file cũ)
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
### Bước 2: Connect ADO và chọn project
|
|
70
|
+
|
|
71
|
+
**Organization:**
|
|
72
|
+
|
|
73
|
+
**Bắt buộc** gọi tool `AskUserQuestion` — không hỏi bằng plain text. Cấu hình:
|
|
74
|
+
- question: `"Azure DevOps organization name?"`
|
|
75
|
+
- options:
|
|
76
|
+
- label `torus-engineering`, description `Org mặc định — nhấn Enter để chọn`
|
|
77
|
+
- label `ats-technology`
|
|
78
|
+
- System tự thêm option "Type something" cho phép nhập tên org khác hoặc paste full URL
|
|
79
|
+
|
|
80
|
+
Kết quả:
|
|
81
|
+
- User nhấn Enter → chọn `torus-engineering`
|
|
82
|
+
- User dùng ↓ → chọn "Type something" → nhập tên org hoặc paste URL
|
|
83
|
+
|
|
84
|
+
Nếu user nhập full URL (ví dụ `https://dev.azure.com/my-org/...`) → tự extract phần org sau `dev.azure.com/`, bỏ mọi path phía sau.
|
|
85
|
+
|
|
86
|
+
**List projects qua MCP:**
|
|
87
|
+
|
|
88
|
+
Sau khi có organization, gọi MCP tool `mcp__azure-devops__core_list_projects` để lấy danh sách projects trong org đó.
|
|
89
|
+
|
|
90
|
+
Hiển thị numbered list và chờ user nhập số:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
Các project trong org "torus-engineering":
|
|
94
|
+
|
|
95
|
+
1. T-Lead (ID: f95c3b00-b3a8-4405-b062-8471a57cabd6)
|
|
96
|
+
2. C-Blok (ID: 5d57bc02-c656-4be7-981f-4ee5ecf4ba0a)
|
|
97
|
+
3. C-GAL (ID: be587215-de0a-4ea2-952a-d5b635b5d748)
|
|
98
|
+
4. C-GTEL (ID: 06e852f7-83f5-48b6-a83f-81bd665e0187)
|
|
99
|
+
...
|
|
100
|
+
|
|
101
|
+
Nhập số thứ tự project:
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Sau khi user nhập số → tự điền `project_name` và `project_id` từ kết quả MCP. Không hỏi user nhập tay.
|
|
105
|
+
|
|
106
|
+
Nếu MCP call thất bại → thông báo lỗi rõ ràng và hỏi user nhập `project_name` và `project_id` thủ công.
|
|
107
|
+
|
|
108
|
+
**Project Code:**
|
|
109
|
+
> Project code là gì? Đây sẽ là prefix cho mọi ticket trong project.
|
|
110
|
+
> (Ví dụ: `GAL-GCC`, `TORUS-BE`, `VNG-APP` — thường là 2–3 từ viết tắt, ngăn cách bởi dấu gạch ngang)
|
|
111
|
+
|
|
112
|
+
Gợi ý: đề xuất project code dựa trên tên project đã chọn (ví dụ "Galaxy GCC" → `GAL-GCC`). User có thể chấp nhận hoặc nhập lại.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
### Bước 3: Nhập team members
|
|
117
|
+
|
|
118
|
+
Hỏi lần lượt từng role. Với mỗi role, nhập email hợp lệ, mỗi người một dòng, Enter trống khi xong:
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
PE (Product Engineer) [bắt buộc]:
|
|
122
|
+
> anh.le@atstechnology.vn
|
|
123
|
+
> minh.ngo@atstechnology.vn
|
|
124
|
+
>
|
|
125
|
+
|
|
126
|
+
SE (Software Engineer):
|
|
127
|
+
> b@atstechnology.vn
|
|
128
|
+
>
|
|
129
|
+
|
|
130
|
+
DE (Data Engineer):
|
|
131
|
+
>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Một người có thể đóng nhiều role — nhập lại ở role tương ứng.
|
|
135
|
+
|
|
136
|
+
**PE là bắt buộc** — nếu user để trống, nhắc lại và yêu cầu nhập ít nhất 1 email hợp lệ trước khi tiếp tục.
|
|
137
|
+
|
|
138
|
+
SE và DE không có ai → để trống (ghi array rỗng `[]`).
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
### Bước 4: Cấu hình Epic Ticket
|
|
143
|
+
|
|
144
|
+
Epic Ticket là ticket đại diện cho toàn bộ project/product đang được code. Mọi Feature/Story sẽ được link vào Epic này.
|
|
145
|
+
|
|
146
|
+
Hỏi user bằng `AskUserQuestion`:
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
question: "Epic Ticket cho project {project_name} ({project_code})?"
|
|
150
|
+
options:
|
|
151
|
+
- label: "Tạo Epic mới"
|
|
152
|
+
description: "Nhập title và mô tả — Claude sẽ tạo Epic trên ADO với prefix [{project_code}]"
|
|
153
|
+
- label: "Nhập ID ticket có sẵn"
|
|
154
|
+
description: "Nhập ID của Epic đã tồn tại trên ADO để validate và lưu vào config"
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
#### Option A: Tạo Epic mới
|
|
160
|
+
|
|
161
|
+
**1. Nhập title:**
|
|
162
|
+
> Epic title? (sẽ được prefix thành `[{project_code}] <title>`)
|
|
163
|
+
|
|
164
|
+
Ví dụ user nhập `Spec Lite Kit` → title cuối là `[SDLC-TEST] Spec Lite Kit`.
|
|
165
|
+
|
|
166
|
+
**2. Nhập mô tả:**
|
|
167
|
+
|
|
168
|
+
Hỏi bằng `AskUserQuestion`:
|
|
169
|
+
```
|
|
170
|
+
question: "Mô tả Epic?"
|
|
171
|
+
options:
|
|
172
|
+
- label: "Tự nhập mô tả"
|
|
173
|
+
description: "Nhập nội dung mô tả thủ công"
|
|
174
|
+
- label: "Dùng nội dung từ spec artifact"
|
|
175
|
+
description: "Chỉ định đường dẫn file spec.md / prd.md — Claude sẽ đọc và dùng làm mô tả"
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Nếu user chọn **"Dùng nội dung từ spec artifact"**:
|
|
179
|
+
- Hỏi đường dẫn file (ví dụ `specs/integrations/001-implement-auth/spec.md`)
|
|
180
|
+
- Đọc file → dùng toàn bộ nội dung làm description của Epic (format Markdown)
|
|
181
|
+
|
|
182
|
+
Nếu user chọn **"Tự nhập mô tả"**:
|
|
183
|
+
- Hỏi plain text mô tả, có thể để trống
|
|
184
|
+
|
|
185
|
+
**3. Tạo Epic qua MCP:**
|
|
186
|
+
|
|
187
|
+
Trước khi tạo, resolve email của PE đầu tiên thành ADO identity ID bằng `mcp__azure-devops__core_get_identity_ids` (dùng email từ `team.PE[0]`).
|
|
188
|
+
|
|
189
|
+
Gọi `mcp__azure-devops__wit_create_work_item` với:
|
|
190
|
+
- `type`: `Epic`
|
|
191
|
+
- `title`: `[{project_code}] <user_title>`
|
|
192
|
+
- `description`: nội dung đã nhập/đọc
|
|
193
|
+
- `assignedTo`: identity ID của PE đầu tiên trong danh sách
|
|
194
|
+
|
|
195
|
+
Sau khi tạo thành công → lưu `id`, `title`, và `url` vào config. URL được tạo theo format:
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
https://dev.azure.com/{organization}/{project_name}/_workitems/edit/{id}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Nếu resolve identity thất bại → tạo Epic không có assignee, thông báo để user tự assign thủ công trên ADO.
|
|
202
|
+
|
|
203
|
+
Nếu MCP call tạo Epic thất bại → thông báo lỗi và cho phép retry hoặc bỏ qua bước này.
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
#### Option B: Nhập ID ticket có sẵn
|
|
208
|
+
|
|
209
|
+
Hỏi user:
|
|
210
|
+
> Nhập ID của Epic ticket (chỉ số, ví dụ: `42`):
|
|
211
|
+
|
|
212
|
+
Sau khi user nhập → **bắt buộc validate qua MCP** bằng `mcp__azure-devops__wit_get_work_item`:
|
|
213
|
+
|
|
214
|
+
**Kiểm tra các điều kiện sau:**
|
|
215
|
+
1. Work item tồn tại trong ADO project đã chọn
|
|
216
|
+
2. `workItemType` phải là `Epic`
|
|
217
|
+
3. Title phải có prefix `[{project_code}]` — nếu không có thì cảnh báo nhưng vẫn cho phép user xác nhận tiếp tục
|
|
218
|
+
|
|
219
|
+
Nếu validation fail (không tồn tại hoặc không phải Epic) → thông báo lỗi cụ thể và cho phép nhập lại.
|
|
220
|
+
|
|
221
|
+
Nếu validation thành công → hiển thị thông tin ticket để user xác nhận:
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
Tìm thấy Epic:
|
|
225
|
+
ID: 42
|
|
226
|
+
Title: [SDLC-TEST] Spec Lite Kit
|
|
227
|
+
State: New
|
|
228
|
+
URL: https://dev.azure.com/torus-engineering/Common/_workitems/edit/42
|
|
229
|
+
|
|
230
|
+
Dùng Epic này? (yes/no)
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Sau khi user confirm → lưu `id`, `title`, và `url` vào config. URL được tạo theo format:
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
https://dev.azure.com/{organization}/{project_name}/_workitems/edit/{id}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
### Bước 5: Cấu hình môi trường
|
|
242
|
+
|
|
243
|
+
**Bắt buộc** hỏi user bằng `AskUserQuestion` — không cho phép bỏ qua:
|
|
244
|
+
|
|
245
|
+
```
|
|
246
|
+
question: "Project này có bao nhiêu môi trường deploy?"
|
|
247
|
+
options:
|
|
248
|
+
- label: "Production only"
|
|
249
|
+
description: "1 môi trường: prod"
|
|
250
|
+
- label: "Development + Production"
|
|
251
|
+
description: "2 môi trường: dev + prod"
|
|
252
|
+
- label: "Development + Staging + Production"
|
|
253
|
+
description: "3 môi trường: dev + stag + prod"
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Lưu kết quả dưới dạng array theo thứ tự từ thấp đến cao:
|
|
257
|
+
|
|
258
|
+
| Lựa chọn | Giá trị lưu |
|
|
259
|
+
|---|---|
|
|
260
|
+
| Production only | `["prod"]` |
|
|
261
|
+
| Development + Production | `["dev", "prod"]` |
|
|
262
|
+
| Development + Staging + Production | `["dev", "stag", "prod"]` |
|
|
263
|
+
|
|
264
|
+
Nếu user chọn "Other" (nhập tay) → parse chuỗi nhập vào (phân cách bởi dấu phẩy, space, hoặc `+`) → normalize thành lowercase array. Ví dụ: `"dev, staging, prod"` → `["dev", "staging", "prod"]`.
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
### Bước 6: Preview và xác nhận
|
|
269
|
+
|
|
270
|
+
Hiển thị preview YAML sẽ được ghi — **chưa ghi file**:
|
|
271
|
+
|
|
272
|
+
```
|
|
273
|
+
Sẽ ghi vào .claude/ado.yaml:
|
|
274
|
+
|
|
275
|
+
organization: torus-engineering
|
|
276
|
+
project_name: Galaxy GCC
|
|
277
|
+
project_code: GAL-GCC
|
|
278
|
+
project_id: "2074c422-31ea-4b9c-9b61-fe0f749fa28d"
|
|
279
|
+
|
|
280
|
+
team:
|
|
281
|
+
PE:
|
|
282
|
+
- anh.le@atstechnology.vn
|
|
283
|
+
- minh.ngo@atstechnology.vn
|
|
284
|
+
SE:
|
|
285
|
+
- b@atstechnology.vn
|
|
286
|
+
- c@atstechnology.vn
|
|
287
|
+
DE:
|
|
288
|
+
- d@atstechnology.vn
|
|
289
|
+
|
|
290
|
+
epic:
|
|
291
|
+
id: 42
|
|
292
|
+
title: "[GAL-GCC] Spec Lite Kit"
|
|
293
|
+
url: "https://dev.azure.com/torus-engineering/Galaxy GCC/_workitems/edit/42"
|
|
294
|
+
|
|
295
|
+
environments:
|
|
296
|
+
- dev
|
|
297
|
+
- stag
|
|
298
|
+
- prod
|
|
299
|
+
|
|
300
|
+
Xác nhận ghi file? (yes/no)
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Nếu user yêu cầu chỉnh sửa → cập nhật preview → hỏi lại.
|
|
304
|
+
|
|
305
|
+
Nếu user bỏ qua bước Epic (không muốn cấu hình ngay) → bỏ qua key `epic` trong YAML, không ghi `epic: null`.
|
|
306
|
+
|
|
307
|
+
**Bước 5 (môi trường) là bắt buộc** — không cho phép bỏ qua. Nếu user chưa chọn, nhắc lại trước khi tiếp tục.
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
### Bước 7: Ghi file
|
|
312
|
+
|
|
313
|
+
Ghi nội dung đã confirm vào `.claude/ado.yaml`.
|
|
314
|
+
|
|
315
|
+
**Kiểm tra .gitignore:**
|
|
316
|
+
|
|
317
|
+
Đọc `.gitignore` ở root project (nếu tồn tại). Nếu có pattern nào match `.claude/ado.yaml` hoặc `.claude/` → **xóa hoặc thêm exception** để đảm bảo file được track bởi git:
|
|
318
|
+
|
|
319
|
+
- Nếu `.gitignore` có dòng `.claude/` → thêm dòng `!.claude/ado.yaml` ngay bên dưới
|
|
320
|
+
- Nếu `.gitignore` có dòng `.claude/ado.yaml` → xóa dòng đó
|
|
321
|
+
|
|
322
|
+
Thông báo kết quả:
|
|
323
|
+
|
|
324
|
+
```
|
|
325
|
+
✓ .claude/ado.yaml đã được tạo/cập nhật
|
|
326
|
+
|
|
327
|
+
{nếu có thay đổi .gitignore}
|
|
328
|
+
✓ .gitignore — đã đảm bảo .claude/ado.yaml được track bởi git
|
|
329
|
+
|
|
330
|
+
Bước tiếp theo:
|
|
331
|
+
- Commit .claude/ado.yaml để share config với team
|
|
332
|
+
- /ado-init → khởi tạo ADO project (tạo boards, iteration, areas...)
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## Verification
|
|
338
|
+
|
|
339
|
+
Trước khi ghi file, kiểm tra:
|
|
340
|
+
|
|
341
|
+
- [ ] `organization` đã được extract — chỉ là tên org, không phải full URL
|
|
342
|
+
- [ ] `project_name` đã được lưu từ kết quả MCP (tên project gốc từ ADO)
|
|
343
|
+
- [ ] `project_id` có dạng GUID (format: `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`)
|
|
344
|
+
- [ ] Mỗi email hợp lệ (có dấu `@`)
|
|
345
|
+
- [ ] `team.PE` có ít nhất 1 email — không được để trống
|
|
346
|
+
- [ ] SE và DE có thể là array rỗng `[]`
|
|
347
|
+
- [ ] Nếu có Epic: `epic.id` là số nguyên, `epic.title` có prefix `[{project_code}]`, `epic.url` là full URL dạng `https://dev.azure.com/{org}/{project_name}/_workitems/edit/{id}`
|
|
348
|
+
- [ ] `environments` là array ít nhất 1 phần tử (bắt buộc), mỗi phần tử là lowercase string không có khoảng trắng, luôn có `prod` ở cuối
|
|
349
|
+
- [ ] User đã confirm preview trước khi ghi file
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ado-create
|
|
3
|
+
description: Tạo Feature và User Story tickets trên ADO từ spec.md của một integration. Set parent là Epic từ ado.yaml, assign cho current user, cập nhật ticket references vào spec.md và frd.md tương ứng.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ado-create
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Đọc `spec.md` của một integration, tạo Feature và User Story tickets trên ADO, rồi ghi ticket ID/title/URL trở lại vào `spec.md` và `frd.md` tương ứng.
|
|
11
|
+
|
|
12
|
+
## Prerequisites
|
|
13
|
+
|
|
14
|
+
- `.claude/ado.yaml` phải tồn tại và có `epic.id` (chạy `/ado-config` nếu chưa có)
|
|
15
|
+
- `frd.md` tương ứng phải tồn tại trong `specs/main/features/` cho mỗi feature
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Process
|
|
20
|
+
|
|
21
|
+
### Bước 1: Load config và xác định current user
|
|
22
|
+
|
|
23
|
+
Đọc `.claude/ado.yaml`. Nếu không tồn tại → dừng và báo lỗi:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
Chưa có .claude/ado.yaml. Hãy chạy /ado-config trước.
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Xác định current user:** Đọc `git config user.email`. Tìm email này trong toàn bộ `team.PE + team.SE + team.DE` của ado.yaml.
|
|
30
|
+
|
|
31
|
+
**Nếu tìm thấy** → dùng email đó làm assignee.
|
|
32
|
+
|
|
33
|
+
**Nếu không tìm thấy** → hỏi bằng `AskUserQuestion`:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
question: "Bạn là ai trong team? (dùng để assign ticket)"
|
|
37
|
+
options: [mỗi email trong team.PE + team.SE + team.DE thành 1 option]
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Sau khi xác định email, resolve thành ADO identity ID bằng `mcp__azure-devops__core_get_identity_ids`.
|
|
41
|
+
|
|
42
|
+
Nếu resolve thất bại → tiếp tục nhưng không set assignee; thông báo để user tự assign trên ADO sau.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
### Bước 2: Chọn integration
|
|
47
|
+
|
|
48
|
+
List tất cả thư mục trong `specs/integrations/` trừ `000-scaffold`. Với mỗi thư mục, đọc frontmatter của `spec.md` để lấy `title` và `status`.
|
|
49
|
+
|
|
50
|
+
Hỏi user bằng `AskUserQuestion`:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
question: "Chọn integration để tạo ADO tickets:"
|
|
54
|
+
options:
|
|
55
|
+
- label: "001-implement-auth — Implement Authentication"
|
|
56
|
+
description: "status: draft | features: F-001"
|
|
57
|
+
- label: "002-implement-todo — Implement Todo Management"
|
|
58
|
+
description: "status: draft | features: F-002, F-003"
|
|
59
|
+
- ...
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Sau khi user chọn → đọc toàn bộ `spec.md` của integration đó.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
### Bước 3: Parse spec.md
|
|
67
|
+
|
|
68
|
+
Extract từ spec.md:
|
|
69
|
+
|
|
70
|
+
**Features:** Tìm các heading theo pattern `### Feature: <name> (<ID>)`.
|
|
71
|
+
Ví dụ: `### Feature: Đăng ký / Đăng nhập (F-001)` → `{id: "F-001", name: "Đăng ký / Đăng nhập"}`
|
|
72
|
+
|
|
73
|
+
**User Stories:** Tìm các heading theo pattern `#### US-FXXX-YYY — <title>`.
|
|
74
|
+
Ví dụ: `#### US-F001-001 — Đăng ký` → `{code: "US-F001-001", title: "Đăng ký", feature_id: "F-001"}`
|
|
75
|
+
|
|
76
|
+
Với mỗi User Story, thu thập thêm:
|
|
77
|
+
- Câu story: dòng `**<role>** muốn **<want>** để **<goal>**.`
|
|
78
|
+
- `Priority`
|
|
79
|
+
- Tất cả ACs bên dưới (từ `**Acceptance Criteria:**` đến heading tiếp theo)
|
|
80
|
+
|
|
81
|
+
**Kiểm tra đã có ADO ticket chưa:** Ngay sau heading của mỗi Feature / User Story, tìm dòng có format `**ADO:**`. Nếu có → đánh dấu `already_created: true`, lưu lại ID/URL hiện có.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
### Bước 4: Preview và xác nhận
|
|
86
|
+
|
|
87
|
+
Hiển thị kế hoạch trước khi tạo — **chưa tạo gì**:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
Integration: 001-implement-auth — Implement Authentication
|
|
91
|
+
Assignee: anh.le@torus.vn
|
|
92
|
+
|
|
93
|
+
Sẽ tạo các tickets sau:
|
|
94
|
+
|
|
95
|
+
Feature Tickets (parent: Epic #24241 — [SDLC-TEST] Spec Lite Kit):
|
|
96
|
+
✦ F-001 — Đăng ký / Đăng nhập [NEW]
|
|
97
|
+
|
|
98
|
+
User Story Tickets:
|
|
99
|
+
✦ US-F001-001 — Đăng ký [NEW] → parent: F-001
|
|
100
|
+
✦ US-F001-002 — Đăng nhập [NEW] → parent: F-001
|
|
101
|
+
✦ US-F001-003 — Đăng xuất [NEW] → parent: F-001
|
|
102
|
+
|
|
103
|
+
Skip (đã có ADO ticket):
|
|
104
|
+
✓ F-002 — ... #12345 (đã tạo trước)
|
|
105
|
+
|
|
106
|
+
Tiếp tục tạo? (yes/no)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Nếu user từ chối → dừng không tạo gì.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
### Bước 5: Tạo Feature Tickets
|
|
114
|
+
|
|
115
|
+
Thực hiện tuần tự với từng Feature chưa có ADO ticket:
|
|
116
|
+
|
|
117
|
+
**5.1 Tìm frd.md:**
|
|
118
|
+
|
|
119
|
+
Map `F-NNN` → tìm thư mục `specs/main/features/` bắt đầu bằng `NNN-`. Đọc `frd.md` trong thư mục đó.
|
|
120
|
+
|
|
121
|
+
Nếu không tìm thấy `frd.md` → cảnh báo, dùng phần mô tả Feature từ `spec.md` làm description thay thế.
|
|
122
|
+
|
|
123
|
+
**5.2 Tạo ticket:**
|
|
124
|
+
|
|
125
|
+
Gọi `mcp__azure-devops__wit_create_work_item` với:
|
|
126
|
+
- `type`: `Feature`
|
|
127
|
+
- `title`: `[{project_code}] [{feature_id}] {feature_name}` — ví dụ: `[SDLC-TEST] [F-001] Đăng ký / Đăng nhập`
|
|
128
|
+
- `description`: toàn bộ nội dung `frd.md` (giữ nguyên format Markdown)
|
|
129
|
+
- `assignedTo`: ADO identity ID của current user (nếu resolve thành công)
|
|
130
|
+
|
|
131
|
+
Sau khi tạo thành công → **ngay lập tức** link parent. Ưu tiên dùng `mcp__azure-devops__wit_add_child_work_items` (parent = Epic ID, child = Feature ticket ID). Nếu tool này không khả dụng, fallback sang `mcp__azure-devops__wit_work_items_link` với:
|
|
132
|
+
- `sourceId`: Feature ticket ID vừa tạo
|
|
133
|
+
- `targetId`: Epic ID từ ado.yaml
|
|
134
|
+
- `relationType`: `System.LinkTypes.Hierarchy-Reverse`
|
|
135
|
+
|
|
136
|
+
**Nếu link parent thất bại:**
|
|
137
|
+
1. Retry một lần
|
|
138
|
+
2. Nếu vẫn fail → đánh dấu Feature này là `orphan` (KHÔNG xóa ticket), ghi vào danh sách cần xử lý thủ công, tiếp tục với Feature tiếp theo. Ticket orphan sẽ được báo cáo nổi bật ở Bước 10.
|
|
139
|
+
|
|
140
|
+
Lưu lại `{id, title, url}`. URL format:
|
|
141
|
+
```
|
|
142
|
+
https://dev.azure.com/{organization}/{project_name}/_workitems/edit/{id}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Nếu tạo ticket thất bại → log lỗi, đánh dấu Feature này là `failed`, skip toàn bộ User Stories thuộc Feature đó, tiếp tục với Feature tiếp theo.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
### Bước 6: Tạo User Story Tickets
|
|
150
|
+
|
|
151
|
+
Thực hiện tuần tự với từng User Story chưa có ADO ticket:
|
|
152
|
+
|
|
153
|
+
**6.1 Xác định parent Feature ticket ID:**
|
|
154
|
+
|
|
155
|
+
Lấy Feature ticket ID theo thứ tự ưu tiên:
|
|
156
|
+
1. Feature vừa tạo ở Bước 5 → dùng ID từ kết quả MCP
|
|
157
|
+
2. Feature đã `already_created` → parse ID từ dòng `**ADO:** [#<ID> — ...](url)` trong `spec.md`
|
|
158
|
+
|
|
159
|
+
Nếu Feature đó là `failed` → skip toàn bộ User Stories thuộc Feature đó, báo cáo ở Bước 10.
|
|
160
|
+
Nếu Feature là `orphan` (tạo thành công nhưng link Epic thất bại) → vẫn dùng Feature ID đó làm parent cho User Stories, nhưng đánh dấu chuỗi này cần review thủ công.
|
|
161
|
+
Nếu không đọc được Feature ticket ID từ bất kỳ nguồn nào → skip User Story này với cảnh báo.
|
|
162
|
+
|
|
163
|
+
**6.2 Build description:**
|
|
164
|
+
|
|
165
|
+
```markdown
|
|
166
|
+
**{role}** muốn **{want}** để **{goal}**.
|
|
167
|
+
|
|
168
|
+
**Priority:** {priority}
|
|
169
|
+
|
|
170
|
+
**Acceptance Criteria:**
|
|
171
|
+
|
|
172
|
+
- AC-code
|
|
173
|
+
- **Given** ...
|
|
174
|
+
- **When** ...
|
|
175
|
+
- **Then** ...
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**6.3 Tạo ticket:**
|
|
179
|
+
|
|
180
|
+
Gọi `mcp__azure-devops__wit_create_work_item` với:
|
|
181
|
+
- `type`: `User Story`
|
|
182
|
+
- `title`: `[{project_code}] [{feature_name}] - {US-code} — {story_title}` — ví dụ: `[SDLC-TEST] [Đăng ký / Đăng nhập] - US-F001-001 — Đăng ký`
|
|
183
|
+
- `description`: description đã build ở 6.2
|
|
184
|
+
- `assignedTo`: ADO identity ID của current user
|
|
185
|
+
|
|
186
|
+
Sau khi tạo thành công → **ngay lập tức** link parent. Ưu tiên dùng `mcp__azure-devops__wit_add_child_work_items` (parent = Feature ticket ID, child = User Story ticket ID). Nếu không khả dụng, fallback sang `mcp__azure-devops__wit_work_items_link` với:
|
|
187
|
+
- `sourceId`: User Story ticket ID vừa tạo
|
|
188
|
+
- `targetId`: Feature ticket ID
|
|
189
|
+
- `relationType`: `System.LinkTypes.Hierarchy-Reverse`
|
|
190
|
+
|
|
191
|
+
**Nếu link parent thất bại:**
|
|
192
|
+
1. Retry một lần
|
|
193
|
+
2. Nếu vẫn fail → đánh dấu User Story này là `orphan` (KHÔNG xóa ticket), ghi vào danh sách cần xử lý thủ công, tiếp tục với User Story tiếp theo.
|
|
194
|
+
|
|
195
|
+
Lưu lại `{id, title, url}`.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
### Bước 7: Cập nhật spec.md
|
|
200
|
+
|
|
201
|
+
Sau khi tất cả tickets đã được tạo, cập nhật `spec.md`:
|
|
202
|
+
|
|
203
|
+
**Với Feature ticket thành công:** Thêm dòng `**ADO:**` ngay sau heading feature, trên dòng trống đầu tiên:
|
|
204
|
+
|
|
205
|
+
```markdown
|
|
206
|
+
### Feature: Đăng ký / Đăng nhập (F-001)
|
|
207
|
+
**ADO:** [#12345 — [SDLC-TEST] Đăng ký / Đăng nhập](https://dev.azure.com/...)
|
|
208
|
+
|
|
209
|
+
**Feature-level Acceptance Criteria:**
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**Với User Story ticket thành công:** Thêm dòng `**ADO:**` ngay sau heading user story:
|
|
213
|
+
|
|
214
|
+
```markdown
|
|
215
|
+
#### US-F001-001 — Đăng ký
|
|
216
|
+
**ADO:** [#12346 — US-F001-001 — Đăng ký](https://dev.azure.com/...)
|
|
217
|
+
|
|
218
|
+
**Nhân viên mới** muốn ...
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
### Bước 8: Cập nhật prd.md
|
|
224
|
+
|
|
225
|
+
Mở `specs/main/prd.md`. Tìm bảng `## Features`.
|
|
226
|
+
|
|
227
|
+
**Nếu bảng chưa có cột `ADO`:** Thêm cột vào header và separator row:
|
|
228
|
+
|
|
229
|
+
```markdown
|
|
230
|
+
| ID | Feature | Mô tả | Priority | Status | ADO |
|
|
231
|
+
| --- | --- | --- | --- | --- | --- |
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Với mỗi Feature ticket vừa tạo thành công, tìm row tương ứng theo `ID` (ví dụ `F-001`) và thêm link vào cột `ADO`:
|
|
235
|
+
|
|
236
|
+
```markdown
|
|
237
|
+
| F-001 | Đăng ký / Đăng nhập | ... | Must | In Progress | [#12345](url) |
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Nếu cột `ADO` đã tồn tại và row đã có giá trị → **không ghi đè**, bỏ qua.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
### Bước 9: Cập nhật frd.md
|
|
245
|
+
|
|
246
|
+
Với mỗi `frd.md` thuộc integration này:
|
|
247
|
+
|
|
248
|
+
Tìm section `## ADO Tickets` trong file.
|
|
249
|
+
|
|
250
|
+
**Nếu chưa có:** Append vào cuối file:
|
|
251
|
+
|
|
252
|
+
```markdown
|
|
253
|
+
|
|
254
|
+
## ADO Tickets
|
|
255
|
+
|
|
256
|
+
| Type | Code | Ticket |
|
|
257
|
+
|------|------|--------|
|
|
258
|
+
| Feature | F-001 | [#12345 — [SDLC-TEST] Đăng ký / Đăng nhập](url) |
|
|
259
|
+
| User Story | US-F001-001 | [#12346 — US-F001-001 — Đăng ký](url) |
|
|
260
|
+
| User Story | US-F001-002 | [#12347 — US-F001-002 — Đăng nhập](url) |
|
|
261
|
+
| User Story | US-F001-003 | [#12348 — US-F001-003 — Đăng xuất](url) |
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
**Nếu đã có:** Append các row mới (tickets vừa tạo) vào cuối bảng. Không xóa row cũ.
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
### Bước 10: Tóm tắt kết quả
|
|
269
|
+
|
|
270
|
+
```
|
|
271
|
+
✓ ADO tickets đã tạo — integration: 001-implement-auth
|
|
272
|
+
|
|
273
|
+
Feature Tickets:
|
|
274
|
+
✓ #12345 — [SDLC-TEST] [F-001] Đăng ký / Đăng nhập
|
|
275
|
+
https://dev.azure.com/torus-engineering/Common/_workitems/edit/12345
|
|
276
|
+
|
|
277
|
+
User Story Tickets:
|
|
278
|
+
✓ #12346 — [SDLC-TEST] [Đăng ký / Đăng nhập] - US-F001-001 — Đăng ký → F-001 #12345
|
|
279
|
+
✓ #12347 — [SDLC-TEST] [Đăng ký / Đăng nhập] - US-F001-002 — Đăng nhập → F-001 #12345
|
|
280
|
+
✓ #12348 — [SDLC-TEST] [Đăng ký / Đăng nhập] - US-F001-003 — Đăng xuất → F-001 #12345
|
|
281
|
+
|
|
282
|
+
Files đã cập nhật:
|
|
283
|
+
✓ specs/integrations/001-implement-auth/spec.md
|
|
284
|
+
✓ specs/main/features/001-auth/frd.md
|
|
285
|
+
✓ specs/main/prd.md
|
|
286
|
+
|
|
287
|
+
{nếu có lỗi tạo ticket}
|
|
288
|
+
✗ US-F001-004 — ... → tạo thất bại: <lý do>
|
|
289
|
+
|
|
290
|
+
{nếu có orphan — cần xử lý thủ công NGAY}
|
|
291
|
+
⚠ ORPHAN — ticket tồn tại nhưng CHƯA có parent:
|
|
292
|
+
#12349 — US-F001-005 — ...
|
|
293
|
+
→ Cần link thủ công: parent = Feature #12345
|
|
294
|
+
→ https://dev.azure.com/torus-engineering/Common/_workitems/edit/12349
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## Verification Checklist
|
|
300
|
+
|
|
301
|
+
Trước khi tạo ticket:
|
|
302
|
+
- [ ] `.claude/ado.yaml` tồn tại và `epic.id` là số nguyên hợp lệ
|
|
303
|
+
- [ ] Integration được chọn có `spec.md` chứa ít nhất 1 Feature
|
|
304
|
+
- [ ] `frd.md` tìm được cho mỗi Feature (cảnh báo nếu thiếu, không dừng)
|
|
305
|
+
|
|
306
|
+
Khi tạo ticket:
|
|
307
|
+
- [ ] Feature type là `Feature` — không phải `Epic` hay `User Story`
|
|
308
|
+
- [ ] User Story type là `User Story`
|
|
309
|
+
- [ ] Parent link được thực hiện **ngay sau khi tạo ticket** — không để cuối batch
|
|
310
|
+
- [ ] Nếu parent link fail: retry 1 lần, nếu vẫn fail → đánh dấu `orphan`, báo cáo ở Bước 10, KHÔNG im lặng bỏ qua
|
|
311
|
+
- [ ] `already_created` Feature: lấy ticket ID từ `**ADO:**` trong spec.md để dùng làm parent cho User Stories
|
|
312
|
+
- [ ] Title Feature theo format `[{project_code}] [{feature_id}] {feature_name}`
|
|
313
|
+
- [ ] Title User Story theo format `[{project_code}] [{feature_name}] - {US-code} — {story_title}`
|
|
314
|
+
|
|
315
|
+
Khi cập nhật file:
|
|
316
|
+
- [ ] `**ADO:**` được thêm vào đúng vị trí trong `spec.md` (ngay sau heading, trước nội dung)
|
|
317
|
+
- [ ] Chỉ ghi khi ticket tạo **thành công** — không ghi nếu failed
|
|
318
|
+
- [ ] `frd.md` section `## ADO Tickets` không duplicate row đã tồn tại
|
|
319
|
+
- [ ] `prd.md` cột `ADO` chỉ thêm vào feature row tương ứng — không ghi đè nếu đã có giá trị
|