spec-lite 1.1.4 → 1.1.6

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 CHANGED
@@ -17,6 +17,10 @@ if (command === 'install') {
17
17
  cpSync(join(pkgRoot, 'skills'), join(claudeDir, 'skills'), { recursive: true })
18
18
  console.log('✓ skills → .claude/skills/')
19
19
 
20
+ // Copy skills-overview.md → .claude/skills/skills-overview.md
21
+ cpSync(join(pkgRoot, 'skills-overview.md'), join(claudeDir, 'skills', 'skills-overview.md'))
22
+ console.log('✓ skills-overview.md → .claude/skills/skills-overview.md')
23
+
20
24
  // Copy templates → .claude/templates/
21
25
  cpSync(join(pkgRoot, 'templates'), join(claudeDir, 'templates'), { recursive: true })
22
26
  console.log('✓ templates → .claude/templates/')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spec-lite",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "description": "Spec-driven development kit for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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ị
@@ -0,0 +1,295 @@
1
+ ---
2
+ name: ado-update
3
+ description: Cập nhật trạng thái (state) cho tất cả User Story và Feature tickets trên ADO theo tiến trình deploy/verify qua từng môi trường được cấu hình trong ado.yaml.
4
+ ---
5
+
6
+ # ado-update
7
+
8
+ ## Overview
9
+
10
+ Đọc `spec.md` của một integration, kiểm tra ADO tickets đã tồn tại chưa, sau đó cho phép user chọn trạng thái mới để cập nhật đồng loạt toàn bộ User Story tickets — và tuỳ chọn cả Feature tickets.
11
+
12
+ ---
13
+
14
+ ## Prerequisites
15
+
16
+ - `.claude/ado.yaml` phải tồn tại và có `environments` (chạy `/ado-config` nếu chưa có)
17
+ - Tất cả Feature và User Story trong integration phải đã có ADO ticket (chạy `/ado-create` nếu chưa có)
18
+
19
+ ---
20
+
21
+ ## State Source
22
+
23
+ State names **không được generate từ `environments`** — chúng được lấy trực tiếp từ ADO bằng `mcp__azure-devops__wit_get_work_item_type`. Mỗi project có thể đặt tên state khác nhau (ví dụ: `dev` có thể là `Deploy Test` thay vì `Deploy Dev`).
24
+
25
+ - **User Story states**: fetch từ ADO work item type `User Story`
26
+ - **Feature states**: fetch từ ADO work item type `Feature`
27
+
28
+ State list hiển thị cho user là danh sách `states` thực tế từ ADO response, **đã qua bước filter theo environments được cấu hình**.
29
+
30
+ ---
31
+
32
+ ## Environment-State Filtering
33
+
34
+ ADO thường định nghĩa state cho mọi environment có thể có (dev, stag, prod). Sau khi fetch, **filter bớt các state không tương ứng với environments trong `.claude/ado.yaml`** trước khi hiển thị cho user.
35
+
36
+ ### Quy tắc filter
37
+
38
+ **Bước 1 — Tách state thành 2 nhóm:**
39
+
40
+ - **Nhóm environment-specific**: state khớp pattern `Deploy *` hoặc `Verify *` (ví dụ: Deploy Test, Verify Test, Deploy Stag, Verify Stag, Deploy Prod, Verify Prod)
41
+ - **Nhóm general**: tất cả state còn lại (New, Pending, In Progress, Done, Removed, v.v.) — giữ nguyên, không filter
42
+
43
+ **Bước 2 — Group environment-specific states thành pairs:**
44
+
45
+ Sắp xếp theo thứ tự xuất hiện trong ADO response, group thành cặp `(Deploy X, Verify X)` theo thứ tự:
46
+ - Pair 0 → tương ứng `environments[0]`
47
+ - Pair 1 → tương ứng `environments[1]`
48
+ - Pair N → tương ứng `environments[N]`
49
+
50
+ **Bước 3 — Giữ chỉ các pairs có index nằm trong danh sách environments:**
51
+
52
+ Environments trong config có bao nhiêu phần tử → giữ bấy nhiêu pairs (theo đúng thứ tự). Pairs thừa (tương ứng env không có trong config) → loại bỏ.
53
+
54
+ ### Ví dụ
55
+
56
+ Config: `environments: [dev, prod]` → 2 environments
57
+
58
+ ADO trả về states (theo thứ tự): New, Pending, In Progress, Deploy Test, Verify Test, Deploy Stag, Verify Stag, Deploy Prod, Verify Prod, Done, Removed
59
+
60
+ Environment-specific pairs (theo thứ tự ADO):
61
+ - Pair 0: (Deploy Test, Verify Test) → `environments[0]` = dev ✓ giữ
62
+ - Pair 1: (Deploy Stag, Verify Stag) → `environments[1]` = prod ✗ nhưng config[1] = prod, không phải stag → loại
63
+ - Pair 2: (Deploy Prod, Verify Prod) → `environments[2]` = không có (chỉ có 2 env) → loại
64
+
65
+ Vì config có 2 environments → giữ 2 pairs đầu tiên: Pair 0 (dev) và Pair 2 (prod):
66
+ - Pair 0: (Deploy Test, Verify Test) → env[0] = dev ✓
67
+ - Pair 2: (Deploy Prod, Verify Prod) → env[1] = prod ✓
68
+
69
+ State list sau filter: New, Pending, In Progress, Deploy Test, Verify Test, Deploy Prod, Verify Prod, Done, Removed
70
+
71
+ > **Lưu ý về mapping positional:** Tổng số pairs ADO trả về có thể nhiều hơn số environments trong config. Map theo vị trí index trong danh sách pairs: pair thứ 0 → env thứ 0, pair thứ 1 → env thứ 1. Pairs có index ≥ số environments trong config → loại bỏ.
72
+
73
+ ---
74
+
75
+ ## Process
76
+
77
+ ### Bước 1: Load config
78
+
79
+ Đọc `.claude/ado.yaml`. Nếu không tồn tại → dừng:
80
+
81
+ ```
82
+ Chưa có .claude/ado.yaml. Hãy chạy /ado-config trước.
83
+ ```
84
+
85
+ Nếu `environments` trống hoặc không tồn tại trong file → dừng:
86
+
87
+ ```
88
+ .claude/ado.yaml chưa có danh sách environments. Hãy chạy /ado-config để cập nhật.
89
+ ```
90
+
91
+ ---
92
+
93
+ ### Bước 2: Chọn integration
94
+
95
+ 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`.
96
+
97
+ Hỏi user bằng `AskUserQuestion`:
98
+
99
+ ```
100
+ question: "Chọn integration để cập nhật ADO ticket status:"
101
+ options:
102
+ - label: "001-implement-auth — Implement Authentication"
103
+ description: "status: draft | features: F-001"
104
+ - label: "002-implement-todo — Implement Todo Management"
105
+ description: "status: draft | features: F-002, F-003"
106
+ ...
107
+ ```
108
+
109
+ Sau khi user chọn → đọc toàn bộ `spec.md` của integration đó.
110
+
111
+ ---
112
+
113
+ ### Bước 3: Parse và kiểm tra ADO tickets
114
+
115
+ **Parse spec.md** để extract:
116
+
117
+ **Features:** Tìm heading `### Feature: <name> (<ID>)` hoặc heading Feature tương đương. Sau mỗi heading, tìm dòng `**ADO F-XXX:**` hoặc `**ADO:**` để lấy ticket ID.
118
+
119
+ **User Stories:** Tìm heading `#### US-FXXX-YYY — <title>`. Sau mỗi heading, tìm dòng `**ADO:**` để lấy ticket ID.
120
+
121
+ **Quy tắc parse ADO ticket ID:** Tìm pattern `[#(\d+)` trong dòng `**ADO**` và extract số đó làm ticket ID.
122
+
123
+ **Kiểm tra đầy đủ tickets:**
124
+
125
+ - Nếu **bất kỳ** Feature hoặc User Story nào **chưa có** dòng `**ADO:**` → dừng và báo:
126
+
127
+ ```
128
+ Integration "002-implement-todo" chưa có đầy đủ ADO tickets.
129
+
130
+ Thiếu tickets:
131
+ ✗ F-002 — Quản lý todo (chưa có Feature ticket)
132
+ ✗ US-F002-003 — Xóa task (chưa có User Story ticket)
133
+
134
+ Hãy chạy /ado-create trước để tạo đầy đủ tickets.
135
+ ```
136
+
137
+ - Nếu **tất cả** đều có → tiếp tục Bước 4.
138
+
139
+ ---
140
+
141
+ ### Bước 4: Fetch states từ ADO và hiển thị tickets hiện tại
142
+
143
+ Thực hiện **song song**:
144
+
145
+ 1. Gọi `mcp__azure-devops__wit_get_work_items_batch_by_ids` với tất cả ticket IDs (Feature + User Story) để lấy state hiện tại.
146
+ 2. Gọi `mcp__azure-devops__wit_get_work_item_type` với `workItemType: "User Story"` để lấy danh sách states thực tế.
147
+ 3. Gọi `mcp__azure-devops__wit_get_work_item_type` với `workItemType: "Feature"` để lấy danh sách Feature states thực tế.
148
+
149
+ Extract `states[].name` từ response của mỗi work item type — đây là danh sách state hợp lệ sẽ dùng ở Bước 5 và 7.
150
+
151
+ Hiển thị tóm tắt trạng thái hiện tại:
152
+
153
+ ```
154
+ Integration: 002-implement-todo — Implement Todo Management
155
+
156
+ User Story Tickets:
157
+ • #24255 — US-F003-001 — Xem Shared Kanban Board [New]
158
+ • #24256 — US-F002-001 — Tạo task mới [New]
159
+ • #24257 — US-F002-002 — Sửa task [Deploy Test]
160
+ • #24258 — US-F002-003 — Xóa task [Verify Test]
161
+
162
+ Feature Tickets:
163
+ • #24253 — F-002 — Quản lý todo [In Development]
164
+ • #24254 — F-003 — Shared dashboard [In Design]
165
+ ```
166
+
167
+ ---
168
+
169
+ ### Bước 5: Chọn state mới cho User Story tickets
170
+
171
+ Dùng danh sách `states[].name` đã fetch từ ADO ở Bước 4, **áp dụng Environment-State Filtering** (xem phần trên) để loại bỏ các state không tương ứng với environments được cấu hình.
172
+
173
+ In ra danh sách đánh số dạng plain text — **không dùng `AskUserQuestion`** vì số state có thể vượt quá 4 options.
174
+
175
+ Ví dụ output với `environments: [dev, prod]` (đã filter bỏ Deploy Stag, Verify Stag):
176
+
177
+ ```
178
+ Chọn state mới cho tất cả User Story tickets:
179
+
180
+ 1. New
181
+ 2. Pending
182
+ 3. Committed
183
+ 4. In Progress
184
+ 5. Deploy Test
185
+ 6. Verify Test
186
+ 7. Deploy Prod
187
+ 8. Verify Prod
188
+ 9. Done
189
+ 10. Removed
190
+
191
+ Nhập số (1–10):
192
+ ```
193
+
194
+ Chờ user nhập số. Nếu input không hợp lệ → in lại danh sách và nhắc nhập lại.
195
+
196
+ ---
197
+
198
+ ### Bước 6: Xác nhận và cập nhật User Story tickets
199
+
200
+ Hiển thị preview trước khi cập nhật:
201
+
202
+ ```
203
+ Sẽ cập nhật 4 User Story tickets → "Verify Dev":
204
+
205
+ • #24255 — US-F003-001 — Xem Shared Kanban Board [New] → [Verify Dev]
206
+ • #24256 — US-F002-001 — Tạo task mới [New] → [Verify Dev]
207
+ • #24257 — US-F002-002 — Sửa task [Deploy Dev] → [Verify Dev]
208
+ • #24258 — US-F002-003 — Xóa task [Verify Dev] → (không đổi)
209
+
210
+ Tiếp tục? (yes/no)
211
+ ```
212
+
213
+ Các ticket đã ở đúng state rồi → hiển thị "(không đổi)", không gọi API update.
214
+
215
+ Nếu user xác nhận → gọi `mcp__azure-devops__wit_update_work_item` tuần tự cho từng ticket cần cập nhật:
216
+ - `id`: ticket ID
217
+ - `state`: state mới đã chọn
218
+
219
+ Nếu update thất bại → log lỗi, tiếp tục với ticket tiếp theo, báo cáo ở Bước 8.
220
+
221
+ ---
222
+
223
+ ### Bước 7: Hỏi về Feature tickets
224
+
225
+ Sau khi hoàn tất User Story, hỏi user bằng `AskUserQuestion`:
226
+
227
+ ```
228
+ question: "Bạn có muốn cập nhật state cho Feature tickets không?"
229
+ options:
230
+ - label: "Có, cập nhật Feature tickets"
231
+ description: "Chọn state mới và cập nhật tất cả Feature tickets của integration này"
232
+ - label: "Không, bỏ qua"
233
+ description: "Giữ nguyên state hiện tại của Feature tickets"
234
+ ```
235
+
236
+ **Nếu user chọn "Không"** → nhảy thẳng đến Bước 8.
237
+
238
+ **Nếu user chọn "Có":**
239
+
240
+ In danh sách đánh số dạng plain text — **không dùng `AskUserQuestion`** — dùng Feature states đã fetch từ ADO ở Bước 4:
241
+
242
+ ```
243
+ Chọn state mới cho tất cả Feature tickets:
244
+
245
+ 1. New
246
+ 2. In Design
247
+ 3. In Development
248
+ 4. Done
249
+ 5. Removed
250
+
251
+ Nhập số (1–5):
252
+ ```
253
+
254
+ Chờ user nhập số. Nếu input không hợp lệ → in lại danh sách và nhắc nhập lại.
255
+
256
+ Hiển thị preview giống Bước 6 cho Feature tickets, xác nhận rồi gọi `mcp__azure-devops__wit_update_work_item` cho từng ticket cần cập nhật.
257
+
258
+ ---
259
+
260
+ ### Bước 8: Tóm tắt kết quả
261
+
262
+ ```
263
+ ✓ Cập nhật ADO ticket status — integration: 002-implement-todo
264
+
265
+ User Story Tickets → "Verify Dev":
266
+ ✓ #24255 — US-F003-001 — Xem Shared Kanban Board
267
+ ✓ #24256 — US-F002-001 — Tạo task mới
268
+ ✓ #24257 — US-F002-002 — Sửa task
269
+ — #24258 — US-F002-003 — Xóa task (không đổi — đã là Verify Dev)
270
+
271
+ Feature Tickets → "In Development":
272
+ ✓ #24253 — F-002 — Quản lý todo
273
+ — #24254 — F-003 — Shared dashboard (không đổi — đã là In Development)
274
+
275
+ {nếu có lỗi}
276
+ ✗ #24260 — US-F002-004 — ... → cập nhật thất bại: <lý do>
277
+ ```
278
+
279
+ ---
280
+
281
+ ## Verification Checklist
282
+
283
+ Trước khi cập nhật:
284
+ - [ ] `.claude/ado.yaml` tồn tại và có `environments` là array không rỗng
285
+ - [ ] Tất cả Features và User Stories trong `spec.md` đều có dòng `**ADO:**` với ticket ID hợp lệ
286
+ - [ ] State list lấy từ ADO qua `wit_get_work_item_type` — **không generate từ `environments`**, không hardcode
287
+ - [ ] State list đã qua **Environment-State Filtering**: chỉ hiển thị Deploy/Verify pairs tương ứng với environments trong config; general states giữ nguyên
288
+ - [ ] State selection dùng numbered list plain text — **không dùng `AskUserQuestion`** (số options vượt giới hạn 4)
289
+ - [ ] User đã xem preview và xác nhận trước khi gọi API
290
+
291
+ Khi cập nhật:
292
+ - [ ] Chỉ gọi API update cho ticket **chưa ở đúng state** — không update nếu state không đổi
293
+ - [ ] Gọi tuần tự, không batch update (để xử lý lỗi từng ticket riêng lẻ)
294
+ - [ ] Nếu 1 ticket fail → tiếp tục với ticket tiếp theo, không dừng toàn bộ
295
+ - [ ] Feature tickets chỉ update khi user **chủ động chọn "Có"** ở Bước 7
@@ -95,7 +95,16 @@ Sau khi confirm, assign F-XXX IDs theo thứ tự tăng dần.
95
95
 
96
96
  ### Bước 4: Scan sâu từng feature
97
97
 
98
- **4a. User stories — infer từ:**
98
+ **4a. User flows — infer từ:**
99
+ - Test file chains nhiều request liên tiếp → detect luồng thao tác có thứ tự
100
+ - Navigation / router config trong UI code (`steps`, `wizard`, `onNext`) → detect bước chuyển màn
101
+ - State machine hoặc status enum (`pending → processing → done`) → detect nhánh edge case
102
+ - Error handling branches trong use case → detect luồng thất bại
103
+
104
+ Đánh dấu source: `(inferred from tests)` hoặc `(inferred from UI navigation)`.
105
+ Nếu không detect được → User Flows section sẽ là NEEDS_CLARIFY.
106
+
107
+ **4b. User stories — infer từ:**
99
108
  - Use case class names và public methods → action descriptions
100
109
  - Route names + HTTP methods → "As a user, I want to POST /auth/register..."
101
110
  - Test `describe` / `it` blocks → `it('should register a new user', ...)` → user story
@@ -149,11 +158,13 @@ Với mỗi feature, generate 2 files dùng templates tương ứng:
149
158
 
150
159
  **`frd.md`** — WHAT (dùng `.claude/templates/main/feature/frd-template.md`):
151
160
  - Description và business goal (infer từ feature name + use case, NEEDS_CLARIFY nếu không rõ)
161
+ - User flows: Mermaid flowchart cho happy case và edge cases (infer từ test chains / UI navigation, NEEDS_CLARIFY nếu không detect được)
152
162
  - User stories (đánh dấu source)
153
163
  - Acceptance criteria (extract từ tests nếu có, NEEDS_CLARIFY nếu không)
154
164
  - Scope: In scope từ detected routes/actions; Out of scope → NEEDS_CLARIFY
155
- - Components consumed: list C-XXX từ Component Index
156
- - Dependencies: feature-to-feature dependencies nếu detect được
165
+ - Dependencies:
166
+ - Feature Dependencies: feature-to-feature dependencies nếu detect được
167
+ - Components Used: list C-XXX từ Component Index (infer từ import statements)
157
168
 
158
169
  **`fdd.md`** — HOW / inter-component (dùng `.claude/templates/main/feature/fdd-template.md`):
159
170
  - Inter-component data flow: sequence diagram từ detected call chain (Mermaid hoặc ASCII)
@@ -65,10 +65,11 @@ frd.md — F-001 Authentication đã tồn tại.
65
65
  Sections hiện có:
66
66
 
67
67
  [1] Overview
68
- [2] Feature-level Acceptance Criteria
69
- [3] User Stories
70
- [4] Scope (In Scope / Out of Scope)
71
- [5] Dependencies
68
+ [2] User Flows
69
+ [3] Feature-level Acceptance Criteria
70
+ [4] User Stories
71
+ [5] Scope (In Scope / Out of Scope)
72
+ [6] Dependencies (Feature Dependencies + Components Used)
72
73
  [A] All — viết lại toàn bộ từ đầu
73
74
  [S] Lên spec từ frd.md hiện tại — frd.md đã đầy đủ, không cần chỉnh
74
75
 
@@ -86,7 +87,7 @@ Lưu lại lựa chọn section.
86
87
 
87
88
  Từ raw requirement, agent xác định features và components liên quan, rồi load các file sau:
88
89
 
89
- - `specs/main/prd.md` — đọc Problem Statement, Target Users, Scope, Feature Index, Component Index
90
+ - `specs/main/prd.md` — đọc Problem Statement, Target Users, Scope, Feature Index, Component Index; **đặc biệt ghi nhận cột `ADO` trong bảng Features** — nếu feature đã có ticket ID thì lưu lại `{feature_id → ado_ticket_id, ado_ticket_title, ado_ticket_url}`
90
91
  - `specs/main/domain.md` — đọc Glossary và Shared Entities
91
92
  - `specs/main/feature/{F-XXX}-{slug}/frd.md` — cho mỗi feature liên quan (nếu file đã tồn tại)
92
93
  - `specs/main/component/{C-XXX}-{slug}/crd.md` — cho mỗi component bị touched (nếu file đã tồn tại)
@@ -162,6 +163,15 @@ Tổng hợp và viết draft `spec.md`:
162
163
 
163
164
  **Cấu trúc file**: dùng `.claude/templates/integrations/spec-template.md` làm skeleton, điền nội dung từ interview vào.
164
165
 
166
+ **ADO references từ prd.md:** Với mỗi Feature heading (`### Feature: <name> (<ID>)`) trong spec.md, nếu feature đó đã có ADO ticket trong `prd.md` → thêm ngay dòng `**ADO:**` bên dưới heading:
167
+
168
+ ```markdown
169
+ ### Feature: Đăng ký / Đăng nhập (F-001)
170
+ **ADO:** [#12345 — [SDLC-TEST] Đăng ký / Đăng nhập](https://dev.azure.com/...)
171
+ ```
172
+
173
+ Điều này đảm bảo `/ado-create` nhận biết feature đã có ticket và không tạo duplicate.
174
+
165
175
  **Cascade Proposals** — agent đề xuất delta cho main artifacts theo các targets sau (chỉ điền nếu thực sự có thay đổi, không thì ghi "Không có thay đổi đề xuất."):
166
176
 
167
177
  ### prd.md
@@ -223,11 +233,11 @@ frd.md — F-001 Authentication đã tồn tại.
223
233
  Sections hiện có:
224
234
 
225
235
  [1] Overview
226
- [2] Components Consumed
236
+ [2] User Flows
227
237
  [3] Feature-level Acceptance Criteria
228
238
  [4] User Stories
229
239
  [5] Scope (In Scope / Out of Scope)
230
- [6] Dependencies
240
+ [6] Dependencies (Feature Dependencies + Components Used)
231
241
  [A] All — viết lại toàn bộ từ đầu
232
242
 
233
243
  Chọn section cần cập nhật (có thể chọn nhiều, ví dụ: 2 3):
@@ -15,13 +15,29 @@ referenced_by:
15
15
 
16
16
  {Mô tả feature này giải quyết vấn đề gì cho user nào, trong 2-3 câu.}
17
17
 
18
- ## Components Consumed
18
+ ## User Flows
19
19
 
20
- Các component feature này dùng tham chiếu đến `specs/main/component/{C-XXX}-...`.
20
+ {Mô tả các luồng thao tác của user để hoàn thành mục tiêu của feature này.}
21
+ {Mỗi flow là một Mermaid flowchart riêng, bao gồm happy case và tất cả edge cases quan trọng.}
21
22
 
22
- | Component | Vai trò trong feature |
23
- | --- | --- |
24
- | `{C-XXX}-{component-name}` | {component này phục vụ cái gì cho feature này} |
23
+ ### Flow 1: {Tên luồng chính}
24
+
25
+ ```mermaid
26
+ flowchart TD
27
+ A([{Điểm bắt đầu}]) --> B[{Bước 1}]
28
+ B --> C{Điều kiện?}
29
+ C -- Happy case --> D[{Bước 2 — thành công}]
30
+ C -- Edge case --> E[{Xử lý lỗi / nhánh phụ}]
31
+ D --> F([{Kết thúc thành công}])
32
+ E --> G([{Kết thúc thất bại / fallback}])
33
+ ```
34
+
35
+ ### Flow 2: {Tên luồng phụ / edge case lớn} *(nếu có)*
36
+
37
+ ```mermaid
38
+ flowchart TD
39
+ A([{Điểm bắt đầu}]) --> B[{...}]
40
+ ```
25
41
 
26
42
  ## Feature-level Acceptance Criteria
27
43
 
@@ -83,6 +99,16 @@ US ID format: `US-F{NNN}-{seq}` — đánh số tăng dần toàn feature.
83
99
 
84
100
  ## Dependencies
85
101
 
102
+ ### Feature Dependencies
103
+
86
104
  | Feature | Loại | Ghi chú |
87
105
  | --- | --- | --- |
88
106
  | {feature-name} | required before / parallel | {lý do} |
107
+
108
+ ### Components Used
109
+
110
+ Tham chiếu đến `specs/main/component/{C-XXX}-...`.
111
+
112
+ | Component | Vai trò trong feature |
113
+ | --- | --- |
114
+ | `{C-XXX}-{component-name}` | {component này phục vụ cái gì cho feature này} |