@educa-corp/sdd-framework 0.9.3 → 0.9.4
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/build.js +11 -0
- package/bin/qc-base-map.json +119 -49
- package/bin/self-check.js +30 -0
- package/core/FRAMEWORK_VERSION +1 -1
- package/core/commands/qc-analyze.md +6 -119
- package/core/commands/qc-design-test.md +123 -143
- package/core/commands/qc-plan.md +6 -119
- package/core/commands/qc-review.md +59 -125
- package/core/commands/qc-run-test.md +6 -119
- package/core/commands/setup-ai-first.md +5 -5
- package/core/commands/update-framework.md +1 -1
- package/core/commands/validate-traces.md +1 -1
- package/core/rules/workflow.md +1 -1
- package/core/skills/qc/qa-analyst/DOC_GAP.template.md +1 -1
- package/core/skills/qc/qa-analyst/spec-breakdown.md +2 -2
- package/core/skills/qc/qa-designer/api/auth-chain.md +155 -0
- package/core/skills/qc/qa-designer/api/auth-sequence.md +75 -0
- package/core/skills/qc/qa-designer/api/common-headers.md +61 -0
- package/core/skills/qc/qa-designer/api/crud-sequence.md +122 -0
- package/core/skills/qc/qa-designer/api/endpoint.md +231 -0
- package/core/skills/qc/qa-designer/api/http-status-codes.md +102 -0
- package/core/skills/qc/qa-designer/e2e/journey.md +13 -8
- package/core/skills/qc/qa-designer/exploratory/charter.md +2 -0
- package/core/skills/qc/qa-designer/exploratory/explore-to-functional.md +7 -4
- package/core/skills/qc/qa-designer/functional/api.md +87 -18
- package/core/skills/qc/qa-designer/functional/gui-feature.md +12 -9
- package/core/skills/qc/qa-designer/functional/gui-screen.md +12 -10
- package/core/skills/qc/qa-designer/integration/api.md +12 -5
- package/core/skills/qc/qa-designer/integration/db.md +12 -6
- package/core/skills/qc/qa-designer/integration/gui.md +12 -5
- package/core/skills/qc/qa-designer/integration/kafka.md +12 -5
- package/core/skills/qc/qa-designer/non-functional.md +12 -5
- package/core/skills/qc/qa-designer/shared/action-keywords-glossary.md +91 -0
- package/core/skills/qc/qa-designer/shared/duplicate-check-procedure.md +105 -0
- package/core/skills/qc/qa-designer/shared/implicit-scenarios.md +22 -0
- package/core/skills/qc/qa-designer/shared/precision-rules.md +198 -0
- package/core/skills/qc/qa-designer/shared/read-doc-gap-inputs.md +25 -0
- package/core/skills/qc/qa-designer/shared/skill-decision-tree.md +93 -0
- package/core/skills/qc/qa-designer/shared/tc-metadata-format.md +243 -0
- package/core/skills/qc/qa-planner/risk-model.md +1 -1
- package/core/skills/qc/qa-reviewer/script/e2e.md +9 -1
- package/core/skills/qc/qa-reviewer/script/exploratory.md +9 -1
- package/core/skills/qc/qa-reviewer/script/functional.md +9 -1
- package/core/skills/qc/qa-reviewer/script/integration.md +9 -1
- package/core/skills/qc/qa-reviewer/script/non-functional.md +9 -1
- package/core/skills/qc/qa-reviewer/shared/read-doc-gap-inputs.md +26 -0
- package/core/skills/qc/qa-reviewer/shared/review-check-groups.md +207 -0
- package/core/skills/qc/qa-reviewer/shared/review-file-template.md +228 -0
- package/core/skills/qc/qa-reviewer/test-case/e2e.md +71 -13
- package/core/skills/qc/qa-reviewer/test-case/exploratory.md +53 -4
- package/core/skills/qc/qa-reviewer/test-case/functional.md +63 -15
- package/core/skills/qc/qa-reviewer/test-case/integration.md +64 -12
- package/core/skills/qc/qa-reviewer/test-case/non-functional.md +72 -13
- package/core/skills/qc/qa-runner/e2e.md +1 -1
- package/docs/02-concepts/pipeline-steps/09-validate-traces.md +1 -1
- package/docs/04-reference/trace-schema.md +1 -1
- package/docs/explain/00-setup-ai-first.md +1 -1
- package/docs/plans/qc-implementation-log.md +145 -3
- package/package.json +1 -1
|
@@ -174,126 +174,13 @@ placeholder bên dưới sẽ rỗng và lệnh sẽ đọc/ghi sai chỗ.
|
|
|
174
174
|
|
|
175
175
|
## Phạm vi QC
|
|
176
176
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
**Chạy TRƯỚC phần logic riêng của lệnh, và SAU `steps/gate.md`.** Bước này chốt bốn thứ mà
|
|
180
|
-
cả 6 trạm QC đều cần, để chúng không tự suy mỗi trạm một kiểu:
|
|
181
|
-
|
|
182
|
-
| Biến | Là gì |
|
|
183
|
-
|---|---|
|
|
184
|
-
| `TICKET-ID` | mã PRD — **thư mục artifact QC mang tên này** |
|
|
185
|
-
| `active_platform` | `web` \| `app` \| `system` \| … — một QC pass khoá đúng MỘT nền |
|
|
186
|
-
| `qc_artifact_dir` | `{paths.qc_dir}/{TICKET-ID}/{active_platform}/` |
|
|
187
|
-
| `uc_list` | các UC của (PRD × nền) này, kèm trạng thái BDD từng UC |
|
|
188
|
-
|
|
189
|
-
> **Vì sao gom về một chỗ.** Luật phân giải nền từng được copy-paste ở 5 lệnh và câu chữ đã
|
|
190
|
-
> lệch nhau. Năm bản của một luật là nơi drift sống: sửa bốn, quên một, và trạm bị quên ghi
|
|
191
|
-
> artifact vào sai thư mục **trong im lặng**.
|
|
192
|
-
|
|
193
|
-
---
|
|
194
|
-
|
|
195
|
-
## 1 — `TICKET-ID`
|
|
196
|
-
|
|
197
|
-
Artifact QC gom theo **PRD**, không theo UC. Nên mọi trạm phải quy được về `TICKET-ID`:
|
|
198
|
-
|
|
199
|
-
| `$ARGUMENTS` là | Cách lấy |
|
|
200
|
-
|---|---|
|
|
201
|
-
| **UC-ID** (`{TICKET-ID}-UC{N}`) | phần **trước** `-UC` — đúng luật `steps/gate.md` Bước 1 dùng để tìm tech-doc gộp |
|
|
202
|
-
| **TICKET-ID** | dùng trực tiếp |
|
|
203
|
-
| một **path file** (`.feature` / PRD / design-spec) | phân giải `{domain}` + `{prd-slug}` theo luật `context-loader` Bước 1, rồi lấy `TICKET-ID` từ tên file PRD `{TICKET-ID}-{prd-slug}.md` — file `.md` duy nhất ở gốc feature folder |
|
|
204
|
-
|
|
205
|
-
Đối chiếu: `TICKET-ID` suy ra phải khớp tên file PRD thật. Lệch → **DỪNG**, in cả hai giá
|
|
206
|
-
trị. (Suy sai `TICKET-ID` là ghi cả một PRD vào sai thư mục — không có bước nào phía sau bắt được.)
|
|
207
|
-
|
|
208
|
-
---
|
|
209
|
-
|
|
210
|
-
## 2 — `active_platform`
|
|
211
|
-
|
|
212
|
-
> **PHẢI phân giải TRƯỚC mọi phép đọc `.feature`.** `{UC-ID}-SC{N}` chỉ độc nhất trong
|
|
213
|
-
> (UC × nền), nên một UC đa nền có **nhiều file `.feature`** — `bdd/web/`, `bdd/app/`,
|
|
214
|
-
> `bdd/system/` — và mỗi file mang `@trace.status` **riêng**: bản web có thể `approved`
|
|
215
|
-
> trong khi bản app còn `draft`. Đọc "file `.feature` của UC" khi chưa biết nền là đọc một
|
|
216
|
-
> file **bất kỳ trong ba**: báo `approved` trong khi bản đang dùng còn nháp, hoặc chặn oan
|
|
217
|
-
> một bản đã duyệt.
|
|
218
|
-
|
|
219
|
-
Theo thứ tự, dừng ở cái đầu tiên khớp:
|
|
220
|
-
|
|
221
|
-
1. `$ARGUMENTS` nêu nền (`web`/`app`/`system`/…) → dùng.
|
|
222
|
-
2. Target là một file `.feature` → đọc `# @trace.platform` của nó.
|
|
223
|
-
3. Glob `{paths.specs_dir}/{domain}/{prd-slug}/bdd/*/` — **đúng một** thư mục nền → dùng nó.
|
|
224
|
-
4. Glob `{paths.qc_dir}/{TICKET-ID}/*/` — **đúng một** thư mục nền đã có artifact → dùng nó.
|
|
225
|
-
*(chỉ dùng cho trạm 2–6; trạm `/qc-analyze` là trạm tạo ra thư mục đó nên không có gì để soi.)*
|
|
226
|
-
5. Nhiều nền mà không suy được → hỏi *"QC pass này cho nền nào? (web/app/system)"*.
|
|
227
|
-
**Có `--yes`:** không hỏi — DỪNG với lỗi rõ ràng, vì đoán bừa nền là ghi artifact vào sai
|
|
228
|
-
thư mục và ghi `qc_status` vào sai sổ trace:
|
|
229
|
-
```
|
|
230
|
-
❌ {TICKET-ID} có {n} nền ({list}) — không suy được nền nào cho QC pass này.
|
|
231
|
-
Chạy headless thì phải nêu tường minh: /{lệnh} {TICKET-ID} web --yes
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
Lưu `active_platform`. Từ đây, **mọi** phép đọc `.feature` chỉ đọc thư mục
|
|
235
|
-
`bdd/{active_platform}/` — không trộn SC chéo nền.
|
|
236
|
-
|
|
237
|
-
---
|
|
238
|
-
|
|
239
|
-
## 3 — `qc_artifact_dir`
|
|
240
|
-
|
|
241
|
-
```
|
|
242
|
-
qc_artifact_dir = {paths.qc_dir}/{TICKET-ID}/{active_platform}/
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
Chứa: `REQUIREMENT_ANALYSIS.md` · `DOC_GAP.md` · `TEST_PLAN.md` · `test-cases/*.Test.md`
|
|
246
|
-
— **mỗi loại đúng MỘT file cho cả PRD**, các UC là mục/hàng bên trong.
|
|
247
|
-
|
|
248
|
-
`{paths.qc_dir}` là folder top-level **nhìn thấy** trong repo QC (mặc định `docs/`, **không**
|
|
249
|
-
phải `.agent/` ẩn) để đội QC mở và xử lý output dễ dàng. Spec chính thức ở lại spec submodule
|
|
250
|
-
của PO — đừng ghi artifact QC vào đó.
|
|
251
|
-
|
|
252
|
-
> **Sổ trace KHÔNG theo layout này.** Nó vẫn là `{paths.trace_dir}/{domain}/{prd-slug}/{UC-ID}-{active_platform}.tsv`
|
|
253
|
-
> — một sổ cho mỗi (UC × nền), vì mỗi hàng là một scenario. Liên kết giữa hai bên đi qua
|
|
254
|
-
> **cột `UC`** của bảng gap, không qua đường dẫn file.
|
|
255
|
-
|
|
256
|
-
---
|
|
257
|
-
|
|
258
|
-
## 4 — `uc_list`
|
|
259
|
-
|
|
260
|
-
Glob `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{active_platform}/*.feature`. Mỗi file → một
|
|
261
|
-
UC: đọc `# @trace.id` (mã UC) và `# @trace.status` từ header.
|
|
262
|
-
|
|
263
|
-
Chia hai nhóm:
|
|
264
|
-
|
|
265
|
-
| Nhóm | Điều kiện | Xử lý |
|
|
266
|
-
|---|---|---|
|
|
267
|
-
| **Trong phạm vi** | `@trace.status: approved` | phân tích / thiết kế / chạy bình thường |
|
|
268
|
-
| **Chưa xét** | khác `approved` | **KHÔNG** phân tích; vẫn ghi một hàng vào bảng phạm vi kèm trạng thái thật |
|
|
269
|
-
|
|
270
|
-
In bảng phạm vi ra trước khi làm gì:
|
|
271
|
-
```
|
|
272
|
-
Phạm vi QC — {TICKET-ID} / {active_platform}
|
|
273
|
-
✅ {UC-ID} {tên UC} approved
|
|
274
|
-
⏸ {UC-ID} {tên UC} draft → chưa xét
|
|
275
|
-
→ {n} UC trong phạm vi · {m} chưa xét
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
**Cờ `--include-draft`:** phân tích cả UC chưa duyệt, nhưng **vẫn in bảng trên** và đánh dấu
|
|
279
|
-
trong artifact là dựa trên BDD nháp.
|
|
280
|
-
|
|
281
|
-
**Không UC nào `approved` và không có `--include-draft` → DỪNG:**
|
|
282
|
-
```
|
|
283
|
-
❌ {TICKET-ID} ({active_platform}): 0/{n} UC có BDD approved — không có gì để chạy.
|
|
284
|
-
Cách đúng: người duyệt đặt `# @trace.status: approved` rồi chạy lại.
|
|
285
|
-
Muốn chạy sớm trên BDD nháp (prototype): thêm --include-draft
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
> **Vì sao có `--include-draft` chứ không chặn cứng.** QC sớm trên BDD nháp là một cách dùng
|
|
289
|
-
> **cố ý được cho phép** từ trước (guard cũ là cảnh báo mềm, không phải chặn). Bỏ hẳn nó là
|
|
290
|
-
> lấy đi một năng lực đang có mà không ai khai. Còn để mặc định `approved`-only thì cái
|
|
291
|
-
> thường gặp là cái an toàn, và cái sớm phải nói ra.
|
|
292
|
-
|
|
293
|
-
> **Vì sao `--yes` không thay được `--include-draft`.** `--yes` nghĩa *"tôi không ngồi đây để
|
|
294
|
-
> trả lời"*; `--include-draft` nghĩa *"tôi biết BDD còn nháp và vẫn muốn chạy"*. Gộp hai cái
|
|
295
|
-
> là để một lần chạy headless âm thầm phân tích spec chưa chốt rồi bàn giao như thể đã chốt.
|
|
177
|
+
**BẮT BUỘC — đọc `.agent/steps/qc-scope.md` và thực thi TOÀN BỘ quy trình trong đó**,
|
|
178
|
+
rồi mới tiếp tục phần bên dưới.
|
|
296
179
|
|
|
180
|
+
Nó chốt bốn thứ mà mọi trạm QC đều cần: `TICKET-ID` · `active_platform` ·
|
|
181
|
+
`qc_artifact_dir` · `uc_list` (kèm trạng thái BDD từng UC, và cờ `--include-draft`).
|
|
182
|
+
Bỏ qua thì artifact QC ghi vào **sai thư mục** và `qc_status` ghi vào **sai sổ trace** —
|
|
183
|
+
cả hai đều xảy ra trong im lặng, không có bước nào phía sau bắt được.
|
|
297
184
|
|
|
298
185
|
> **Trạm này vẫn gọi theo TỪNG UC** *(B11)* — thiết kế và chạy test **thật sự** làm tăng dần
|
|
299
186
|
> theo UC, nên giữ khả năng làm UC1 khi UC3 chưa xong là đúng. Chỉ **chỗ đọc/ghi** đổi: mọi
|
|
@@ -318,16 +205,61 @@ tồn tại cho UC và mới hơn → review script. Nếu mơ hồ, hỏi.
|
|
|
318
205
|
|
|
319
206
|
## Skills (`{paths.qc_skills_dir}/qa-reviewer/`)
|
|
320
207
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
208
|
+
**Nạp trước — nhưng đúng vai:**
|
|
209
|
+
|
|
210
|
+
| File | Vai nào | Cho gì |
|
|
211
|
+
|---|---|---|
|
|
212
|
+
| `shared/read-doc-gap-inputs.md` | **cả hai** | Nạp **đủ** mọi tài liệu nguồn theo bảng *Tài liệu đầu vào đã đọc* của `DOC_GAP.md` — soát mù thì kết luận "0 lỗi" là vô nghĩa |
|
|
213
|
+
| `shared/review-file-template.md` | **cả hai** | Khuôn file kết quả · thang điểm `XX/100` · luật ghi file · nguyên tắc *mặc định hoài nghi* |
|
|
214
|
+
| ↳ §*Kiểm tra cấu trúc TC* của file đó | **chỉ vai 1** | Tầng kiểm các luật của trạm 3: ATOMIC 1-bullet · không ký tự `\|` · cụm từ mơ hồ · teardown đúng chỗ · marker ≠ oracle |
|
|
215
|
+
| `shared/review-check-groups.md` | **chỉ vai 1** | **7 nhóm kiểm tra** chạy tuần tự · registry 46 nhãn lỗi · **7 mẫu-hay-thiếu** của Nhóm 6 · nền tảng ISTQB · anti-pattern |
|
|
216
|
+
|
|
217
|
+
> ⚠️ **Vai 2 (soát code) KHÔNG nạp 7 nhóm kiểm tra.** Chúng kiểm **cấu trúc file test case** —
|
|
218
|
+
> áp vào file Python là bảo reviewer đi tìm `#### Expected Result` trong một Page Object, rồi
|
|
219
|
+
> gắn nhãn lỗi cho thứ đáng lẽ không có ở đó. Vai 2 dùng bộ tiêu chí riêng ở `script/*.md`.
|
|
220
|
+
|
|
221
|
+
**Rồi chọn theo vai + tầng, nạp MỘT file:**
|
|
222
|
+
- Soát test-case: `test-case/{functional,e2e,integration,non-functional,exploratory}.md`
|
|
223
|
+
- Soát script: `script/{functional,e2e,integration,non-functional,exploratory}.md`
|
|
324
224
|
|
|
325
225
|
## Review focus
|
|
326
226
|
|
|
327
227
|
- **Test-case:** mọi `{UC-ID}-SC{N}` đã phủ? happy + negative + boundary? expected cụ thể? trace (`BR-xx` + `@trace.verifies` SC) có mặt? không có TC orphan?
|
|
328
228
|
- **Script:** khớp `.Test.md` 1-1? Page Object 3 lớp + BasePage gọn? `expect()` không phải bare assert? không hard-code URL/cred/timeout, không `time.sleep`, không Allure? selector theo priority (data-testid→role→…)? 100% TC đã script (không còn Draft)?
|
|
329
229
|
|
|
330
|
-
Sinh findings (
|
|
230
|
+
Sinh findings (mức độ + vị trí + cách sửa), chấm điểm, ra verdict.
|
|
231
|
+
|
|
232
|
+
**KHÔNG tự sửa** file TC hay code. Chỉ nhận xét và chấm điểm — người sửa là `/qc-design-test`
|
|
233
|
+
(vai 1) hoặc `/qc-run-test` (vai 2). *Reviewer tự sửa rồi tự duyệt là bỏ mất cái cổng.*
|
|
234
|
+
|
|
235
|
+
## Output
|
|
236
|
+
|
|
237
|
+
Ghi vào **`{qc_artifact_dir}test-cases/REVIEW_<FEATURE>.md`** — đứng **cạnh** file TC vừa soát:
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
{qc_artifact_dir}test-cases/
|
|
241
|
+
├── TC_<FEATURE>.Test.md
|
|
242
|
+
├── REVIEW_<FEATURE>.md ← soát file trên
|
|
243
|
+
├── TC_<FEATURE>_API.Test.md
|
|
244
|
+
└── REVIEW_<FEATURE>_API.md ← soát file trên
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
⚠️ **Tên file review KHÔNG có đuôi `.Test.md`.** Đuôi đó là của file test case; gắn vào file
|
|
248
|
+
review sẽ làm `/qc-run-test` nhặt nó lên như một file test case rồi cố sinh script từ một bảng điểm.
|
|
249
|
+
|
|
250
|
+
Khuôn đầy đủ + quy tắc ghi: `shared/review-file-template.md`. Ba điều bắt buộc:
|
|
251
|
+
|
|
252
|
+
- **Điểm `XX/100`** — trừ 5đ mỗi `FAIL`, 2đ mỗi `WARN`. Verdict **suy ra được**:
|
|
253
|
+
`≥80` VÀ không còn `FAIL` chặn → `APPROVED`; ngược lại `NEEDS_FIX`.
|
|
254
|
+
- **Bảng Tổng quan THÊM một hàng mỗi vòng**, không ghi đè — đó là cách duy nhất thấy được điểm
|
|
255
|
+
có tăng không. Các bảng chi tiết thì ghi đè phần của tầng mình.
|
|
256
|
+
- **Hai vai ghi vào CÙNG một file**, phân biệt bằng cột `Tầng`. Chúng cách nhau một trạm, nên
|
|
257
|
+
hàng của vai sau **không được ghi đè** hàng của vai trước.
|
|
258
|
+
|
|
259
|
+
> **Vì sao cổng này phải ghi ra file** *(B13)*. Trước đây lệnh chỉ nói *"sinh findings"* — không
|
|
260
|
+
> nói ghi đâu, dạng gì, và điểm là `A/B/C/D` **không có luật chấm**. Hệ quả: hai người soát ra
|
|
261
|
+
> hai kết quả, và **vòng 2 không so được với vòng 1** — tức không ai biết sửa xong có tốt lên
|
|
262
|
+
> không. Một cổng không để lại dấu vết đo được thì không phải cổng, nó là một lượt đọc.
|
|
331
263
|
|
|
332
264
|
## Report
|
|
333
265
|
|
|
@@ -335,8 +267,10 @@ Sinh findings (severity + vị trí + fix). Verdict APPROVED hoặc NEEDS_FIX.
|
|
|
335
267
|
Output Artifacts · Next) cho report cuối, kèm khối bên dưới.
|
|
336
268
|
|
|
337
269
|
```
|
|
338
|
-
/qc-review Hoàn tất — {UC-ID} ({test-case | script}
|
|
339
|
-
|
|
270
|
+
/qc-review Hoàn tất — {UC-ID} ({soát test-case | soát script}) vòng #{N}
|
|
271
|
+
Điểm : {XX}/100 ({fail} FAIL × −5đ · {warn} WARN × −2đ){nếu có vòng trước: " ← vòng #{N-1}: {YY}/100"}
|
|
272
|
+
Verdict: {APPROVED | NEEDS_FIX} — {n} findings ({crit} chặn)
|
|
273
|
+
File : {qc_artifact_dir}test-cases/REVIEW_<FEATURE>.md (thêm 1 hàng vào bảng Tổng quan)
|
|
340
274
|
Next (test-case APPROVED): /qc-run-test {UC-ID}
|
|
341
275
|
Next (script APPROVED) : /qc-report {UC-ID} rồi tạo PR
|
|
342
276
|
(NEEDS_FIX → fix artifact bị gắn cờ, rồi chạy lại /qc-review {UC-ID})
|
|
@@ -174,126 +174,13 @@ placeholder bên dưới sẽ rỗng và lệnh sẽ đọc/ghi sai chỗ.
|
|
|
174
174
|
|
|
175
175
|
## Phạm vi QC
|
|
176
176
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
**Chạy TRƯỚC phần logic riêng của lệnh, và SAU `steps/gate.md`.** Bước này chốt bốn thứ mà
|
|
180
|
-
cả 6 trạm QC đều cần, để chúng không tự suy mỗi trạm một kiểu:
|
|
181
|
-
|
|
182
|
-
| Biến | Là gì |
|
|
183
|
-
|---|---|
|
|
184
|
-
| `TICKET-ID` | mã PRD — **thư mục artifact QC mang tên này** |
|
|
185
|
-
| `active_platform` | `web` \| `app` \| `system` \| … — một QC pass khoá đúng MỘT nền |
|
|
186
|
-
| `qc_artifact_dir` | `{paths.qc_dir}/{TICKET-ID}/{active_platform}/` |
|
|
187
|
-
| `uc_list` | các UC của (PRD × nền) này, kèm trạng thái BDD từng UC |
|
|
188
|
-
|
|
189
|
-
> **Vì sao gom về một chỗ.** Luật phân giải nền từng được copy-paste ở 5 lệnh và câu chữ đã
|
|
190
|
-
> lệch nhau. Năm bản của một luật là nơi drift sống: sửa bốn, quên một, và trạm bị quên ghi
|
|
191
|
-
> artifact vào sai thư mục **trong im lặng**.
|
|
192
|
-
|
|
193
|
-
---
|
|
194
|
-
|
|
195
|
-
## 1 — `TICKET-ID`
|
|
196
|
-
|
|
197
|
-
Artifact QC gom theo **PRD**, không theo UC. Nên mọi trạm phải quy được về `TICKET-ID`:
|
|
198
|
-
|
|
199
|
-
| `$ARGUMENTS` là | Cách lấy |
|
|
200
|
-
|---|---|
|
|
201
|
-
| **UC-ID** (`{TICKET-ID}-UC{N}`) | phần **trước** `-UC` — đúng luật `steps/gate.md` Bước 1 dùng để tìm tech-doc gộp |
|
|
202
|
-
| **TICKET-ID** | dùng trực tiếp |
|
|
203
|
-
| một **path file** (`.feature` / PRD / design-spec) | phân giải `{domain}` + `{prd-slug}` theo luật `context-loader` Bước 1, rồi lấy `TICKET-ID` từ tên file PRD `{TICKET-ID}-{prd-slug}.md` — file `.md` duy nhất ở gốc feature folder |
|
|
204
|
-
|
|
205
|
-
Đối chiếu: `TICKET-ID` suy ra phải khớp tên file PRD thật. Lệch → **DỪNG**, in cả hai giá
|
|
206
|
-
trị. (Suy sai `TICKET-ID` là ghi cả một PRD vào sai thư mục — không có bước nào phía sau bắt được.)
|
|
207
|
-
|
|
208
|
-
---
|
|
209
|
-
|
|
210
|
-
## 2 — `active_platform`
|
|
211
|
-
|
|
212
|
-
> **PHẢI phân giải TRƯỚC mọi phép đọc `.feature`.** `{UC-ID}-SC{N}` chỉ độc nhất trong
|
|
213
|
-
> (UC × nền), nên một UC đa nền có **nhiều file `.feature`** — `bdd/web/`, `bdd/app/`,
|
|
214
|
-
> `bdd/system/` — và mỗi file mang `@trace.status` **riêng**: bản web có thể `approved`
|
|
215
|
-
> trong khi bản app còn `draft`. Đọc "file `.feature` của UC" khi chưa biết nền là đọc một
|
|
216
|
-
> file **bất kỳ trong ba**: báo `approved` trong khi bản đang dùng còn nháp, hoặc chặn oan
|
|
217
|
-
> một bản đã duyệt.
|
|
218
|
-
|
|
219
|
-
Theo thứ tự, dừng ở cái đầu tiên khớp:
|
|
220
|
-
|
|
221
|
-
1. `$ARGUMENTS` nêu nền (`web`/`app`/`system`/…) → dùng.
|
|
222
|
-
2. Target là một file `.feature` → đọc `# @trace.platform` của nó.
|
|
223
|
-
3. Glob `{paths.specs_dir}/{domain}/{prd-slug}/bdd/*/` — **đúng một** thư mục nền → dùng nó.
|
|
224
|
-
4. Glob `{paths.qc_dir}/{TICKET-ID}/*/` — **đúng một** thư mục nền đã có artifact → dùng nó.
|
|
225
|
-
*(chỉ dùng cho trạm 2–6; trạm `/qc-analyze` là trạm tạo ra thư mục đó nên không có gì để soi.)*
|
|
226
|
-
5. Nhiều nền mà không suy được → hỏi *"QC pass này cho nền nào? (web/app/system)"*.
|
|
227
|
-
**Có `--yes`:** không hỏi — DỪNG với lỗi rõ ràng, vì đoán bừa nền là ghi artifact vào sai
|
|
228
|
-
thư mục và ghi `qc_status` vào sai sổ trace:
|
|
229
|
-
```
|
|
230
|
-
❌ {TICKET-ID} có {n} nền ({list}) — không suy được nền nào cho QC pass này.
|
|
231
|
-
Chạy headless thì phải nêu tường minh: /{lệnh} {TICKET-ID} web --yes
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
Lưu `active_platform`. Từ đây, **mọi** phép đọc `.feature` chỉ đọc thư mục
|
|
235
|
-
`bdd/{active_platform}/` — không trộn SC chéo nền.
|
|
236
|
-
|
|
237
|
-
---
|
|
238
|
-
|
|
239
|
-
## 3 — `qc_artifact_dir`
|
|
240
|
-
|
|
241
|
-
```
|
|
242
|
-
qc_artifact_dir = {paths.qc_dir}/{TICKET-ID}/{active_platform}/
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
Chứa: `REQUIREMENT_ANALYSIS.md` · `DOC_GAP.md` · `TEST_PLAN.md` · `test-cases/*.Test.md`
|
|
246
|
-
— **mỗi loại đúng MỘT file cho cả PRD**, các UC là mục/hàng bên trong.
|
|
247
|
-
|
|
248
|
-
`{paths.qc_dir}` là folder top-level **nhìn thấy** trong repo QC (mặc định `docs/`, **không**
|
|
249
|
-
phải `.agent/` ẩn) để đội QC mở và xử lý output dễ dàng. Spec chính thức ở lại spec submodule
|
|
250
|
-
của PO — đừng ghi artifact QC vào đó.
|
|
251
|
-
|
|
252
|
-
> **Sổ trace KHÔNG theo layout này.** Nó vẫn là `{paths.trace_dir}/{domain}/{prd-slug}/{UC-ID}-{active_platform}.tsv`
|
|
253
|
-
> — một sổ cho mỗi (UC × nền), vì mỗi hàng là một scenario. Liên kết giữa hai bên đi qua
|
|
254
|
-
> **cột `UC`** của bảng gap, không qua đường dẫn file.
|
|
255
|
-
|
|
256
|
-
---
|
|
257
|
-
|
|
258
|
-
## 4 — `uc_list`
|
|
259
|
-
|
|
260
|
-
Glob `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{active_platform}/*.feature`. Mỗi file → một
|
|
261
|
-
UC: đọc `# @trace.id` (mã UC) và `# @trace.status` từ header.
|
|
262
|
-
|
|
263
|
-
Chia hai nhóm:
|
|
264
|
-
|
|
265
|
-
| Nhóm | Điều kiện | Xử lý |
|
|
266
|
-
|---|---|---|
|
|
267
|
-
| **Trong phạm vi** | `@trace.status: approved` | phân tích / thiết kế / chạy bình thường |
|
|
268
|
-
| **Chưa xét** | khác `approved` | **KHÔNG** phân tích; vẫn ghi một hàng vào bảng phạm vi kèm trạng thái thật |
|
|
269
|
-
|
|
270
|
-
In bảng phạm vi ra trước khi làm gì:
|
|
271
|
-
```
|
|
272
|
-
Phạm vi QC — {TICKET-ID} / {active_platform}
|
|
273
|
-
✅ {UC-ID} {tên UC} approved
|
|
274
|
-
⏸ {UC-ID} {tên UC} draft → chưa xét
|
|
275
|
-
→ {n} UC trong phạm vi · {m} chưa xét
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
**Cờ `--include-draft`:** phân tích cả UC chưa duyệt, nhưng **vẫn in bảng trên** và đánh dấu
|
|
279
|
-
trong artifact là dựa trên BDD nháp.
|
|
280
|
-
|
|
281
|
-
**Không UC nào `approved` và không có `--include-draft` → DỪNG:**
|
|
282
|
-
```
|
|
283
|
-
❌ {TICKET-ID} ({active_platform}): 0/{n} UC có BDD approved — không có gì để chạy.
|
|
284
|
-
Cách đúng: người duyệt đặt `# @trace.status: approved` rồi chạy lại.
|
|
285
|
-
Muốn chạy sớm trên BDD nháp (prototype): thêm --include-draft
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
> **Vì sao có `--include-draft` chứ không chặn cứng.** QC sớm trên BDD nháp là một cách dùng
|
|
289
|
-
> **cố ý được cho phép** từ trước (guard cũ là cảnh báo mềm, không phải chặn). Bỏ hẳn nó là
|
|
290
|
-
> lấy đi một năng lực đang có mà không ai khai. Còn để mặc định `approved`-only thì cái
|
|
291
|
-
> thường gặp là cái an toàn, và cái sớm phải nói ra.
|
|
292
|
-
|
|
293
|
-
> **Vì sao `--yes` không thay được `--include-draft`.** `--yes` nghĩa *"tôi không ngồi đây để
|
|
294
|
-
> trả lời"*; `--include-draft` nghĩa *"tôi biết BDD còn nháp và vẫn muốn chạy"*. Gộp hai cái
|
|
295
|
-
> là để một lần chạy headless âm thầm phân tích spec chưa chốt rồi bàn giao như thể đã chốt.
|
|
177
|
+
**BẮT BUỘC — đọc `.agent/steps/qc-scope.md` và thực thi TOÀN BỘ quy trình trong đó**,
|
|
178
|
+
rồi mới tiếp tục phần bên dưới.
|
|
296
179
|
|
|
180
|
+
Nó chốt bốn thứ mà mọi trạm QC đều cần: `TICKET-ID` · `active_platform` ·
|
|
181
|
+
`qc_artifact_dir` · `uc_list` (kèm trạng thái BDD từng UC, và cờ `--include-draft`).
|
|
182
|
+
Bỏ qua thì artifact QC ghi vào **sai thư mục** và `qc_status` ghi vào **sai sổ trace** —
|
|
183
|
+
cả hai đều xảy ra trong im lặng, không có bước nào phía sau bắt được.
|
|
297
184
|
|
|
298
185
|
> **Trạm này vẫn gọi theo TỪNG UC** *(B11)* — thiết kế và chạy test **thật sự** làm tăng dần
|
|
299
186
|
> theo UC, nên giữ khả năng làm UC1 khi UC3 chưa xong là đúng. Chỉ **chỗ đọc/ghi** đổi: mọi
|
|
@@ -448,13 +448,13 @@ Hướng dẫn: "Mở `specs/domain-knowledge/core-entities.md` và định ngh
|
|
|
448
448
|
|
|
449
449
|
## Step 6 — Cài VS Code Extension (Khuyến nghị)
|
|
450
450
|
|
|
451
|
-
Khuyến nghị user cài extension VS Code **
|
|
451
|
+
Khuyến nghị user cài extension VS Code **SDD Board** — nó cung cấp panel Review Board + Living Documentation tích hợp với workflow này.
|
|
452
452
|
|
|
453
453
|
```bash
|
|
454
|
-
code --install-extension
|
|
454
|
+
code --install-extension EducaCorp.sdd-board
|
|
455
455
|
```
|
|
456
456
|
|
|
457
|
-
Hoặc: VS Code → `Ctrl+Shift+P` → **"Extensions: Install from Marketplace"** → tìm **
|
|
457
|
+
Hoặc: VS Code → `Ctrl+Shift+P` → **"Extensions: Install from Marketplace"** → tìm **SDD Board**.
|
|
458
458
|
|
|
459
459
|
**Nó làm gì:**
|
|
460
460
|
- 📋 **Review Board** — UI trực quan để review findings từ `/refine-prd`, `/review-context`, `/review-tech-docs`
|
|
@@ -557,7 +557,7 @@ Next:
|
|
|
557
557
|
4. Điền specs/domain-knowledge/core-entities.md
|
|
558
558
|
5. git add và commit 4 file đó
|
|
559
559
|
6. Cài VS Code extension:
|
|
560
|
-
code --install-extension
|
|
560
|
+
code --install-extension EducaCorp.sdd-board
|
|
561
561
|
7. /define-product để bắt đầu feature đầu tiên
|
|
562
562
|
```
|
|
563
563
|
|
|
@@ -591,7 +591,7 @@ Next:
|
|
|
591
591
|
3. Điền specs/domain-knowledge/core-entities.md ← entity glossary
|
|
592
592
|
4. git add và commit các file đó
|
|
593
593
|
5. Cài VS Code extension:
|
|
594
|
-
code --install-extension
|
|
594
|
+
code --install-extension EducaCorp.sdd-board
|
|
595
595
|
6. /define-product để bắt đầu feature đầu tiên
|
|
596
596
|
|
|
597
597
|
⚠️ Nhắc handoff team dev:
|
|
@@ -193,7 +193,7 @@ Your content was preserved:
|
|
|
193
193
|
Review & commit:
|
|
194
194
|
git diff .agent/
|
|
195
195
|
git add .agent/ .claude/commands/
|
|
196
|
-
git commit -m "chore: upgrade
|
|
196
|
+
git commit -m "chore: upgrade sdd-framework v{current} → v{latest}"
|
|
197
197
|
{umbrella mode: this is the umbrella root — service submodules need no framework update}
|
|
198
198
|
|
|
199
199
|
---
|
|
@@ -1223,7 +1223,7 @@ Schema:
|
|
|
1223
1223
|
- `test_classes`: dùng `[]` (không phải `"—"`) khi không có test class
|
|
1224
1224
|
- `tech_doc_revision` / `fe_tech_doc_revision`: dùng integer; `0` nếu chưa sinh
|
|
1225
1225
|
- `code_coverage_pct` / `test_coverage_pct`: làm tròn về integer gần nhất (0–100)
|
|
1226
|
-
- **`status` trong JSON CỐ TÌNH chỉ có 4 giá trị** `OK`/`DRIFT`/`GAP`/`UNTRACKED` — KHÔNG ghi `ORPHANED` vào field này. VS Code extension "
|
|
1226
|
+
- **`status` trong JSON CỐ TÌNH chỉ có 4 giá trị** `OK`/`DRIFT`/`GAP`/`UNTRACKED` — KHÔNG ghi `ORPHANED` vào field này. VS Code extension "SDD Board" (sống **ngoài** repo này) switch trên `status`; thêm giá trị thứ 5 sẽ rơi vào nhánh không khớp và có thể làm row mất khỏi panel.
|
|
1227
1227
|
Row `ORPHANED` xuất ra JSON là: `"status": "DRIFT"` + `"orphaned": true`. Panel chưa hỗ trợ vẫn hiện nó như `DRIFT` — đủ đúng về nghĩa ("code không khớp spec, cần xử lý") và **không im lặng**; panel có đọc `orphaned` thì hiện nhãn riêng. Chi tiết đầy đủ luôn có ở `orphaned[]` và ở report terminal.
|
|
1228
1228
|
**TSV giữ nguyên chữ `ORPHANED`** trong cột `status` — TSV là nguồn-sự-thật, JSON chỉ là bản xuất cho panel.
|
|
1229
1229
|
- `orphaned` (boolean): `true` chỉ khi cột `status` của TSV là `ORPHANED`; mọi row khác ghi `false` (đừng bỏ trống — panel đọc field vắng dễ ra `undefined`).
|
package/core/rules/workflow.md
CHANGED
|
@@ -129,7 +129,7 @@ Trước khi lưu file gap, kiểm tra **từng hàng** trong bảng gap:
|
|
|
129
129
|
- [ ] **Có section `Phạm vi phân tích`** – bảng mỗi UC một hàng kèm `@trace.status` + Đã phân tích? + Số gap. UC chưa duyệt vẫn có hàng, ghi `⏸ Chưa xét`. Thiếu bảng này thì không ai phân biệt được *"đã xét, không thấy gap"* với *"chưa xét"*.
|
|
130
130
|
- [ ] **11 cột đủ** – đúng thứ tự: `ID | UC | Loại | Vấn đề cần confirm | Câu hỏi / Lý do cần confirm & Gợi ý | Trích đoạn tài liệu (Evidence) | Giao cho đội | Mức độ | Người trả lời | Trạng thái | Câu trả lời`
|
|
131
131
|
- [ ] **Cột 2 = `UC`** – mã UC đầy đủ (`<TICKET-ID>-UC{N}`), hoặc `— (toàn PRD)` cho gap `GAP-GEN-`. Mọi UC có gap phải khớp một hàng `✅` ở bảng *Phạm vi phân tích*.
|
|
132
|
-
- [ ] **ID dạng `GAP-UC{N}-{nnn}`** (hoặc `GAP-GEN-{nnn}`) – KHÔNG dùng `GAP-01` phẳng: số phẳng sẽ bị đánh lại khi phân tích lại một UC, làm đứt `🚫 Block: [GAP-
|
|
132
|
+
- [ ] **ID dạng `GAP-UC{N}-{nnn}`** (hoặc `GAP-GEN-{nnn}`) – KHÔNG dùng `GAP-01` phẳng: số phẳng sẽ bị đánh lại khi phân tích lại một UC, làm đứt `🚫 Block: [GAP-UC1-001]` trong test case đã có.
|
|
133
133
|
- [ ] **Cột 4 = `Vấn đề cần confirm`** – KHÔNG viết tắt thành `Vấn đề`
|
|
134
134
|
- [ ] **Cột 5 = `Câu hỏi / Lý do cần confirm & Gợi ý`** – bắt buộc có đủ 4 phần, tách bằng `<br/>`:
|
|
135
135
|
```
|
|
@@ -29,7 +29,7 @@ Bóc tách spec/PRD/user story thô thành mô tả yêu cầu có cấu trúc c
|
|
|
29
29
|
vào phân tích/BR/AC. Với file Confluence/HTML/MHTML: phát hiện qua thẻ `<s>`,
|
|
30
30
|
`<strike>`, `<del>` hoặc style `text-decoration: line-through`.
|
|
31
31
|
3. Xác định: feature name, actor/role, mục tiêu nghiệp vụ, phạm vi (in/out scope).
|
|
32
|
-
4. Đánh dấu phần MƠ HỒ / THIẾU → ghi vào `DOC_GAP.md` (gap GAP-
|
|
32
|
+
4. Đánh dấu phần MƠ HỒ / THIẾU → ghi vào `DOC_GAP.md` (gap `GAP-UC{N}-{nnn}`; gap thuộc cả PRD → `GAP-GEN-{nnn}`).
|
|
33
33
|
|
|
34
34
|
---
|
|
35
35
|
|
|
@@ -58,6 +58,6 @@ Phần spec-breakdown là **mục đầu tiên** của `REQUIREMENT_ANALYSIS.md`
|
|
|
58
58
|
- Danh sách giả định và câu hỏi mở (đánh dấu rõ điều CHƯA chắc)
|
|
59
59
|
|
|
60
60
|
Đồng thời ghi mọi khoảng trống phát hiện vào `{qc_artifact_dir}DOC_GAP.md`
|
|
61
|
-
(theo `{paths.qc_skills_dir}/qa-analyst/DOC_GAP.template.md`), mỗi gap có ID `GAP-
|
|
61
|
+
(theo `{paths.qc_skills_dir}/qa-analyst/DOC_GAP.template.md`), mỗi gap có ID `GAP-UC{N}-{nnn}` — mã mang UC để phân tích lại một UC không đánh số lại UC khác.
|
|
62
62
|
|
|
63
63
|
Kết thúc bằng gợi ý: feature đã đủ rõ để chuyển sang `qa-planner` (phân tích rủi ro) chưa.
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.0
|
|
3
|
+
updated: 2026-09-04
|
|
4
|
+
ported_from: ui-automation-testing
|
|
5
|
+
upstream_path: skills/qa-tc-designer/api-testcase-designer/api/templates/auth-chain.md
|
|
6
|
+
upstream_sha: ef8f9761f1b53d0ccd752f8fe0c13a427fa15f45
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
> **VIẾT LẠI, không copy** *(B12)* — cùng lý do với `endpoint.md`: bản upstream có trước luật
|
|
10
|
+
> ATOMIC (2026-07-09), gộp nhiều kết cục vào một `**Expected:**` và dùng hệ mã
|
|
11
|
+
> `API-<FEATURE>-AUTH-001`. Ba nhóm ca giữ nguyên; cấu trúc theo `shared/tc-metadata-format.md`.
|
|
12
|
+
|
|
13
|
+
# Khuôn TC — chuỗi xác thực (login → token → gọi endpoint được bảo vệ)
|
|
14
|
+
|
|
15
|
+
Dùng khi TC phải đăng nhập lấy token trước khi gọi endpoint chính. Thứ tự gọi và điểm verify
|
|
16
|
+
của từng chuỗi: xem `auth-sequence.md`.
|
|
17
|
+
|
|
18
|
+
Phủ **3 nhóm ca**: chuỗi thành công · token hết hạn · login sai mật khẩu.
|
|
19
|
+
|
|
20
|
+
> **Một chuỗi auth KHÔNG phải một TC.** Chuỗi có nhiều bước, mỗi bước có kết cục riêng —
|
|
21
|
+
> nên nó là **nhiều TC độc lập**, mỗi TC giữ FULL steps để tự tới được trạng thái cần assert.
|
|
22
|
+
> Đây đúng là chỗ luật ATOMIC dễ bị bỏ nhất, vì cảm giác "một chuỗi = một ca".
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Nhóm ca 1 — Chuỗi thành công
|
|
27
|
+
|
|
28
|
+
### TC_<FEATURE>_101 — login trả về access_token
|
|
29
|
+
|
|
30
|
+
- **Title:** Login role `<role>` với thông tin đúng trả về access_token
|
|
31
|
+
- **Feature:** <TICKET-ID> — <Tên feature>
|
|
32
|
+
- **Priority:** P0
|
|
33
|
+
- **Status:** Draft
|
|
34
|
+
- **Author:** AI
|
|
35
|
+
- **Tags:** api, happy-path, auth, <feature-tag>
|
|
36
|
+
- **Trace:** BR-xx
|
|
37
|
+
- **@trace.verifies:** {UC-ID}-SC{N}
|
|
38
|
+
|
|
39
|
+
#### Preconditions
|
|
40
|
+
- Tài khoản role `<role>` đã tồn tại (username `<username>`, password `<password>`).
|
|
41
|
+
|
|
42
|
+
#### Test Data
|
|
43
|
+
- Method: POST
|
|
44
|
+
- Path: `/auth/login`
|
|
45
|
+
- Headers: Content-Type: application/json
|
|
46
|
+
- Body:
|
|
47
|
+
```json
|
|
48
|
+
{ "username": "<username>", "password": "<password>" }
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
#### Test Steps
|
|
52
|
+
1. **[Action]** Gửi `POST /auth/login` với body trên.
|
|
53
|
+
2. **[Verify]** Đọc `body.access_token`.
|
|
54
|
+
|
|
55
|
+
#### Expected Result
|
|
56
|
+
- HTTP 200 AND `body.access_token` exists
|
|
57
|
+
|
|
58
|
+
> ✅ Compound hợp lệ — cả hai vế nói về **cùng một** kết cục: "login thành công và có token".
|
|
59
|
+
|
|
60
|
+
### TC_<FEATURE>_102 — token lấy được gọi được endpoint bảo vệ
|
|
61
|
+
|
|
62
|
+
- **Title:** Token của role `<role>` gọi <METHOD> <protected_path> trả về <success_code>
|
|
63
|
+
- **Priority:** P0
|
|
64
|
+
- **Tags:** api, happy-path, auth, <feature-tag>
|
|
65
|
+
- **Trace:** BR-xx
|
|
66
|
+
|
|
67
|
+
#### Preconditions
|
|
68
|
+
- Tài khoản role `<role>` đã tồn tại.
|
|
69
|
+
|
|
70
|
+
#### Test Steps
|
|
71
|
+
1. **[Action]** Gửi `POST /auth/login` lấy `access_token`.
|
|
72
|
+
2. **[Action]** Gửi `<METHOD> <protected_path>` với `Authorization: Bearer {access_token}`.
|
|
73
|
+
3. **[Verify]** Đọc status code của request thứ hai.
|
|
74
|
+
|
|
75
|
+
#### Expected Result
|
|
76
|
+
- HTTP `<success_code>`
|
|
77
|
+
|
|
78
|
+
> ⚠️ Bước 1 **lặp lại đủ**, không viết "dùng token từ TC_101". Mỗi TC tách phải tự chạy độc
|
|
79
|
+
> lập — nếu nó phụ thuộc TC khác đã chạy thì thứ tự chạy trở thành điều kiện ẩn, và chạy riêng
|
|
80
|
+
> một TC sẽ fail vì lý do không liên quan tới thứ nó kiểm.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Nhóm ca 2 — Token hết hạn
|
|
85
|
+
|
|
86
|
+
### TC_<FEATURE>_103 — token hết hạn trả về 401
|
|
87
|
+
|
|
88
|
+
- **Priority:** P0
|
|
89
|
+
- **Tags:** api, negative, auth, security
|
|
90
|
+
- **Trace:** BR-xx
|
|
91
|
+
|
|
92
|
+
#### Preconditions
|
|
93
|
+
- Có sẵn một token đã quá thời hạn (`<expired_token>` — seed hoặc lấy từ fixture).
|
|
94
|
+
|
|
95
|
+
#### Test Data
|
|
96
|
+
- Headers: Authorization: Bearer `<expired_token>`
|
|
97
|
+
|
|
98
|
+
#### Test Steps
|
|
99
|
+
1. **[Action]** Gửi `<METHOD> <protected_path>` với token đã hết hạn.
|
|
100
|
+
2. **[Verify]** Đọc status code.
|
|
101
|
+
|
|
102
|
+
#### Expected Result
|
|
103
|
+
- HTTP 401
|
|
104
|
+
|
|
105
|
+
*Chuỗi refresh token (nếu API có) là nhóm ca riêng — xem `auth-sequence.md` §Chuỗi 2. Mỗi bước
|
|
106
|
+
của chuỗi refresh cũng là một TC.*
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Nhóm ca 3 — Login sai mật khẩu
|
|
111
|
+
|
|
112
|
+
### TC_<FEATURE>_104 — sai password trả về 401
|
|
113
|
+
|
|
114
|
+
- **Priority:** P0
|
|
115
|
+
- **Tags:** api, negative, auth, security
|
|
116
|
+
- **Trace:** BR-xx
|
|
117
|
+
|
|
118
|
+
#### Test Data
|
|
119
|
+
- Body: `{ "username": "<username>", "password": "<wrong_password>" }`
|
|
120
|
+
|
|
121
|
+
#### Test Steps
|
|
122
|
+
1. **[Action]** Gửi `POST /auth/login` với password sai.
|
|
123
|
+
2. **[Verify]** Đọc status code.
|
|
124
|
+
|
|
125
|
+
#### Expected Result
|
|
126
|
+
- HTTP 401
|
|
127
|
+
|
|
128
|
+
### TC_<FEATURE>_105 — sai password KHÔNG trả về token
|
|
129
|
+
|
|
130
|
+
- **Priority:** P0
|
|
131
|
+
- **Tags:** api, negative, auth, security
|
|
132
|
+
- **Trace:** BR-xx
|
|
133
|
+
|
|
134
|
+
#### Test Steps
|
|
135
|
+
1. **[Action]** Gửi `POST /auth/login` với password sai.
|
|
136
|
+
2. **[Verify]** Kiểm trường `access_token` trong body.
|
|
137
|
+
|
|
138
|
+
#### Expected Result
|
|
139
|
+
- `body.access_token` not exists
|
|
140
|
+
|
|
141
|
+
> **Vì sao tách khỏi TC_104 dù cùng một request.** *"Trả 401"* và *"không phát token"* là hai
|
|
142
|
+
> kết cục **fail độc lập được**: một API hỏng có thể trả 401 mà vẫn kèm token trong body. Gộp
|
|
143
|
+
> lại thì TC pass khi chỉ một nửa đúng — và nửa còn lại là lỗ bảo mật.
|
|
144
|
+
>
|
|
145
|
+
> Đây chính là luật *"assertion loại-trừ (KHÔNG có / KHÔNG xảy ra) là oracle THẬT"* ở
|
|
146
|
+
> `shared/tc-metadata-format.md`. Khi tách bằng script, kiểm lại không đánh rơi các bullet
|
|
147
|
+
> phủ định — chúng dễ bị bỏ nhất.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Không cần Teardown
|
|
152
|
+
|
|
153
|
+
Cả 5 TC trên **không tạo bản ghi thật** — chúng chỉ login và đọc. Không thêm dòng
|
|
154
|
+
`#### Teardown` cho có. Thêm khi và chỉ khi TC tạo tài khoản mới hoặc đổi trạng thái thật; lúc
|
|
155
|
+
đó ghi `[Teardown: deactivate user via admin API]` *(`shared/precision-rules.md` §8)*.
|