@educa-corp/fw 0.8.1 → 0.10.0

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/CHANGELOG.md CHANGED
@@ -3,6 +3,26 @@
3
3
  > `fw install` in các mục của những version mới hơn bản đang cài trong dự án.
4
4
  > Mỗi lần sửa lệnh, khuôn, bộ câu hỏi hay công cụ đều phải tăng version và thêm một mục ở đây. Test sẽ báo lỗi nếu version chưa có mục.
5
5
 
6
+ ## 0.10.0 — 2026-10-02
7
+
8
+ - **Lệnh mới `/bdd <UC-ID>`**: viết kịch bản BDD cho một UC từ PRD đã duyệt, mỗi UC một file `{domain}/{slug}/bdd/UC-001.feature`. Có 2 lượt: lượt 1 trình dàn ý (kèm bảng nhánh của từng BR và các điểm giao nhận với UC khác), lượt 2 ghi file rồi kiểm độ phủ. Chỉ đọc đúng phần PRD của UC đó: với UC-001 của LMS là 15 KB thay vì 91 KB.
9
+ - **Mã kịch bản ổn định** `UC-001-SC01`: không đánh số lại, không dùng lại. Kịch bản bỏ đi còn lại dòng `# Đã bỏ (v…)`.
10
+ - **Tag Gherkin thật** cho từng kịch bản: mã, nền tảng (`@web @app`), loại (`@happy @alternative @edge @negative`), và mã đầy đủ của AC/BR được phủ.
11
+ - **Đã có file thì bù**: tìm AC/BR chưa có kịch bản, kịch bản trỏ tới mục đã bỏ, các mục PRD đổi sau version BDD viết theo. `/bdd <UC-ID> change <mô tả>` dùng khi kịch bản chưa đủ ý; nếu là yêu cầu mới thì chỉ sang `/prd change`.
12
+ - **Duyệt BDD** chỉ được khi độ phủ đủ, hết 🤖, PRD đang `approved`, và BDD viết theo đúng version PRD hiện tại.
13
+ - **PRD có dòng `Nền tảng`** ở Tổng quan (mặc định cho mọi UC), UC nào chạy khác thì ghi riêng. Thiếu dòng này thì PRD không duyệt được. PRD đã có: chạy `/prd <EPIC-ID> change khai nền tảng: web`.
14
+ - `spec_edit`: `where` · `context` (đọc phần PRD cần cho BDD) · `next-sc` · `scenario` (theo mã kịch bản hoặc mã AC/BR) · `sc` (thay, thêm, bỏ kịch bản theo mã) · `bddcheck` (kiểm khuôn, tag, độ phủ). `set`, `pending`, `confirm` dùng được với file `.feature`.
15
+
16
+ ## 0.9.0 — 2026-10-02
17
+
18
+ - **Sửa theo mã**: `spec_edit item` sửa hoặc thêm dòng BR / AC theo mã (`UC-003-BR10`), chỉ cần viết dòng mới. Chặn đổi mã, dùng lại mã, nguồn bằng lời. Áp bản sửa tốn ít output hơn hẳn (lần đo trước: 81 KB nội dung sửa cho 39 finding).
19
+ - **Đọc đúng phần cần**: `spec_edit uc <file> UC-003` (một UC) · `spec_edit finding <file> F17` (một finding).
20
+ - **`/prd refine` ghi quyết định ngay sau mỗi đợt** (`spec_edit decide`), `bác` bắt buộc có lý do. Nghỉ quá 1 giờ thì `/clear` rồi gọi lại lệnh, không mất gì.
21
+ - **`/prd refine` áp bản sửa bằng một sub-agent Opus**, phiên chính chỉ hỏi và ghi quyết định (lần đo trước: phiên quyết + áp phình tới 268K ngữ cảnh, khoảng 2,4M token).
22
+ - **Cảnh báo PRD quá 60 KB** khi `coverage` / `flowcheck`. `/product` (epic) và `/prd` (chia UC) hỏi tách epic khi dự kiến hơn 8 UC.
23
+ - **Luật chung tách ra `ref/common.md`**: xưng hô, kiểm Python, config, cách hỏi (tối đa 4 câu, ngôn ngữ nghiệp vụ, 🤖/✅), cách sửa file bằng `spec_edit`. Mọi lệnh đọc file này trong lệnh Bash đầu tiên, nên không tốn thêm lượt gọi. File lệnh nhẹ đi: `/product` 8,2 → 6,0 KB, `/prd` 6,5 → 5,1 KB. Sửa một luật chung chỉ cần sửa một chỗ.
24
+ - **Xưng hô cố định**: AI gọi người dùng là "bạn" và tự xưng "tôi" ở mọi lệnh. Không dùng "mình", "em", "anh/chị". Trước bản này, AI tự chọn cách xưng hô và thường tự xưng "mình".
25
+
6
26
  ## 0.8.1 — 2026-10-01
7
27
 
8
28
  - Hướng dẫn có thêm loại trang **Cách làm** (`.fw/guide/cach-lam/`), gồm các bước làm một việc cụ thể kèm câu gõ mẫu. Trang đầu tiên: **Cách quyết finding sau khi refine** (cho PO / BA).
