@educa-corp/sdd-framework
v0.9.3
Published
Spec Driven Development workflow framework for Claude Code
Downloads
2,580
Maintainers
Readme
SDD Framework
An SDD Framework workflow framework for Claude Code.
Guides your team through a complete feature lifecycle — Discovery → PRD → Design-Spec → BDD → Tech Design → Code → Dev self-check → QC automation — with AI review gates at every transition and end-to-end traceability.
📚 Documentation
Toàn bộ tài liệu nằm trong docs/, chia theo vai trò và chủ đề:
| Bạn là… | Bắt đầu ở |
|---------|-----------|
| Người mới / cài đặt lần đầu | 01 · Getting Started |
| Muốn hiểu cách nó hoạt động | 02 · Concepts — pipeline từng bước · traceability |
| Product Owner / BA | Guide · Product Owner |
| Developer (FE / BE / App) | Guide · Developer |
| Tester / QA | Guide · Tester / QA — gồm cả pipeline QC tự động (/qc-*) |
| Kiến trúc sư / Lead | Guide · Architect |
| Tra cứu lệnh / schema / module | 04 · Reference |
| Muốn hiểu từng lệnh làm gì bên trong | explain/ — một trang cho mỗi lệnh |
Quick Start
Requires Node.js (check: node -v).
# 1. Install framework (--hooks bật data-guard: chặn AI đọc/ghi .env, *.key, secrets/…)
# Single-service:
npx @educa-corp/sdd-framework --init --module java-spring --hooks
# Multi-service monorepo:
npx @educa-corp/sdd-framework --init --hooks \
--services backend:java-spring,web-admin:react,app-mobile:flutter
# 2. Open the project in Claude Code, then:
/setup-ai-first
# 3. Fill in the generated config (CLAUDE.md, .agent/project-context.yaml,
# specs/domain-knowledge/*), then start your first feature:
/define-productFull install paths (upgrade, umbrella, uninstall) → Getting Started › Installation. First feature end-to-end → Getting Started › Quick Start.
Workflow at a glance
Phase 0 Setup /setup-ai-first · /generate-architecture
Phase 1 Discovery /define-product
Phase 2 PRD /generate-prd (lần đầu)
/extend-prd (THÊM vào PRD đã duyệt)
/amend-prd (ĐỔI một yêu cầu đã duyệt)
/refine-prd · /review-context
Phase 2b Design Spec /generate-design-spec (FE/App only)
Phase 3 BDD /generate-bdd · /review-context
Phase 4 Tech Design /generate-tech-docs · /review-tech-docs · /map-testids
Phase 5 Code /generate-code · /review-code · /fix-bug · /debug
Phase 6 Dev self-check /dev-gen-test · /dev-run-test · /dev-smoke-test → dev_selftest
Phase 6b QC automation /qc-analyze → /qc-plan → /qc-design-test
→ /qc-review → /qc-run-test → /qc-report → qc_status
Phase 7 Trace /validate-traces · /generate-spec-manifest
Phase 8 Tester feedback /report-bug · /propose-scenario → /sync → /extend-prd
Cross-cutting /sync · /learn · /update-framework33 lệnh. Pipeline chi tiết → Concepts › Pipeline Steps. Bảng đầy đủ mọi command → Reference › Commands.
Bốn nhánh dễ chọn nhầm
| Tình huống | Lệnh đúng | Thao tác ghi | Vì sao không phải lệnh kia |
|---|---|---|---|
| PRD chưa có | /generate-prd | Write cả file | — |
| PRD đã có, thêm UC/AC/BR | /extend-prd | Edit add-only | /generate-prd DỪNG HẲN trên file đã có (§Guard — không hỏi Y/N) và chỉ sang đây — ghi đè sẽ mất changelog và đánh số lại BR, phá @trace.business_rules trong mọi .feature đã sinh |
| PRD đã có, sửa vấn đề review chỉ ra | /refine-prd → Review Board → --resume | Edit trong phạm vi finding | /refine-prd không thêm được yêu cầu mới; nó tự cấm đụng section ngoài findings |
| PRD đã có, PO muốn ĐỔI một yêu cầu đang đúng cú pháp | /amend-prd | Edit tại chỗ — output KHÔNG phải superset | Ba lệnh trên đều từ chối đúng việc này: /extend-prd chỉ add-only, /refine-prd chỉ áp finding do chính nó tìm ra, /generate-prd thì huỷ changelog |
Vì sao nhánh thứ tư quan trọng hơn nó trông (GAPS-v4 G54). Mọi drift detector so nhãn version, không so nội dung — 0 content hash trong toàn bộ codebase. Nên PRD bị sửa tay mà không bump version là điểm mù tuyệt đối:
/validate-tracesthấy version khớp ⇒ sạch ·gate-tracethấy report khớp sổ ⇒ PASS ·require-fresh-auditthấy PR không chạm tag ⇒ không đòi audit. Ba tầng xanh, và ba tầng đều đúng theo định nghĩa của chính chúng. Trước/amend-prd, ba lệnh có sẵn từ chối đúng việc PO cần làm — nên hành vi hợp lý duy nhất còn lại là mở file.mdra gõ. Thiết kế tự tạo ra con đường nó không canh được. Cửa sau giờ có chuông: cờ 🔴PRD_UNTRACKED_EDIT(schema →spec_edit_detection).
Traceability
Mỗi dòng code truy ngược về một scenario trong .feature. Trạng thái sống ở
.trace/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv — một sổ cho mỗi UC × platform, 24 cột.
{platform} = delivery surface: system · web · app · webview (bundle web nhúng trong app native).
PRD ──► Scenario ──► Code ──► Test
│ │ │ │
└─ prd_version · sc_version · gen_ver · test_count ──► status: OK / DRIFT / GAP / UNTRACKED/validate-traces đối chiếu hai chiều (spec→code và code→spec) rồi phân tầng cảnh báo:
| Mức | Cờ | Nghĩa |
|:---:|---|---|
| 🔴 chặn PR | SEAM_UNWIRED · STUB_UNRESOLVED · ORPHANED · TRACE_ORPHAN | Code đang hỏng — luồng ghép chạy vào hàm rỗng, hoặc code trỏ vào scenario đã bị xoá. Build xanh + test từng-UC xanh không phát hiện được |
| 🔴 không chặn PR (có chủ ý) | PRD_UNTRACKED_EDIT | Tài liệu bị sửa ngoài đường chính thức — nội dung PRD đổi mà nhãn Version không đổi, nên mọi phán đoán version cho PRD đó đang dựa vào một nhãn không còn đúng. Cố ý không vào gate.blocking: nó nói về spec, không phải code hỏng, và mọi project đang chạy đều có nợ tồn ⇒ chặn ngay sẽ làm người ta tắt cổng, mất luôn 4 cờ trên |
| 🟠 không chặn | PRD_DRIFT · BDD_DRIFT · TECHDOC_DRIFT · DESIGNSPEC_DRIFT … | Code chưa theo kịp spec — nợ khác loại |
| ⓘ không phải lỗi | PRD_STALE_REF · TECHDOC_STALE_REF | Version lệch nhưng changelog không nêu UC này → chỉ con trỏ cũ. Sạch bằng --realign-prd-version |
Hết cờ 🔴 ≠ sạch.
Nó cũng append một dòng delta vào .trace/trace-history.jsonl mỗi lần chạy — thứ trả lời
"đang tiến hay lùi", không chỉ "hiện tại thế nào".
⚠️ .trace/ phải được commit; .trace-mirror/ thì không. Cái đầu là sổ gốc, không dựng lại
được. Kiểm dự án đang chạy: git -C {spec_source} check-ignore .trace — có kết quả là đang mất dữ liệu.
⚠️ Và nó cần luật merge. Sổ nằm trong git, được nhiều người ghi trên nhiều nhánh song song —
nên {trace_dir}/.gitattributes phải có *.tsv / *.jsonl → text eol=lf merge=union.
Không có: merge song song conflict, và giải bằng "take mine" là mất row của người kia, im lặng.
/setup-ai-first tạo sẵn · /sync Step 4c kiểm và tạo hộ. Playbook khi conflict →
Concepts › Traceability.
Chi tiết → Reference › Trace Schema · Concepts › Traceability.
Contract tự canh
Contract trace có một nguồn-sự-thật máy đọc: bin/trace-schema.json. Hai checker đọc nó,
canh hai thứ khác nhau:
| | Canh gì | Chạy khi nào |
|---|---|---|
| bin/self-check.js | Contract — lệnh có gọi đúng tên cột/field không | npm run build · fail build nếu lệch |
| bin/lint-trace.js | Dữ liệu — sổ .trace/** thật có đúng hình dạng đó không | --lint-trace · exit 1 nếu lệch |
| bin/gate-trace.js | Cổng — sổ có cờ 🔴 nào không, và report có còn tươi | --gate-trace · exit 1 nếu có |
✅ 42 tag + 24 cột TSV + 1 bảng phụ + 3 hàng đợi + 8 vocabulary — contract khớp mọi lệnh
+ sổ trace thật được canh bởi bin/lint-trace.js (13 rule) — R8 giữ nó theo kịp schemaself-check — 15 rule, mỗi rule sinh ra từ một lỗi có thật
| Rule | Bắt gì |
|---|---|
| R1 | field/hàng đợi có người đọc mà không ai ghi |
| R2 | có người ghi mà không ai đọc — field chết |
| R3 | schema khai một lệnh là producer/consumer mà file của nó không nhắc tới (chỉ canh "có nhắc" — xem R15 cho những field cần canh "có dùng") |
| R4 | {paths.X} dùng mà không khai — và ngược lại, key chết |
| R5 | pattern đã bị cấm quay trở lại |
| R6 | giá trị enum khai mà không xuất hiện ở đâu |
| R7 | audit flag thiếu counter trong Step 7 và summary → dashboard mù |
| R8 | lint-trace tụt lại sau schema — vocabulary không neo được, n trùng/hổng, bảng phụ ngoài phạm vi |
| R9 | cổng chặn PR neo vào counter không tồn tại → gate mù trong im lặng; cờ 🟠 lọt vào danh sách chặn; hoặc key ở cấp gốc biên bản có consumer mà không producer (R9(h) — report.domain từng có 1 consumer chặn-PR và 0 producer) |
| R10 | file CI tụt lại sau schema — job require-fresh-audit grep 7 tag; thiếu một tag ⇒ job luôn xanh |
| R11 | lệnh không tự khai mức chặn CHECKPOINT, hoặc nhãn lệch schema ⇒ agent tự suy, và suy nhẹ hơn thì --yes bỏ qua được cổng không bao giờ được bỏ |
| R15 | "nhắc tên" ≠ "dùng" — R3 chỉ hỏi "file có nhắc tên field không", nên một câu tuyên bố cố ý bỏ qua ("dev_selftest trực giao với status") cũng thoả mãn nó: R3 xác nhận contract bằng đúng câu văn đang phủ nhận contract (đó là G55). R15 siết opt-in (strict_use_check) cho field mà trả lời sai gây hại im lặng — đòi field xuất hiện trong một dòng bảng, nơi framework này viết mọi luật rẽ nhánh |
| R14 | quyền khẳng định pass — chủ cột dev_selftest/qc_status không thực sự đọc status (R3 bị một câu "trực giao" thoả mãn); hoặc lint-trace không phát T12 / không đọc schema; hoặc fail bị nhét vào positive_values (che tin xấu) |
| R13 | phát hiện sửa spec ngoài đường — spec_baseline không được GHI như một key trong trace-report.json ⇒ cờ PRD_UNTRACKED_EDIT không bao giờ bật, mà R6/R7 vẫn ✅ (chúng chỉ canh nửa báo-cáo) |
| R12 | dòng changelog — producer không khai {changelog_scope} ⇒ row mơ hồ ⇒ 🟠 cho MỌI UC; hoặc consumer không hiểu [no-behavior] / phép phân giải BR/AC → UC sở hữu ⇒ UC đổi thật bị xếp ⓘ và --realign dán nhãn lại |
lint-trace — 13 rule trên sổ sách thật
npx @educa-corp/sdd-framework --lint-trace # exit 1 nếu sổ hỏng
npx @educa-corp/sdd-framework --lint-trace --warn-only # xem nợ tồn, chưa chặn
npx @educa-corp/sdd-framework --version # bản nào đang chạy? (npx cache theo version)Mọi output đều mang version.
Lint trace v0.7.5 …·Trace gate v0.7.5 …· vàframework_versiontrong--json. Vì sao cần:npxcache theo version, một biến CI rỗng làmpkg@${VAR}thànhpkg@⇒ resolve vềlatestmà log không nói gì. Nên câu "lỗi này sửa chưa?" trước đây không trả lời được từ log — đúng lúc cần nhất. Một cổng quyết định PR nào được merge thì phải nói nó là ai.
| Rule | Bắt gì |
|---|---|
| T1 | header lệch 24 cột (vắng ở đuôi là OK — backward-compat) |
| T2 | row sai số ô — một dấu tab thiếu dồn mọi ô sang trái, kèm chẩn đoán chỗ lệch |
| T3 | giá trị ngoài vocabulary (DRIFTED thay DRIFT · dev_selftest=passed · một ngày nằm trong ô status) |
| T4 | sc_id trùng trong một sổ |
| T5 | tên sổ không khớp {UC-ID}-{platform}.tsv → cả sổ vô hình với /validate-traces |
| T6 | ô ngày không parse được (2026-13-45) |
| T7 | marker conflict git còn trong sổ |
| T8 | trace-history.jsonl có dòng hỏng / thiếu key |
| T9 | sổ mồ côi — không có .feature tương ứng (warning) |
| T10 | sổ thiếu luật merge (merge=union + text eol=lf) — hỏi thẳng git check-attr (warning · gate nâng thành chặn) |
| T11 | sổ đang bị gitignore — hỏi thẳng git check-ignore (warning · gate nâng thành chặn) |
| T12 | row vừa status ∈ {DRIFT, ORPHANED} vừa mang dev_selftest/qc_status = pass — rule đầu tiên nhìn NHIỀU Ô cùng lúc: T1–T8 kiểm hình dạng từng ô, nên trạng thái này là một sổ hoàn toàn hợp lệ với 11 rule cũ (warning) |
| T13 | KHÔNG kiểm được T10/T11 — thiếu binary git, hoặc sổ ngoài mọi repo git. Loại thứ tư: không phải "có cái sai", không phải "nợ", không phải "bảo vệ đang tắt" — mà "không biết bảo vệ có bật hay không". Trước T13, ca này làm G0 in sổ được bảo vệ — 2/2 điều kiện trên bằng chứng chưa bao giờ thu (warning · gate nâng thành chặn) |
/validate-traces Step 1.0 tự chạy lint trước khi đọc, và dừng nếu sổ hỏng: Step 3 tính lại
status rồi Step 6 ghi ngược vào TSV, nên chạy tiếp trên row đã lệch cột sẽ nướng cái lệch đó
vào sổ vĩnh viễn — và sổ trace không regenerate được.
gate-trace — cổng chặn PR
npx @educa-corp/sdd-framework --gate-trace # exit 1 nếu có cờ 🔴Biên bản có scope không bao giờ là biên bản đầy đủ.
/validate-traces --domain/--prd/--ucghiscopevào report; G2 fail nếuscope.kind !== "all", không ngoại lệ — nó không đếm xem trên đĩa có bao nhiêu domain. Bản cũ hỏi "còn domain nào khác không", nên repo một domain thì một biên bản hẹp-theo-PRD lọt qua. Thêm cờ scope mà không siết G2 là biến cổng thành sân khấu.
Ba tầng, mỗi tầng vô nghĩa nếu tầng trước chưa xanh:
| | Tầng | Bắt gì |
|:---:|---|---|
| G0 | Sổ được bảo vệ? | Sổ có nằm trong git? Git có biết cách gộp sổ? Kiểm cấu trúc của một quyển sổ sắp mất thì vô nghĩa — nên hỏi trước |
| G1 | Sổ đúng hình dạng? (gọi lint-trace) | Phán trạng thái trên sổ lệch cột là phán trên dữ liệu rác |
| G2 | Report còn tươi? | Đối chiếu từng scenario theo khoá {sc_id, platform} ↔ sổ TSV. Không có tầng này thì cổng là sân khấu: chạy một lần, commit report, rồi sửa gì cũng được — CI đọc report cũ, cho qua mãi |
| G3 | Có cờ 🔴? | orphaned · trace_orphan · seam_unwired · stub_unresolved — nêu tên thủ phạm kèm câu fix |
Khoá phải gồm platform: sc_id một mình không định danh được scenario — "sc_id trùng số
giữa các platform là 2 scenario khác nhau". Và so từng SC, không chỉ tổng số, vì ca thường
gặp nhất khi spec tiến hoá là một SC bị xoá + một SC được thêm — tổng không đổi, report cũ vẫn
trông như tươi.
G0 là loại thứ ba, cố ý tách khỏi gate.blocking:
| | Nói gì | Ví như |
|---|---|---|
| 🔴 gate.blocking (4 cờ) | Đang có cái sai trong code | Động cơ đang hỏng |
| 🟠 cờ nợ | Code chưa theo kịp spec | Đến hạn thay dầu |
| G0 | Chưa có gì sai, nhưng bảo vệ đang tắt | Chưa cài dây an toàn |
Trộn G0 vào blocking là làm mờ đúng ranh giới mà R9(e) tồn tại để giữ.
Cả hai điều kiện G0 đã được lint-trace phát hiện dưới dạng ⚠️; gate nâng chúng thành lỗi
chặn — một implementation, hai mức: pre-push nhắc, CI chặn. Chặn git push vì một dòng cấu
hình sẽ dạy dev gõ --no-verify, và mất luôn phần lint thật.
Ba ca mà một cổng viết cẩu thả sẽ PASS im lặng, và ở đây đều FAIL:
| Ca | Vì sao phải fail |
|---|---|
| Counter bị đổi tên | summary[counter] là undefined, và undefined > 0 là false → ✅ trên code hỏng |
| Không có report | "chưa audit" ≠ "sạch" |
| Report chỉ phủ một domain | Cho qua là cấp giấy xanh cho thứ chưa ai xem |
Giới hạn — in ra mỗi lần chạy, kể cả khi xanh. Cổng chứng minh "report khớp SỔ". Chỉ
/validate-traceschứng minh được "sổ khớp CODE" (quét tag trong source, đọc.feature, so version). Nên nó bắt ca "quên chạy lại", không bắt ca "sửa code mà không đụng sổ" — bịt nốt bằng jobrequire-fresh-audittrong template.
Mẫu sẵn dùng: .agent/templates/ci/trace-gate.yml (GitHub Actions) · .agent/templates/ci/trace-gate.gitlab-ci.yml (GitLab CI) · .agent/templates/hooks/pre-push.
Bản GitLab đã vá bốn bẫy dịch — hai bẫy ỒN (tags: thiếu ⇒ job stuck · Node thiếu ⇒ npx: not found) và hai bẫy IM LẶNG: GIT_DEPTH: 0 thiếu ⇒ git diff rỗng ⇒ job xanh giả · image không có git (node:*-alpine/*-slim) ⇒ T10/T11 không chạy. self-check R10 canh cả hai file khớp danh sách 7 tag.
Chi tiết → Guide › Architect › Cắm vào CI.
Cờ 🟠 cố ý không chặn. Chúng là nợ, không phải code hỏng. Cổng đỏ liên tục sẽ bị tắt,
mất luôn cả phần 🔴 — nên R9 fail build nếu ai nhét một cờ 🟠 vào gate.blocking.
Đổi contract: sửa bin/trace-schema.json trước, rồi mới sửa lệnh.
Philosophy
Write the spec first. Generate the code from the spec. Trace everything.
- Humans define what — acceptance criteria, business rules, platform requirements.
- AI generates how — BDD scenarios, tech design, code, tests — adapted to the platform.
- Every artifact is reviewed before proceeding to the next phase.
- Every line of code traces back to a scenario in a
.featurefile. - In multi-service projects, each service evolves independently while sharing the same workflow.
- Một tín hiệu đã hết đúng phải bị hạ xuống, không được giữ. Đổi spec thì
dev_selftestvàqc_statuscũ mất hiệu lực — giữ mộtpasssinh ra từ spec đã bị sửa là báo cáo sai.
Companion
SDD Board — VS Code extension đọc .trace/ hoặc
.trace-mirror/: dashboard Living Documentation + Review Board cho findings.
Framework version: see npm — npm view @educa-corp/sdd-framework version. Build internals & directory map → Concepts › Architecture.
