@edupia-tutor/spec-driven-docs 0.14.1 → 0.14.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/bin/index.js +12 -1
- package/commands/debug.md +5 -5
- package/commands/define-product.md +38 -36
- package/commands/define-product.tmpl +33 -31
- package/commands/dev-gen-test.md +5 -5
- package/commands/dev-run-test.md +5 -5
- package/commands/dev-smoke-test.md +5 -5
- package/commands/fix-bug.md +5 -5
- package/commands/generate-bdd.md +5 -5
- package/commands/generate-code.md +5 -5
- package/commands/generate-design-spec.md +7 -7
- package/commands/generate-design-spec.tmpl +2 -2
- package/commands/generate-prd.md +19 -16
- package/commands/generate-prd.tmpl +10 -7
- package/commands/generate-spec-manifest.md +7 -7
- package/commands/generate-spec-manifest.tmpl +2 -2
- package/commands/generate-tech-docs.md +5 -5
- package/commands/learn.md +5 -5
- package/commands/map-testids.md +5 -5
- package/commands/propose-scenario.md +5 -5
- package/commands/qc-analyze.md +6 -6
- package/commands/qc-analyze.tmpl +1 -1
- package/commands/qc-design-test.md +5 -5
- package/commands/qc-plan.md +5 -5
- package/commands/qc-report.md +5 -5
- package/commands/qc-review.md +5 -5
- package/commands/qc-run-test.md +5 -5
- package/commands/refine-prd.md +8 -8
- package/commands/refine-prd.tmpl +3 -3
- package/commands/report-bug.md +5 -5
- package/commands/review-code.md +5 -5
- package/commands/review-context.md +9 -9
- package/commands/review-context.tmpl +4 -4
- package/commands/review-tech-docs.md +5 -5
- package/commands/setup-ai-first.md +5 -5
- package/commands/setup-ai-first.tmpl +3 -3
- package/commands/sync.md +1 -1
- package/commands/sync.tmpl +1 -1
- package/commands/validate-traces.md +7 -7
- package/commands/validate-traces.tmpl +2 -2
- package/core/FRAMEWORK_VERSION +1 -1
- package/core/commands/debug.md +5 -5
- package/core/commands/define-product.md +38 -36
- package/core/commands/dev-gen-test.md +5 -5
- package/core/commands/dev-run-test.md +5 -5
- package/core/commands/dev-smoke-test.md +5 -5
- package/core/commands/fix-bug.md +5 -5
- package/core/commands/generate-bdd.md +5 -5
- package/core/commands/generate-code.md +5 -5
- package/core/commands/generate-design-spec.md +7 -7
- package/core/commands/generate-prd.md +19 -16
- package/core/commands/generate-spec-manifest.md +7 -7
- package/core/commands/generate-tech-docs.md +5 -5
- package/core/commands/learn.md +5 -5
- package/core/commands/map-testids.md +5 -5
- package/core/commands/propose-scenario.md +5 -5
- package/core/commands/qc-analyze.md +6 -6
- package/core/commands/qc-design-test.md +5 -5
- package/core/commands/qc-plan.md +5 -5
- package/core/commands/qc-report.md +5 -5
- package/core/commands/qc-review.md +5 -5
- package/core/commands/qc-run-test.md +5 -5
- package/core/commands/refine-prd.md +8 -8
- package/core/commands/report-bug.md +5 -5
- package/core/commands/review-code.md +5 -5
- package/core/commands/review-context.md +9 -9
- package/core/commands/review-tech-docs.md +5 -5
- package/core/commands/setup-ai-first.md +5 -5
- package/core/commands/sync.md +1 -1
- package/core/commands/validate-traces.md +7 -7
- package/core/skills/code/SKILL.md +5 -5
- package/core/skills/debug/SKILL.md +3 -3
- package/core/skills/design-spec/SKILL.md +6 -6
- package/core/skills/prd/SKILL.md +8 -8
- package/core/skills/setup-ai-first/SKILL.md +1 -1
- package/core/skills/spec/SKILL.md +4 -4
- package/core/skills/test/SKILL.md +8 -8
- package/core/steps/context-loader.md +3 -3
- package/core/steps/gate.md +2 -2
- package/core/templates/prd.template.md +4 -4
- package/core/templates/project-context.yaml +2 -2
- package/docs/01-getting-started/core-concepts.md +1 -1
- package/docs/01-getting-started/quickstart.md +7 -7
- package/docs/02-guides/developer/bdd-and-trace.md +1 -1
- package/docs/02-guides/developer/scenarios.md +5 -5
- package/docs/02-guides/product-owner/handoff-checklist.md +1 -1
- package/docs/02-guides/product-owner/scenarios.md +23 -23
- package/docs/02-guides/tester/bug-reporting.md +2 -2
- package/docs/02-guides/tester/reading-specs.md +2 -2
- package/docs/02-guides/tester/scenarios.md +1 -1
- package/docs/02-guides/tester/spec-manifest.md +3 -3
- package/docs/02-guides/tester/workflow.md +1 -1
- package/docs/03-concepts/architecture.md +3 -3
- package/docs/03-concepts/pipeline.md +3 -3
- package/docs/04-operations/sync-and-update.md +5 -5
- package/docs/05-reference/command-cheatsheet.md +2 -2
- package/docs/05-reference/commands.md +8 -8
- package/package.json +1 -1
- package/scripts/migrate-specs.js +5 -3
- package/scripts/rename-prd-files.js +174 -0
- package/skills/code/SKILL.md +5 -5
- package/skills/debug/SKILL.md +3 -3
- package/skills/design-spec/SKILL.md +6 -6
- package/skills/design-spec/SKILL.tmpl +1 -1
- package/skills/prd/SKILL.md +8 -8
- package/skills/prd/SKILL.tmpl +2 -2
- package/skills/setup-ai-first/SKILL.md +1 -1
- package/skills/setup-ai-first/SKILL.tmpl +1 -1
- package/skills/spec/SKILL.md +4 -4
- package/skills/spec/SKILL.tmpl +2 -2
- package/skills/test/SKILL.md +8 -8
- package/steps/context-loader.md +3 -3
- package/steps/gate.md +2 -2
- package/templates/prd.template.md +4 -4
- package/templates/project-context.yaml +2 -2
|
@@ -20,11 +20,11 @@ Output: `specs/product-definition/FEAT-01-login.md`
|
|
|
20
20
|
```
|
|
21
21
|
Agent tự động: đọc product definition · expand thành PRD đầy đủ với UC, AC, BR · nhắc nếu bạn viết UI details · kiểm tra terminology với business-dictionary.
|
|
22
22
|
|
|
23
|
-
Output: `specs/auth/FEAT-01-login/
|
|
23
|
+
Output: `specs/auth/FEAT-01-login/FEAT-01-login.md`
|
|
24
24
|
|
|
25
25
|
**Bước 3 — Review nội dung:**
|
|
26
26
|
```
|
|
27
|
-
/refine-prd specs/auth/FEAT-01-login/
|
|
27
|
+
/refine-prd specs/auth/FEAT-01-login/FEAT-01-login.md
|
|
28
28
|
```
|
|
29
29
|
Agent fan-out 4 lens (QA/DEV/SA/PO) chạy song song, rồi chạy completeness-critic loop cho đến khi một vòng không tìm ra finding mới, cuối cùng dedup + resolve conflict. Findings đầy đủ trong 1 lần chạy.
|
|
30
30
|
|
|
@@ -33,12 +33,12 @@ Mở findings file, xem xét từng finding: `accepted` → apply · `modified`
|
|
|
33
33
|
> **Finding khó hiểu? Bấm 💬 Giải thích.** Nếu một finding mô tả nặng tính kỹ thuật, dùng nút **💬 Giải thích** trên Review Board (extension Spec Driven Docs Tools). Claude sẽ giải thích lại bằng ngôn ngữ no-tech + đề xuất phương án cụ thể (cover cả edge case) ngay trong terminal, và **chờ bạn confirm trước khi apply** vào PRD — tránh refine nhiều vòng. Prompt sửa được qua setting `reviewBoard.clarifyPrompt` (không cần cài lại extension).
|
|
34
34
|
|
|
35
35
|
```
|
|
36
|
-
/review-context --resume specs/auth/FEAT-01-login/
|
|
36
|
+
/review-context --resume specs/auth/FEAT-01-login/FEAT-01-login.md
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
**Bước 4 — Final check:**
|
|
40
40
|
```
|
|
41
|
-
/review-context specs/auth/FEAT-01-login/
|
|
41
|
+
/review-context specs/auth/FEAT-01-login/FEAT-01-login.md
|
|
42
42
|
```
|
|
43
43
|
Kiểm tra: `@trace.status`, `@trace.domain`, completeness.
|
|
44
44
|
|
|
@@ -51,7 +51,7 @@ Kiểm tra: `@trace.status`, `@trace.domain`, completeness.
|
|
|
51
51
|
|
|
52
52
|
**Bước 6 — Tạo Design Spec (FE/App):**
|
|
53
53
|
```
|
|
54
|
-
/generate-design-spec specs/auth/FEAT-01-login/
|
|
54
|
+
/generate-design-spec specs/auth/FEAT-01-login/FEAT-01-login.md
|
|
55
55
|
```
|
|
56
56
|
Agent hỏi platform (web / app). PO phải cung cấp **Figma link node-level** (URL chứa `?node-id=`, lấy bằng right-click vào frame → "Copy link to selection") cho **mỗi screen**. Screen nào thiếu link → bị flag ❌ Missing, Status giữ `draft`, `/generate-bdd` bị BLOCKED cho đến khi đủ link.
|
|
57
57
|
|
|
@@ -59,7 +59,7 @@ Sau khi Designer review + confirm đủ Figma node-id links → `@trace.status:
|
|
|
59
59
|
|
|
60
60
|
**Bước 7 — Generate BDD:**
|
|
61
61
|
```
|
|
62
|
-
/generate-bdd specs/auth/FEAT-01-login/
|
|
62
|
+
/generate-bdd specs/auth/FEAT-01-login/FEAT-01-login.md
|
|
63
63
|
```
|
|
64
64
|
Agent hỏi: **"Platform? (1) web (2) app (3) system"**
|
|
65
65
|
- Chọn `web` → `specs/auth/FEAT-01-login/bdd/web/FEAT-01-UC1-login-web.feature`
|
|
@@ -111,7 +111,7 @@ git push
|
|
|
111
111
|
|
|
112
112
|
**Bước 1 — Design Spec:**
|
|
113
113
|
```
|
|
114
|
-
/generate-design-spec specs/auth/FEAT-01-login/
|
|
114
|
+
/generate-design-spec specs/auth/FEAT-01-login/FEAT-01-login.md
|
|
115
115
|
```
|
|
116
116
|
Output: `specs/auth/FEAT-01-login/design-spec/FEAT-01-design-spec-web.md`
|
|
117
117
|
|
|
@@ -119,7 +119,7 @@ Mỗi screen cần Figma link node-id. Screen thiếu → flag ❌ Missing, BLOC
|
|
|
119
119
|
|
|
120
120
|
**Bước 2 — Generate BDD:**
|
|
121
121
|
```
|
|
122
|
-
/generate-bdd specs/auth/FEAT-01-login/
|
|
122
|
+
/generate-bdd specs/auth/FEAT-01-login/FEAT-01-login.md
|
|
123
123
|
```
|
|
124
124
|
|
|
125
125
|
| Lần | Platform | Output |
|
|
@@ -147,12 +147,12 @@ cat .agent/review/FEAT-01-login-prd-review-context-findings.yaml
|
|
|
147
147
|
|
|
148
148
|
**Bước 3 — Apply:**
|
|
149
149
|
```
|
|
150
|
-
/review-context --resume specs/auth/FEAT-01-login/
|
|
150
|
+
/review-context --resume specs/auth/FEAT-01-login/FEAT-01-login.md
|
|
151
151
|
```
|
|
152
152
|
|
|
153
153
|
**Bước 4 — Re-review:**
|
|
154
154
|
```
|
|
155
|
-
/review-context specs/auth/FEAT-01-login/
|
|
155
|
+
/review-context specs/auth/FEAT-01-login/FEAT-01-login.md
|
|
156
156
|
```
|
|
157
157
|
Lặp lại cho đến khi `recommendation: APPROVED`.
|
|
158
158
|
|
|
@@ -167,12 +167,12 @@ Lặp lại cho đến khi `recommendation: APPROVED`.
|
|
|
167
167
|
|
|
168
168
|
**Bước 2 — Sửa nội dung:**
|
|
169
169
|
```
|
|
170
|
-
/refine-prd specs/auth/FEAT-01-login/
|
|
170
|
+
/refine-prd specs/auth/FEAT-01-login/FEAT-01-login.md "Thêm yêu cầu: hỗ trợ đăng nhập bằng OTP"
|
|
171
171
|
```
|
|
172
172
|
|
|
173
173
|
**Bước 3 — Review lại:**
|
|
174
174
|
```
|
|
175
|
-
/review-context specs/auth/FEAT-01-login/
|
|
175
|
+
/review-context specs/auth/FEAT-01-login/FEAT-01-login.md
|
|
176
176
|
/review-context --resume (nếu cần fix)
|
|
177
177
|
```
|
|
178
178
|
|
|
@@ -183,7 +183,7 @@ Lặp lại cho đến khi `recommendation: APPROVED`.
|
|
|
183
183
|
# major bump (2.0) nếu thay đổi cơ bản
|
|
184
184
|
```
|
|
185
185
|
```bash
|
|
186
|
-
git add specs/auth/FEAT-01-login/
|
|
186
|
+
git add specs/auth/FEAT-01-login/FEAT-01-login.md
|
|
187
187
|
git commit -m "feat(auth): update FEAT-01 PRD v1.1 — add OTP login AC"
|
|
188
188
|
git push
|
|
189
189
|
```
|
|
@@ -239,7 +239,7 @@ services:
|
|
|
239
239
|
2. Quyết định PRD nào đúng.
|
|
240
240
|
3. Sửa file:
|
|
241
241
|
```
|
|
242
|
-
/review-context --resume specs/auth/FEAT-01-login/
|
|
242
|
+
/review-context --resume specs/auth/FEAT-01-login/FEAT-01-login.md
|
|
243
243
|
# với finding P3: modified: "session timeout cập nhật thành 2 giờ theo FEAT-05"
|
|
244
244
|
```
|
|
245
245
|
4. Cả 2 PRD phải nhất quán trước khi dev team generate BDD.
|
|
@@ -268,20 +268,20 @@ git push
|
|
|
268
268
|
```
|
|
269
269
|
specs/
|
|
270
270
|
├── auth/
|
|
271
|
-
│ ├── FEAT-01-login/
|
|
272
|
-
│ └── FEAT-08-sso/
|
|
271
|
+
│ ├── FEAT-01-login/FEAT-01-login.md (approved)
|
|
272
|
+
│ └── FEAT-08-sso/FEAT-08-sso.md (draft)
|
|
273
273
|
├── payment/
|
|
274
|
-
│ ├── FEAT-03-checkout/
|
|
275
|
-
│ └── FEAT-11-refund/
|
|
274
|
+
│ ├── FEAT-03-checkout/FEAT-03-checkout.md (approved)
|
|
275
|
+
│ └── FEAT-11-refund/FEAT-11-refund.md (draft)
|
|
276
276
|
└── loyalty/
|
|
277
|
-
└── FEAT-06-points/
|
|
277
|
+
└── FEAT-06-points/FEAT-06-points.md (in-review)
|
|
278
278
|
```
|
|
279
279
|
|
|
280
280
|
**Gợi ý:** Hoàn thiện 1 PRD đến `approved` trước khi bắt đầu PRD tiếp theo. Chỉ PRD `approved` mới được dev team sử dụng.
|
|
281
281
|
|
|
282
282
|
```bash
|
|
283
283
|
# Xem nhanh tất cả PRDs và status:
|
|
284
|
-
grep -r "@trace.status" specs/ --include="
|
|
284
|
+
grep -r "@trace.status" specs/ --include="*.md"
|
|
285
285
|
```
|
|
286
286
|
|
|
287
287
|
---
|
|
@@ -297,7 +297,7 @@ grep -r "@trace.status" specs/ --include="prd.md"
|
|
|
297
297
|
```
|
|
298
298
|
|
|
299
299
|
```
|
|
300
|
-
/review-context specs/auth/FEAT-01-login/
|
|
300
|
+
/review-context specs/auth/FEAT-01-login/FEAT-01-login.md
|
|
301
301
|
→ Phải thấy recommendation: APPROVED và 0 critical findings
|
|
302
302
|
```
|
|
303
303
|
|
|
@@ -306,13 +306,13 @@ grep -r "@trace.status" specs/ --include="prd.md"
|
|
|
306
306
|
[FEAT-01] PRD Login đã approved — sẵn sàng implement
|
|
307
307
|
|
|
308
308
|
Domain: auth
|
|
309
|
-
File: my-project-specs/specs/auth/FEAT-01-login/
|
|
309
|
+
File: my-project-specs/specs/auth/FEAT-01-login/FEAT-01-login.md
|
|
310
310
|
Version: 1.0
|
|
311
311
|
Design Spec (Web): my-project-specs/specs/auth/FEAT-01-login/design-spec/FEAT-01-design-spec-web.md
|
|
312
312
|
|
|
313
313
|
Lệnh để bắt đầu:
|
|
314
314
|
git submodule update --remote my-project-specs
|
|
315
|
-
/review-context my-project-specs/specs/auth/FEAT-01-login/
|
|
315
|
+
/review-context my-project-specs/specs/auth/FEAT-01-login/FEAT-01-login.md
|
|
316
316
|
```
|
|
317
317
|
|
|
318
318
|
---
|
|
@@ -45,7 +45,7 @@ Service : BE / Web / App
|
|
|
45
45
|
Severity : Critical / Major / Minor
|
|
46
46
|
|
|
47
47
|
Spec context:
|
|
48
|
-
PRD : specs/{domain}/{prd-slug}/prd.md (v{x.x})
|
|
48
|
+
PRD : specs/{domain}/{prd-slug}/{TICKET-ID}-{prd-slug}.md (v{x.x})
|
|
49
49
|
BDD : {bdd path} → Scenario: "{scenario title}"
|
|
50
50
|
Tech Doc : {tech_docs path}
|
|
51
51
|
|
|
@@ -77,7 +77,7 @@ Service : BE
|
|
|
77
77
|
Severity : Major
|
|
78
78
|
|
|
79
79
|
Spec context:
|
|
80
|
-
PRD : specs/auth/FT-001-login/
|
|
80
|
+
PRD : specs/auth/FT-001-login/FT-001-login.md (v1.0)
|
|
81
81
|
BDD : free-trial-specs/specs/auth/FT-001-login/bdd/system/FT-001-login.feature
|
|
82
82
|
→ Scenario: "Lock account after 5 failed attempts"
|
|
83
83
|
Tech Doc : free-trial-specs/specs/auth/FT-001-login/tech-docs/FT-001-auth-api.md
|
|
@@ -18,7 +18,7 @@ Sau khi chạy `/generate-spec-manifest`, tra manifest để lấy paths:
|
|
|
18
18
|
```yaml
|
|
19
19
|
# spec-manifest.yaml
|
|
20
20
|
FT-001:
|
|
21
|
-
prd: "my-project-specs/specs/auth/FT-001-login/
|
|
21
|
+
prd: "my-project-specs/specs/auth/FT-001-login/FT-001-login.md"
|
|
22
22
|
bdd:
|
|
23
23
|
be: "my-project-specs/specs/auth/FT-001-login/bdd/system/FT-001-UC1-login-system.feature"
|
|
24
24
|
web: "my-project-specs/specs/auth/FT-001-login/bdd/web/FT-001-UC1-login-web.feature"
|
|
@@ -26,7 +26,7 @@ FT-001:
|
|
|
26
26
|
be: "my-project-specs/specs/auth/FT-001-login/tech-docs/FT-001-auth-api.md"
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
**Bước 1: Đọc PRD** tại `my-project-specs/specs/auth/FT-001-login/
|
|
29
|
+
**Bước 1: Đọc PRD** tại `my-project-specs/specs/auth/FT-001-login/FT-001-login.md`
|
|
30
30
|
*(nằm trong spec submodule — shared repo của PO)*
|
|
31
31
|
|
|
32
32
|
```markdown
|
|
@@ -16,7 +16,7 @@ git pull && git submodule update --remote --recursive
|
|
|
16
16
|
# 3. Kiểm tra status
|
|
17
17
|
# FT-042:
|
|
18
18
|
# status: approved ← ✅ có thể test
|
|
19
|
-
# prd: "specs/payment/FT-042-checkout/
|
|
19
|
+
# prd: "specs/payment/FT-042-checkout/FT-042-checkout.md"
|
|
20
20
|
# bdd:
|
|
21
21
|
# be: "free-trial-specs/specs/payment/FT-042-checkout/bdd/system/FT-042-UC1-checkout-system.feature"
|
|
22
22
|
# web: "free-trial-specs/specs/payment/FT-042-checkout/bdd/web/FT-042-UC1-checkout-web.feature"
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
## Spec-Manifest Là Gì Và Tại Sao Cần
|
|
6
6
|
|
|
7
|
-
Trong umbrella repo (có `spec_source`), **mọi spec đều nằm trong spec submodule** — gom theo feature-package: mỗi PRD có một thư mục `specs/{domain}/{prd-slug}/` chứa tất cả artifact (`prd.md`, `bdd/{platform}/`, `tech-docs/`, `design-spec/`), trải trên nhiều domain:
|
|
7
|
+
Trong umbrella repo (có `spec_source`), **mọi spec đều nằm trong spec submodule** — gom theo feature-package: mỗi PRD có một thư mục `specs/{domain}/{prd-slug}/` chứa tất cả artifact (`{TICKET-ID}-{prd-slug}.md`, `bdd/{platform}/`, `tech-docs/`, `design-spec/`), trải trên nhiều domain:
|
|
8
8
|
|
|
9
9
|
```
|
|
10
10
|
free-trial-umbrella/ ← umbrella (Claude Code mở ở đây)
|
|
11
11
|
├── free-trial-specs/ ← SPEC submodule — TẤT CẢ spec ở đây
|
|
12
12
|
│ └── specs/
|
|
13
13
|
│ └── auth/FT-001-login/ ← feature-package (1 PRD = 1 thư mục)
|
|
14
|
-
│ ├── prd.md ← PRD
|
|
14
|
+
│ ├── {TICKET-ID}-{prd-slug}.md ← PRD
|
|
15
15
|
│ ├── design-spec/... ← Design Spec
|
|
16
16
|
│ ├── bdd/system/... ← BDD System (BE)
|
|
17
17
|
│ ├── bdd/web/... ← BDD Web (FE)
|
|
@@ -30,7 +30,7 @@ features:
|
|
|
30
30
|
FT-001:
|
|
31
31
|
domain: auth
|
|
32
32
|
status: approved
|
|
33
|
-
prd: "specs/auth/FT-001-login/
|
|
33
|
+
prd: "specs/auth/FT-001-login/FT-001-login.md"
|
|
34
34
|
pdd: "specs/product-definition/auth/FT-001-def.md"
|
|
35
35
|
tech_docs:
|
|
36
36
|
be: "free-trial-specs/specs/auth/FT-001-login/tech-docs/FT-001-UC1-auth-api.md"
|
|
@@ -16,7 +16,7 @@ git pull && git submodule update --remote --recursive
|
|
|
16
16
|
Lookup FT-042 trong spec-manifest.yaml
|
|
17
17
|
→ status: approved? ✅ (nếu draft → dừng, báo PO)
|
|
18
18
|
→ ghi lại paths (tất cả đều nằm trong submodule):
|
|
19
|
-
prd: {spec_source}/specs/{domain}/{prd-slug}/prd.md
|
|
19
|
+
prd: {spec_source}/specs/{domain}/{prd-slug}/{TICKET-ID}-{prd-slug}.md
|
|
20
20
|
bdd.system: {spec_source}/specs/{domain}/{prd-slug}/bdd/system/FT-042-*.feature
|
|
21
21
|
bdd.web: {spec_source}/specs/{domain}/{prd-slug}/bdd/web/FT-042-*.feature
|
|
22
22
|
tech_docs.be: {spec_source}/specs/{domain}/{prd-slug}/tech-docs/FT-042-*.md
|
|
@@ -58,7 +58,7 @@ LAYER 5 — OUTPUT (artifacts in consumer proj)
|
|
|
58
58
|
Spec module (cross-team, via {spec_source}):
|
|
59
59
|
specs/product-definition/
|
|
60
60
|
specs/{domain}/{prd-slug}/ — feature package gom mọi artifact của một PRD:
|
|
61
|
-
prd.md · bdd/ (web/app/system) · tech-docs/ (API contract + FE tech-design) · design-spec/
|
|
61
|
+
{TICKET-ID}-{prd-slug}.md · bdd/ (web/app/system) · tech-docs/ (API contract + FE tech-design) · design-spec/
|
|
62
62
|
feedback/
|
|
63
63
|
.trace/{domain}/{prd-slug}/*.tsv (authoritative, committed — một chỗ cho PM) · .living-docs/ (gitignored)
|
|
64
64
|
Service submodule (per-service):
|
|
@@ -76,10 +76,10 @@ LAYER 5 — OUTPUT (artifacts in consumer proj)
|
|
|
76
76
|
|
|
77
77
|
## Data flow — một command chạy như thế nào
|
|
78
78
|
|
|
79
|
-
Ví dụ `/generate-bdd specs/payment/process-payment/
|
|
79
|
+
Ví dụ `/generate-bdd specs/payment/process-payment/{TICKET-ID}-process-payment.md`:
|
|
80
80
|
|
|
81
81
|
```
|
|
82
|
-
User types: /generate-bdd specs/payment/process-payment/
|
|
82
|
+
User types: /generate-bdd specs/payment/process-payment/{TICKET-ID}-process-payment.md
|
|
83
83
|
│
|
|
84
84
|
[L0] data-guard.js check tool calls real-time → đọc .env/*.key → BLOCK + warn
|
|
85
85
|
│
|
|
@@ -24,7 +24,7 @@ Vòng đời feature đi qua các phase, mỗi transition có một **AI review
|
|
|
24
24
|
|-------|-----|----------|--------|
|
|
25
25
|
| **0. Setup** *(one-time)* | Tech Lead | `/setup-ai-first`, `/sync`, `/sync-figma-*` | Config files, submodules, component catalog |
|
|
26
26
|
| **1. Discovery** | PO + AI | `/define-product` | `specs/product-definition/{TICKET-ID}-{slug}.md` |
|
|
27
|
-
| **2. PRD** | AI → SA/PO review | `/generate-prd`, `/refine-prd`, `/review-context` | `specs/{domain}/{prd-slug}/prd.md` |
|
|
27
|
+
| **2. PRD** | AI → SA/PO review | `/generate-prd`, `/refine-prd`, `/review-context` | `specs/{domain}/{prd-slug}/{TICKET-ID}-{prd-slug}.md` |
|
|
28
28
|
| **2b. Design Spec** *(FE/App only)* | AI → Designer/PO sign-off | `/generate-design-spec` | `specs/{domain}/{prd-slug}/design-spec/{TICKET-ID}-design-spec-{platform}.md` |
|
|
29
29
|
| **3. BDD Spec** | AI → SA/Dev review | `/generate-bdd`, `/review-context` | `specs/{domain}/{prd-slug}/bdd/{UC-ID}.feature` |
|
|
30
30
|
| **4. Tech Design** *(platform-aware)* | AI → SA/Lead review | `/generate-tech-docs`, `/review-tech-docs` | BE: `specs/{domain}/{prd-slug}/tech-docs/{UC-ID}-tech-design.md` (API contract) · FE/App: `{UC-ID}-tech-design-{platform}.md` (client design — **gated** trên System BDD + BE contract) |
|
|
@@ -48,7 +48,7 @@ Phase 1: Discovery
|
|
|
48
48
|
business rules → business logic → AC → validation matrix)
|
|
49
49
|
|
|
50
50
|
Phase 2: PRD
|
|
51
|
-
/generate-prd ────────────→ specs/{domain}/{prd-slug}/prd.md
|
|
51
|
+
/generate-prd ────────────→ specs/{domain}/{prd-slug}/{TICKET-ID}-{prd-slug}.md
|
|
52
52
|
/refine-prd ──────────────→ .agent/review/{prd-slug}-findings.yaml
|
|
53
53
|
[Review Board: Accept/Modify/Reject]
|
|
54
54
|
/refine-prd --resume → apply + bump version
|
|
@@ -180,7 +180,7 @@ Mọi command bắt đầu ở đây, theo thứ tự:
|
|
|
180
180
|
```
|
|
181
181
|
CHECKPOINT
|
|
182
182
|
-----------
|
|
183
|
-
Target : specs/auth/FEAT-042-login/
|
|
183
|
+
Target : specs/auth/FEAT-042-login/FEAT-042-login.md
|
|
184
184
|
Project : My App
|
|
185
185
|
Tech stack : TypeScript / React 18
|
|
186
186
|
Module : react
|
|
@@ -100,7 +100,7 @@ npx @edupia-tutor/spec-driven-docs --migrate-specs --apply
|
|
|
100
100
|
```
|
|
101
101
|
|
|
102
102
|
Lệnh sẽ:
|
|
103
|
-
- Di chuyển `specs/prd/{domain}/{slug}.md` → `specs/{domain}/{slug}/
|
|
103
|
+
- Di chuyển `specs/prd/{domain}/{slug}.md` → `specs/{domain}/{slug}/{TICKET-ID}-{slug}.md`, và `specs/bdd|tech-docs|design-spec/{domain}/…` → `specs/{domain}/{prd-slug}/{bdd|tech-docs|design-spec}/…`; flat `.trace/{UC-ID}.tsv` → `.trace/{domain}/{prd-slug}/{UC-ID}.tsv`.
|
|
104
104
|
- Suy ra `{prd-slug}` cho mỗi file BDD/tech-doc/design-spec/trace bằng cách đọc header `@trace.source` (PRD nguồn) hoặc tag `@trace.uc` (map qua index `.feature`).
|
|
105
105
|
- Dùng `git mv` cho file đã track (giữ history), `fs.rename` cho phần còn lại.
|
|
106
106
|
- Rewrite các tham chiếu nội bộ (`@trace.source`, đường dẫn `specs/…`) trong những file vừa move.
|
|
@@ -130,7 +130,7 @@ Claude Code luôn mở ở **umbrella repo** (không mở trong service submodul
|
|
|
130
130
|
SPEC SUBMODULE SERVICE SUBMODULE(s)
|
|
131
131
|
(PO sở hữu · origin riêng) (Dev sở hữu · origin riêng)
|
|
132
132
|
specs/{domain}/{prd-slug}/ src/ (chỉ code + tooling)
|
|
133
|
-
prd.md · bdd/ (web/app/system)
|
|
133
|
+
{TICKET-ID}-{prd-slug}.md · bdd/ (web/app/system)
|
|
134
134
|
design-spec/ · tech-docs/
|
|
135
135
|
feedback/ (bug · proposal · prd-change)
|
|
136
136
|
.trace/{domain}/{prd-slug}/*.tsv (qc_status + dev_selftest — write area của dev/QC)
|
|
@@ -257,7 +257,7 @@ Topology giả định cho mọi ví dụ dưới đây:
|
|
|
257
257
|
```bash
|
|
258
258
|
cd my-project-specs && git pull
|
|
259
259
|
# /generate-prd · /generate-design-spec · /generate-bdd (web/app/system) · set @trace.status: approved
|
|
260
|
-
git add specs/payment/checkout/
|
|
260
|
+
git add specs/payment/checkout/{TICKET-ID}-checkout.md \
|
|
261
261
|
specs/payment/checkout/design-spec/FT-042-checkout-design.md \
|
|
262
262
|
specs/payment/checkout/bdd/system/FT-042-UC1-checkout-system.feature \
|
|
263
263
|
specs/payment/checkout/bdd/web/FT-042-UC1-checkout-web.feature \
|
|
@@ -416,7 +416,7 @@ cd my-project-web
|
|
|
416
416
|
/sync # pull + submodule + Living Docs
|
|
417
417
|
git add my-project-specs && git commit -m "chore: sync specs" && git push
|
|
418
418
|
|
|
419
|
-
/review-context my-project-specs/specs/{domain}/{prd-slug}/prd.md
|
|
419
|
+
/review-context my-project-specs/specs/{domain}/{prd-slug}/{TICKET-ID}-{prd-slug}.md
|
|
420
420
|
# → P0: @trace.domain khớp services config? @trace.status: approved?
|
|
421
421
|
# Đọc Web BDD do PO generate (KHÔNG tự generate BDD):
|
|
422
422
|
# my-project-specs/specs/{domain}/{prd-slug}/bdd/web/{TICKET-ID}-UC*.feature
|
|
@@ -449,7 +449,7 @@ cd my-project-be
|
|
|
449
449
|
/sync
|
|
450
450
|
# → cũng liệt kê "📥 New tester feedback" → /fix-bug · promote proposal · báo PO
|
|
451
451
|
|
|
452
|
-
/review-context my-project-specs/specs/{domain}/{prd-slug}/prd.md
|
|
452
|
+
/review-context my-project-specs/specs/{domain}/{prd-slug}/{TICKET-ID}-{prd-slug}.md
|
|
453
453
|
# Đọc System BDD: my-project-specs/specs/{domain}/{prd-slug}/bdd/system/{TICKET-ID}-UC*.feature
|
|
454
454
|
|
|
455
455
|
/generate-tech-docs {domain}/{TICKET-ID}-UC1
|
|
@@ -62,8 +62,8 @@ Có **4 lệnh review** cho **4 loại artifact khác nhau**. Đây là điểm
|
|
|
62
62
|
|
|
63
63
|
| Tôi muốn review… | Cách dùng (ví dụ) | Nó kiểm cái gì | Ai chạy |
|
|
64
64
|
|---|---|---|---|
|
|
65
|
-
| **PRD — nội dung & độ đầy đủ** | `/refine-prd specs/auth/login/
|
|
66
|
-
| **PRD — chất lượng trước khi approve** | `/review-context specs/auth/login/
|
|
65
|
+
| **PRD — nội dung & độ đầy đủ** | `/refine-prd specs/auth/login/{TICKET-ID}-login.md` | 4 lens QA·DEV·SA·PO: AC có test được? edge case? scope rõ? | PO |
|
|
66
|
+
| **PRD — chất lượng trước khi approve** | `/review-context specs/auth/login/{TICKET-ID}-login.md` | P-checks: banned term, mơ hồ, mâu thuẫn PRD khác, thiếu section, routing `@trace.domain` | PO |
|
|
67
67
|
| **BDD `.feature`** | `/review-context specs/auth/login/bdd/system/FEAT-01-UC1-login.feature` | B-checks: mỗi AC/BR → có ≥1 scenario? Gherkin R1–R10, compliance C1–C5 | SA/Dev |
|
|
68
68
|
| **Tech design** | `/review-tech-docs specs/auth/login/tech-docs/FEAT-01-UC1-tech-design.md` | T-checks: đúng layer/architecture, entity, trace BDD, cross-team API sign-off | Dev/SA |
|
|
69
69
|
| **Code** | `/review-code FEAT-01-UC1` | 4 lens: Security · Performance · Architecture · Test coverage | Dev |
|
|
@@ -56,12 +56,12 @@
|
|
|
56
56
|
|
|
57
57
|
| Command | Cách dùng (ví dụ) | Output | When to use |
|
|
58
58
|
|---------|-------------------|--------|-------------|
|
|
59
|
-
| `/generate-prd` | `/generate-prd specs/product-definition/FEAT-01-login.md` | `specs/{domain}/{prd-slug}/prd.md` | After define-product. Thêm `API Source: existing` + section "Existing API Contract" cho feature brownfield. |
|
|
60
|
-
| `/refine-prd` | `/refine-prd specs/auth/login/
|
|
61
|
-
| `/refine-prd --resume` | `/refine-prd --resume specs/auth/login/
|
|
62
|
-
| `/review-context` (PRD) | `/review-context specs/auth/login/
|
|
63
|
-
| `/review-context --fix` | `/review-context --fix specs/auth/login/
|
|
64
|
-
| `/review-context --resume` | `/review-context --resume specs/auth/login/
|
|
59
|
+
| `/generate-prd` | `/generate-prd specs/product-definition/FEAT-01-login.md` | `specs/{domain}/{prd-slug}/{TICKET-ID}-{prd-slug}.md` | After define-product. Thêm `API Source: existing` + section "Existing API Contract" cho feature brownfield. |
|
|
60
|
+
| `/refine-prd` | `/refine-prd specs/auth/login/{TICKET-ID}-login.md` | `.agent/review/{prd-slug}-findings.yaml` | After generate-prd — fan-out 4 review lens + completeness-critic loop, mở Review Board. |
|
|
61
|
+
| `/refine-prd --resume` | `/refine-prd --resume specs/auth/login/{TICKET-ID}-login.md` | Applied findings + bumped version | Sau khi review trong Review Board (nút ⚡ Apply tự chạy lệnh này). |
|
|
62
|
+
| `/review-context` (PRD) | `/review-context specs/auth/login/{TICKET-ID}-login.md` | `.agent/review/{prd-slug}-review-context-findings.yaml` | Quality gate bắt buộc trước Phase 3. Checks: banned terms (P1), ambiguity (P2), conflicts (P3), completeness (P4). |
|
|
63
|
+
| `/review-context --fix` | `/review-context --fix specs/auth/login/{TICKET-ID}-login.md` | Applies all auto-fixable findings immediately | Dev quick-fix, không cần Review Board. |
|
|
64
|
+
| `/review-context --resume` | `/review-context --resume specs/auth/login/{TICKET-ID}-login.md` | Applies accepted findings + bump version | PO/SA review — human quyết từng finding. |
|
|
65
65
|
|
|
66
66
|
---
|
|
67
67
|
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
|
|
70
70
|
| Command | Cách dùng (ví dụ) | Output | When to use |
|
|
71
71
|
|---------|-------------------|--------|-------------|
|
|
72
|
-
| `/generate-design-spec` | `/generate-design-spec specs/auth/login/
|
|
72
|
+
| `/generate-design-spec` | `/generate-design-spec specs/auth/login/{TICKET-ID}-login.md` | `specs/{domain}/{prd-slug}/design-spec/{TICKET-ID}-design-spec-{platform}.md` | FE/App: sau khi PRD approved, trước BDD. PO phải cấp **node-level Figma frame link** (URL có `?node-id=`) cho mỗi screen; AI fetch từng frame qua Figma MCP. Screen thiếu link → ❌ Missing, spec ở draft và chặn sign-off + `/generate-bdd`. |
|
|
73
73
|
|
|
74
74
|
> BE teams bỏ qua Phase 2b — đọc PRD trực tiếp rồi `/generate-bdd`.
|
|
75
75
|
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
|
|
80
80
|
| Command | Cách dùng (ví dụ) | Output | When to use |
|
|
81
81
|
|---------|-------------------|--------|-------------|
|
|
82
|
-
| `/generate-bdd` | `/generate-bdd specs/auth/login/
|
|
82
|
+
| `/generate-bdd` | `/generate-bdd specs/auth/login/{TICKET-ID}-login.md` | `specs/{domain}/{prd-slug}/bdd/{UC-ID}.feature` (multi-service: `{prd-slug}/bdd/{service}/{UC-ID}.feature`) | After PRD approved (+ Design Spec sign-off cho FE/App). Đọc Service/Module từ PRD metadata, áp platform vocabulary, hiện SC outline chờ confirm. **Thứ tự outside-in: web → app → system**; `system` **tổng hợp từ web+app BDD** (web&app lệch contract → CHECKPOINT chọn union/platform-hint/separate-endpoints, ghi `@system.resolution:`; chỉ-BE → từ PRD). PRD lớn (>3 UC hoặc >300 dòng) → orchestration mode (1 sub-agent / UC). |
|
|
83
83
|
| `/review-context` (BDD) | `/review-context specs/auth/login/bdd/system/FEAT-01-UC1-login.feature` | `.agent/review/{uc-id}-review-bdd-findings.yaml` | Quality gate bắt buộc trước Phase 4. Checks: PRD coverage (mỗi AC + BR → ≥1 SC), Gherkin R1–R10, compliance C1–C5. |
|
|
84
84
|
| `/review-context --fix` | `/review-context --fix specs/auth/login/bdd/web/FEAT-01-UC1-login.feature` | Auto-fix terminology, metadata, coverage matrix | Dev quick-fix. |
|
|
85
85
|
| `/review-context --resume` | `/review-context --resume specs/auth/login/bdd/system/FEAT-01-UC1-login.feature` | Applies accepted findings + bump bdd_version | SA review. |
|
package/package.json
CHANGED
package/scripts/migrate-specs.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* artifact-type-first layout to the FEATURE-PACKAGE layout.
|
|
6
6
|
*
|
|
7
7
|
* OLD NEW
|
|
8
|
-
* specs/prd/{domain}/{slug}.md specs/{domain}/{slug}/
|
|
8
|
+
* specs/prd/{domain}/{slug}.md specs/{domain}/{slug}/{TICKET-ID}-{slug}.md
|
|
9
9
|
* specs/bdd/{domain}/{rest} specs/{domain}/{prd-slug}/bdd/{rest}
|
|
10
10
|
* specs/tech-docs/{domain}/{file} specs/{domain}/{prd-slug}/tech-docs/{file}
|
|
11
11
|
* specs/design-spec/{domain}/{file} specs/{domain}/{prd-slug}/design-spec/{file}
|
|
@@ -83,7 +83,7 @@ const ticketToSlug = {}; // `${domain}/${TICKET}` -> slug (from PRD metadata)
|
|
|
83
83
|
const addSlug = (domain, slug) => { (prdByDomain[domain] = prdByDomain[domain] || new Set()).add(slug); };
|
|
84
84
|
const onlySlug = domain => { const s = prdByDomain[domain]; return s && s.size === 1 ? [...s][0] : null; };
|
|
85
85
|
|
|
86
|
-
// ── Phase 1 — PRDs: specs/prd/{domain}/{slug}.md → specs/{domain}/{slug}/
|
|
86
|
+
// ── Phase 1 — PRDs: specs/prd/{domain}/{slug}.md → specs/{domain}/{slug}/{TICKET-ID}-{slug}.md ──
|
|
87
87
|
const prdRoot = path.join(specsAbs, 'prd');
|
|
88
88
|
for (const file of walk(prdRoot).filter(f => f.endsWith('.md'))) {
|
|
89
89
|
const parts = rel(file).split('/'); // [SPECS, 'prd', domain, ...rest, name.md]
|
|
@@ -98,7 +98,9 @@ for (const file of walk(prdRoot).filter(f => f.endsWith('.md'))) {
|
|
|
98
98
|
if (ticket) ticketToSlug[`${domain}/${ticket}`] = slug;
|
|
99
99
|
let m; const reUcG = new RegExp(reUcName.source, 'g');
|
|
100
100
|
while ((m = reUcG.exec(body))) ucToSlug[`${domain}/${m[1]}`] = ucToSlug[`${domain}/${m[1]}`] || slug;
|
|
101
|
-
|
|
101
|
+
// PRD file name follows the {TICKET-ID}-{slug}.md convention (falls back to {slug}.md if no ticket found)
|
|
102
|
+
const prdFile = ticket ? `${ticket}-${slug}.md` : `${slug}.md`;
|
|
103
|
+
moves.push({ from: file, to: path.join(specsAbs, domain, slug, prdFile), type: 'prd' });
|
|
102
104
|
}
|
|
103
105
|
|
|
104
106
|
// ── Phase 2 — BDD: specs/bdd/{domain}/{rest} → specs/{domain}/{prd-slug}/bdd/{rest}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* rename-prd-files.js — rename feature-package PRD files from the old fixed
|
|
5
|
+
* name `prd.md` to the `{TICKET-ID}-{slug}.md` convention.
|
|
6
|
+
*
|
|
7
|
+
* OLD NEW
|
|
8
|
+
* specs/{domain}/{slug}/prd.md specs/{domain}/{slug}/{TICKET-ID}-{slug}.md
|
|
9
|
+
*
|
|
10
|
+
* For each `specs/{domain}/{slug}/prd.md`:
|
|
11
|
+
* - slug = the feature-package folder name (parent dir)
|
|
12
|
+
* - TICKET-ID is read from the PRD body — the Metadata table row
|
|
13
|
+
* (| **PRD ID** | … | / | **Ticket** | … |) or, failing that, the leading
|
|
14
|
+
* token of the H1 title (`# SEG01-…`). PRDs where no ticket can be resolved
|
|
15
|
+
* are LEFT IN PLACE and listed in the report — never renamed to a guess.
|
|
16
|
+
*
|
|
17
|
+
* After moving, any reference to the old `…/{slug}/prd.md` path inside other
|
|
18
|
+
* spec / trace files (.md, .feature, .tsv, .yaml) is rewritten to the new path.
|
|
19
|
+
*
|
|
20
|
+
* DRY-RUN by default (prints the plan, changes nothing). Pass --apply to execute.
|
|
21
|
+
* Tracked files move with `git mv` to preserve history; the rest with fs.rename.
|
|
22
|
+
*
|
|
23
|
+
* Usage (from the consumer project root):
|
|
24
|
+
* node scripts/rename-prd-files.js # dry-run, prints plan
|
|
25
|
+
* node scripts/rename-prd-files.js --apply # execute the rename
|
|
26
|
+
* node scripts/rename-prd-files.js --specs specs --trace .trace --root .
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
const fs = require('fs');
|
|
30
|
+
const path = require('path');
|
|
31
|
+
const { execSync } = require('child_process');
|
|
32
|
+
|
|
33
|
+
// ── args ────────────────────────────────────────────────────────────────────
|
|
34
|
+
const argv = process.argv.slice(2);
|
|
35
|
+
const has = f => argv.includes(f);
|
|
36
|
+
const flag = (f, d) => { const i = argv.indexOf(f); return i !== -1 ? argv[i + 1] : d; };
|
|
37
|
+
|
|
38
|
+
const APPLY = has('--apply');
|
|
39
|
+
const ROOT = path.resolve(flag('--root', '.'));
|
|
40
|
+
const SPECS = flag('--specs', 'specs');
|
|
41
|
+
const TRACE = flag('--trace', '.trace');
|
|
42
|
+
|
|
43
|
+
const specsAbs = path.join(ROOT, SPECS);
|
|
44
|
+
const traceAbs = path.join(ROOT, TRACE);
|
|
45
|
+
|
|
46
|
+
// ── git tracked set (for `git mv`) ────────────────────────────────────────────
|
|
47
|
+
let tracked = null;
|
|
48
|
+
try {
|
|
49
|
+
const out = execSync('git ls-files', { cwd: ROOT, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
50
|
+
tracked = new Set(out.split('\n').filter(Boolean).map(p => p.replace(/\\/g, '/')));
|
|
51
|
+
} catch { tracked = null; }
|
|
52
|
+
|
|
53
|
+
const rel = abs => path.relative(ROOT, abs).replace(/\\/g, '/');
|
|
54
|
+
const isTracked = abs => !!(tracked && tracked.has(rel(abs)));
|
|
55
|
+
|
|
56
|
+
// ── helpers ───────────────────────────────────────────────────────────────────
|
|
57
|
+
function walk(dir) {
|
|
58
|
+
const out = [];
|
|
59
|
+
if (!fs.existsSync(dir)) return out;
|
|
60
|
+
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
61
|
+
const p = path.join(dir, e.name);
|
|
62
|
+
if (e.isDirectory()) out.push(...walk(p));
|
|
63
|
+
else out.push(p);
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
const head = (file, n = 16384) => { try { return fs.readFileSync(file, 'utf8').slice(0, n); } catch { return ''; } };
|
|
68
|
+
|
|
69
|
+
// Extract the TICKET-ID from a PRD body. Tries the Metadata table first, then the H1 title.
|
|
70
|
+
function extractTicket(body) {
|
|
71
|
+
// | **PRD ID** | SEG01 | / | **Ticket** | [SEG01](...) | / | **TICKET-ID** | SEG01 |
|
|
72
|
+
let m = body.match(/\|\s*\*\*\s*(?:PRD ID|Ticket(?:\s*ID)?|TICKET-ID|Mã(?:\s*ticket)?)\s*\*\*\s*\|\s*\[?\s*([A-Za-z][A-Za-z0-9_.-]*?)\s*\]?\s*(?:\]\([^)]*\))?\s*\|/i);
|
|
73
|
+
if (m) return m[1];
|
|
74
|
+
// H1 title: "# SEG01-segment-scoring-service ..." or "# SEG01 Feature Name"
|
|
75
|
+
m = body.match(/^#\s+([A-Za-z][A-Za-z0-9_.]*(?:-?\d+)?)\b/m);
|
|
76
|
+
if (m) return m[1];
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ── plan ───────────────────────────────────────────────────────────────────────
|
|
81
|
+
const moves = []; // { from(abs), to(abs) }
|
|
82
|
+
const unresolved = []; // { file(rel), reason }
|
|
83
|
+
|
|
84
|
+
// Scan specs/{domain}/{slug}/prd.md (PRD lives directly in the feature-package folder)
|
|
85
|
+
for (const file of walk(specsAbs).filter(f => path.basename(f) === 'prd.md')) {
|
|
86
|
+
const parts = rel(file).split('/'); // [SPECS, domain, slug, 'prd.md']
|
|
87
|
+
if (parts.length < 4) { unresolved.push({ file: rel(file), reason: `not a feature-package PRD (expected ${SPECS}/{domain}/{slug}/prd.md)` }); continue; }
|
|
88
|
+
const slug = parts[parts.length - 2];
|
|
89
|
+
const ticket = extractTicket(head(file));
|
|
90
|
+
if (!ticket) { unresolved.push({ file: rel(file), reason: 'no TICKET-ID found (add a Metadata "PRD ID"/"Ticket" row or an H1 title, then re-run)' }); continue; }
|
|
91
|
+
const to = path.join(path.dirname(file), `${ticket}-${slug}.md`);
|
|
92
|
+
if (rel(to) === rel(file)) continue; // already correctly named (shouldn't happen for prd.md)
|
|
93
|
+
moves.push({ from: file, to });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ── old→new ref map (repo-root-relative, forward slashes) ──────────────────────
|
|
97
|
+
const refMap = new Map();
|
|
98
|
+
for (const m of moves) refMap.set(rel(m.from), rel(m.to));
|
|
99
|
+
|
|
100
|
+
// ── report ──────────────────────────────────────────────────────────────────────
|
|
101
|
+
console.log('');
|
|
102
|
+
console.log('╔════════════════════════════════════════════╗');
|
|
103
|
+
console.log(`║ rename-prd-files — ${APPLY ? 'APPLY' : 'DRY RUN'}${' '.repeat(APPLY ? 16 : 14)}║`);
|
|
104
|
+
console.log('╚════════════════════════════════════════════╝');
|
|
105
|
+
console.log(`Root : ${ROOT}`);
|
|
106
|
+
console.log(`Specs : ${SPECS}/ Trace: ${TRACE}/ Git: ${tracked ? 'yes (git mv)' : 'no (fs move)'}`);
|
|
107
|
+
console.log('');
|
|
108
|
+
if (moves.length === 0 && unresolved.length === 0) {
|
|
109
|
+
console.log(`Nothing to rename — no ${SPECS}/{domain}/{slug}/prd.md files found (already on the {TICKET-ID}-{slug}.md convention?).`);
|
|
110
|
+
process.exit(0);
|
|
111
|
+
}
|
|
112
|
+
console.log(`Planned renames: ${moves.length}`);
|
|
113
|
+
console.log('');
|
|
114
|
+
for (const m of moves) console.log(` ${rel(m.from)}\n → ${rel(m.to)}`);
|
|
115
|
+
if (unresolved.length) {
|
|
116
|
+
console.log('');
|
|
117
|
+
console.log('⚠️ Left in place (fix the PRD, then re-run):');
|
|
118
|
+
for (const u of unresolved) console.log(` ${u.file}\n ${u.reason}`);
|
|
119
|
+
}
|
|
120
|
+
console.log('');
|
|
121
|
+
|
|
122
|
+
// ── apply ────────────────────────────────────────────────────────────────────────
|
|
123
|
+
function gitMv(from, to) {
|
|
124
|
+
fs.mkdirSync(path.dirname(to), { recursive: true });
|
|
125
|
+
execSync(`git mv -k "${rel(from)}" "${rel(to)}"`, { cwd: ROOT, stdio: ['ignore', 'ignore', 'pipe'] });
|
|
126
|
+
}
|
|
127
|
+
function fsMv(from, to) {
|
|
128
|
+
fs.mkdirSync(path.dirname(to), { recursive: true });
|
|
129
|
+
fs.renameSync(from, to);
|
|
130
|
+
}
|
|
131
|
+
function rewriteRefs(absFile) {
|
|
132
|
+
if (!/\.(md|feature|tsv|ya?ml)$/.test(absFile)) return 0;
|
|
133
|
+
let txt; try { txt = fs.readFileSync(absFile, 'utf8'); } catch { return 0; }
|
|
134
|
+
let n = 0, out = txt;
|
|
135
|
+
for (const [oldRef, newRef] of refMap) {
|
|
136
|
+
if (out.includes(oldRef)) { out = out.split(oldRef).join(newRef); n++; }
|
|
137
|
+
}
|
|
138
|
+
if (n) fs.writeFileSync(absFile, out, 'utf8');
|
|
139
|
+
return n;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (!APPLY) {
|
|
143
|
+
console.log('DRY RUN — nothing changed. Re-run with --apply to execute.');
|
|
144
|
+
process.exit(0);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
let moved = 0, failed = 0;
|
|
148
|
+
for (const m of moves) {
|
|
149
|
+
try {
|
|
150
|
+
if (fs.existsSync(m.to)) throw new Error('target already exists');
|
|
151
|
+
(isTracked(m.from) ? gitMv : fsMv)(m.from, m.to);
|
|
152
|
+
moved++;
|
|
153
|
+
} catch (e) {
|
|
154
|
+
failed++;
|
|
155
|
+
console.log(` ❌ ${rel(m.from)} — ${e.message}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// rewrite references to the old prd.md paths across specs/ and .trace/
|
|
160
|
+
let rewritten = 0;
|
|
161
|
+
const scanForRefs = [...walk(specsAbs), ...walk(traceAbs)];
|
|
162
|
+
for (const f of scanForRefs) rewritten += rewriteRefs(f) > 0 ? 1 : 0;
|
|
163
|
+
|
|
164
|
+
console.log('');
|
|
165
|
+
console.log(`✅ Renamed ${moved}/${moves.length} PRD file(s)${failed ? ` (${failed} failed)` : ''}.`);
|
|
166
|
+
console.log(`✅ Rewrote internal references in ${rewritten} file(s).`);
|
|
167
|
+
if (unresolved.length) console.log(`⚠️ ${unresolved.length} file(s) left in place (see list above).`);
|
|
168
|
+
console.log('');
|
|
169
|
+
console.log('Next:');
|
|
170
|
+
console.log(' 1. Review the renames (git status / git diff).');
|
|
171
|
+
console.log(' 2. Grep your CODE for stale `…/prd.md` refs the move did not touch.');
|
|
172
|
+
console.log(' 3. Run /validate-traces to confirm coverage still resolves.');
|
|
173
|
+
console.log(' 4. Commit.');
|
|
174
|
+
console.log('');
|