@@ -0,0 +1,68 @@
1
+ ---
2
+ description: Viết kịch bản BDD cho một UC từ PRD đã duyệt (UC-ID), bù khi PRD đổi, hoặc đổi theo mô tả (UC-ID change)
3
+ argument-hint: "<UC-ID> [change <mô tả>] [--force]"
4
+ ---
5
+
6
+ # /bdd
7
+
8
+ Mục đích: biến một UC của PRD đã duyệt thành **kịch bản BDD** (file `.feature`, Gherkin). Mỗi kịch bản có **mã ổn định** `UC-001-SC01`. Kịch bản là spec để dev viết code và test, và là nguồn để QC thiết kế test case. Mã này cũng là khoá nối code (`@trace.implements`), test (`@trace.verifies`) và QC.
9
+
10
+ **Xưng hô: gọi người dùng là "bạn", tự xưng "tôi".** Không dùng "mình", "em", "anh/chị", "chúng ta".
11
+
12
+ - `/bdd <UC-ID>`: chưa có file thì **tạo**. Đã có file thì **bù** những gì PRD mới đổi hoặc còn thiếu.
13
+ - `/bdd <UC-ID> change <mô tả>`: thêm, sửa hoặc bỏ kịch bản theo mô tả. Ví dụ QC thấy một nhánh của BR chưa có kịch bản.
14
+
15
+ Tham số: `$ARGUMENTS`
16
+
17
+ ## Bước 1 — Nạp context
18
+
19
+ 1. Chạy **một** lệnh Bash: `cat .fw/core/ref/common.md .fw/config.yaml; python .fw/core/tools/spec_edit.py --check`. Làm đúng theo `common.md` (luật chung: xưng hô, Python, config, cách hỏi, cách sửa file bằng `SE`). Không có `common.md` thì báo *"Chưa cài framework vào dự án này. Chạy `npx @educa-corp/fw install` ở thư mục gốc dự án."*
20
+ 2. Tìm PRD: `SE where {specs} <UC-ID>`. Kết quả là `D`. File BDD: `F = {thư mục của D}/bdd/<UC-ID>.feature`.
21
+ 3. Đọc đầu vào **duy nhất** từ PRD: `SE context D <UC-ID>`. Lệnh này in Tổng quan, các hành trình có UC này, các dòng Màn hình, khối UC, và đúng các mục của UC khác mà UC này trỏ tới. **Không đọc cả PRD.** Cần thêm một UC khác thì chỉ đọc `SE uc D UC-xxx`.
22
+ 4. Đọc `{specs}/product/glossary.md` nếu có. Viết đúng thuật ngữ.
23
+
24
+ ## Bước 2 — Chọn chế độ
25
+
26
+ Xét **từ trên xuống**, gặp dòng nào khớp trước thì theo dòng đó.
27
+
28
+ | Tình huống | Làm gì |
29
+ |---|---|
30
+ | UC đã bỏ trong PRD (tiêu đề gạch ngang) | Dừng: *"UC-xxx đã bỏ trong PRD (v…). Không viết BDD cho UC đã bỏ."* |
31
+ | PRD chưa khai **Nền tảng**: không có dòng `Nền tảng` ở Tổng quan, cũng không có trong UC | Dừng: *"PRD chưa khai nền tảng. Chạy `/prd EP-xx change khai nền tảng: web …` trước. UC nào chạy khác mặc định thì nêu riêng."* |
32
+ | PRD chưa `approved`, **không** có `--force` | Dừng: *"PRD chưa duyệt. Duyệt PRD trước, hoặc chạy `/bdd UC-xxx --force` để viết sớm (BDD sẽ không duyệt được cho tới khi PRD được duyệt)."* |
33
+ | Không có `change`, chưa có `F` | Chế độ **tạo**: đọc `.fw/core/ref/bdd/writing.md` và `.fw/core/ref/bdd/new.md` |
34
+ | Không có `change`, **đã có** `F` | Chế độ **bù**: đọc `.fw/core/ref/bdd/writing.md` và `.fw/core/ref/bdd/change.md` |
35
+ | Có `change`, đã có `F` | Chế độ **đổi**: đọc `.fw/core/ref/bdd/writing.md` và `.fw/core/ref/bdd/change.md` |
36
+ | Có `change`, chưa có `F` | Dừng: *"Chưa có BDD cho UC-xxx. Chạy `/bdd UC-xxx` trước."* |
37
+
38
+ Có `--force` khi PRD chưa duyệt: in cảnh báo, và thêm dòng `# Viết khi PRD còn draft (--force)` ngay dưới header của `F`.
39
+
40
+ ## Bước 3 — Luật riêng của BDD
41
+
42
+ Ngoài luật chung (`common.md`) và luật viết (`writing.md`):
43
+ 1. **Mã ổn định.** `UC-NNN-SCnn` đánh số trong từng UC. Mã đã cấp thì **không bao giờ đổi, không dùng lại**. Mã mới lấy bằng `SE next-sc F`. Kịch bản bỏ đi còn lại dòng `# Đã bỏ (v…) @mã — tên`, do `SE sc` tự ghi.
44
+ 2. **Tag của mỗi kịch bản:**
45
+ - đúng **1** mã `@UC-NNN-SCnn`;
46
+ - ít nhất 1 nền tảng, chỉ dùng những nền tảng UC khai;
47
+ - đúng **1** loại: `@happy` · `@alternative` · `@edge` · `@negative`;
48
+ - **mã đầy đủ** của mọi AC/BR mà kịch bản phủ, ví dụ `@UC-001-AC01 @UC-003-BR14`.
49
+ 3. **Phủ.** Mọi AC và BR còn dùng của UC đều phải có mặt trong ít nhất một kịch bản, trực tiếp hoặc qua kịch bản của BR dùng nó. Không viết kịch bản cho điều PRD không có.
50
+ 4. **Lệnh `SE` riêng của BDD:**
51
+ - `SE next-sc F`: mã kế tiếp.
52
+ - `SE scenario F <mã SC | mã AC/BR>`: đọc kịch bản theo mã.
53
+ - `SE sc F`: thay, thêm, bỏ kịch bản theo mã. Chỉ viết khối mới, không chép khối cũ.
54
+ - `SE bddcheck F`: kiểm khuôn, tag và độ phủ.
55
+ 5. **Duyệt.** `status=approved` chỉ đặt được khi `bddcheck` sạch, không còn `🤖`, PRD đang `approved`, `prd_version` của `F` bằng version của PRD, và có người duyệt. Hỏi *"Ai duyệt BDD này?"* (mặc định là người đã duyệt PRD), rồi đặt trong **một** lệnh: `SE set F status=approved approved_by=<tên> approved_at=YYYY-MM-DD`. `SE` tự chặn nếu chưa đủ.
56
+
57
+ ## Bước 4 — Kết thúc
58
+
59
+ In ra đúng khối sau:
60
+
61
+ ```
62
+ ---
63
+ Trạng thái : {✅ Đã duyệt v{version} | 🟡 Nháp v{version} — còn {n} mục 🤖}
64
+ Đã ghi : {F}
65
+ Kiểm : {dòng số liệu đầu tiên của `SE bddcheck F`}
66
+ Luồng : Product → PRD → [BDD ◀ bạn ở đây] → TDD · Design-spec → Code → Test → QC
67
+ Bước tiếp : {trả lời / xác nhận các mục trên | `/clear` rồi `/bdd UC-xxx` (UC đầu tiên trong dòng "UC chưa có BDD" của bddcheck) | mọi UC đã có BDD: TDD (sắp có)}
68
+ ```
package/commands/prd.md CHANGED
@@ -7,18 +7,17 @@ argument-hint: "<EPIC-ID> [refine | change <mô tả thay đổi>] [--force]"
7
7
 
8
8
  Mục đích: biến epic đã làm rõ (`/product`) thành **PRD chính thức**, gồm các use case, Business Rule (BR) và **Acceptance Criteria (điều kiện nghiệm thu)**, viết tắt **AC**, có **mã ổn định**. Sau đó PRD là nguồn cho BDD, TDD và code.
9
9
 
10
+ **Xưng hô: gọi người dùng là "bạn", tự xưng "tôi".** Không dùng "mình", "em", "anh/chị", "chúng ta".
11
+
10
12
  - `/prd <EPIC-ID>`: tạo PRD từ epic `ready`.
13
+ - `/prd <EPIC-ID> refine`: rà nội dung PRD qua 4 lăng kính. **Bắt buộc** trước khi duyệt.
11
14
  - `/prd <EPIC-ID> change <mô tả>`: thêm, sửa hoặc bỏ nội dung trong PRD đã có.
12
15
 
13
16
  Tham số: `$ARGUMENTS`
14
17
 
15
18
  ## Bước 1 — Nạp context
16
19
 
17
- Nếu **trước lệnh này** phiên đã có hội thoại khác, dòng đầu tiên in: *"💡 Phiên này đã dài. Nên `/clear` rồi gọi lại lệnh để rẻ hơn, vì mọi thứ đã chốt đều nằm trong file."*
18
-
19
- 1. Chạy **một** lệnh Bash: `python .fw/core/tools/spec_edit.py --check && cat .fw/config.yaml`
20
- - Lỗi không tìm thấy python: thử `python3`, rồi `py -3`, và dùng lệnh chạy được cho cả phiên. Cả ba đều lỗi thì **DỪNG NGAY** và báo: *"❌ Máy chưa có Python 3.8+. Cài Python (Windows: `winget install Python.Python.3.12`), mở terminal mới rồi chạy lại lệnh."*
21
- - Không có `.fw/config.yaml`: dừng và báo *"Chưa cài framework. Chạy `npx @educa-corp/fw install` ở thư mục gốc dự án."*
20
+ 1. Chạy **một** lệnh Bash: `cat .fw/core/ref/common.md .fw/config.yaml; python .fw/core/tools/spec_edit.py --check`. Làm đúng theo `common.md` (luật chung: xưng hô, Python, config, cách hỏi, cách sửa file bằng `SE`). Không có `common.md` thì báo *"Chưa cài framework vào dự án này. Chạy `npx @educa-corp/fw install` ở thư mục gốc dự án."*
22
21
  2. Tìm file epic: `{specs}/product/epics/{EPIC-ID}-*.md`. Đọc frontmatter để lấy `slug`, `domain`, `status`.
23
22
  3. File PRD: `D = {specs}/{domain}/{slug}/prd.md`.
24
23
  4. Đọc `{specs}/product/glossary.md` nếu có, và `SE section {specs}/product/product.md constraints`. Viết đúng thuật ngữ. PRD không được đi ngược ràng buộc nào. BR bắt nguồn từ ràng buộc thì ghi `(nguồn: CON-01)`. `SE` báo không có mục đó (khuôn cũ): coi như chưa có ràng buộc, và nhắc một dòng *"Chạy `/product` để bổ sung Ràng buộc và Giai đoạn cho tầng sản phẩm."*
@@ -28,26 +27,20 @@ Nếu **trước lệnh này** phiên đã có hội thoại khác, dòng đầu
28
27
  | Tình huống | Làm gì |
29
28
  |---|---|
30
29
  | Không có `change`, chưa có `D`, epic `ready` | Chế độ **tạo**: đọc `.fw/core/ref/prd/new.md` |
31
- | Không có `change`, chưa có `D`, epic **chưa** `ready` | Dừng: *"EP-xx chưa làm rõ xong. Chạy `/product EP-xx` trước."* Có `--force` thì làm tiếp, nhưng in cảnh báo, ghi vào mục 4 của PRD dòng *"Tạo khi epic chưa ready (--force)"*, và không cho `approved` khi epic còn câu hỏi mở |
30
+ | Không có `change`, chưa có `D`, epic **chưa** `ready` | Dừng: *"EP-xx chưa làm rõ xong. Chạy `/product EP-xx` trước."* Có `--force` thì làm tiếp, nhưng in cảnh báo, ghi vào mục Câu hỏi còn mở của PRD dòng *"Tạo khi epic chưa ready (--force)"*, và không cho `approved` khi epic còn câu hỏi mở |
32
31
  | Không có `change` / `refine`, **đã có** `D` | Dừng: *"PRD đã có. Rà nội dung: `/prd EP-xx refine` · Đổi: `/prd EP-xx change <mô tả>`."* Không ghi đè |
