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.
@@ -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ị