@edupia-tutor/spec-driven-docs 0.14.0 → 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 +436 -436
- package/commands/debug.tmpl +111 -111
- package/commands/define-product.md +350 -345
- package/commands/define-product.tmpl +69 -64
- package/commands/dev-gen-test.md +365 -365
- package/commands/dev-gen-test.tmpl +63 -63
- package/commands/dev-run-test.md +376 -376
- package/commands/dev-run-test.tmpl +74 -74
- package/commands/dev-smoke-test.md +341 -341
- package/commands/dev-smoke-test.tmpl +60 -60
- package/commands/fix-bug.md +403 -403
- package/commands/fix-bug.tmpl +78 -78
- package/commands/generate-bdd.md +513 -513
- package/commands/generate-bdd.tmpl +211 -211
- package/commands/generate-code.md +481 -483
- package/commands/generate-code.tmpl +179 -181
- package/commands/generate-design-spec.md +497 -497
- package/commands/generate-design-spec.tmpl +220 -220
- package/commands/generate-prd.md +452 -400
- package/commands/generate-prd.tmpl +50 -200
- package/commands/generate-spec-manifest.md +340 -340
- package/commands/generate-spec-manifest.tmpl +59 -59
- package/commands/generate-tech-docs.md +365 -365
- package/commands/generate-tech-docs.tmpl +84 -84
- package/commands/learn.md +347 -347
- package/commands/learn.tmpl +22 -22
- package/commands/map-testids.md +322 -322
- package/commands/map-testids.tmpl +41 -41
- package/commands/propose-scenario.md +335 -335
- package/commands/propose-scenario.tmpl +54 -54
- package/commands/qc-analyze.md +323 -324
- package/commands/qc-analyze.tmpl +42 -43
- package/commands/qc-design-test.md +304 -304
- package/commands/qc-design-test.tmpl +23 -23
- package/commands/qc-plan.md +297 -297
- package/commands/qc-plan.tmpl +16 -16
- package/commands/qc-report.md +302 -302
- package/commands/qc-report.tmpl +21 -21
- package/commands/qc-review.md +298 -298
- package/commands/qc-review.tmpl +17 -17
- package/commands/qc-run-test.md +337 -337
- package/commands/qc-run-test.tmpl +35 -35
- package/commands/refine-prd.md +428 -430
- package/commands/refine-prd.tmpl +62 -62
- package/commands/report-bug.md +351 -351
- package/commands/report-bug.tmpl +70 -70
- package/commands/review-code.md +364 -364
- package/commands/review-code.tmpl +39 -39
- package/commands/review-context.md +578 -580
- package/commands/review-context.tmpl +212 -212
- package/commands/review-tech-docs.md +427 -427
- package/commands/review-tech-docs.tmpl +146 -146
- package/commands/setup-ai-first.md +239 -239
- package/commands/setup-ai-first.tmpl +133 -133
- package/commands/sync.md +145 -145
- package/commands/sync.tmpl +93 -93
- package/commands/update-framework.md +88 -88
- package/commands/update-framework.tmpl +36 -36
- package/commands/validate-traces.md +381 -381
- package/commands/validate-traces.tmpl +100 -100
- package/core/FRAMEWORK_VERSION +1 -1
- package/core/commands/debug.md +436 -436
- package/core/commands/define-product.md +350 -345
- package/core/commands/dev-gen-test.md +365 -365
- package/core/commands/dev-run-test.md +376 -376
- package/core/commands/dev-smoke-test.md +341 -341
- package/core/commands/fix-bug.md +403 -403
- package/core/commands/generate-bdd.md +513 -513
- package/core/commands/generate-code.md +481 -483
- package/core/commands/generate-design-spec.md +497 -497
- package/core/commands/generate-prd.md +452 -400
- package/core/commands/generate-spec-manifest.md +340 -340
- package/core/commands/generate-tech-docs.md +365 -365
- package/core/commands/learn.md +347 -347
- package/core/commands/map-testids.md +322 -322
- package/core/commands/propose-scenario.md +335 -335
- package/core/commands/qc-analyze.md +323 -324
- package/core/commands/qc-design-test.md +304 -304
- package/core/commands/qc-plan.md +297 -297
- package/core/commands/qc-report.md +302 -302
- package/core/commands/qc-review.md +298 -298
- package/core/commands/qc-run-test.md +337 -337
- package/core/commands/refine-prd.md +428 -430
- package/core/commands/report-bug.md +351 -351
- package/core/commands/review-code.md +364 -364
- package/core/commands/review-context.md +578 -580
- package/core/commands/review-tech-docs.md +427 -427
- package/core/commands/setup-ai-first.md +239 -239
- package/core/commands/sync.md +145 -145
- package/core/commands/update-framework.md +88 -88
- package/core/commands/validate-traces.md +381 -381
- package/core/skills/code/SKILL.md +389 -389
- package/core/skills/debug/SKILL.md +391 -391
- package/core/skills/design-spec/SKILL.md +318 -318
- package/core/skills/discovery/SKILL.md +7 -547
- package/core/skills/prd/SKILL.md +298 -394
- package/core/skills/setup-ai-first/SKILL.md +80 -80
- package/core/skills/spec/SKILL.md +178 -178
- package/core/skills/test/SKILL.md +604 -604
- package/core/steps/capture-lesson.md +44 -44
- package/core/steps/context-loader.md +175 -175
- package/core/steps/gate.md +54 -54
- package/core/steps/report-footer.md +52 -52
- package/core/steps/review-fanout.md +85 -87
- package/core/steps/spawn-agent.md +45 -45
- package/core/steps/trace-mirror.md +21 -21
- package/core/templates/architecture.template.md +37 -37
- package/core/templates/design-spec.template.md +77 -77
- package/core/templates/platform-guide.template.md +47 -47
- package/core/templates/prd.template.md +107 -232
- package/core/templates/product-definition.template.md +101 -88
- 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/publishing.md +20 -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 +389 -389
- package/skills/code/SKILL.tmpl +56 -56
- package/skills/debug/SKILL.md +391 -391
- package/skills/debug/SKILL.tmpl +60 -60
- package/skills/design-spec/SKILL.md +318 -318
- package/skills/design-spec/SKILL.tmpl +37 -37
- package/skills/discovery/SKILL.md +7 -547
- package/skills/discovery/SKILL.tmpl +7 -140
- package/skills/prd/SKILL.md +298 -394
- package/skills/prd/SKILL.tmpl +40 -151
- package/skills/setup-ai-first/SKILL.md +80 -80
- package/skills/setup-ai-first/SKILL.tmpl +28 -28
- package/skills/spec/SKILL.md +178 -178
- package/skills/spec/SKILL.tmpl +20 -20
- package/skills/test/SKILL.md +604 -604
- package/skills/test/SKILL.tmpl +44 -44
- package/steps/capture-lesson.md +44 -44
- package/steps/context-loader.md +175 -175
- package/steps/gate.md +54 -54
- package/steps/report-footer.md +52 -52
- package/steps/review-fanout.md +85 -87
- package/steps/spawn-agent.md +45 -45
- package/steps/trace-mirror.md +21 -21
- package/templates/architecture.template.md +37 -37
- package/templates/design-spec.template.md +77 -77
- package/templates/platform-guide.template.md +47 -47
- package/templates/prd.template.md +107 -232
- package/templates/product-definition.template.md +101 -88
- package/templates/project-context.yaml +2 -2
|
@@ -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
|
|
@@ -48,13 +48,28 @@ npm whoami
|
|
|
48
48
|
3. Điền:
|
|
49
49
|
- Name: `publish-spec-driven-docs`
|
|
50
50
|
- Expiration: 1 year
|
|
51
|
-
-
|
|
51
|
+
- **Bypass 2FA**: **bật** (bắt buộc — nếu không, publish sẽ bị chặn với lỗi `403 ... Two-factor authentication ... is required`)
|
|
52
|
+
- Packages and scopes: chọn `@edupia-tutor/spec-driven-docs` (hoặc cả scope `@edupia-tutor`) → **Read and write**
|
|
52
53
|
4. Copy token, lưu vào nơi an toàn
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
> ⚠️ **KHÔNG** có flag `npm publish --token <token>` — npm sẽ hiểu `<token>` là tên package và báo lỗi `404 Not Found`. Token phải nạp qua npm config/`.npmrc` như dưới.
|
|
56
|
+
|
|
57
|
+
Publish với token — nạp token vào config trước, rồi publish:
|
|
58
|
+
|
|
59
|
+
```powershell
|
|
60
|
+
# Nạp token (ghi đè token đăng nhập hiện tại trong .npmrc)
|
|
61
|
+
npm config set //registry.npmjs.org/:_authToken <your-token>
|
|
62
|
+
|
|
63
|
+
npm publish --access public
|
|
64
|
+
|
|
65
|
+
# (tùy chọn) gỡ token khỏi .npmrc sau khi xong — sẽ phải npm login lại lần sau
|
|
66
|
+
npm config delete //registry.npmjs.org/:_authToken
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Cách khác — dùng OTP (nếu account đã bật 2FA app, không cần token bypass):**
|
|
55
70
|
|
|
56
71
|
```powershell
|
|
57
|
-
npm publish --
|
|
72
|
+
npm publish --access public --otp=<mã-6-số>
|
|
58
73
|
```
|
|
59
74
|
|
|
60
75
|
---
|
|
@@ -86,6 +101,8 @@ Lệnh này tự động cập nhật `version` trong `package.json` và tạo g
|
|
|
86
101
|
npm publish
|
|
87
102
|
```
|
|
88
103
|
|
|
104
|
+
> Nếu gặp `403 ... Two-factor authentication ... is required`: thêm `--otp=<mã-6-số>`, hoặc dùng granular token có **Bypass 2FA** (xem mục **2.2 — Tạo Access Token**). Access `public` đã set sẵn trong `package.json` (`publishConfig`).
|
|
105
|
+
|
|
89
106
|
### Bước 4 — Push git (bao gồm tag vừa tạo)
|
|
90
107
|
|
|
91
108
|
```powershell
|
|
@@ -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('');
|