33
32
  | Có `refine`, đã có `D` | Chế độ **rà nội dung**: đọc `.fw/core/ref/prd/refine.md` |
34
33
  | Có `change`, đã có `D` | Chế độ **đổi**: đọc `.fw/core/ref/prd/change.md` |
35
34
  | Có `change` hoặc `refine`, chưa có `D` | Dừng: *"Chưa có PRD. Chạy `/prd EP-xx` trước."* |
36
35
 
37
- ## Bước 3 — Luật chung
36
+ ## Bước 3 — Luật riêng của PRD
38
37
 
38
+ Ngoài luật chung (`common.md`):
39
39
  1. **Mã ổn định.** `UC-NNN` đánh số trên toàn sản phẩm. `UC-NNN-BRnn`, `UC-NNN-ACnn` đánh số trong từng UC. Mã đã cấp thì **không bao giờ đổi, không dùng lại**. Thêm mới thì lấy số kế tiếp trong UC đó. Mục bỏ đi thì giữ dòng, gạch ngang nội dung, và ghi *"Đã bỏ (v…)"*.
40
40
  2. **Nguồn.** Mọi BR và AC phải ghi `(nguồn: …)`, và **chỉ ghi mã**: mã epic (`BR3`, `AC1`), ràng buộc (`CON-02`), hoặc `PRD` (thêm khi viết PRD, PO đã duyệt). Không ghi lời giải thích. `SE` chặn nếu sai.
41
- 3. **Dấu.** Nội dung chuyển nguyên ý từ mục `✅` của epic thì giữ `✅`. Chỗ nào AI **tự thêm, tách hoặc suy ra** thì gắn `🤖`. Chỉ PO mới đổi được `🤖` thành `✅`.
42
- 4. **Ngôn ngữ nghiệp vụ.** Không nói API, bảng dữ liệu hay framework.
43
- 5. **Tối đa 4 câu hỏi mỗi lượt, tính cả câu phụ.**
44
- 6. **Sửa file: CHỈ dùng `spec_edit.py`** (gọi là `SE`). Không dùng Edit/Write, không tự viết script:
45
- - Tạo: `SE create <file> <<'EOF'` … `EOF` · Sửa: `SE edit <file> <<'EOF'` `[{"old": "…", "new": "…"}]` `EOF` (gom mọi chỗ sửa của một lượt vào một lần gọi)
46
- - Frontmatter: `SE set <file> version=1.1 status=draft updated=YYYY-MM-DD`
47
- - `SE pending <file>` · `SE confirm <file> UC-003-BR02 UC-003-AC01` · `SE next-uc {specs}` · `SE coverage <epic> <prd>` · `SE flowcheck <prd>`
48
- - Đọc **một mục**: `SE section <file> <mã>`. Mã mục là `<!-- sec:… -->` ở tiêu đề (vd `constraints`, `usecases`, `open`). **Luôn tìm mục theo mã**, không theo số hay tên tiêu đề, không tự cắt file bằng `sed`/`grep`. Khi sửa, giữ nguyên `<!-- sec:… -->`.
49
- - `SE` báo lỗi thì **không có gì được ghi**. Đọc lại file, sửa lệnh rồi chạy lại. Không bỏ qua lỗi. Lỗi mà **không in dòng nào** là Python chưa kịp chạy: chạy lại đúng lệnh đó một lần.
50
- 7. **Duyệt.** `status=approved` chỉ đặt được khi không còn `🤖`, `open_questions=0`, **đã refine đúng version này** (`refined` = `version`, không còn critical/major chưa quyết), và có người duyệt. Chưa refine thì báo *"Chạy `/prd EP-xx refine` trước khi duyệt."* Hỏi PO *"Ai duyệt PRD này?"* (mặc định là PO của epic), rồi đặt trong **một** lệnh: `SE set D status=approved approved_by=<tên> approved_at=YYYY-MM-DD`. `SE` tự chặn nếu chưa đủ. Không tìm cách lách.
41
+ 3. **Dấu.** Nội dung chuyển nguyên ý từ mục `✅` của epic thì giữ `✅`. Chỗ nào AI **tự thêm, tách hoặc suy ra** thì gắn `🤖`.
42
+ 4. **Lệnh `SE` riêng của PRD:** `SE next-uc {specs}` (mã UC kế tiếp) · `SE coverage <epic> <prd>` (không rơi BR/AC nào của epic) · `SE flowcheck <prd>` (mọi UC có mặt trong User flow).
43
+ 5. **Duyệt.** `status=approved` chỉ đặt được khi không còn `🤖`, `open_questions=0`, User flow đủ, **đã refine đúng version này** (`refined` = `version`, không còn critical/major chưa quyết), và có người duyệt. Chưa refine thì báo *"Chạy `/prd EP-xx refine` trước khi duyệt."* Hỏi PO *"Ai duyệt PRD này?"* (mặc định là PO của epic), rồi đặt trong **một** lệnh: `SE set D status=approved approved_by=<tên> approved_at=YYYY-MM-DD`. `SE` tự chặn nếu chưa đủ.
51
44
 
52
45
  ## Bước 4 — Kết thúc
53
46
 
@@ -5,7 +5,9 @@ argument-hint: "[EPIC-ID | tên tính năng]"
5
5
 
6
6
  # /product
7
7
 
8
- Mục đích: **hỏi ngược lại PO** để làm rõ những gì PO biết mà chưa viết ra, **trước** khi viết PRD. Giá trị của lệnh nằm ở **câu hỏi**, không nằm ở việc chép lại tài liệu.
8
+ Mục đích: **hỏi ngược lại PO** để làm rõ những gì PO biết mà chưa viết ra, **trước** khi viết PRD. Giá trị nằm ở **câu hỏi**, không ở việc chép lại tài liệu.
9
+
10
+ **Xưng hô: gọi người dùng là "bạn", tự xưng "tôi".** Không dùng "mình", "em", "anh/chị", "chúng ta".
9
11
 
10
12
  - `/product`: tầng **sản phẩm**, gồm tầm nhìn, nhóm người dùng, danh sách epic.
11
13
  - `/product <EPIC-ID | tên>`: làm rõ yêu cầu cho **một epic**.
@@ -14,15 +16,9 @@ Tham số: `$ARGUMENTS`
14
16
 
15
17
  ## Bước 1 — Nạp context (chỉ những gì cần)
16
18
 
17
- Nếu **trước lệnh này** phiên đã có hội thoại khác (một lệnh khác, hoặc một lần `/product` trước), thì dòng đầu tiên in ra: *"💡 Phiên này đã dài. Nên `/clear` rồi gọi lại lệnh để rẻ hơn, vì mọi thứ đã chốt đều nằm trong file."* Sau đó vẫn làm tiếp bình thường.
18
-
19
- 1. Chạy **một** lệnh Bash: `python .fw/core/tools/spec_edit.py --check && cat .fw/config.yaml`
20
- - Lỗi "không tìm thấy python": thử lại lần lượt với `python3`, rồi `py -3`, và dùng lệnh chạy được cho cả phiên. Cả ba đều lỗi thì **DỪNG NGAY**, không hỏi gì thêm, và báo: *"❌ Máy chưa có Python 3.8+. Cài Python (Windows: `winget install Python.Python.3.12`), mở terminal mới rồi chạy lại lệnh."*
21
- - Không có `.fw/config.yaml`: dừng và báo *"Chưa cài framework vào dự án này. Chạy `npx @educa-corp/fw install` ở thư mục gốc dự án."*
22
- - Lấy `specs` (thư mục spec) và `tracker` từ config.
19
+ 1. Chạy **một** lệnh Bash: `cat .fw/core/ref/common.md .fw/config.yaml; python .fw/core/tools/spec_edit.py --check`. Làm đúng theo `common.md` (luật chung: xưng hô, Python, config, cách hỏi, cách sửa file bằng `SE`). Không có `common.md` thì báo *"Chưa cài framework vào dự án này. Chạy `npx @educa-corp/fw install` ở thư mục gốc dự án."*
23
20
  2. Đặt `P = {specs}/product`.
