spec-lite 1.4.0 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -2
- package/package.json +1 -1
- package/skills/spec-frd/SKILL.md +311 -0
- package/skills/spec-prd/SKILL.md +105 -6
- package/skills/spec-remove/SKILL.md +588 -0
- package/skills-overview.md +27 -2
- package/templates/main/feature/frd-template.md +1 -0
- package/templates/main/prd-template.md +16 -1
package/README.md
CHANGED
|
@@ -22,11 +22,14 @@ Chạy một lần để bootstrap main artifacts, sau đó vào Integration Pip
|
|
|
22
22
|
/spec-prd → /spec-sad
|
|
23
23
|
│
|
|
24
24
|
▼
|
|
25
|
+
/spec-frd [F-XXX] (tùy chọn — BA author frd.md trước, spec-first)
|
|
26
|
+
│
|
|
27
|
+
▼
|
|
25
28
|
Integration Pipeline
|
|
26
29
|
```
|
|
27
30
|
|
|
28
31
|
#### `/spec-prd`
|
|
29
|
-
Tạo hoặc cập nhật `specs/main/prd.md` thông qua interview có cấu trúc. Đồng thời scaffold `specs/main/domain.md` skeleton.
|
|
32
|
+
Tạo hoặc cập nhật `specs/main/prd.md` thông qua interview có cấu trúc. Đồng thời scaffold `specs/main/domain.md` skeleton. Nhận tùy chọn một nguồn baseline (path/@file/paste proposal/BRD) để pre-fill interview.
|
|
30
33
|
|
|
31
34
|
Sections: Problem Statement · Target Users · Scope · Features · Components · Non-Functional Requirements · Business Constraints
|
|
32
35
|
|
|
@@ -35,6 +38,15 @@ Tạo hoặc cập nhật `specs/main/sad.md`. Yêu cầu `prd.md` và `domain.m
|
|
|
35
38
|
|
|
36
39
|
Sections: Architectural Style · System Overview · Tech Stack · Cross-Cutting Concerns · Inter-Service Communication · Infrastructure Overview · Architectural Guardrails
|
|
37
40
|
|
|
41
|
+
#### `/spec-frd [F-XXX]` *(tùy chọn)*
|
|
42
|
+
BA author `specs/main/feature/{F-XXX}-*/frd.md` trực tiếp qua interview, **trước** khi DEV bắt đầu integration — spec-first ở feature level. Cặp greenfield đối xứng với `/spec-brownfield-feature`. Nhận F-XXX (hoặc chọn từ Feature Index) + tùy chọn nguồn baseline (path/@file/paste).
|
|
43
|
+
|
|
44
|
+
**Hai gate input (làm chặt):** (1) **Single-feature** — nguồn liên quan đúng 1 feature; xác định >1 → dừng, mô tả rõ lý do tách, redirect `/spec-prd`. (2) **Create-only** — frd.md đã tồn tại → dừng, redirect `/spec-new` (thay đổi feature đã spec đi qua integration để delta cascade + tech/test). Feature mới đơn lẻ chưa có trong Index → skill offer **register một row vào prd Features** rồi author.
|
|
45
|
+
|
|
46
|
+
Phạm vi hẹp: **chủ yếu frd.md** (+ tối đa một feature row vào prd nếu register). Reference component frd phụ thuộc (Components Used); component cần-nhưng-chưa-có ghi như *candidate* để `/spec-sad`/architect chốt boundary. **KHÔNG** tạo `crd.md`/`cdd.md` — component artifacts sinh ở integration time qua `/spec-new` cascade. Change History operation = `manual`. Nếu bỏ qua bước này, `/spec-new` vẫn tự tạo frd làm fallback.
|
|
47
|
+
|
|
48
|
+
Sections: Overview · User Flows · Feature Acceptance Criteria · User Stories · Verification Rules · Scope · Dependencies
|
|
49
|
+
|
|
38
50
|
---
|
|
39
51
|
|
|
40
52
|
## Brownfield — project đã có code
|
|
@@ -152,6 +164,7 @@ Pre-flight yêu cầu git working tree clean — rollback dùng `git checkout --
|
|
|
152
164
|
|---------|--------|
|
|
153
165
|
| `/spec-prd` | `specs/main/prd.md`, `specs/main/domain.md` (skeleton) |
|
|
154
166
|
| `/spec-sad` | `specs/main/sad.md` |
|
|
167
|
+
| `/spec-frd` | `specs/main/feature/{F-XXX}-*/frd.md` *(+ register feature row vào `prd.md` nếu feature mới)* |
|
|
155
168
|
| `/spec-brownfield-init` | `specs/main/prd.md`, `specs/main/domain.md`, `specs/main/sad.md` |
|
|
156
169
|
| `/spec-brownfield-component` | `specs/main/component/{C-XXX}-*/crd.md + cdd.md` |
|
|
157
170
|
| `/spec-brownfield-feature` | `specs/main/feature/{F-XXX}-*/frd.md + fdd.md` |
|
|
@@ -165,4 +178,4 @@ Pre-flight yêu cầu git working tree clean — rollback dùng `git checkout --
|
|
|
165
178
|
| `/review-integration` | *(findings report — không tạo file)* |
|
|
166
179
|
| `/review-everything` | `specs/integrations/{NNN}-{slug}/review-findings.md` *(qua /spec-new)* |
|
|
167
180
|
|
|
168
|
-
|
|
181
|
+
Feature artifacts (`frd.md`) ở greenfield có thể author trước bằng `/spec-frd`, hoặc mọc dần qua **cascade proposals** từ integrations (`/spec-new` fallback). Component artifacts (`crd.md`/`cdd.md`) ở greenfield chỉ mọc qua cascade — không có skill author trực tiếp (`/spec-frd` chỉ reference component, không tạo crd/cdd).
|
package/package.json
CHANGED
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spec-frd
|
|
3
|
+
description: Author MỚI frd.md (Feature Requirements Document) trực tiếp ở feature level qua interview. Role BA, chạy trước integration. CREATE-only, đúng một feature/lần: frd đã tồn tại → redirect /spec-new (delta cascade); nguồn nhiều feature → redirect /spec-prd. Nhận F-XXX từ argument (hoặc chọn từ prd Feature Index) + tùy chọn nguồn baseline (path/@file/paste). Chỉ author frd.md (+ register feature row vào prd nếu feature mới) — reference component, KHÔNG tạo crd/cdd.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# spec-frd
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Author `specs/main/feature/{F-XXX}-{feature-slug}/frd.md` trực tiếp qua interview — **spec-first ở feature level**, do **BA** chạy trước khi bất kỳ integration nào bắt đầu.
|
|
11
|
+
|
|
12
|
+
`frd.md` là **what to build** của một feature: Overview, User Flows, Feature AC, User Stories, Verification Rules, Scope, Dependencies. Đây là baseline ổn định, **author một lần** — mọi thay đổi sau đó đi qua `/spec-new` (delta cascade).
|
|
13
|
+
|
|
14
|
+
Skill này là cặp greenfield đối xứng với `/spec-brownfield-feature` (vốn reverse-engineer frd từ code). Khác biệt: `/spec-frd` author *forward* từ interview, không scan code.
|
|
15
|
+
|
|
16
|
+
**Hai ràng buộc input (làm chặt):**
|
|
17
|
+
1. **Đúng một feature mỗi lần chạy** — xác định > 1 feature → DỪNG, mô tả rõ lý do, redirect `/spec-prd` (Bước 1a).
|
|
18
|
+
2. **CREATE-only** — frd.md đã tồn tại → DỪNG, redirect `/spec-new` để phân tích delta + cascade + downstream (tech/test) (Bước 1c).
|
|
19
|
+
|
|
20
|
+
**Phạm vi hẹp — chủ yếu frd.md:**
|
|
21
|
+
- ✅ Author frd.md (7 sections) cho **một** feature **chưa có frd**.
|
|
22
|
+
- ✅ *Reference* component frd phụ thuộc (Components Used) + ghi component cần-nhưng-chưa-có như **candidate**.
|
|
23
|
+
- ✅ Nếu feature mục tiêu là feature mới chưa có trong Index → **register một row vào `prd.md > Features`** (side-effect hợp lệ duy nhất lên prd).
|
|
24
|
+
- ❌ KHÔNG tạo/sửa `crd.md`/`cdd.md` — component artifacts ra đời ở integration time qua `/spec-new` cascade.
|
|
25
|
+
- ❌ KHÔNG tạo `fdd.md` (inter-component design) hay `tsd.md` (test) — để skill/role khác lo.
|
|
26
|
+
- ❌ KHÔNG đổi status feature đã có, không đụng sad/domain.
|
|
27
|
+
|
|
28
|
+
## When to Use
|
|
29
|
+
|
|
30
|
+
- Greenfield: BA muốn đặc tả **một feature chưa có frd** *trước* khi DEV bắt đầu integration.
|
|
31
|
+
- `prd.md` đã tồn tại (feature có thể đã trong Index, hoặc là feature mới đơn lẻ → skill offer register vào Index).
|
|
32
|
+
|
|
33
|
+
## When NOT to Use
|
|
34
|
+
|
|
35
|
+
- `prd.md` chưa có → chạy `/spec-prd` trước.
|
|
36
|
+
- **frd.md đã tồn tại** (thay đổi feature đã spec) → dùng `/spec-new` (delta cascade + tech/test). `/spec-frd` không update frd.
|
|
37
|
+
- **Nguồn trải nhiều feature** → dùng `/spec-prd` để khai Feature Index trước.
|
|
38
|
+
- Brownfield onboarding (reverse-engineer từ code) → dùng `/spec-brownfield-feature`.
|
|
39
|
+
- Muốn thiết kế technical / inter-component → `/spec-tech` (integration) hoặc fdd qua cascade.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Process
|
|
44
|
+
|
|
45
|
+
### Bước 0: Nạp nguồn yêu cầu (tùy chọn)
|
|
46
|
+
|
|
47
|
+
Giống `/spec-prd` Bước 0. Xác định có nguồn baseline cho feature không (proposal, mô tả feature, ghi chú họp, wireframe note):
|
|
48
|
+
|
|
49
|
+
1. **ARGUMENT chứa path / `@file`** → đọc file đó (`.md`/`.txt`/PDF).
|
|
50
|
+
2. **ARGUMENT chứa text dài (paste)** → dùng làm nguồn.
|
|
51
|
+
3. **Không có** → hỏi một lần:
|
|
52
|
+
> Bạn có tài liệu/nguồn cho feature này không? Nhập **đường dẫn file**, **paste nội dung**, hoặc `không` để interview từ đầu.
|
|
53
|
+
|
|
54
|
+
Lưu ý: ARGUMENT thường vừa chứa **F-XXX** (Bước 1) vừa có thể kèm path — tách hai phần. Nếu chỉ có F-XXX thì hỏi nguồn như trên.
|
|
55
|
+
|
|
56
|
+
Có nguồn → trích baseline cho từng section frd (overview, flows, stories, AC, rules, scope, dependencies). Đánh dấu cái nào trích được, cái nào nguồn không đề cập. Áp **quy tắc baseline** giống `/spec-prd`: reuse những gì có; validate; phần thiếu mới hỏi.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
### Bước 1: Xác định feature
|
|
61
|
+
|
|
62
|
+
**Precondition:** đọc `specs/main/prd.md`. Nếu không tồn tại / template rỗng → dừng:
|
|
63
|
+
> `prd.md` chưa có nội dung. Hãy chạy `/spec-prd` trước.
|
|
64
|
+
|
|
65
|
+
`/spec-frd` là skill **CREATE-only, đúng một feature mỗi lần chạy**. Xác định feature mục tiêu qua ba gate — phải pass cả ba mới vào interview.
|
|
66
|
+
|
|
67
|
+
#### 1a. Single-feature gate — chỉ liên quan đúng 1 feature
|
|
68
|
+
|
|
69
|
+
Đánh giá ARGUMENT + nguồn baseline mô tả **bao nhiêu feature riêng biệt** — mỗi feature = một outcome/luồng nghiệp vụ độc lập (dùng litmus test trong `/spec-prd`).
|
|
70
|
+
|
|
71
|
+
- **Xác định > 1 feature** → **DỪNG** và **mô tả rõ lý do** tại sao là nhiều feature, không chỉ báo chung chung:
|
|
72
|
+
> Mình xác định nguồn này trải **{N} feature** riêng biệt:
|
|
73
|
+
> 1. {tên feature A} — outcome: {…}; persona: {…}; luồng: {…}
|
|
74
|
+
> 2. {tên feature B} — outcome: {…}; persona: {…}; luồng: {…}
|
|
75
|
+
> Lý do tách: {mỗi cái có outcome/luồng độc lập, không phải biến thể của cùng một luồng — chiếu litmus test}.
|
|
76
|
+
>
|
|
77
|
+
> `/spec-frd` chỉ author một feature mỗi lần. Hãy chạy `/spec-prd` để khai {N} feature này vào Feature Index trước, rồi chạy `/spec-frd F-XXX` cho từng cái.
|
|
78
|
+
|
|
79
|
+
(Nếu có F-XXX chỉ định nhưng nguồn vẫn trải nhiều feature → vẫn dừng và mô tả lý do; không tự ý cắt phần thuộc F-XXX, vì BA cần thấy bức tranh đầy đủ để khai Index.)
|
|
80
|
+
- **Đúng 1 feature** → tiếp 1b.
|
|
81
|
+
|
|
82
|
+
#### 1b. Resolve feature mục tiêu
|
|
83
|
+
|
|
84
|
+
- **F-XXX có trong Feature Index** → dùng.
|
|
85
|
+
- **Feature mới — KHÔNG có trong Index** (đúng một) → **offer register**:
|
|
86
|
+
> Feature "{tên}" chưa có trong prd Feature Index. Mình sẽ thêm vào Index rồi author frd:
|
|
87
|
+
> F-{auto next} | {tên} | {mô tả 1 câu} | {priority?} | TODO
|
|
88
|
+
> Đồng ý? [y / sửa / n]
|
|
89
|
+
- `y` → auto-pick `F-XXX` = max(seq)+1 trong Index; **giữ lại để Bước 7 ghi row `[NEW]` vào prd + Change History**.
|
|
90
|
+
- `n` → dừng, gợi ý `/spec-prd` để khai feature trước.
|
|
91
|
+
- **Không có F-XXX và không có nguồn** → hiển thị Feature Index để chọn (chỉ feature **chưa có frd.md**):
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
Features chưa có frd.md:
|
|
95
|
+
|
|
96
|
+
[1] F-001 — Authentication (High) [TODO]
|
|
97
|
+
[3] F-003 — App Browsing & Opt-in (High) [TODO]
|
|
98
|
+
|
|
99
|
+
(F-002 đã có frd.md → thay đổi đi qua /spec-new)
|
|
100
|
+
|
|
101
|
+
Chọn feature để author frd:
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
#### 1c. Create-only gate — frd.md CHƯA tồn tại
|
|
105
|
+
|
|
106
|
+
Kiểm tra `specs/main/feature/{F-XXX}-*/frd.md`.
|
|
107
|
+
|
|
108
|
+
- **Chưa tồn tại** → tiếp Bước 2 (author mới).
|
|
109
|
+
- **Đã tồn tại** → **DỪNG**, redirect `/spec-new`:
|
|
110
|
+
> frd.md cho {F-XXX} đã tồn tại. Mọi thay đổi feature đã được spec phải đi qua `/spec-new` — skill đó phân tích delta, cascade lên frd/crd/prd/domain, và kéo theo việc kỹ thuật/test (`/spec-tech`, `/spec-test`).
|
|
111
|
+
> Chạy: `/spec-new {F-XXX}` (hoặc `/spec-new <mô tả thay đổi>`).
|
|
112
|
+
|
|
113
|
+
`/spec-frd` **không** update frd đã có — giữ một làn ghi delta duy nhất (`/spec-new`) để đảm bảo traceability và downstream không bị bỏ sót.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
### Bước 2: Load context
|
|
118
|
+
|
|
119
|
+
Load:
|
|
120
|
+
- `specs/main/prd.md` — Problem Statement, Target Users (personas), Scope, **row của feature này** trong Feature Index (tên, mô tả, priority), Component Index, **cột ADO** (nếu feature có ticket → lưu lại để spec.md sau này không tạo duplicate).
|
|
121
|
+
- `specs/main/domain.md` — Glossary + Shared Entities liên quan.
|
|
122
|
+
- `specs/main/sad.md` — bảng Components (góc nhìn kiến trúc, để biết C-XXX nào đã có boundary).
|
|
123
|
+
- `specs/main/component/{C-XXX}-*/crd.md` — Public Interface của các component khả năng feature sẽ dùng (nếu đã tồn tại).
|
|
124
|
+
|
|
125
|
+
Tóm tắt context + surface assumptions:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
TỪ PRD & DOMAIN TÔI HIỂU:
|
|
129
|
+
- Feature: {F-XXX — tên — mô tả ngắn từ prd} (priority: {...})
|
|
130
|
+
- Vấn đề tổng: {problem statement ngắn}
|
|
131
|
+
- Personas liên quan: {từ Target Users}
|
|
132
|
+
- Glossary/entities liên quan: {từ domain.md}
|
|
133
|
+
- Components có sẵn có thể dùng: {C-XXX — tên}
|
|
134
|
+
|
|
135
|
+
ASSUMPTIONS TÔI ĐANG ĐẶT RA:
|
|
136
|
+
1. {scope của feature}
|
|
137
|
+
2. {component feature có thể phụ thuộc}
|
|
138
|
+
→ Sửa lại nếu sai trước khi tiếp tục.
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
### Bước 3: Interview
|
|
144
|
+
|
|
145
|
+
Hỏi tuần tự, từng phần — không hỏi tất cả cùng lúc. Nếu Bước 0 có nguồn → trình bày baseline đã trích rồi xin confirm/sửa; phần nguồn không đề cập mới hỏi từ đầu.
|
|
146
|
+
|
|
147
|
+
**Phần 1 — Overview:**
|
|
148
|
+
> Feature này giải quyết vấn đề gì, cho persona nào? (2-3 câu, góc nhìn user/business)
|
|
149
|
+
|
|
150
|
+
**Phần 2 — User Flows:**
|
|
151
|
+
> User thao tác qua những bước nào để đạt mục tiêu? Có những nhánh edge case / thất bại nào quan trọng?
|
|
152
|
+
> (Mình sẽ vẽ mỗi luồng thành một Mermaid flowchart — happy case + edge cases.)
|
|
153
|
+
|
|
154
|
+
**Phần 3 — User Stories:**
|
|
155
|
+
> Liệt kê các stories ở cấp feature: "{Persona} muốn {hành động} để {mục tiêu}". Mỗi story có priority (Must/Should/Could) và acceptance criteria (Given/When/Then).
|
|
156
|
+
|
|
157
|
+
**Phần 4 — Feature Acceptance Criteria:**
|
|
158
|
+
> Có criteria nào áp cho *toàn* feature mà story lẻ không cover? (e2e liên story, cross-story consistency, NFR như performance/accessibility, data & migration)
|
|
159
|
+
> Mỗi cái Given/When/Then, **Then phải đo được**.
|
|
160
|
+
|
|
161
|
+
**Phần 5 — Verification Rules:**
|
|
162
|
+
> Với mỗi input field trong các stories, mình sẽ suggest 2-4 phương án validation để BA chọn (xem "Verification Rules — quy ước sinh" bên dưới). BA là người quyết định.
|
|
163
|
+
|
|
164
|
+
**Phần 6 — Scope:**
|
|
165
|
+
> Feature này làm gì (In Scope)? Có gì liên quan nhưng KHÔNG làm (Out of Scope) + lý do?
|
|
166
|
+
|
|
167
|
+
**Phần 7 — Dependencies:**
|
|
168
|
+
> - **Feature dependencies:** feature này cần feature nào xong trước, hay chạy song song?
|
|
169
|
+
> - **Components Used:** feature này dùng component nào? (Mình sẽ map sang C-XXX có sẵn; component cần-nhưng-chưa-có sẽ ghi như candidate — xem Bước 4.)
|
|
170
|
+
|
|
171
|
+
Câu trả lời vague → hỏi lại để làm rõ (ngưỡng đo được, field cụ thể, nhánh xử lý).
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
### Bước 4: Xử lý component (mức reference + candidate)
|
|
176
|
+
|
|
177
|
+
`/spec-frd` **không carve component**. Chỉ làm hai việc:
|
|
178
|
+
|
|
179
|
+
1. **Component đã có C-XXX** (trong prd Component Index) → ghi vào `Dependencies > Components Used` với vai trò trong feature.
|
|
180
|
+
|
|
181
|
+
2. **Component feature cần nhưng chưa có** → KHÔNG tạo crd/cdd, KHÔNG tự thêm vào prd Component Index. Thay vào đó:
|
|
182
|
+
- Ghi trong Components Used với **tên đề xuất** + flag `(candidate — chưa carve)`.
|
|
183
|
+
- Thêm một mục vào draft **Open Questions** (hoặc note cuối draft) để `/spec-sad`/architect chốt boundary, hoặc `/spec-new` formal-register + tạo crd/cdd ở integration time.
|
|
184
|
+
|
|
185
|
+
Lý do: giữ **một authority duy nhất** cho việc carve component (architect qua `/spec-sad`, hoặc cascade qua `/spec-new`). BA chỉ khai báo *nhu cầu*, không quyết boundary. (Xem quy tắc Given/Derived trong `/spec-prd`.)
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
### Bước 5: Write — sinh draft
|
|
190
|
+
|
|
191
|
+
Dùng `.claude/templates/main/feature/frd-template.md` làm skeleton, điền nội dung từ interview.
|
|
192
|
+
|
|
193
|
+
**ID assignment** (luôn là create — frd mới): US `US-F{NNN}-001+`, Story AC `AC-F{NNN}-001+`, Feature AC `FAC-F{NNN}-001+` (counter độc lập với Story AC), VR `VR-F{NNN}-001+`. `NNN` = số của F-XXX. Flow đánh số từ 1.
|
|
194
|
+
|
|
195
|
+
**Frontmatter** frd mới: theo template, `status: draft`, `owner: BA`, `feature_id: F-XXX`.
|
|
196
|
+
|
|
197
|
+
Hiển thị **toàn bộ draft** cho user — chưa ghi file. Kèm danh sách component candidate (nếu có) và VR còn `TBD`.
|
|
198
|
+
|
|
199
|
+
#### Verification Rules — quy ước sinh
|
|
200
|
+
|
|
201
|
+
Áp dụng khi sinh section Verification Rules. **Tái dùng nguyên quy ước của `/spec-new`** (xem [spec-new SKILL.md](../spec-new/SKILL.md) → "Verification Rules — quy ước sinh"). Tóm tắt:
|
|
202
|
+
|
|
203
|
+
- VR là **business decision — BA owns**. Agent đóng vai **option-suggester**, KHÔNG tự assert rule.
|
|
204
|
+
- Mỗi input field → suggest 2-4 phương án validation + luôn có `Custom` và `TBD`.
|
|
205
|
+
- BA chọn → auto-assign `VR-F{NNN}-{seq}`. `TBD` → vẫn assign ID, ghi `TBD` ở cột Rule, list ra cuối draft.
|
|
206
|
+
- **Cấm:** tự điền rule chưa hỏi BA; đưa regex/validator/error message vào bảng (đó là HOW/UI copy); dùng tech type (`varchar(255)`) thay vì semantic type.
|
|
207
|
+
- Heuristic suggest theo field name: xem bảng trong spec-new.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
### Bước 6: Review — xác nhận với user
|
|
212
|
+
|
|
213
|
+
> Draft frd trên đã đúng chưa?
|
|
214
|
+
> - User Flows có cover đủ happy + edge case không?
|
|
215
|
+
> - User Stories + AC đo được chưa?
|
|
216
|
+
> - Verification Rules đã confirm với BA chưa (không còn TBD ngoài ý muốn)?
|
|
217
|
+
> - Components Used đúng chưa? Component candidate (nếu có) có hợp lý để chuyển cho /spec-sad không?
|
|
218
|
+
|
|
219
|
+
Chỉ ghi file sau khi user confirm. Yêu cầu chỉnh → cập nhật draft → hỏi lại.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
### Bước 7: Save
|
|
224
|
+
|
|
225
|
+
**7a. Ghi `specs/main/feature/{F-XXX}-{slug}/frd.md`** — tạo thư mục nếu chưa có. Status `draft` (lifecycle riêng của artifact).
|
|
226
|
+
|
|
227
|
+
Slug feature lấy từ tên trong prd Feature Index, kebab-case (ví dụ F-001 "Authentication" → `F-001-authentication`).
|
|
228
|
+
|
|
229
|
+
**7b. Append Change History entry** vào `## Change History` cuối frd.md — operation = `manual` (author trực tiếp, không qua integration; cùng quy ước với brownfield skills, theo `conventions.md` §5.5):
|
|
230
|
+
|
|
231
|
+
```markdown
|
|
232
|
+
### {YYYY-MM-DD} — manual — create
|
|
233
|
+
|
|
234
|
+
- **All sections**: initial feature authoring qua /spec-frd
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
(Luôn là `create` — `/spec-frd` không update frd đã có; thay đổi đi qua `/spec-new`.)
|
|
238
|
+
|
|
239
|
+
**7b'. (Chỉ khi Bước 1b register feature mới)** Ghi row `[NEW]` vào `prd.md > Features`:
|
|
240
|
+
|
|
241
|
+
```
|
|
242
|
+
F-{XXX} | {tên} | {mô tả 1 câu} | {priority} | TODO
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Và append Change History entry vào prd.md (theo `conventions.md` §5.5):
|
|
246
|
+
|
|
247
|
+
```markdown
|
|
248
|
+
### {YYYY-MM-DD} — manual — update
|
|
249
|
+
|
|
250
|
+
- **Features**:
|
|
251
|
+
- [NEW] F-XXX — {tên} (registered qua /spec-frd)
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Đây là **side-effect hợp lệ duy nhất** của `/spec-frd` lên prd — thêm một feature row. Việc này atomic với 7a/7b: nếu fail thì rollback cả frd.
|
|
255
|
+
|
|
256
|
+
**7c. KHÔNG đụng gì khác.** Không đổi status của các feature *đã có* (frd tồn tại ≠ integration bắt đầu; marker "→ frd.md tồn tại" derive từ file existence). Không thêm component vào Index (chỉ candidate). Không tạo crd/cdd/fdd/tsd. Không đụng sad/domain.
|
|
257
|
+
|
|
258
|
+
**7d. Thông báo kết quả:**
|
|
259
|
+
|
|
260
|
+
```
|
|
261
|
+
✓ specs/main/feature/{F-XXX}-{slug}/frd.md đã được tạo (status: draft)
|
|
262
|
+
|
|
263
|
+
{nếu có} Component candidate cần carve (chuyển cho architect / integration):
|
|
264
|
+
- {tên đề xuất} — {vai trò}
|
|
265
|
+
|
|
266
|
+
{nếu có} Verification Rules còn TBD:
|
|
267
|
+
- VR-F{NNN}-{seq} — {field}
|
|
268
|
+
|
|
269
|
+
Bước tiếp theo:
|
|
270
|
+
- /spec-tsd F-XXX → QC bootstrap test spec từ frd này
|
|
271
|
+
- /spec-new F-XXX → DEV bắt đầu integration (frd sẽ được consume, crd/cdd sinh qua cascade)
|
|
272
|
+
{nếu có candidate} - /spec-sad → architect chốt boundary cho component candidate
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Common Rationalizations
|
|
278
|
+
|
|
279
|
+
| Rationalization | Reality |
|
|
280
|
+
| --- | --- |
|
|
281
|
+
| "Để /spec-new tự đẻ frd cho nhanh" | frd là *feature requirements* — việc của BA. Để integration đẻ ra = DEV phải đoán yêu cầu. |
|
|
282
|
+
| "BA cứ tạo luôn crd cho component cần" | Carve component là quyết định kiến trúc. BA tạo crd sớm = boundary sai sớm. Chỉ reference. |
|
|
283
|
+
| "Verification rule mình tự điền cho nhanh" | VR là business decision. Agent tự assert = rule sai mà không ai review. |
|
|
284
|
+
| "User Flows vẽ sau cũng được" | Flow buộc phải nghĩ edge case. Không có flow = AC thiếu nhánh thất bại. |
|
|
285
|
+
|
|
286
|
+
## Red Flags
|
|
287
|
+
|
|
288
|
+
- frd dùng từ không đo được trong AC ("hoạt động đúng", "nhanh", "đẹp")
|
|
289
|
+
- User Stories không có persona rõ hoặc không có AC
|
|
290
|
+
- Verification Rules tự điền mà chưa hỏi BA
|
|
291
|
+
- Tạo crd.md/cdd.md (vượt phạm vi — đó là integration time)
|
|
292
|
+
- Component candidate không được surface cho architect
|
|
293
|
+
- **Update frd đã tồn tại** thay vì redirect `/spec-new` (vi phạm CREATE-only)
|
|
294
|
+
- Cắt phần thuộc một F-XXX từ nguồn nhiều feature thay vì dừng + mô tả lý do
|
|
295
|
+
|
|
296
|
+
## Verification
|
|
297
|
+
|
|
298
|
+
- [ ] `prd.md` tồn tại
|
|
299
|
+
- [ ] **Single-feature gate**: nguồn liên quan đúng 1 feature; nếu >1 đã DỪNG và mô tả rõ lý do tách + redirect `/spec-prd`
|
|
300
|
+
- [ ] **Create-only gate**: frd.md của feature mục tiêu CHƯA tồn tại; nếu đã có đã redirect `/spec-new`
|
|
301
|
+
- [ ] Feature mục tiêu có trong Index, HOẶC feature mới đơn lẻ đã được user đồng ý register (Bước 1b)
|
|
302
|
+
- [ ] frd.md có đủ 7 sections (luôn create mới)
|
|
303
|
+
- [ ] Mỗi User Story có persona + priority + ít nhất 1 AC Given/When/Then
|
|
304
|
+
- [ ] Feature AC dùng ID `FAC-F{NNN}-{seq}` (counter độc lập với `AC-F{NNN}`), Then đo được
|
|
305
|
+
- [ ] Verification Rules đã confirm với BA (không tự assert); không chứa regex/code/error message; semantic type
|
|
306
|
+
- [ ] ID bắt đầu từ 001 (create mới)
|
|
307
|
+
- [ ] Components Used reference C-XXX có sẵn; component mới ghi candidate + surface cho /spec-sad
|
|
308
|
+
- [ ] Nếu register feature mới: prd Features có row [NEW] + Change History entry; status feature đã có KHÔNG đổi
|
|
309
|
+
- [ ] KHÔNG tạo crd/cdd/fdd/tsd; KHÔNG đụng sad/domain
|
|
310
|
+
- [ ] Change History entry operation = `manual` (luôn `create`)
|
|
311
|
+
- [ ] User đã confirm trước khi ghi file
|
package/skills/spec-prd/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: spec-prd
|
|
3
|
-
description: Điền hoặc cập nhật prd.md — Product Requirements Document ở product level. Cũng scaffold domain.md skeleton (glossary placeholder + Shared Entities rỗng). Dùng khi prd.md còn là template rỗng hoặc cần review/cập nhật.
|
|
3
|
+
description: Điền hoặc cập nhật prd.md — Product Requirements Document ở product level. Nhận tùy chọn một nguồn yêu cầu (đường dẫn file/@file hoặc paste proposal/BRD/ghi chú) làm baseline để pre-fill interview. Cũng scaffold domain.md skeleton (glossary placeholder + Shared Entities rỗng). Dùng khi prd.md còn là template rỗng hoặc cần review/cập nhật.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# spec-prd
|
|
@@ -26,8 +26,96 @@ PRD không chứa: tech stack, implementation details, entity schema, glossary,
|
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
29
|
+
## Khái niệm: Feature vs Component
|
|
30
|
+
|
|
31
|
+
Section này là nền tảng để điền **Phần 4 (Features)** và **Phần 5 (Components)**. Đọc trước khi interview.
|
|
32
|
+
|
|
33
|
+
### Nguyên tắc gốc
|
|
34
|
+
|
|
35
|
+
**Component là đơn vị ownership; Feature là đơn vị delivery.** Component bền vững theo thời gian; Feature là một luồng nghiệp vụ consume một hoặc nhiều component. Quan hệ giữa hai khái niệm là **N–N** — không mechanical-derive cái này từ cái kia.
|
|
36
|
+
|
|
37
|
+
### Litmus test — phân loại một mục là Feature hay Component
|
|
38
|
+
|
|
39
|
+
Chạy qua các phép thử; đa số phiếu nghiêng đâu thì xếp vào đó:
|
|
40
|
+
|
|
41
|
+
| Phép thử | → Component | → Feature |
|
|
42
|
+
| --- | --- | --- |
|
|
43
|
+
| **Ownership** (quan trọng nhất) | Sở hữu entity + rule + interface | Điều phối/tiêu thụ dữ liệu & rule của thứ khác |
|
|
44
|
+
| **Lifetime** | Xóa hết luồng nghiệp vụ vẫn còn tồn tại | Bỏ đi, không component nào mất gì |
|
|
45
|
+
| **Hướng cắt** | Ngang — một năng lực dùng lại bởi N luồng | Dọc — UI→logic→data cho một luồng |
|
|
46
|
+
| **Đặt tên** | Danh từ hệ thống (`auth`, `payment`) | Luồng nghiệp vụ (`checkout-flow`, `password-reset`) |
|
|
47
|
+
| **Trả lời** | "Phần nào của hệ thống chịu trách nhiệm X?" | "User làm được gì, nhận giá trị gì?" |
|
|
48
|
+
|
|
49
|
+
### Quy tắc đặt tên (cho cả Feature và Component)
|
|
50
|
+
|
|
51
|
+
**Goldilocks:** đặt tên ở mức trừu tượng **cao nhất mà vẫn truyền đạt đúng MỘT trách nhiệm/luồng rõ ràng**. Cao hơn → mất boundary; thấp hơn → rò rỉ chi tiết. Tên dùng kebab-case.
|
|
52
|
+
|
|
53
|
+
**Component — theo năng lực bền vững, không theo công nghệ hiện tại:**
|
|
54
|
+
- ✅ `notification`, `auth`, `file-storage`, `payment-gateway`
|
|
55
|
+
- ❌ Quá cụ thể (rò rỉ impl): `email-sender` (mai thêm SMS/push?), `stripe-client`, `s3-uploader`
|
|
56
|
+
- ❌ Quá mơ hồ (mất boundary): `core`, `utils`, `manager`, `engine`, `service`, `data`
|
|
57
|
+
- Phép thử: *"Mai đổi nhà cung cấp / thêm kênh, tên còn đúng không?"* Không → quá cụ thể.
|
|
58
|
+
|
|
59
|
+
**Feature — theo outcome của một luồng hoàn chỉnh:**
|
|
60
|
+
- ✅ `user-registration`, `password-reset`, `checkout`
|
|
61
|
+
- ❌ Quá rộng (thành feature area, ôm nhiều luồng): `user-management`, `account`, `admin`
|
|
62
|
+
- ❌ Quá hẹp (chỉ một biến thể của luồng): `register-with-google`, `reset-password-via-sms-otp`
|
|
63
|
+
- Phép thử: *"Đây là MỘT luồng, hay cái ô chứa nhiều luồng?"* Cái ô → quá rộng.
|
|
64
|
+
|
|
65
|
+
### Định nghĩa một Component
|
|
66
|
+
|
|
67
|
+
**Một component = một khối có (1) boundary rõ + interface tường minh, và (2) một lý do duy nhất để thay đổi.**
|
|
68
|
+
|
|
69
|
+
- Tính chất (1) là điều kiện *cần*; (2) là guardrail chống "tầng kỹ thuật" lọt vào. "Tầng controller" có boundary rõ nhưng đổi vì N lý do (auth đổi, payment đổi...) → cohesion bằng 0 → **không** phải component.
|
|
70
|
+
- Áp đúng tiêu chí "một lý do thay đổi" thì ranh giới theo capability/domain sẽ **tự hiện ra** — không cần áp luật "phải chia theo domain" từ ngoài vào.
|
|
71
|
+
- Mỗi component đồng thời có **mặt domain** (`crd.md` — WHAT/contract) và **mặt kỹ thuật** (`cdd.md` — HOW/internal design). Đừng phân loại component thành "domain component" hay "kỹ thuật component" — đó chỉ là mô tả *nguồn* cohesion, không phải luật cấu trúc.
|
|
72
|
+
|
|
73
|
+
### Component nào khai ở PRD? — Logic Given vs Derived
|
|
74
|
+
|
|
75
|
+
Feature Index điền **đầy đủ** ở PRD. Component thì **không** — chỉ khai những component có boundary đã *chín*. Độ chín xác định bằng thủ tục quyết định, không cảm tính.
|
|
76
|
+
|
|
77
|
+
**Litmus gốc:** *"Cùng bộ yêu cầu này, một architect giỏi khác có thể vẽ boundary này khác đi một cách hợp lý không?"* — KHÔNG (bị ép, một cách vẽ) → **Given, khai ở PRD**. CÓ (một lựa chọn đánh đổi) → **Derived, để `/spec-sad`**.
|
|
78
|
+
|
|
79
|
+
**Thủ tục 3 câu** (YES đầu tiên thắng):
|
|
80
|
+
|
|
81
|
+
| # | Câu hỏi | Nếu YES |
|
|
82
|
+
| --- | --- | --- |
|
|
83
|
+
| 1. External | Nó bọc/adapt một hệ thống hay bên thứ ba **ngoài codebase** mà ta buộc phải tích hợp? | **Given** → khai PRD (vd `payment-gateway` tích hợp Stripe, `email-service` tích hợp SendGrid) |
|
|
84
|
+
| 2. Mandated-substrate | Nó là nền tảng kỹ thuật dùng chung mà yêu cầu nói rõ phải có, **độc lập với cách carve lõi nghiệp vụ**? | **Given** → khai PRD (vd `auth`, `file-storage`, `notification`) |
|
|
85
|
+
| 3. Còn lại | Boundary phụ thuộc cách carve lõi nghiệp vụ, hoặc phụ thuộc đánh đổi NFR (scale, isolation, consistency, team topology)? | **Derived** → KHÔNG khai, để `/spec-sad` (vd `order`, `pricing`, `inventory`) |
|
|
86
|
+
|
|
87
|
+
Ranh giới câu 2 vs câu 3 = **"boundary có độc lập với quyết định chia lõi nghiệp vụ không?"** Độc lập → Given; phụ thuộc → Derived.
|
|
88
|
+
|
|
89
|
+
### Khi input context đã có sẵn feature/component
|
|
90
|
+
|
|
91
|
+
Input là **baseline, không phải chân lý tuyệt đối**:
|
|
92
|
+
|
|
93
|
+
- Reuse tên/ID/boundary nếu input đã có → không tự đẻ cấu trúc song song.
|
|
94
|
+
- Vẫn chạy litmus test (phân loại) + Given/Derived để **validate**. Nếu input gọi X là "component" mà nó fail ownership test → flag, đề xuất reclassify thành feature (không im lặng bê nguyên).
|
|
95
|
+
- Component **Derived** do input cung cấp → ghi nhận như *candidate*, chuyển sang `/spec-sad`, **không** nhồi vào Component Index của PRD.
|
|
96
|
+
- Phần input thiếu → mới interview để bù.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
29
100
|
## Process
|
|
30
101
|
|
|
102
|
+
### Bước 0: Nạp nguồn yêu cầu (tùy chọn)
|
|
103
|
+
|
|
104
|
+
Trước khi interview, xác định có **nguồn yêu cầu** (proposal, BRD, ghi chú họp, draft cũ) để dùng làm baseline không. Thứ tự ưu tiên:
|
|
105
|
+
|
|
106
|
+
1. **ARGUMENT là path / `@file`** → đọc file đó. Hỗ trợ `.md`, `.txt`, PDF.
|
|
107
|
+
2. **ARGUMENT là text dài (paste trực tiếp)** → dùng luôn làm nguồn.
|
|
108
|
+
3. **Không có ARGUMENT** → hỏi một lần:
|
|
109
|
+
> Bạn có tài liệu/nguồn yêu cầu nào để mình tham khảo không? Nhập **đường dẫn file**, **paste nội dung**, hoặc `không` để interview từ đầu.
|
|
110
|
+
|
|
111
|
+
Nếu có nguồn → đọc và **trích baseline** cho từng section PRD (problem, users, scope, features, components, NFR, constraints). Đánh dấu cái nào trích được, cái nào nguồn không đề cập.
|
|
112
|
+
|
|
113
|
+
Áp **quy tắc baseline** (xem section "Khi input context đã có sẵn feature/component"): reuse tên/ID/boundary; validate feature/component qua litmus + Given/Derived; flag mục phân loại sai; component Derived → candidate cho `/spec-sad`, không nhồi vào Component Index.
|
|
114
|
+
|
|
115
|
+
Nếu không có nguồn → bỏ qua, interview từ đầu như bình thường.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
31
119
|
### Bước 1: Kiểm tra preconditions
|
|
32
120
|
|
|
33
121
|
Đọc `specs/main/prd.md`:
|
|
@@ -79,6 +167,10 @@ PRD không chứa: tech stack, implementation details, entity schema, glossary,
|
|
|
79
167
|
|
|
80
168
|
### Bước 2: Gather — interview requirements
|
|
81
169
|
|
|
170
|
+
**Nếu Bước 0 đã nạp được nguồn:** interview chuyển từ "hỏi trắng" thành **xác nhận + bù chỗ thiếu**. Với mỗi phần, trình bày baseline đã trích rồi hỏi user confirm/sửa; chỉ những phần nguồn không đề cập mới hỏi từ đầu. Bỏ qua phần nào nguồn đã đủ rõ và user xác nhận.
|
|
171
|
+
|
|
172
|
+
**Nếu không có nguồn:** interview từ đầu như mô tả bên dưới.
|
|
173
|
+
|
|
82
174
|
Trước khi hỏi, list ra các assumptions đang tạm thời:
|
|
83
175
|
|
|
84
176
|
```
|
|
@@ -105,9 +197,15 @@ Sau đó hỏi tuần tự, từng phần một — không hỏi tất cả cùn
|
|
|
105
197
|
> Hệ thống cần implement những features gì? Mỗi feature gồm: tên ngắn, mô tả 1 câu (làm gì, cho ai), priority (Must/Should/Could).
|
|
106
198
|
> (Đây sẽ là Feature Index mà các FRD sau này sẽ tham chiếu.)
|
|
107
199
|
|
|
108
|
-
**Phần 5 — Components:**
|
|
109
|
-
> Hệ thống
|
|
110
|
-
>
|
|
200
|
+
**Phần 5 — Components (chỉ component có boundary Given):**
|
|
201
|
+
> Hệ thống chắc chắn phải tích hợp hệ thống ngoài nào (vd `payment-gateway`, `email-service`), hoặc cần nền tảng kỹ thuật dùng chung nào độc lập với cách carve lõi nghiệp vụ (vd `auth`, `file-storage`, `notification`)?
|
|
202
|
+
> Mỗi component gồm: tên kebab-case + 1 câu mô tả responsibility.
|
|
203
|
+
>
|
|
204
|
+
> Áp **thủ tục Given vs Derived** (xem section "Khái niệm: Feature vs Component" ở trên) cho mỗi ứng viên:
|
|
205
|
+
> - **Given** (trúng câu 1 External hoặc câu 2 Mandated-substrate) → khai vào Component Index.
|
|
206
|
+
> - **Derived** (câu 3 — boundary phụ thuộc cách carve lõi nghiệp vụ hoặc đánh đổi NFR, vd `order`, `pricing`) → **KHÔNG** khai. Để `/spec-sad` chốt, hoặc mọc qua `/spec-new F-XXX` cascade.
|
|
207
|
+
>
|
|
208
|
+
> **KHÔNG** mechanical-derive components từ feature areas (vd: thấy "Pricing" trong yêu cầu → tạo ngay `C-pricing`; đó là Derived). Section này có thể chỉ có 3-6 entries, hoặc thậm chí trống. Đừng cố fill cho đủ.
|
|
111
209
|
|
|
112
210
|
**Phần 6 — Non-Functional Requirements:**
|
|
113
211
|
> Có yêu cầu về performance, security, availability, scalability không?
|
|
@@ -200,8 +298,9 @@ Trước khi kết thúc, kiểm tra:
|
|
|
200
298
|
- [ ] Problem Statement từ góc nhìn business, không mention tech stack
|
|
201
299
|
- [ ] Mỗi persona có: tên vai trò, mục tiêu, pain point
|
|
202
300
|
- [ ] Out of Scope có ít nhất 1 item với lý do
|
|
203
|
-
- [ ] Features có ít nhất 1 item, mỗi item có ID (F-XXX), tên, mô tả, priority
|
|
204
|
-
- [ ] Components:
|
|
301
|
+
- [ ] Features có ít nhất 1 item, mỗi item có ID (F-XXX), tên, mô tả, priority. Mỗi item pass litmus test (đơn vị delivery, không phải ownership)
|
|
302
|
+
- [ ] Components: mọi entry là **Given** (trúng câu 1 External hoặc câu 2 Mandated-substrate). Không có component **Derived** (boundary phụ thuộc carve lõi nghiệp vụ — thuộc `/spec-sad`). Có thể trống. Mỗi item có ID (C-XXX), tên kebab-case, mô tả 1 câu
|
|
303
|
+
- [ ] Nếu input context có sẵn feature/component: đã reuse làm baseline, đã validate qua litmus + Given/Derived, đã flag mục phân loại sai (nếu có)
|
|
205
304
|
- [ ] Mỗi NFR có target đo được (không phải "nhanh", "bảo mật chung chung")
|
|
206
305
|
- [ ] domain.md tồn tại (đã scaffold skeleton hoặc có nội dung sẵn)
|
|
207
306
|
- [ ] User đã confirm trước khi file được ghi
|
|
@@ -0,0 +1,588 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spec-remove
|
|
3
|
+
description: Remove một feature toàn diện — tạo removal integration với Code Inventory, Reverse Dependency Audit, reverse-TDD test strategy, và Finalize Plan (move feature artifacts sang specs/removed/ + đóng ADO tickets) như task cuối trong todo.md. Nhận F-XXX làm argument.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# spec-remove
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Tạo removal integration cho 1 feature đã tồn tại. Output là `spec.md` với đầy đủ:
|
|
11
|
+
|
|
12
|
+
- **Code Inventory** — code, route, DB, feature flag, config liên quan
|
|
13
|
+
- **Reverse Dependency Audit** — ai còn reference, an toàn xoá hay không
|
|
14
|
+
- **Test Strategy** — reverse-TDD (regression test "thing is gone")
|
|
15
|
+
- **Finalize Plan** — move feature artifacts sang `specs/removed/` + đóng ADO tickets, được DEV chạy như task cuối trong `todo.md`
|
|
16
|
+
- **Changes blocks** — `[REMOVE]` markers cho mọi artifact bị touched
|
|
17
|
+
|
|
18
|
+
Skill **không** sinh `tech.md` / `plan.md` / `todo.md`. Sau khi `spec.md` được approve, chạy `/spec-tech` → `/plan` → `/build` như flow thường. `spec.md` đủ giàu để 3 skill đó hoạt động không cần modification.
|
|
19
|
+
|
|
20
|
+
## When to Use
|
|
21
|
+
|
|
22
|
+
- Một feature đã ship và cần decommission (deprecated, business pivot, replaced by feature khác)
|
|
23
|
+
- Cần xoá toàn bộ code + spec + ADO state một cách an toàn, có audit trail
|
|
24
|
+
- Có nhiều reverse-dep cần được liệt kê và quyết định rõ ràng trước khi xoá
|
|
25
|
+
|
|
26
|
+
## When NOT to Use
|
|
27
|
+
|
|
28
|
+
- Chỉ muốn xoá 1 US / 1 AC / 1 VR khỏi feature → dùng `/spec-new` với marker `[REMOVE]` cho item đó. Feature vẫn sống.
|
|
29
|
+
- Feature chưa từng được implement (chỉ có frd.md, chưa có code) → dùng `/spec-new` với block `[REMOVE]` cho frd.md, không cần workflow này.
|
|
30
|
+
- Muốn pause / disable tạm thời mà giữ code → đây không phải removal, dùng feature flag thay vì skill này.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Prerequisites
|
|
35
|
+
|
|
36
|
+
- `specs/main/feature/{F-XXX}-*/frd.md` tồn tại
|
|
37
|
+
- `specs/main/prd.md` có row của feature trong Feature Index
|
|
38
|
+
- (Optional) `.claude/ado.yaml` cấu hình nếu muốn đóng ADO tickets ở finalize step
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Process
|
|
43
|
+
|
|
44
|
+
### Bước 1: Validate argument
|
|
45
|
+
|
|
46
|
+
Argument BẮT BUỘC là Feature ID dạng `F-XXX` (3 chữ số). Nếu argument thiếu hoặc sai format → dừng:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
spec-remove cần Feature ID. Ví dụ: /spec-remove F-001
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Tìm thư mục `specs/main/feature/F-XXX-*/`:
|
|
53
|
+
- 0 matches → báo lỗi feature không tồn tại, dừng.
|
|
54
|
+
- ≥ 2 matches → báo lỗi data inconsistency (nhiều thư mục cùng prefix), dừng.
|
|
55
|
+
- 1 match → tiếp.
|
|
56
|
+
|
|
57
|
+
Đọc `frd.md` frontmatter:
|
|
58
|
+
- Nếu `status: removed` → hỏi:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
F-XXX đã có status `removed`. Bạn muốn:
|
|
62
|
+
[1] Re-finalize (move artifacts + close ADO lại, idempotent)
|
|
63
|
+
[2] Tạo removal integration mới (có thể bạn chưa cleanup code lần trước)
|
|
64
|
+
[3] Hủy
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
### Bước 2: Load context
|
|
70
|
+
|
|
71
|
+
Đọc các file sau:
|
|
72
|
+
|
|
73
|
+
**Bắt buộc:**
|
|
74
|
+
- `specs/main/feature/{F-XXX}-*/frd.md` — full content
|
|
75
|
+
- `specs/main/feature/{F-XXX}-*/fdd.md` — nếu tồn tại
|
|
76
|
+
- `specs/main/prd.md` — Feature Index (capture ADO ticket ID cho F-XXX), Component Index, NFR
|
|
77
|
+
- `specs/main/domain.md` — Glossary + Shared Entities (xác định entity nào owned bởi component thuộc F-XXX)
|
|
78
|
+
|
|
79
|
+
**Components used by F-XXX:**
|
|
80
|
+
|
|
81
|
+
Trích từ `frd.md` section `Components Used` + `fdd.md` section `Components Touched`. Với mỗi C-YYY:
|
|
82
|
+
- `specs/main/component/{C-YYY}-*/crd.md`
|
|
83
|
+
- `specs/main/component/{C-YYY}-*/cdd.md` — nếu tồn tại
|
|
84
|
+
|
|
85
|
+
**Reverse dependency scan:**
|
|
86
|
+
|
|
87
|
+
Với mỗi C-YYY mà F-XXX sử dụng, grep `specs/main/feature/F-*/frd.md` (trừ F-XXX) tìm references tới C-YYY. Mọi feature khác có reference → load `frd.md` của feature đó để hiểu nó dùng C-YYY làm gì.
|
|
88
|
+
|
|
89
|
+
Output context summary cho user:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
F-XXX — {feature title}
|
|
93
|
+
Status: {Done/In Progress/...}
|
|
94
|
+
ADO: #{ticket_id} ({current state}) {nếu prd.md có cột ADO}
|
|
95
|
+
|
|
96
|
+
Components dùng bởi F-XXX:
|
|
97
|
+
- C-YYY-{slug} — {role} ({exclusive | shared with F-AAA, F-BBB})
|
|
98
|
+
- ...
|
|
99
|
+
|
|
100
|
+
Reverse-dep features (dùng chung component với F-XXX):
|
|
101
|
+
⚠ F-AAA {title} — dùng C-YYY {interface_name}
|
|
102
|
+
⚠ F-BBB {title} — dùng C-ZZZ {interface_name}
|
|
103
|
+
{hoặc} ✓ Không có reverse-dep — F-XXX hoàn toàn cô lập
|
|
104
|
+
|
|
105
|
+
Glossary terms từ domain.md tham chiếu trong F-XXX:
|
|
106
|
+
- {term} {(unique to F-XXX | shared)}
|
|
107
|
+
- ...
|
|
108
|
+
|
|
109
|
+
Shared entities owned bởi components của F-XXX:
|
|
110
|
+
- {Entity} (Owner: C-YYY) — {used by F-XXX only | also F-AAA}
|
|
111
|
+
- ...
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
### Bước 3: Interview ngắn
|
|
117
|
+
|
|
118
|
+
Hỏi 2 câu, tuần tự:
|
|
119
|
+
|
|
120
|
+
**3.1 — Lý do remove:**
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
Lý do remove F-XXX? (sẽ ghi vào Change History + ADO closure comment)
|
|
124
|
+
> ___
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**3.2 — Removal strategy:**
|
|
128
|
+
|
|
129
|
+
Dùng `AskUserQuestion`:
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
Removal strategy:
|
|
133
|
+
[1] Single-shot — xoá hết trong 1 deploy. Phù hợp khi feature off-traffic, internal-only, không có DB schema lớn.
|
|
134
|
+
[2] Phased — disable trước (feature flag off + deprecation banner), soak period, sau đó xoá code. Phù hợp khi có DB / external API / traffic gradual.
|
|
135
|
+
[3] Phased + drop schema riêng — như Phased nhưng tách thêm 1 integration cho DROP TABLE/COLUMN sau khi code đã xoá và observed.
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Nếu chọn `[2]` hoặc `[3]` → hỏi soak period (1-2 tuần là baseline):
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
Soak period giữa các phase (ngày)?
|
|
142
|
+
> ___
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Phased và Phased+drop schema → ghi nhận để Bước 6 (sinh draft) có Removal Phases section.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
### Bước 4: Code Discovery
|
|
150
|
+
|
|
151
|
+
Mục tiêu: build **Code Inventory** — danh sách code cụ thể sẽ bị xoá.
|
|
152
|
+
|
|
153
|
+
**Nguồn discovery (kết hợp):**
|
|
154
|
+
|
|
155
|
+
1. **fdd.md / cdd.md** — nếu artifact có ghi file path / module path cụ thể trong section như "Implementation Notes" → dùng làm seed trực tiếp.
|
|
156
|
+
2. **Component slug** — search filesystem cho directory matching `{C-YYY}-{slug}` (kebab) hoặc camelCase variant.
|
|
157
|
+
3. **Public Interface signatures** — từ `crd.md` Public Interface, lấy function/class/endpoint name → grep codebase.
|
|
158
|
+
4. **Route paths** — từ `frd.md` User Flows / `fdd.md` sequence diagrams, extract API path patterns (`/api/...`) → grep route registrations.
|
|
159
|
+
5. **Owned Entities** — từ `domain.md` Shared Entities (owned bởi component của F-XXX), table name → grep migrations + queries.
|
|
160
|
+
6. **Feature flag names** — nếu được nhắc trong artifact → grep config files.
|
|
161
|
+
7. **Test files** — sau khi xác định module paths, grep `tests/` cho cùng prefix / cùng tên.
|
|
162
|
+
|
|
163
|
+
**Tools:** `Grep`, `Glob`, `Bash` (`rg`, `find`). Khi không chắc filesystem layout, hỏi user 1 câu: "Codebase root ở `src/` hay project có monorepo structure khác?"
|
|
164
|
+
|
|
165
|
+
**Output Code Inventory** dạng table, group theo category:
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
Code Inventory for F-XXX:
|
|
169
|
+
|
|
170
|
+
ROUTES / API ENDPOINTS:
|
|
171
|
+
[1] POST /api/auth/login → src/routes/auth.ts:12-50
|
|
172
|
+
[2] POST /api/auth/logout → src/routes/auth.ts:52-80
|
|
173
|
+
[3] POST /api/auth/refresh → src/routes/auth.ts:82-115
|
|
174
|
+
|
|
175
|
+
SOURCE MODULES:
|
|
176
|
+
[4] src/services/auth/ → entire directory (8 files)
|
|
177
|
+
[5] src/middleware/auth-token.ts
|
|
178
|
+
[6] src/utils/jwt.ts → ⚠ also used by F-007 (reverse-dep)
|
|
179
|
+
|
|
180
|
+
TESTS:
|
|
181
|
+
[7] tests/auth/ → 12 files
|
|
182
|
+
[8] tests/integration/auth-flow.test.ts
|
|
183
|
+
|
|
184
|
+
DATABASE:
|
|
185
|
+
[9] table `sessions` → migration drop_sessions.sql cần tạo
|
|
186
|
+
[10] table `refresh_tokens` → migration cần tạo
|
|
187
|
+
[11] users.last_login_at column → ⚠ used by F-007 analytics
|
|
188
|
+
|
|
189
|
+
FEATURE FLAGS:
|
|
190
|
+
[12] ff_new_auth → src/config/flags.ts:12
|
|
191
|
+
|
|
192
|
+
CONFIG / ENV:
|
|
193
|
+
[13] AUTH_SECRET, AUTH_TTL → .env.example, src/config/index.ts
|
|
194
|
+
|
|
195
|
+
OTHER (best-effort, manual verify):
|
|
196
|
+
- Grafana dashboard "Auth metrics" — không scan được tự động, BA verify tay
|
|
197
|
+
- Docs site có section /docs/auth/ — verify tay
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Mỗi item có thể là `safe` (xanh) hoặc `⚠ has external ref` (cần quyết định ở Bước 5).
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
### Bước 5: Reverse Dependency Audit
|
|
205
|
+
|
|
206
|
+
Với mỗi item trong Code Inventory, grep external references (ngoài thư mục chính của F-XXX). Mọi reference `⚠` cần user quyết định.
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
Reverse-dep audit:
|
|
210
|
+
|
|
211
|
+
[6] src/utils/jwt.ts
|
|
212
|
+
External refs found:
|
|
213
|
+
- src/services/admin/sessions.ts:34 — imports `verifyJWT`
|
|
214
|
+
- src/services/api-gateway/auth-check.ts:12 — imports `signJWT`
|
|
215
|
+
|
|
216
|
+
Quyết định:
|
|
217
|
+
[a] Keep file — không xoá src/utils/jwt.ts (chỉ xoá phần exclusive của F-XXX bên trong nếu có)
|
|
218
|
+
[b] Migrate consumer first — abort removal, tạo integration migration F-007 + api-gateway sang alternative trước
|
|
219
|
+
[c] Remove anyway — xoá luôn, downstream tự fix (rủi ro cao, cần justify)
|
|
220
|
+
Chọn: ___
|
|
221
|
+
|
|
222
|
+
[11] users.last_login_at column
|
|
223
|
+
External refs found:
|
|
224
|
+
- src/analytics/login-tracking.ts:88 — SELECT this column
|
|
225
|
+
Quyết định: ___
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Mọi item `⚠` đều phải có quyết định trước khi sang Bước 6. Nếu user chọn `[b]` cho bất kỳ item nào → dừng skill, instruct:
|
|
229
|
+
|
|
230
|
+
```
|
|
231
|
+
F-XXX chưa thể remove vì có reverse-dep chưa migrate:
|
|
232
|
+
- {item} blocked by {consumer}
|
|
233
|
+
|
|
234
|
+
Tạo integration migration trước:
|
|
235
|
+
/spec-new "Migrate {consumer} away from {item}"
|
|
236
|
+
|
|
237
|
+
Sau khi migration deploy xong, chạy lại /spec-remove F-XXX.
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
### Bước 6: Sinh draft spec.md
|
|
243
|
+
|
|
244
|
+
Xác định slug và NNN giống `/spec-new`:
|
|
245
|
+
- Slug: `remove-{f-xxx-slug}` (ví dụ `remove-f001-authentication`)
|
|
246
|
+
- NNN: max của thư mục hiện có trong `specs/integrations/` + 1, format 3 chữ số.
|
|
247
|
+
|
|
248
|
+
Output path: `specs/integrations/{NNN}-remove-{f-xxx-slug}/spec.md`
|
|
249
|
+
|
|
250
|
+
Cấu trúc spec.md:
|
|
251
|
+
|
|
252
|
+
```markdown
|
|
253
|
+
---
|
|
254
|
+
id: "{NNN}"
|
|
255
|
+
slug: "remove-{f-xxx-slug}"
|
|
256
|
+
title: "Remove {F-XXX} {feature title}"
|
|
257
|
+
features: [{F-XXX}]
|
|
258
|
+
components: [{C-YYY list những component bị touched}]
|
|
259
|
+
status: approved
|
|
260
|
+
removal: true
|
|
261
|
+
created: {YYYY-MM-DD}
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## Context
|
|
265
|
+
{tóm tắt frd/fdd/components/reverse-deps đã load ở Bước 2}
|
|
266
|
+
|
|
267
|
+
## Problem Statement
|
|
268
|
+
{lý do remove từ Bước 3.1 — ghi từ góc nhìn business/product, không phải tech}
|
|
269
|
+
|
|
270
|
+
## Removal Strategy
|
|
271
|
+
{Single-shot | Phased | Phased + schema drop} — chi tiết theo lựa chọn:
|
|
272
|
+
|
|
273
|
+
### Phase 1: Disable (chỉ khi Phased)
|
|
274
|
+
- Tắt feature flag `ff_xxx`
|
|
275
|
+
- Deprecation banner trên UI (nếu user-facing)
|
|
276
|
+
- Telemetry warning log mỗi lần feature được hit
|
|
277
|
+
- Soak: {N} ngày, monitor traffic = 0
|
|
278
|
+
|
|
279
|
+
### Phase 2: Remove code
|
|
280
|
+
- Xoá code per Code Inventory dưới
|
|
281
|
+
- Regression tests (xem Test Strategy)
|
|
282
|
+
|
|
283
|
+
### Phase 3: Drop schema (chỉ khi Phased + schema drop)
|
|
284
|
+
- Tạo integration riêng sau {N} ngày Phase 2 deployed
|
|
285
|
+
- Migration DROP TABLE / DROP COLUMN
|
|
286
|
+
|
|
287
|
+
## Code Inventory
|
|
288
|
+
{copy table từ Bước 4, đã loại bỏ các item user quyết định `[a] Keep`}
|
|
289
|
+
|
|
290
|
+
## Reverse Dependency Audit
|
|
291
|
+
{liệt kê mỗi item ⚠ + quyết định user đã chọn, kèm lý do/justify}
|
|
292
|
+
|
|
293
|
+
## Test Strategy (Reverse-TDD)
|
|
294
|
+
|
|
295
|
+
Pattern cho mỗi target:
|
|
296
|
+
|
|
297
|
+
1. **Baseline check (trước khi xoá):** ghi nhận test hiện có hoặc viết quick smoke test xác nhận thing exists và functional. Mục đích: confirm mental model trước khi xoá.
|
|
298
|
+
|
|
299
|
+
2. **Delete trong 1 commit:**
|
|
300
|
+
- Xoá source code
|
|
301
|
+
- Xoá test files cũ tương ứng
|
|
302
|
+
- Update import statements
|
|
303
|
+
|
|
304
|
+
3. **Regression assertion (sau khi xoá):** thêm test khẳng định thing is gone:
|
|
305
|
+
- Route → assert GET/POST trả 404 (hoặc proper error code)
|
|
306
|
+
- Exported function/class → assert import fails (compile-time check, không cần runtime test)
|
|
307
|
+
- DB table/column → migration test confirm DROP applied, query trả error
|
|
308
|
+
- Feature flag → assert flag key không tồn tại trong config
|
|
309
|
+
|
|
310
|
+
4. **Full suite run:** mọi test khác phải pass. Nếu có test fail → reverse-dep chưa detect đủ, rollback commit, audit lại.
|
|
311
|
+
|
|
312
|
+
Regression tests **được giữ lại** trong codebase như guardrail — future-self không vô tình re-add feature đã removed.
|
|
313
|
+
|
|
314
|
+
## Finalize Plan
|
|
315
|
+
|
|
316
|
+
Đây là **task cuối** trong todo.md (sẽ được /plan tự nhặt). DEV thực thi sau khi mọi removal task khác xong và đã deploy verify.
|
|
317
|
+
|
|
318
|
+
### Actions:
|
|
319
|
+
|
|
320
|
+
1. **Move feature artifacts:**
|
|
321
|
+
```bash
|
|
322
|
+
mkdir -p specs/removed
|
|
323
|
+
mv specs/main/feature/{F-XXX}-{slug}/ specs/removed/{F-XXX}-{slug}/
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
2. **Append Change History** vào `specs/removed/{F-XXX}-{slug}/frd.md` (nếu file còn tồn tại sau move):
|
|
327
|
+
```markdown
|
|
328
|
+
### {YYYY-MM-DD} — [{NNN}-remove-{slug}](../../integrations/{NNN}-remove-{slug}/spec.md) — removed
|
|
329
|
+
- **Feature decommissioned**: moved from specs/main/feature/ to specs/removed/
|
|
330
|
+
- Reason: {lý do từ Problem Statement}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
3. **Update prd.md Feature Index:**
|
|
334
|
+
- Row F-XXX: status → `Removed`
|
|
335
|
+
- Add note column hoặc inline: `(see specs/removed/{F-XXX}-{slug}/)`
|
|
336
|
+
|
|
337
|
+
4. **Close ADO tickets** (nếu prd.md có ADO ticket ID cho F-XXX):
|
|
338
|
+
- Feature ticket → state `Removed`
|
|
339
|
+
- Tất cả User Story tickets thuộc F-XXX → state `Removed`
|
|
340
|
+
- Comment trên mỗi ticket: "Decommissioned per integration {NNN}-remove-{slug}. Reason: {lý do}"
|
|
341
|
+
- Dùng `mcp__azure-devops__wit_update_work_item` (state) + `mcp__azure-devops__wit_add_work_item_comment` (comment)
|
|
342
|
+
- Nếu ADO state name khác (vd "Closed") → xem `.claude/ado.yaml` hoặc fetch từ `wit_get_work_item_type`
|
|
343
|
+
|
|
344
|
+
5. **Verify finalize:**
|
|
345
|
+
- `ls specs/main/feature/ | grep {F-XXX}` → không còn match
|
|
346
|
+
- `ls specs/removed/{F-XXX}-{slug}/` → tồn tại
|
|
347
|
+
- prd.md grep `F-XXX` → status `Removed`
|
|
348
|
+
- ADO ticket fetch → state khớp
|
|
349
|
+
|
|
350
|
+
## Changes
|
|
351
|
+
<!-- Changes blocks theo format chuẩn của spec-template.md, áp dụng cho mọi artifact bị touched. Xem markers [NEW]/[MODIFY {field}]/[REMOVE] theo conventions §5.5. -->
|
|
352
|
+
|
|
353
|
+
### prd.md
|
|
354
|
+
**Operation:** update
|
|
355
|
+
**Format reference:** [prd-template.md](../../templates/main/prd-template.md)
|
|
356
|
+
|
|
357
|
+
#### Features (Feature Index)
|
|
358
|
+
- Row [MODIFY status]: `F-XXX` {current status} → `Removed`
|
|
359
|
+
- {nếu có note column} Row [MODIFY note]: `F-XXX` add note "see specs/removed/"
|
|
360
|
+
|
|
361
|
+
#### Components (Component Index) — chỉ component exclusive với F-XXX
|
|
362
|
+
- Row [MODIFY status]: `C-YYY` {current status} → `Removed`
|
|
363
|
+
- ... (component shared thì KHÔNG đổi status)
|
|
364
|
+
|
|
365
|
+
### feature/{F-XXX}-{slug}/frd.md
|
|
366
|
+
**Operation:** update
|
|
367
|
+
**Format reference:** [frd-template.md](../../templates/main/feature/frd-template.md)
|
|
368
|
+
|
|
369
|
+
<!--
|
|
370
|
+
Đánh dấu mọi item bằng [REMOVE]. File sẽ bị move sang specs/removed/ ở Finalize step
|
|
371
|
+
nhưng cascade content vẫn ghi vào file gốc trước (để Change History entry được apply).
|
|
372
|
+
-->
|
|
373
|
+
|
|
374
|
+
#### User Stories
|
|
375
|
+
- US-FXXX-001 [REMOVE] — feature decommissioned
|
|
376
|
+
- US-FXXX-002 [REMOVE] — feature decommissioned
|
|
377
|
+
- ... (mọi US)
|
|
378
|
+
|
|
379
|
+
#### Acceptance Criteria
|
|
380
|
+
- AC-FXXX-* [REMOVE] — feature decommissioned
|
|
381
|
+
|
|
382
|
+
#### Verification Rules
|
|
383
|
+
- VR-FXXX-* [REMOVE] — feature decommissioned
|
|
384
|
+
|
|
385
|
+
#### Frontmatter
|
|
386
|
+
- [MODIFY status]: `draft|approved|...` → `removed`
|
|
387
|
+
|
|
388
|
+
### feature/{F-XXX}-{slug}/fdd.md *(nếu tồn tại)*
|
|
389
|
+
**Operation:** update
|
|
390
|
+
**Format reference:** [fdd-template.md](../../templates/main/feature/fdd-template.md)
|
|
391
|
+
|
|
392
|
+
#### Flow Sequences
|
|
393
|
+
- [REMOVE] FS-FXXX-* — feature decommissioned
|
|
394
|
+
|
|
395
|
+
#### Data Models
|
|
396
|
+
- [REMOVE] {model} — feature decommissioned
|
|
397
|
+
|
|
398
|
+
#### Frontmatter
|
|
399
|
+
- [MODIFY status]: → `removed`
|
|
400
|
+
|
|
401
|
+
### component/{C-YYY}-{slug}/crd.md *(lặp cho mỗi component bị touched)*
|
|
402
|
+
**Operation:** update
|
|
403
|
+
**Format reference:** [crd-template.md](../../templates/main/component/crd-template.md)
|
|
404
|
+
|
|
405
|
+
<!--
|
|
406
|
+
Component exclusive với F-XXX:
|
|
407
|
+
- Toàn bộ sections [REMOVE]
|
|
408
|
+
- Frontmatter status → removed
|
|
409
|
+
|
|
410
|
+
Component shared (vẫn còn feature khác dùng):
|
|
411
|
+
- Chỉ [REMOVE] những Public Interface / Responsibility / Owned Entity
|
|
412
|
+
chỉ phục vụ F-XXX (đã audit ở Bước 5)
|
|
413
|
+
- Giữ nguyên phần còn lại
|
|
414
|
+
- Frontmatter status KHÔNG đổi
|
|
415
|
+
-->
|
|
416
|
+
|
|
417
|
+
#### Public Interface
|
|
418
|
+
- {interface} [REMOVE] — only used by F-XXX, no other consumer
|
|
419
|
+
|
|
420
|
+
#### Owned Entities
|
|
421
|
+
- {Entity} [REMOVE] — exclusive to F-XXX
|
|
422
|
+
|
|
423
|
+
### domain.md
|
|
424
|
+
**Operation:** update
|
|
425
|
+
**Format reference:** [domain-template.md](../../templates/main/domain-template.md)
|
|
426
|
+
|
|
427
|
+
#### Glossary
|
|
428
|
+
- {term} [REMOVE] — unique to F-XXX, no other reference
|
|
429
|
+
|
|
430
|
+
#### Shared Entities
|
|
431
|
+
- {Entity} [REMOVE] — orphan after F-XXX removal, no other component owns
|
|
432
|
+
|
|
433
|
+
## Out of Scope
|
|
434
|
+
- {Migration của reverse-dep features tới alternative — separate integration nếu có}
|
|
435
|
+
- {Documentation site cleanup — manual task ngoài integration}
|
|
436
|
+
- {Grafana dashboard cleanup — manual task}
|
|
437
|
+
|
|
438
|
+
## Cascade Summary
|
|
439
|
+
|
|
440
|
+
| Artifact | Operation | Summary |
|
|
441
|
+
| --- | --- | --- |
|
|
442
|
+
| `prd.md` | update | F-XXX status → Removed; {N} components status → Removed |
|
|
443
|
+
| `feature/F-XXX-*/frd.md` | update | All items [REMOVE]; status → removed; folder move tại Finalize |
|
|
444
|
+
| `feature/F-XXX-*/fdd.md` | update | All items [REMOVE]; status → removed |
|
|
445
|
+
| `component/C-YYY-*/crd.md` | update | All [REMOVE] (exclusive) / {N} items [REMOVE] (shared) |
|
|
446
|
+
| `domain.md` | update | {N} glossary [REMOVE], {N} entity [REMOVE] |
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
### Bước 7: Review — xác nhận với user
|
|
452
|
+
|
|
453
|
+
Hiển thị toàn bộ draft. Hỏi:
|
|
454
|
+
|
|
455
|
+
```
|
|
456
|
+
Draft trên đã đúng chưa?
|
|
457
|
+
- Code Inventory đầy đủ và chính xác?
|
|
458
|
+
- Reverse-dep audit đã quyết định hết các ⚠?
|
|
459
|
+
- Removal Strategy phù hợp (single-shot vs phased)?
|
|
460
|
+
- Finalize Plan đủ steps?
|
|
461
|
+
- Changes blocks dùng [REMOVE] đúng chỗ (exclusive vs shared)?
|
|
462
|
+
|
|
463
|
+
Sau khi confirm, agent sẽ auto-apply Changes blocks lên main artifacts.
|
|
464
|
+
File feature artifacts (frd/fdd) KHÔNG bị move ngay — chỉ apply [REMOVE] markers
|
|
465
|
+
+ Change History entry. Move sang specs/removed/ là task cuối trong todo.md,
|
|
466
|
+
do /build chạy sau khi mọi deletion task khác xong.
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
Chỉ tiến hành Bước 8 sau khi user confirm.
|
|
470
|
+
|
|
471
|
+
---
|
|
472
|
+
|
|
473
|
+
### Bước 8: Save + Auto-cascade
|
|
474
|
+
|
|
475
|
+
Giống `/spec-new` Bước 7, nhưng với removal-specific extensions.
|
|
476
|
+
|
|
477
|
+
**[8.1] Ghi spec.md** với status `approved`, `removal: true` trong frontmatter. Frontmatter `features` chứa F-XXX, `components` chứa list components touched.
|
|
478
|
+
|
|
479
|
+
**[8.2] Auto-apply Changes blocks** vào main artifacts. Thứ tự: `prd.md` → `domain.md` → `sad.md` → `component/*/crd.md` → `component/*/cdd.md` → `feature/F-XXX-*/frd.md` → `feature/F-XXX-*/fdd.md`.
|
|
480
|
+
|
|
481
|
+
Áp dụng marker [REMOVE] theo conventions §5.5:
|
|
482
|
+
- Xoá item khỏi artifact, ID không tái sử dụng, không renumber.
|
|
483
|
+
- Khi toàn bộ items trong frd/fdd của F-XXX bị [REMOVE] → đổi frontmatter `status: removed`.
|
|
484
|
+
|
|
485
|
+
**[8.3] Append Change History entry** vào mọi artifact bị touched (conventions §5.5). Entry format chuẩn:
|
|
486
|
+
|
|
487
|
+
```markdown
|
|
488
|
+
### {YYYY-MM-DD} — [{NNN}-remove-{slug}](../../integrations/{NNN}-remove-{slug}/spec.md) — update
|
|
489
|
+
|
|
490
|
+
- **{Section name}**:
|
|
491
|
+
- [REMOVE] {ID/item} — feature decommissioned ({lý do ngắn})
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
**[8.4] Side-effects:**
|
|
495
|
+
|
|
496
|
+
- Trong prd.md: row F-XXX status đổi `Removed` ngay (không chờ finalize). Lý do: spec.md đã approved tức là quyết định removal đã được ký, status reflect quyết định ngay.
|
|
497
|
+
- ADO tickets KHÔNG transition ngay. Chỉ transition khi DEV chạy task Finalize ở `/build`. Lý do: tránh case rollback removal sau khi spec approve nhưng chưa deploy.
|
|
498
|
+
- File feature/F-XXX-*/ KHÔNG move ngay. Lý do giống ADO — chỉ move sau khi code thật đã xoá và verified.
|
|
499
|
+
|
|
500
|
+
**[8.5] Thông báo kết quả:**
|
|
501
|
+
|
|
502
|
+
```
|
|
503
|
+
✓ specs/integrations/{NNN}-remove-{f-xxx-slug}/spec.md đã được tạo (status: approved, removal: true)
|
|
504
|
+
|
|
505
|
+
Auto-cascade applied:
|
|
506
|
+
✓ prd.md — F-XXX status → Removed; {N} components status → Removed
|
|
507
|
+
✓ domain.md — {N} glossary/entity [REMOVE]
|
|
508
|
+
✓ component/C-YYY-*/crd.md — {summary}
|
|
509
|
+
✓ feature/F-XXX-*/frd.md — all items [REMOVE], status → removed
|
|
510
|
+
✓ feature/F-XXX-*/fdd.md — all items [REMOVE], status → removed
|
|
511
|
+
|
|
512
|
+
⚠ File feature/F-XXX-*/ vẫn ở specs/main/feature/. Sẽ được move sang specs/removed/ ở task cuối todo.md.
|
|
513
|
+
⚠ ADO tickets giữ nguyên state. Sẽ được close ở task cuối todo.md (cần .claude/ado.yaml).
|
|
514
|
+
|
|
515
|
+
Bước tiếp theo:
|
|
516
|
+
/spec-tech → thiết kế delete order, migration SQL, regression test cases
|
|
517
|
+
/plan → break down deletion tasks + finalize task cuối
|
|
518
|
+
/build → execute deletion + finalize
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
**Nếu apply fail** (markers reference ID không tồn tại, reverse-dep audit chưa hoàn tất, file không ghi được) → dừng, báo lỗi cụ thể, **không** ghi spec.md. Yêu cầu user fix draft.
|
|
522
|
+
|
|
523
|
+
---
|
|
524
|
+
|
|
525
|
+
## Downstream Integration (informational)
|
|
526
|
+
|
|
527
|
+
Skill này chỉ sinh `spec.md`. Để biết các skill sau xử lý removal flavor như nào:
|
|
528
|
+
|
|
529
|
+
- **`/spec-tech`** đọc `spec.md`, thấy `removal: true` + Code Inventory + Test Strategy + Finalize Plan → sinh `tech.md` với:
|
|
530
|
+
- Section "Delete Order" liệt kê file paths theo Code Inventory
|
|
531
|
+
- Section "Migration SQL" nếu có DB target (DROP + rollback)
|
|
532
|
+
- Section "Regression Tests" theo Test Strategy pattern
|
|
533
|
+
- Section "Finalize Task" passthrough nguyên xi từ spec.md Finalize Plan
|
|
534
|
+
|
|
535
|
+
- **`/plan`** đọc cả spec.md + tech.md → sinh `plan.md` + `todo.md`. Task cuối todo.md = Finalize task với 5 sub-actions như Finalize Plan của spec.md.
|
|
536
|
+
|
|
537
|
+
- **`/build`** chạy tuần tự todo.md. Khi tới Finalize task:
|
|
538
|
+
- Move folder bằng shell mv
|
|
539
|
+
- Edit prd.md
|
|
540
|
+
- Append Change History
|
|
541
|
+
- Gọi ADO API để transition tickets (cần `.claude/ado.yaml` configured)
|
|
542
|
+
- Verify outputs
|
|
543
|
+
|
|
544
|
+
Nếu `/spec-tech` hoặc `/plan` hiện tại chưa nhặt được removal flavor → có thể cần update sau (separate work). Trong v1, spec.md đủ rõ ràng để 2 skill đó produce reasonable output kể cả không có removal-awareness explicit.
|
|
545
|
+
|
|
546
|
+
---
|
|
547
|
+
|
|
548
|
+
## Common Rationalizations
|
|
549
|
+
|
|
550
|
+
| Rationalization | Reality |
|
|
551
|
+
| --- | --- |
|
|
552
|
+
| "Grep nhanh, không cần Code Inventory chi tiết" | Inventory sót item = code chết nằm trong repo vô thời hạn. Audit trail mất. |
|
|
553
|
+
| "Reverse-dep nhỏ thôi, xoá luôn rồi fix sau" | Một import dangling phá CI cả team. Audit trước rẻ hơn rollback. |
|
|
554
|
+
| "Feature flag off là xong, không cần xoá code" | Code dead vẫn phải maintain (security patch, dependency upgrade). Xoá hẳn mới sạch. |
|
|
555
|
+
| "Single-shot cho nhanh, soak period làm gì" | Có DB / external traffic mà single-shot = rollback đắt khi phát hiện consumer chưa migrate. |
|
|
556
|
+
| "Skip Finalize, để folder ở main feature là được" | Active dir bị noise. Sau 5 features removed, không phân biệt được active vs dead. |
|
|
557
|
+
|
|
558
|
+
## Red Flags
|
|
559
|
+
|
|
560
|
+
- Code Inventory empty hoặc chỉ có 1-2 file cho 1 feature đã ship → discovery chưa đủ rộng, xem lại sources
|
|
561
|
+
- Reverse-dep audit không có ⚠ nào cho component shared → grep chưa đủ kỹ
|
|
562
|
+
- Removal Strategy single-shot nhưng có DB schema lớn hoặc external traffic > 0 → cân nhắc Phased
|
|
563
|
+
- Test Strategy chỉ có "delete code" mà không có regression test → future re-add risk
|
|
564
|
+
- Finalize Plan thiếu ADO closure mà prd.md có ticket ID → audit trail không đầy đủ
|
|
565
|
+
- Changes block frd.md mark [REMOVE] nhưng không đổi `status: removed` trong frontmatter → inconsistent state
|
|
566
|
+
|
|
567
|
+
## Verification
|
|
568
|
+
|
|
569
|
+
Trước khi user confirm (Bước 7):
|
|
570
|
+
|
|
571
|
+
- [ ] Code Inventory liệt kê đủ 7 category (route / module / test / DB / flag / config / other)
|
|
572
|
+
- [ ] Mỗi item ⚠ trong Reverse-dep audit đã có quyết định rõ ràng (a/b/c)
|
|
573
|
+
- [ ] Nếu có item chọn `[b] Migrate first` → skill đã dừng, không tạo spec
|
|
574
|
+
- [ ] Removal Strategy match scale: single-shot cho nhỏ, phased cho lớn
|
|
575
|
+
- [ ] Test Strategy có 4 sub-step: baseline / delete / regression / full-suite
|
|
576
|
+
- [ ] Finalize Plan có 5 actions: move folder / change history / prd update / ADO close / verify
|
|
577
|
+
- [ ] Changes blocks: exclusive component → all [REMOVE]; shared component → chỉ items của F-XXX [REMOVE]
|
|
578
|
+
- [ ] frd.md / fdd.md frontmatter có [MODIFY status] → removed
|
|
579
|
+
|
|
580
|
+
Sau khi user confirm (Bước 8):
|
|
581
|
+
|
|
582
|
+
- [ ] spec.md frontmatter `removal: true`
|
|
583
|
+
- [ ] Auto-cascade chạy đúng thứ tự prd → domain → sad → crd → cdd → frd → fdd
|
|
584
|
+
- [ ] Mọi artifact bị touched có Change History entry
|
|
585
|
+
- [ ] prd.md row F-XXX status = Removed (đổi ngay sau approve)
|
|
586
|
+
- [ ] File feature/F-XXX-*/ VẪN ở specs/main/feature/ (chưa move — chỉ move ở Finalize task)
|
|
587
|
+
- [ ] ADO tickets KHÔNG bị transition (chưa close — chỉ close ở Finalize task)
|
|
588
|
+
- [ ] Notification cuối ghi rõ 2 ⚠ về việc folder + ADO chưa được động vào
|
package/skills-overview.md
CHANGED
|
@@ -8,8 +8,9 @@ Dùng khi bắt đầu dự án mới chưa có code. Mục tiêu: bootstrap `pr
|
|
|
8
8
|
|
|
9
9
|
| Command | Reads | Writes |
|
|
10
10
|
| --- | --- | --- |
|
|
11
|
-
| `/spec-prd` | — | `specs/main/prd.md`, `specs/main/domain.md` *(skeleton)* |
|
|
11
|
+
| `/spec-prd` | — *(tùy chọn: nguồn baseline path/@file/paste)* | `specs/main/prd.md`, `specs/main/domain.md` *(skeleton)* |
|
|
12
12
|
| `/spec-sad` | `prd.md`, `domain.md` | `specs/main/sad.md` |
|
|
13
|
+
| `/spec-frd [F-XXX]` *(tùy chọn)* | `prd.md`, `domain.md`, `sad.md`, `crd(s)` *(+ nguồn baseline)* | `specs/main/feature/{F-XXX}-*/frd.md` *(+ register feature row vào `prd.md` nếu feature mới)* |
|
|
13
14
|
|
|
14
15
|
### `/spec-prd`
|
|
15
16
|
|
|
@@ -48,12 +49,36 @@ Nếu `prd.md` chưa có → dừng, yêu cầu chạy `/spec-prd` trước.
|
|
|
48
49
|
|
|
49
50
|
---
|
|
50
51
|
|
|
52
|
+
### `/spec-frd [F-XXX]` *(tùy chọn)*
|
|
53
|
+
|
|
54
|
+
BA author `specs/main/feature/{F-XXX}-*/frd.md` trực tiếp qua interview — **spec-first ở feature level**, chạy *trước* khi DEV bắt đầu integration. Cặp greenfield đối xứng với `/spec-brownfield-feature` (vốn reverse-engineer frd từ code).
|
|
55
|
+
|
|
56
|
+
Nhận F-XXX từ argument (hoặc chọn từ prd Feature Index) + tùy chọn nguồn baseline (path/@file/paste như `/spec-prd`). Yêu cầu `prd.md` tồn tại.
|
|
57
|
+
|
|
58
|
+
**Hai gate input (làm chặt) — phải pass cả hai mới author:**
|
|
59
|
+
- **Single-feature**: nguồn liên quan **đúng 1 feature**. Xác định > 1 feature → **dừng + mô tả rõ lý do tách** (outcome/luồng/persona của từng cái) → redirect `/spec-prd` để khai Feature Index.
|
|
60
|
+
- **Create-only**: frd.md của feature mục tiêu **chưa tồn tại**. Đã tồn tại → **dừng, redirect `/spec-new`** (thay đổi feature đã spec phải đi qua integration để delta cascade + kéo theo `/spec-tech`/`/spec-test`).
|
|
61
|
+
- Feature mới **đơn lẻ** chưa có trong Index → offer **register một row vào `prd.md > Features`** rồi author.
|
|
62
|
+
|
|
63
|
+
**Sections template** (7): Overview · User Flows · Feature Acceptance Criteria · User Stories · Verification Rules · Scope · Dependencies
|
|
64
|
+
|
|
65
|
+
**Phạm vi hẹp — chủ yếu `frd.md`:**
|
|
66
|
+
- Reference component frd phụ thuộc (Components Used → C-XXX có sẵn).
|
|
67
|
+
- Component cần-nhưng-chưa-có → ghi *candidate* + Open Question cho `/spec-sad`/architect chốt boundary.
|
|
68
|
+
- Có thể register **một** feature row vào prd (side-effect hợp lệ duy nhất lên prd). **KHÔNG** tạo `crd.md`/`cdd.md` (sinh ở integration time qua `/spec-new` cascade), không tạo `fdd.md`/`tsd.md`, không đổi status feature đã có, không đụng sad/domain.
|
|
69
|
+
- Change History operation = `manual`. Verification Rules dùng quy ước option-suggester của `/spec-new` (BA owns).
|
|
70
|
+
|
|
71
|
+
Bỏ qua bước này cũng được — `/spec-new` sẽ tự tạo frd làm fallback khi integration đầu tiên chạm tới feature.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
51
75
|
### Thứ tự thực hiện
|
|
52
76
|
|
|
53
77
|
```
|
|
54
78
|
/spec-prd → /spec-sad
|
|
55
79
|
│
|
|
56
80
|
│ (có thể chạy /scaffold để khởi tạo project structure)
|
|
81
|
+
│ (tùy chọn /spec-frd [F-XXX] — BA author frd.md trước)
|
|
57
82
|
│
|
|
58
83
|
▼
|
|
59
84
|
→ Integration Pipeline
|
|
@@ -595,7 +620,7 @@ Cập nhật state đồng loạt cho User Story (và tuỳ chọn Feature) tick
|
|
|
595
620
|
## Ghi chú
|
|
596
621
|
|
|
597
622
|
- Cascade proposals trong `spec.md` và `tech.md` do human review và apply thủ công — không có skill riêng.
|
|
598
|
-
- **Greenfield**:
|
|
623
|
+
- **Greenfield**: Feature artifacts (`frd.md`) có thể author trước bằng `/spec-frd`, hoặc mọc dần qua cascade từ integrations (`/spec-new` fallback). Component artifacts (`crd.md`/`cdd.md`) chỉ mọc qua cascade — `/spec-frd` chỉ reference component, không tạo crd/cdd.
|
|
599
624
|
- **Brownfield**: Component và Feature artifacts được bootstrap bởi `spec-brownfield-component` và `spec-brownfield-feature` — sau đó tiếp tục mọc qua cascade như bình thường.
|
|
600
625
|
- Thứ tự trong một integration: `spec-new` → `spec-tech` → `plan` → `build`.
|
|
601
626
|
- `frontend-design` và `frontend-ui-engineering` được `build` invoke tự động — không cần gọi thủ công.
|
|
@@ -6,6 +6,7 @@ owner: "{BA}"
|
|
|
6
6
|
feature_id: "{Feature ID từ PRD Feature Index}"
|
|
7
7
|
referenced_by:
|
|
8
8
|
- conventions.md > 3. Main Artifacts > 3.3 Feature level > frd.md > Cấu trúc
|
|
9
|
+
- skills/spec-frd/SKILL.md > Process > Bước 5: Write — sinh draft
|
|
9
10
|
- skills/spec-new/SKILL.md > Process > Bước 5: Write — sinh draft > feature/{F-XXX}/frd.md
|
|
10
11
|
- templates/integrations/spec-template.md > Changes > feature/{F-XXX}/frd.md
|
|
11
12
|
---
|
|
@@ -35,13 +35,28 @@ Tại sao cần giải quyết bây giờ.
|
|
|
35
35
|
|
|
36
36
|
## Features
|
|
37
37
|
|
|
38
|
+
Đặt tên feature theo **outcome của một luồng hoàn chỉnh**, kebab-case, đủ khái quát mà vẫn là *một* luồng — không quá rộng (`user-management` là feature area), không quá hẹp (`register-with-google` chỉ là biến thể). ✅ `user-registration`, `password-reset`, `checkout`.
|
|
39
|
+
|
|
38
40
|
| ID | Feature | Mô tả | Priority | Status |
|
|
39
41
|
| --- | --- | --- | --- | --- |
|
|
40
42
|
| F-001 | {tên feature} | {mô tả ngắn — feature làm gì, cho ai} | High/Medium/Low | TODO/DONE |
|
|
41
43
|
|
|
42
44
|
## Components
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
Một component = một khối có **boundary rõ + interface tường minh** và **một lý do duy nhất để thay đổi**. Không phân loại component thành "domain" hay "kỹ thuật" — mỗi component đều có mặt domain (`crd.md`) lẫn mặt kỹ thuật (`cdd.md`).
|
|
47
|
+
|
|
48
|
+
Đặt tên component theo **năng lực bền vững**, không theo công nghệ hiện tại, kebab-case. ✅ `notification`, `auth`, `file-storage`. ❌ quá cụ thể (`email-sender`, `stripe-client`) hoặc quá mơ hồ (`core`, `utils`, `manager`).
|
|
49
|
+
|
|
50
|
+
Section này **chỉ liệt kê component có boundary _Given_** — tức boundary bị ép từ ngoài, chỉ có một cách vẽ hợp lý. Áp thủ tục:
|
|
51
|
+
- **Câu 1 (External):** bọc/adapt hệ thống ngoài ta buộc phải tích hợp? (vd `payment-gateway` tích hợp Stripe, `email-service` tích hợp SendGrid) → Given, khai ở đây.
|
|
52
|
+
- **Câu 2 (Mandated-substrate):** nền tảng kỹ thuật dùng chung mà yêu cầu bắt buộc, độc lập với cách carve lõi nghiệp vụ? (vd `auth`, `file-storage`, `notification`) → Given, khai ở đây.
|
|
53
|
+
- **Còn lại (Derived):** boundary phụ thuộc cách carve lõi nghiệp vụ hoặc đánh đổi NFR (vd `order`, `pricing`, `inventory`) → **KHÔNG** khai ở đây.
|
|
54
|
+
|
|
55
|
+
**Component Derived mọc dần qua:**
|
|
56
|
+
- `/spec-sad` — architect lock component boundaries dựa trên full feature index + NFRs
|
|
57
|
+
- `/spec-new F-XXX` cascade — khi analyze 1 feature, discover component mới nếu cần và register vào đây qua Change History
|
|
58
|
+
|
|
59
|
+
Chi tiết về vai trò và thiết kế nằm trong `specs/main/component/{C-XXX}-{component-name}/`.
|
|
45
60
|
|
|
46
61
|
| ID | Component | Mô tả ngắn | Status |
|
|
47
62
|
| --- | --- | --- | --- |
|