24
- 3. Chế độ epic: đọc thêm `SE section P/product.md actors`, `… epics`, `… constraints` (gộp trong một lệnh Bash) và `P/glossary.md` nếu có. Epic không được đi ngược một ràng buộc `CON-xx`. PO muốn làm vậy thì hỏi PO có sửa ràng buộc ở tầng sản phẩm không.
25
- **Không** đọc PRD khác, trừ khi PO nhắc tới một tính năng liên quan.
21
+ 3. Chế độ epic: đọc thêm `SE section P/product.md actors`, `… epics`, `… constraints` (gộp trong một lệnh Bash) và `P/glossary.md` nếu có. Epic không được đi ngược một ràng buộc `CON-xx`. PO muốn làm vậy thì hỏi PO có sửa ràng buộc ở tầng sản phẩm không. Không đọc PRD khác, trừ khi PO nhắc tới.
26
22
  4. **Bảng thuật ngữ cũ.** Nếu `{specs}/domain-knowledge/business-dictionary.md` (của framework cũ) có **dòng thuật ngữ thật** (không chỉ là khuôn trống), thì ở lượt hỏi đầu, đề xuất gộp các thuật ngữ đó vào `P/glossary.md`. PO đồng ý thì gộp, sau đó hỏi PO xoá file cũ hay giữ. Mục tiêu là dự án chỉ còn **một** bảng thuật ngữ.
27
23
 
28
24
  ## Bước 2 — Xác định file đích
@@ -40,16 +36,12 @@ Xác định `id` và `slug` của epic:
40
36
 
41
37
  **File đích đã tồn tại** thì đọc `.fw/core/ref/product/resume.md` và làm theo đó. Không ghi đè.
42
38
 
43
- ## Bước 3 — Luật khi hỏi (áp cho mọi checkpoint)
39
+ ## Bước 3 — Luật riêng khi làm rõ yêu cầu
44
40
 
45
- 1. **AI trích, PO xác nhận.** PO dán tài liệu vào thì đó là **nguyên liệu**, không phải câu trả lời thay cho các bước.
46
- - Mục mà tài liệu đã có: trình bản trích với dấu `🤖`, rồi hỏi *"Đúng chưa, cần sửa gì?"*
47
- - Mục mà tài liệu chưa có: hỏi mới.
48
- - Chỉ khi PO xác nhận thì mới đổi `🤖` thành `✅`. **Không bao giờ tự đổi thay PO.**
41
+ Ngoài luật chung (`common.md` mục 3):
42
+ 1. **Tài liệu PO dán vào là nguyên liệu**, không phải câu trả lời thay cho các bước. Mục mà tài liệu đã có thì trình bản trích với dấu `🤖`, rồi hỏi *"Đúng chưa, cần sửa gì?"*. Mục mà tài liệu chưa có thì hỏi mới.
49
43
  2. **Không bỏ checkpoint**, kể cả khi tài liệu rất dày.
50
- 3. **Tối đa 4 câu hỏi mỗi lượt, tính cả câu phụ.** Mọi chỗ cần PO trả lời hoặc xác nhận đều được **đánh số** trong 4 câu đó, không kèm thêm "còn vài điểm…" ở ngoài. Còn câu thì để lượt sau.
51
- 4. **Chỉ nói ngôn ngữ nghiệp vụ.** Không hỏi và không đề xuất API, bảng dữ liệu hay framework.
52
- 5. Gặp **thuật ngữ mới** (lặp từ 2 lần trở lên, chưa có trong `glossary.md`) thì đưa vào lượt hỏi kế tiếp: nghĩa là gì, có thêm vào `glossary.md` không.
44
+ 3. Gặp **thuật ngữ mới** (lặp từ 2 lần trở lên, chưa có trong `glossary.md`) thì đưa vào lượt hỏi kế tiếp: nghĩa là gì, có thêm vào `glossary.md` không.
53
45
 
54
46
  ## Bước 4 — Đi qua các checkpoint
55
47
 
@@ -59,16 +51,8 @@ Xác định `id` và `slug` của epic:
59
51
 
60
52
  Trước checkpoint 1 của epic, AI tự điền mục **Bối cảnh hệ thống** (nhóm người dùng liên quan, tính năng đã có liên quan, thuật ngữ mới). Mục này không cần PO.
61
53
 
62
- **Sửa file: CHỈ dùng `spec_edit.py`** (gọi là `SE` bên dưới). Không dùng Edit/Write, không tự viết script:
63
- - Tạo file mới: `SE create <file> <<'EOF'` … nội dung … `EOF`
64
- - Sửa nội dung: `SE edit <file> <<'EOF'` `[{"old": "…", "new": "…"}]` `EOF`. Gom mọi chỗ sửa của một lượt vào **một** lần gọi. Đoạn lặp giống nhau thì thêm `"all": true`.
65
- - Frontmatter: `SE set <file> checkpoint=1 open_questions=3 updated=YYYY-MM-DD`
66
- - Xem các mục còn chờ PO: `SE pending <file>`. PO xác nhận các mục có mã: `SE confirm <file> AC2 AC3 BR8b`
67
- - Đọc một mục: `SE section <file> <mã>` (mã là `<!-- sec:… -->` ở tiêu đề). **Luôn tìm mục theo mã**, không theo số hay tên. Khi sửa, giữ nguyên `<!-- sec:… -->`.
68
- - `SE` báo lỗi thì **không có gì được ghi**. Đọc lại file, sửa lệnh rồi chạy lại. Không bỏ qua lỗi. Lỗi mà **không in dòng nào** là Python chưa kịp chạy: chạy lại đúng lệnh đó một lần.
69
-
70
54
  **Sau mỗi checkpoint** mà PO đã chốt:
71
- 1. **Ghi file ngay.** Không đợi tới cuối, để lần sau chạy tiếp được.
55
+ 1. **Ghi file ngay** (bằng `SE`, xem `common.md` mục 4). Không đợi tới cuối, để lần sau chạy tiếp được.
72
56
  2. `SE set` các trường `checkpoint`, `open_questions` (đếm số dòng trong mục `sec:open` của file, **không** đếm câu vừa hỏi trong lượt), `updated`.
73
57
  3. Checkpoint chỉ được tính là chốt khi **mọi mục của nó mang `✅`**. Còn mục `🤖` thì không tăng `checkpoint`.
74
58
 
@@ -26,6 +26,8 @@ Chỉ những khái niệm bạn **gặp khi dùng** các lệnh hiện có.
26
26
  | **AC** (Acceptance Criteria, điều kiện nghiệm thu) | Điều kiện kiểm được là đạt hay không đạt, dạng *"Khi … thì …"* | UC-002-AC01: Khi tài khoản mới quá 7 ngày chưa đăng nhập thì bị chuyển inactive, đăng nhập bị từ chối |
27
27
  | **Ràng buộc** | Điều kiện áp cho **mọi epic**, mã `CON-01`… | CON-01: Audit log không được xoá hay sửa |
28
28
  | **User flow** (hành trình) | Đường đi của một actor qua nhiều UC, có rẽ nhánh và nhánh lỗi, vẽ bằng sơ đồ trong PRD. Mã `J1`, `J2`… | J1 Nhân sự mới vào hệ thống: UC-001 → UC-003 → UC-005 |
29
+ | **Kịch bản BDD** (scenario) | Một hành vi cụ thể của hệ thống, viết dạng *Given / When / Then*, dev viết code và test theo đó. Mỗi UC có một file `.feature` | UC-001-SC01: Import có dòng trùng email với tài khoản đã có |
30
+ | **Nền tảng** | Nơi người dùng dùng tính năng: `web`, `app`… Khai ở Tổng quan của PRD, UC nào khác thì ghi riêng | Nền tảng: web · app |
29
31
  | **Checkpoint** | Một điểm dừng để bạn chốt. `/product` có 2 (sản phẩm) hoặc 3 (epic) checkpoint | — |
30
32
 
31
33
  ## Mã ổn định
@@ -35,6 +37,7 @@ Chỉ những khái niệm bạn **gặp khi dùng** các lệnh hiện có.
35
37
  | UC | `UC-001` | Toàn sản phẩm, mọi epic dùng chung một dãy |
36
38
  | Business Rule trong PRD | `UC-003-BR02` | Trong từng UC |
37
39
  | AC trong PRD | `UC-003-AC04` | Trong từng UC |
40
+ | Kịch bản BDD | `UC-003-SC01` | Trong từng UC |
38
41
  | Business Rule / AC trong epic | `BR1.`, `AC1.` | Trong epic. Chèn giữa thì dùng `BR8a.` |
39
42
 
40
43
  **Mã đã cấp không bao giờ đổi và không dùng lại.** Mục bỏ đi được giữ lại, gạch ngang và ghi *"Đã bỏ (v1.1)"*. Nhờ vậy BDD, code và test sau này luôn trỏ đúng mục.
@@ -1,7 +1,7 @@
1
1
  # Hướng dẫn sử dụng `@educa-corp/fw`
2
2
 
3
3
  > Framework làm việc với Claude Code: đưa một tính năng đi từ **ý tưởng → làm rõ yêu cầu → PRD → …**, AI hỏi và viết, con người xác nhận ở mỗi bước.
4
- > Hướng dẫn này viết cho **bản 0.8.1**. Chỉ mô tả những lệnh **đã có**. Lệnh mới có thì hướng dẫn mới được bổ sung.
4
+ > Hướng dẫn này viết cho **bản 0.10.0**. Chỉ mô tả những lệnh **đã có**. Lệnh mới có thì hướng dẫn mới được bổ sung.
5
5
  > Trong dự án đã cài framework, bản hướng dẫn đúng với version đang dùng nằm ở **`.fw/guide/`**. Có thể hỏi Claude: *"Đọc .fw/guide và cho biết cách đổi PRD"*.
6
6
 
7
7
  ---
@@ -12,7 +12,7 @@
12
12
  |---|---|
13
13
  | Cài vào dự án và chạy lần đầu | [Bắt đầu](01-bat-dau.md) |
14
14
  | Hiểu vài khái niệm trước khi dùng (UC, BR, AC, 🤖/✅…) | [Khái niệm](02-khai-niem.md) |
15
- | Biết **vai trò của mình** dùng lệnh nào | [PO / BA](vai-tro/po-ba.md) · *Dev, QC: sắp có* |
15
+ | Biết **vai trò của bạn** dùng lệnh nào | [PO / BA](vai-tro/po-ba.md) · *Dev, QC: sắp có* |
16
16
  | Làm một việc cụ thể, từng bước, có câu gõ mẫu | **Cách làm:** [Quyết finding sau khi refine](cach-lam/quyet-finding-refine.md) |
17
17
  | Tra cứu một lệnh cụ thể | Bảng lệnh ngay bên dưới |
18
18
  | Gặp lỗi | [Xử lý sự cố](xu-ly-su-co.md) |
@@ -22,10 +22,10 @@
22
22
  ## Pipeline hiện có
23
23
 
24
24
  ```
25
- cài framework ──► /product ──► /product EP-xx ──► /prd EP-xx ──► /prd EP-xx refine ──► duyệt ┄┄► (/bdd — sắp có)
26
- tầng làm rõ một viết PRD rà nội dung
27
- sản phẩm tính năng ▲ │ (bắt buộc)
28
- └── /prd EP-xx change ◄──┘ đổi PRD thì refine lại
25
+ cài framework ──► /product ──► /product EP-xx ──► /prd EP-xx ──► /prd EP-xx refine ──► duyệt ──► /bdd UC-xxx ──► duyệt
26
+ tầng làm rõ một viết PRD rà nội dung mỗi UC một
27
+ sản phẩm tính năng ▲ │ (bắt buộc) file kịch bản
28
+ └── /prd EP-xx change ◄──┘ đổi PRD thì refine lại, rồi /bdd UC-xxx để bù
29
29
  ```
30
30
 
31
31
  Mỗi lệnh kết thúc bằng một khối giống nhau. Bạn chỉ cần đọc dòng **Bước tiếp**:
@@ -51,6 +51,8 @@ Bước tiếp : `/clear` rồi `/product EP-01`
51
51
  | `/prd <EPIC-ID>` | PO / BA | Viết **PRD chính thức** từ epic đã làm rõ | [/prd](lenh/prd.md) |
52
52
  | `/prd <EPIC-ID> refine` | PO / BA | **Rà nội dung** PRD qua 4 lăng kính. **Bắt buộc** trước khi duyệt | [/prd refine](lenh/prd-refine.md) |
53
53
  | `/prd <EPIC-ID> change <mô tả>` | PO / BA | Thêm, sửa hoặc bỏ nội dung PRD | [/prd](lenh/prd.md) |
54
+ | `/bdd <UC-ID>` | PO / BA | Viết **kịch bản BDD** cho một UC. Đã có thì **bù** phần PRD mới đổi | [/bdd](lenh/bdd.md) |
55
+ | `/bdd <UC-ID> change <mô tả>` | PO / BA · QC · Dev | Thêm, sửa, bỏ kịch bản khi chưa đủ ý | [/bdd](lenh/bdd.md#đổi-bdd-uc-001-change-mô-tả) |
54
56
 
55
57
  ---
56
58
 
@@ -40,6 +40,8 @@ Nên chia thành 4–5 tin nhắn, đừng dồn tất cả vào một lần:
40
40
 
41
41
  Quyết theo nhóm thì Claude **liệt kê lại đúng các mã** sẽ bị áp và hỏi *"Đúng chưa?"*. Kiểm danh sách đó trước khi trả lời "đúng".
42
42
 
43
+ **Mỗi đợt quyết được lưu vào file ngay.** Bạn dừng giữa chừng được. **Nghỉ quá 1 giờ thì `/clear` rồi gọi lại `/prd EP-01 refine`**, đừng để phiên mở qua đêm: phiên cũ phải nạp lại toàn bộ khi bạn quay lại, đo thực tế tốn khoảng 470K token cho một lần nghỉ qua đêm.
44
+
43
45
  ## 3. Chọn quyết định nào
44
46
 
45
47
  | Quyết định | Dùng khi | Lưu ý |
@@ -79,7 +81,7 @@ Cách này hợp khi bạn muốn đọc kỹ từng finding, hoặc cần hỏi
79
81
  ## 6. Sau khi quyết xong
80
82
 
81
83
  Khi mọi critical và major đã có quyết định:
82
- 1. Claude áp các finding `nhận` và `sửa` vào PRD, tăng version (ví dụ 1.2 → 1.3), ghi Lịch sử thay đổi.
84
+ 1. Claude giao việc áp cho **một agent riêng**: agent đọc từng finding, sửa PRD theo mã, tăng version (ví dụ 1.2 → 1.3), ghi Lịch sử thay đổi, rồi báo lại một dòng.
83
85
  2. Bảng **Tóm tắt** trong `prd-refine.md` có thêm số **nhận · sửa · bác · hoãn**.
84
86
  3. Claude nhắc `/clear` rồi `/prd EP-01 refine` để chạy **lượt 2**. Lượt này chỉ soi phần vừa sửa, nhanh hơn nhiều.
85
87
 
@@ -0,0 +1,94 @@
1
+ [← Hướng dẫn](../README.md) · [Bảng lệnh](../README.md#bảng-lệnh)
2
+
3
+ # `/bdd` — kịch bản BDD cho một use case
4
+
5
+ > Biến một UC của PRD đã duyệt thành **kịch bản BDD** (file `.feature`, viết theo Gherkin). Mỗi kịch bản có **mã ổn định** `UC-001-SC01`. Dev viết code và test theo kịch bản, còn QC thiết kế test case từ kịch bản.
6
+
7
+ | | Tạo | Bù | Đổi |
8
+ |---|---|---|---|
9
+ | **Gõ** | `/bdd UC-001` | `/bdd UC-001` | `/bdd UC-001 change <mô tả>` |
10
+ | **Khi nào** | Chưa có BDD cho UC này | Đã có BDD, PRD vừa đổi | Kịch bản có nhưng **chưa đủ ý** |
11
+ | **Ai** | PO / BA | PO / BA | PO / BA, hoặc QC / dev báo thiếu |
12
+ | **Cần có trước** | PRD `approved`, có dòng **Nền tảng** | như bên trái | BDD đã có |
13
+ | **Số lượt** | 2 | 2 | 2 |
14
+ | **Ghi ra** | `specs/{domain}/{slug}/bdd/UC-001.feature` | cùng file, version tăng | cùng file, version tăng |
15
+
16
+ ---
17
+
18
+ ## Tạo: `/bdd UC-001`
19
+
20
+ AI chỉ đọc **đúng phần PRD cần cho UC này**: Tổng quan, các hành trình có UC, các dòng Màn hình, khối UC, và các BR của UC khác mà UC này trỏ tới. Với UC-001 của LMS, phần này khoảng 15 KB, trong khi cả PRD là 91 KB.
21
+
22
+ **Lượt 1: dàn ý.** AI trình ba bảng, chưa viết Given/When/Then. Ví dụ minh hoạ, dựng từ UC-001 của LMS:
23
+
24
+ | Mã | Kịch bản | Loại | Nền tảng | Phủ |
25
+ |---|---|---|---|---|
26
+ | UC-001-SC01 | Import có dòng trùng email với tài khoản đã có | happy | web | AC01 · BR04 |
27
+ | UC-001-SC02 | Username không hợp lệ ("@", có dấu, khoảng trắng) | negative | web | AC07 · BR11 |
28
+
29
+ - **Bảng nhánh**: các BR có nhiều nhánh, mỗi nhánh ứng với kịch bản nào. Bạn soát xem có nhánh nào bị sót không.
30
+ - **Điểm giao nhận** với UC khác, lấy từ User flow. Ví dụ *"→ UC-003: người dùng nhận email có link đặt mật khẩu"*. Lỗi ở chỗ nối giữa các UC hay bị phát hiện muộn nhất, nên phải viết rõ.
31
+
32
+ Bạn đồng ý, hoặc sửa: *"tách SC02 làm hai"*, *"thiếu nhánh email trống"*.
33
+
34
+ **Lượt 2: ghi và duyệt.**
35
+ 1. AI ghi cả file trong một lần.
36
+ 2. Công cụ **kiểm độ phủ**: mọi AC và BR của UC đều phải có mặt trong ít nhất một kịch bản. Thiếu thì AI bổ sung, không được tự bỏ.
37
+ 3. AI chỉ in các mục 🤖, tức những chỗ phải giả định vì PRD chưa ghi, ví dụ câu báo lỗi. Bạn xác nhận theo mã: *"OK UC-001-SC02"*.
38
+ 4. AI hỏi *"Ai duyệt BDD này?"* rồi đặt `status: approved`.
39
+
40
+ ## File BDD trông như thế nào
41
+
42
+ ```gherkin
43
+ # ── Import file ──
44
+ @UC-001-SC01 @web @happy @UC-001-AC01 @UC-001-BR04
45
+ Scenario: Import có dòng trùng email với tài khoản đã có
46
+ Given đã có tài khoản nhân sự với email "an@edupia.vn"
47
+ When Admin import file 10 dòng, trong đó 2 dòng dùng email "an@edupia.vn"
48
+ Then 8 tài khoản được tạo
49
+ And 2 dòng được báo lỗi kèm lý do
50
+ ```
51
+
52
+ Dòng `@…` là **tag**. Mỗi kịch bản có đủ bốn loại tag:
53
+
54
+ | Tag | Nghĩa |
55
+ |---|---|
56
+ | `@UC-001-SC01` | Mã kịch bản. Không bao giờ đổi. Code và test trỏ về kịch bản bằng mã này |
57
+ | `@web` `@app` | Nền tảng. Hành vi giống nhau thì một kịch bản mang cả hai tag. Hành vi khác nhau thì tách thành hai kịch bản |
58
+ | `@happy` `@alternative` `@edge` `@negative` | Loại: thành công · luồng khác vẫn thành công · biên, giới hạn · bị từ chối, lỗi |
59
+ | `@UC-001-AC01` `@UC-001-BR04` | AC và BR mà kịch bản này kiểm |
60
+
61
+ Các biến thể của cùng một luật được gộp thành **`Scenario Outline`** kèm bảng `Examples`, ví dụ ba kiểu username không hợp lệ nằm trong một bảng. Giá trị biên ghi trong BR phải có cả hai phía: 1.000 dòng được nhận, 1.001 dòng bị từ chối.
62
+
63
+ ## Nền tảng
64
+
65
+ PRD khai nền tảng ở Tổng quan, ví dụ `- **Nền tảng:** web · app`. UC nào chạy khác thì ghi dòng riêng trong UC. **Thiếu dòng này thì PRD không duyệt được, và `/bdd` dừng.** PRD tạo bằng bản trước 0.10.0 chưa có dòng này, nên phải chạy `/prd EP-01 change khai nền tảng: web` trước.
66
+
67
+ Khác nhau chỉ ở giao diện (bố cục, cử chỉ) thì **không** tách kịch bản, vì đó là việc của design-spec. Chỉ tách khi **kết quả** khác nhau.
68
+
69
+ ---
70
+
71
+ ## Bù: `/bdd UC-001` khi đã có file
72
+
73
+ Dùng sau khi PRD đổi (`/prd EP-01 change`, refine, rồi duyệt lại). Công cụ tự tìm ra:
74
+ - AC hoặc BR **chưa có kịch bản** nào;
75
+ - kịch bản trỏ tới mục **đã bỏ** trong PRD;
76
+ - các mục đổi nội dung kể từ version PRD mà BDD viết theo (đọc từ Lịch sử thay đổi của PRD).
77
+
78
+ AI trình kế hoạch *thêm · sửa · bỏ* theo mã, bạn duyệt rồi AI áp. Không có gì để bù thì AI báo *"BDD đã khớp PRD"* và dừng.
79
+
80
+ ## Đổi: `/bdd UC-001 change <mô tả>`
81
+
82
+ Dùng khi kịch bản **có rồi nhưng chưa đủ ý**, và công cụ không tự bắt được. Ví dụ:
83
+
84
+ ```
85
+ /bdd UC-001 change BR01 mới có kịch bản email đã thuộc người khác, thiếu nhánh email trống và sai định dạng
86
+ ```
87
+
88
+ Nếu điều bạn mô tả **chưa có trong PRD**, thì đó là thay đổi yêu cầu. AI sẽ từ chối và chỉ sang `/prd EP-01 change …`, vì kịch bản không được có điều PRD không ghi.
89
+
90
+ ## Lưu ý
91
+
92
+ - **Mã không bao giờ đổi.** Kịch bản bỏ đi vẫn còn một dòng `# Đã bỏ (v1.1) @UC-001-SC05 — …` trong file, và số đó không bị dùng lại.
93
+ - **Kịch bản E2E** đi qua nhiều UC (các hành trình J1, J2… trong User flow) do QC làm, không nằm trong `/bdd`.
94
+ - Đổi BDD đã `approved` thì file quay về `draft` và phải duyệt lại. BDD chỉ duyệt được khi viết theo **đúng version PRD hiện tại**.
@@ -11,7 +11,7 @@
11
11
  | **Cần có trước** | Epic `ready` (xem [/product](product.md)) | PRD đã có |
12
12
  | **Số lượt** | 2 | 2 |
13
13
  | **Ghi ra** | `specs/{domain}/{slug}/prd.md` · epic chuyển `handed-off` | `prd.md`, version tăng (1.0 → 1.1) |
14
- | **Bước tiếp** | [`/prd EP-01 refine`](prd-refine.md) → duyệt PRD → `/bdd UC-xxx` *(sắp có)* | [`/prd EP-01 refine`](prd-refine.md) (chỉ rà phần vừa đổi) → duyệt lại |
14
+ | **Bước tiếp** | [`/prd EP-01 refine`](prd-refine.md) → duyệt PRD → [`/bdd UC-xxx`](bdd.md) | [`/prd EP-01 refine`](prd-refine.md) (chỉ rà phần vừa đổi) → duyệt lại → [`/bdd UC-xxx`](bdd.md) để bù |
15
15
 
16
16
  ---
17
17
 
@@ -51,7 +51,7 @@ Acceptance Criteria (điều kiện nghiệm thu)
51
51
  - UC-001-AC01. Khi Admin import file 10 dòng, trong đó 2 dòng trùng email thì 8 tài khoản được tạo, 2 dòng được báo lỗi kèm lý do. (nguồn: AC1)
52
52
  ```
53
53
 
54
- Gồm 6 mục: **Tổng quan** (mục tiêu, actor, phạm vi, ràng buộc áp dụng) · **User flow** · **Use case** · **Màn hình** · **Câu hỏi còn mở** · **Lịch sử thay đổi**.
54
+ Gồm 6 mục: **Tổng quan** (mục tiêu, actor, **nền tảng**, phạm vi, ràng buộc áp dụng) · **User flow** · **Use case** · **Màn hình** · **Câu hỏi còn mở** · **Lịch sử thay đổi**.
55
55
 
56
56
  **User flow** là các **hành trình** xuyên suốt nhiều UC: actor đi qua những UC nào, rẽ nhánh ở đâu, gặp lỗi thì đi đâu. Mỗi hành trình gồm một dòng trong bảng và một sơ đồ (GitLab hiển thị sẵn):
57
57
 
@@ -91,6 +91,7 @@ Dùng cho **mọi** thay đổi: thêm, sửa, bỏ.
91
91
 
92
92
  ## Lưu ý
93
93
 
94
+ - **Nền tảng** (`web`, `app`…) ghi ở Tổng quan và là mặc định cho mọi UC. UC nào chạy khác thì ghi dòng riêng trong UC. Thiếu dòng này thì PRD không duyệt được, vì BDD cần nó để tách kịch bản theo nền tảng. PRD tạo bằng bản trước 0.10.0: `/prd EP-01 change khai nền tảng: web`.
94
95
  - **Bạn được tự sửa tay PRD.** Nhưng giữ nguyên mã, dấu ✅ / 🤖 và đoạn `<!-- sec:… -->`. Sửa nhiều thì nên dùng `change`, để AI tìm giúp các mục bị kéo theo.
95
96
  - **Không sửa epic sau khi đã có PRD.** Epic lúc này chỉ còn là lịch sử.
96
97
  - PRD tạo bằng bản framework cũ (trước 0.6.1) có thể còn ghi nguồn bằng lời, ví dụ *"(nguồn: PO chốt khi viết PRD)"*. Lần sửa đầu tiên AI sẽ được yêu cầu đổi các chỗ đó thành mã, thường là `PRD`.
@@ -7,9 +7,9 @@
7
7
  ## Đường đi của bạn
8
8
 
9
9
  ```
10
- /product ──► /product EP-xx ──► /prd EP-xx ──► /prd EP-xx refine ──► duyệt PRD ──► (giao cho BDD — sắp có)
11
- ▲ │
12
- └─ /prd EP-xx change ◄┘ khi yêu cầu thay đổi
10
+ /product ──► /product EP-xx ──► /prd EP-xx ──► /prd EP-xx refine ──► duyệt PRD ──► /bdd UC-xxx ──► duyệt BDD
11
+ ▲ │ (từng UC)
12
+ └─ /prd EP-xx change ◄┘ khi yêu cầu thay đổi, rồi /bdd UC-xxx để bù
13
13
  ```
14
14
 
15
15
  | Bước | Lệnh | Bạn làm gì | Hướng dẫn |
@@ -18,7 +18,8 @@
18
18
  | 2 | `/product EP-xx` | Trả lời AI hỏi về tính năng. Đây là chỗ **quan trọng nhất**: câu trả lời càng rõ thì PRD càng ít phải sửa | [/product](../lenh/product.md#một-epic-product-ep-01) |
19
19
  | 3 | `/prd EP-xx` | Duyệt cách chia UC, xác nhận các mục 🤖 | [/prd](../lenh/prd.md) |
20
20
  | 4 | `/prd EP-xx refine` | Quyết từng finding: nhận, sửa, bác hay hoãn. Tối đa 2 lượt. Xong thì duyệt PRD | [/prd refine](../lenh/prd-refine.md) |
21
- | 5 | `/prd EP-xx change …` | Khi yêu cầu đổi. Duyệt kế hoạch thay đổi, refine lại phần vừa đổi, rồi duyệt lại PRD | [/prd](../lenh/prd.md#đổi-prd-prd-ep-01-change-mô-tả) |
21
+ | 5 | `/bdd UC-xxx` | Với từng UC: duyệt dàn ý kịch bản (soát xem có sót nhánh nào không), xác nhận các mục 🤖, duyệt BDD | [/bdd](../lenh/bdd.md) |
22
+ | 6 | `/prd EP-xx change …` | Khi yêu cầu đổi. Duyệt kế hoạch thay đổi, refine lại phần vừa đổi, duyệt lại PRD, rồi `/bdd UC-xxx` để bù | [/prd](../lenh/prd.md#đổi-prd-prd-ep-01-change-mô-tả) |
22
23
 
23
24
  ## Cách làm thường gặp
24
25
 
@@ -20,6 +20,7 @@
20
20
  | AI chạy lại cùng một lệnh `spec_edit` | Lần trước Python thoát mà không chạy (thường gặp với bản Store) | Bình thường, AI được dặn chạy lại một lần |
21
21
  | `không đặt được status=approved: còn 3 dòng 🤖` | Còn mục chưa được bạn xác nhận | Xác nhận các mục AI liệt kê |
22
22
  | `… chưa có approved_by` | Chưa ghi người duyệt | Trả lời câu *"Ai duyệt?"* |
23
+ | `⚠ PRD 89 KB (ngưỡng 60 KB) …` | PRD lớn, mọi bước sau đều nạp toàn bộ | Không chặn. Cân nhắc tách epic. Epic mới thì nên tách từ bước `/product` |
23
24
  | `PRD chưa có mục User flow` | PRD tạo bằng bản trước 0.8.0 | Chạy `/prd EP-xx change thêm User flow` |
24
25
  | `UC chưa có mặt trong hành trình nào của User flow: UC-007` | Có UC chưa được vẽ vào sơ đồ nào | AI sẽ bổ sung. Hoặc chạy `/prd EP-xx change thêm UC-007 vào user flow` |
25
26
  | `… bản v1.2 chưa refine` | PRD chưa được rà nội dung ở version này | Chạy `/prd EP-xx refine` |
@@ -27,6 +28,10 @@
27
28
  | `Bản v1.1 đã refine xong` | Gọi refine lại khi PRD chưa đổi | Không cần làm gì. Thật sự muốn rà lại từ đầu thì thêm `--full` |
28
29
  | `chưa được PRD dùng tới: BR7, AC12` | Có BR hoặc AC của epic chưa được đưa vào PRD | AI sẽ bổ sung. Nếu bạn muốn bỏ thì nói rõ |
29
30
  | `(nguồn: …) chỉ được ghi mã …` | PRD đang ghi nguồn bằng lời (thường là PRD tạo bằng bản trước 0.6.1) | AI sẽ đổi thành mã, thường là `PRD` |
31
+ | `chưa khai Nền tảng cho UC-001, UC-002` | PRD chưa có dòng Nền tảng (thường là PRD tạo bằng bản trước 0.10.0) | Chạy `/prd EP-xx change khai nền tảng: web` (hoặc `web · app`) |
32
+ | `AC/BR của UC-001 chưa có kịch bản nào: …` | BDD còn sót AC hoặc BR | AI sẽ bổ sung. Đã duyệt BDD rồi mà PRD mới thêm mục thì chạy `/bdd UC-001` để bù |
33
+ | `@UC-001-BR08 đã bỏ trong PRD` | Kịch bản trỏ tới mục PRD vừa bỏ | Chạy `/bdd UC-001`: AI đề xuất sửa hoặc bỏ kịch bản đó |
34
+ | `⚠ PRD đã ở v1.6, BDD viết theo v1.5` | PRD đổi sau khi viết BDD | Chạy `/bdd UC-xxx` để bù. BDD chỉ duyệt được khi viết theo đúng version PRD hiện tại |
30
35
  | `💡 Phiên này đã dài. Nên /clear …` | Phiên đang mang theo hội thoại cũ | Gõ `/clear` rồi gọi lại lệnh |
31
36
  | `EP-xx chưa làm rõ xong. Chạy /product EP-xx trước` | Epic chưa `ready` | Chạy tiếp `/product EP-xx`. Thật sự cần PRD sớm thì thêm `--force`, PRD sẽ được ghi chú là tạo khi epic chưa xong |
32
37
  | `PRD đã có …` | Gọi `/prd EP-xx` khi PRD đã tồn tại | Rà nội dung: `/prd EP-xx refine` · Đổi: `/prd EP-xx change <mô tả>` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@educa-corp/fw",
3
- "version": "0.8.1",
3
+ "version": "0.10.0",
4
4
  "description": "Framework làm việc với Claude Code cho phòng PTPM",
5
5
  "bin": {
6
6
  "fw": "bin/fw.js"
@@ -0,0 +1,47 @@
1
+ # /bdd — chế độ bù và chế độ đổi
2
+
3
+ Cả hai chế độ đều sửa **theo mã**: không đánh số lại, mã đã bỏ không dùng lại. Chỉ viết khối mới, không chép khối cũ.
4
+
5
+ ## Bù — `/bdd UC-xxx` khi đã có file
6
+
7
+ Mục đích: đưa BDD theo kịp PRD. Ví dụ PRD vừa qua `/prd change`, hoặc có AC/BR chưa có kịch bản.
8
+
9
+ 1. Chạy `SE bddcheck F`. Ghi lại:
10
+ - **lỗi**: AC/BR chưa có kịch bản, tag trỏ tới mục đã bỏ hoặc không có;
11
+ - **cảnh báo** *"PRD đã ở v…, BDD viết theo v…"*.
12
+ 2. Có cảnh báo version thì đọc `SE section D history`. Lấy các dòng có version **lớn hơn** `prd_version` của `F`, rồi lọc ra những mục **thuộc UC này** (mã UC, BR, AC nêu trong dòng). Đây là các mục đã **đổi nội dung**, mà `bddcheck` không tự biết được. Dòng chỉ ghi mã finding thì đọc `SE finding {thư mục của D}/review/prd-refine.md F…` để biết mục nào đổi.
13
+ 3. Không có lỗi, cũng không có mục nào đổi: báo *"BDD của UC-xxx đã khớp PRD v…: {dòng số liệu}. Muốn thêm hoặc sửa kịch bản: `/bdd UC-xxx change <mô tả>`."*, rồi sang Bước 4 của lệnh.
14
+ 4. Đọc các kịch bản liên quan bằng `SE scenario F <mã AC/BR>`, lệnh này in mọi kịch bản gắn mã đó. Cùng lúc chỉ cần đọc đúng mục PRD trong kết quả `SE context`.
15
+ 5. Lập **kế hoạch**, rồi sang phần **Áp**.
16
+
17
+ ## Đổi — `/bdd UC-xxx change <mô tả>`
18
+
19
+ Mục đích: kịch bản **có rồi nhưng chưa đủ ý**, mà script không bắt được. Ví dụ BR có 3 nhánh nhưng chỉ có kịch bản cho 1 nhánh. Thường do PO, dev hoặc QC phát hiện.
20
+
21
+ 1. Lấy mô tả từ `$ARGUMENTS`. Không có mô tả thì hỏi *"Bạn muốn thêm, sửa hay bỏ kịch bản nào?"* rồi dừng.
22
+ 2. Đối chiếu mô tả với kết quả `SE context`:
23
+ - Hành vi **đã có** trong một AC/BR của UC: lập kế hoạch, rồi sang phần **Áp**.
24
+ - Hành vi **chưa có** trong AC/BR nào, hoặc **trái** với PRD: **từ chối**. Báo *"Điều này chưa có trong PRD (gần nhất là {mã}: …). Đây là thay đổi yêu cầu: chạy `/prd EP-xx change …` trước, rồi `/bdd UC-xxx` để bù."*, rồi dừng.
25
+
26
+ ## Kế hoạch (chung cho bù và đổi)
27
+
28
+ | Mã | Loại | Vì sao | Hiện tại → Sẽ thành |
29
+ |---|---|---|---|
30
+ | UC-001-SC04 | sửa | UC-001-BR14 đổi 1.000 → 2.000 dòng (v1.6) | 1.001 dòng bị từ chối → 2.001 dòng bị từ chối |
31
+ | UC-001-SC15 | thêm | UC-001-AC10 mới (v1.6) | — → Import file có dòng thiếu họ tên |
32
+ | UC-001-SC09 | bỏ | UC-001-BR08 đã bỏ (v1.6) | ~~Username Admin đặt bị trùng~~ |
33
+
34
+ Mỗi ô "Sẽ thành" chỉ một dòng, không viết Given/When/Then. Kèm tối đa 4 câu hỏi, chỉ khi cần.
35
+
36
+ ## Áp
37
+
38
+ Khi PO đồng ý kế hoạch:
39
+
40
+ 1. Lấy mã cho kịch bản mới bằng `SE next-sc F`, rồi tăng dần.
41
+ 2. Áp mọi thay đổi bằng **một** lần `SE sc F`:
42
+ - `{"id": mã, "new": khối}`: thay cả khối, giữ nguyên mã;
43
+ - `{"after": mã | "end", "new": khối}`: thêm sau một kịch bản, hoặc cuối file;
44
+ - `{"remove": mã, "version": "<version mới>"}`: bỏ, để lại dòng `# Đã bỏ (v…)`.
45
+ 3. Chạy `SE bddcheck F` cho tới khi sạch.
46
+ 4. Tăng version phụ (1.0 → 1.1) và đặt lại header trong **một** lệnh: `SE set F version=… prd_version=<version PRD> updated=…`. Nếu `F` đang `approved` thì đặt luôn `status=draft approved_by=— approved_at=—`.
47
+ 5. Báo lại cho PO. Không in lại cả file, chỉ tóm tắt những gì đã đổi. Không còn `🤖` thì hỏi *"Duyệt lại bản v1.1 không?"*. PO đồng ý thì duyệt theo luật 5 (Duyệt) trong Bước 3 của lệnh.
package/ref/bdd/new.md ADDED
@@ -0,0 +1,39 @@
1
+ # /bdd — chế độ tạo
2
+
3
+ Chỉ **2 lượt** hỏi-đáp. PRD đã được duyệt và refine, nên không hỏi lại những gì PRD đã ghi rõ.
4
+
5
+ ## Lượt 1 — Dàn ý
6
+
7
+ 1. Từ kết quả `SE context`, liệt kê mọi AC và BR **còn dùng** của UC. Với từng BR, tách các nhánh trong cột Business Logic (luật 2.1 trong `writing.md`).
8
+ 2. Lập dàn ý theo `writing.md`. Mã bắt đầu từ `UC-NNN-SC01`, tăng dần theo thứ tự trong file. Gom theo chủ đề nghiệp vụ.
9
+ 3. Trình cho PO **ba phần**, không trình nội dung Given/When/Then:
10
+
11
+ **a. Dàn ý**
12
+
13
+ | Mã | Kịch bản | Loại | Nền tảng | Phủ |
14
+ |---|---|---|---|---|
15
+ | UC-001-SC01 | Import có dòng trùng email với tài khoản đã có | happy | web | AC01 · BR04 |
16
+ | UC-001-SC02 | Username không hợp lệ (Outline: "@", có dấu, khoảng trắng) | negative | web | AC07 · BR11 |
17
+
18
+ **b. Nhánh.** Chỉ liệt kê các BR có từ 2 nhánh trở lên, để PO soát xem có sót nhánh nào không:
19
+
20
+ | BR | Nhánh | Kịch bản |
21
+ |---|---|---|
22
+ | UC-001-BR01 | Email trống · sai định dạng | SC03 (dòng 1, 2) |
23
+ | | Đã thuộc nhân sự khác | SC04 |
24
+
25
+ **c. Điểm giao nhận** với UC khác, lấy từ User flow. Mỗi điểm một dòng, ví dụ *"→ UC-003: người dùng nhận email có link đặt mật khẩu (Then của SC06)"*.
26
+
27
+ Kèm tối đa 4 câu hỏi, chỉ khi cần. Ví dụ: BR không tìm được kịch bản nào, điều phải giả định vì PRD chưa ghi, chỗ PRD mơ hồ. Không có gì cần hỏi thì chỉ hỏi *"Dàn ý này được chưa?"*.
28
+
29
+ ## Lượt 2 — Ghi file
30
+
31
+ Khi PO đồng ý dàn ý (có chỉnh thì làm theo chỉnh):
32
+
33
+ 1. Tạo `F` bằng **một** lần `SE create`, theo khuôn `.fw/core/templates/bdd.feature`:
34
+ - Header: `prd_version` = version PRD đang có (dòng đầu của `SE context`), `version: 1.0`, `status: draft`.
35
+ - Thay các chỗ `{…}` trong dòng comment hướng dẫn của khuôn bằng mã UC thật.
36
+ - Chỗ AI giả định thì thêm dòng `# 🤖 UC-NNN-SCnn: …` ngay trên tag (luật 1.6 trong `writing.md`).
37
+ 2. Chạy `SE bddcheck F`. Có lỗi thì sửa bằng **một** lần `SE sc F` (thay hoặc thêm theo mã), rồi chạy lại cho tới khi sạch. **Không được tự bỏ tag AC/BR để qua kiểm.** BR nào không viết được kịch bản thì hỏi PO.
38
+ 3. Chạy `SE pending F`. **Chỉ trình các mục `🤖`** và dòng số liệu của `bddcheck`, không in lại cả file. Nhắc PO: *"Mở file để đọc toàn bộ. Xác nhận theo mã, ví dụ 'OK UC-001-SC07', hoặc sửa, ví dụ 'SC07: câu báo là …'."*
39
+ 4. PO xác nhận thì chạy `SE confirm F <mã…>`. PO sửa thì thay khối bằng `SE sc F` và bỏ dòng `🤖` của kịch bản đó. Không còn `🤖` thì duyệt theo luật 5 (Duyệt) trong Bước 3 của lệnh.