@educa-corp/sdd-framework 0.9.7 → 0.9.8

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.
Files changed (104) hide show
  1. package/bin/qc-base-map.json +13 -11
  2. package/bin/self-check.js +49 -4
  3. package/bin/trace-schema.json +3226 -3187
  4. package/core/FRAMEWORK_VERSION +1 -1
  5. package/core/commands/qc-analyze.md +2 -2
  6. package/core/commands/qc-automation-assess.md +3 -3
  7. package/core/commands/qc-design-script.md +60 -30
  8. package/core/commands/qc-design-test.md +79 -7
  9. package/core/commands/qc-plan.md +1 -1
  10. package/core/commands/qc-report.md +85 -76
  11. package/core/commands/qc-review-script.md +25 -16
  12. package/core/commands/qc-review-testcase.md +8 -7
  13. package/core/commands/qc-run-manualtest.md +1 -1
  14. package/core/commands/qc-run-script.md +15 -8
  15. package/core/modules/qc-playwright-ts/module.yaml +13 -0
  16. package/core/modules/qc-playwright-ts/stack-profile.yaml +99 -0
  17. package/core/modules/qc-wdio-appium/module.yaml +20 -0
  18. package/core/modules/qc-wdio-appium/stack-profile.yaml +107 -0
  19. package/core/skills/qc/qa-analyst/data-flow.md +1 -1
  20. package/core/skills/qc/qa-automation-assess/matrix.md +6 -3
  21. package/core/skills/qc/{qa-runner → qa-designer}/exploratory/session.md +8 -2
  22. package/core/skills/qc/qa-designer/functional/api.md +1 -1
  23. package/core/skills/qc/qa-designer/functional/job.md +128 -0
  24. package/core/skills/qc/qa-designer/integration/api.md +1 -1
  25. package/core/skills/qc/qa-designer/integration/db.md +1 -1
  26. package/core/skills/qc/qa-designer/integration/{kafka.md → queue.md} +20 -4
  27. package/core/skills/qc/qa-designer/shared/skill-decision-tree.md +17 -0
  28. package/core/skills/qc/qa-designer/shared/tc-metadata-format.md +17 -0
  29. package/core/skills/qc/qa-reviewer/script/_shared/review-rules.md +121 -0
  30. package/core/skills/qc/qa-reviewer/script/api/auth.md +49 -0
  31. package/core/skills/qc/qa-reviewer/script/api/endpoint.md +89 -0
  32. package/core/skills/qc/qa-reviewer/script/api/security.md +46 -0
  33. package/core/skills/qc/qa-reviewer/script/exploratory.md +2 -2
  34. package/core/skills/qc/qa-reviewer/script/mobile/e2e.md +41 -0
  35. package/core/skills/qc/qa-reviewer/script/mobile/functional.md +90 -0
  36. package/core/skills/qc/qa-reviewer/script/mobile/integration.md +41 -0
  37. package/core/skills/qc/qa-reviewer/script/mobile/non-functional.md +43 -0
  38. package/core/skills/qc/qa-reviewer/script/web/e2e.md +46 -0
  39. package/core/skills/qc/qa-reviewer/script/web/functional.md +111 -0
  40. package/core/skills/qc/qa-reviewer/script/web/integration.md +46 -0
  41. package/core/skills/qc/qa-reviewer/script/web/non-functional.md +49 -0
  42. package/core/skills/qc/qa-reviewer/shared/read-doc-gap-inputs.md +1 -1
  43. package/core/skills/qc/qa-reviewer/shared/review-file-template.md +26 -7
  44. package/core/skills/qc/qa-reviewer/test-case/e2e.md +1 -1
  45. package/core/skills/qc/qa-reviewer/test-case/exploratory.md +1 -1
  46. package/core/skills/qc/qa-reviewer/test-case/functional.md +1 -1
  47. package/core/skills/qc/qa-reviewer/test-case/integration.md +1 -1
  48. package/core/skills/qc/qa-reviewer/test-case/non-functional.md +1 -1
  49. package/core/skills/qc/qa-script-designer/_shared/api-conventions.md +94 -0
  50. package/core/skills/qc/qa-script-designer/_shared/file-naming-and-folders.md +109 -0
  51. package/core/skills/qc/qa-script-designer/_shared/mobile-conventions.md +196 -0
  52. package/core/skills/qc/qa-script-designer/_shared/web-conventions.md +257 -0
  53. package/core/skills/qc/qa-script-designer/api/auth.md +43 -0
  54. package/core/skills/qc/qa-script-designer/api/endpoint.md +61 -0
  55. package/core/skills/qc/qa-script-designer/api/security.md +41 -0
  56. package/core/skills/qc/qa-script-designer/mobile/e2e.md +35 -0
  57. package/core/skills/qc/qa-script-designer/mobile/functional/feature.md +32 -0
  58. package/core/skills/qc/qa-script-designer/mobile/functional/screen.md +42 -0
  59. package/core/skills/qc/qa-script-designer/mobile/integration.md +39 -0
  60. package/core/skills/qc/qa-script-designer/mobile/non-functional.md +39 -0
  61. package/core/skills/qc/qa-script-designer/web/e2e.md +36 -0
  62. package/core/skills/qc/qa-script-designer/web/functional/api.md +39 -0
  63. package/core/skills/qc/qa-script-designer/web/functional/gui-feature.md +34 -0
  64. package/core/skills/qc/qa-script-designer/web/functional/gui-screen.md +42 -0
  65. package/core/skills/qc/qa-script-designer/web/integration.md +43 -0
  66. package/core/skills/qc/qa-script-designer/web/non-functional.md +42 -0
  67. package/core/skills/qc/qa-script-runner/mobile/run.md +38 -0
  68. package/core/skills/qc/qa-script-runner/report.md +41 -0
  69. package/core/skills/qc/qa-script-runner/web/run.md +48 -0
  70. package/core/steps/qc-scope.md +43 -0
  71. package/core/steps/report-footer.md +2 -2
  72. package/docs/02-concepts/pipeline-steps/07-dev-selftest.md +1 -1
  73. package/docs/02-concepts/pipeline-steps/08-qc-automation.md +10 -10
  74. package/docs/02-concepts/pipeline-steps/10-feedback-loop.md +1 -1
  75. package/docs/02-concepts/traceability.md +1 -1
  76. package/docs/03-guides/developer.md +1 -1
  77. package/docs/03-guides/tester-qa.md +40 -12
  78. package/docs/04-reference/commands.md +1 -1
  79. package/docs/04-reference/modules.md +2 -1
  80. package/docs/explain/17-qc-design-test.md +2 -2
  81. package/docs/explain/19-qc-run-test.md +4 -4
  82. package/docs/explain/20-qc-report.md +1 -1
  83. package/docs/explain/23-fix-bug.md +2 -2
  84. package/docs/plans/qc-surgery/01-checklist.md +18 -6
  85. package/docs/plans/qc-surgery/PLAN_v2.md +295 -0
  86. package/docs/plans/qc-surgery/exec-S-ap-stack-typescript.md +420 -0
  87. package/docs/plans/qc-surgery/exec-S0-guard-cam-stack-cu.md +400 -0
  88. package/docs/plans/qc-surgery/exec-S1-hai-module-thay-qc-playwright.md +267 -0
  89. package/docs/plans/qc-surgery/exec-S2-qa-runner-thanh-script-designer-runner.md +340 -0
  90. package/docs/plans/qc-surgery/exec-S3-viet-lai-tieu-chi-review-script.md +322 -0
  91. package/docs/plans/qc-surgery/exec-S5-an-theo-don-dau-vet-stack-cu.md +292 -0
  92. package/package.json +1 -1
  93. package/core/modules/qc-playwright/stack-profile.yaml +0 -66
  94. package/core/skills/qc/qa-reviewer/script/e2e.md +0 -95
  95. package/core/skills/qc/qa-reviewer/script/functional.md +0 -109
  96. package/core/skills/qc/qa-reviewer/script/integration.md +0 -99
  97. package/core/skills/qc/qa-reviewer/script/non-functional.md +0 -134
  98. package/core/skills/qc/qa-runner/e2e.md +0 -49
  99. package/core/skills/qc/qa-runner/functional/api.md +0 -35
  100. package/core/skills/qc/qa-runner/functional/gui-feature.md +0 -57
  101. package/core/skills/qc/qa-runner/functional/gui-screen.md +0 -61
  102. package/core/skills/qc/qa-runner/integration.md +0 -47
  103. package/core/skills/qc/qa-runner/non-functional.md +0 -49
  104. package/core/skills/qc/qa-runner/report/report.md +0 -37
@@ -6,8 +6,9 @@ ported_from: ai-automation-qc-base
6
6
 
7
7
  # /qc-review-testcase — QC Review Gate: test case
8
8
 
9
- > Stage 4 của QC automation pipeline native (qc-analyze → qc-plan → qc-design-test →
10
- > **qc-review-testcase** → qc-design-script → qc-run-script → qc-report). Soát `.Test.md` do
9
+ > Trạm 4/9 của dây chuyền QC automation (qc-analyze → qc-plan → qc-design-test → **qc-review-testcase** →
10
+ > qc-automation-assess → qc-design-script → qc-review-script → qc-run-script qc-run-manualtest
11
+ > → qc-report). Soát `.Test.md` do
11
12
  > `/qc-design-test` sinh: coverage · độ rõ · trace. Cặp với `/qc-review-script` — hai lệnh, hai vai.
12
13
 
13
14
  ## Gate
@@ -339,10 +340,10 @@ File **phải** chứa đúng một dòng theo khuôn này, ở §Tổng quan:
339
340
  ```
340
341
  hoặc
341
342
  ```
342
- **Verdict:** NEEDS_FIX
343
+ **Verdict:** REVISION_REQUIRED ← hoặc REJECTED khi có BLOCKER
343
344
  ```
344
345
 
345
- `APPROVED` khi **điểm `≥80` không còn `FAIL` chặn**; ngược lại `NEEDS_FIX`.
346
+ Verdict suy từ **số đếm lỗi**, không từ điểm — `≥1 BLOCKER``REJECTED` · `≥1 MAJOR` `REVISION_REQUIRED` · chỉ MINOR/SUGGESTION → `APPROVED_WITH_SUGGESTIONS` · sạch `APPROVED`. Xem `qa-reviewer/shared/review-file-template.md` §Verdict.
346
347
 
347
348
  > **Đây là contract, không phải định dạng cho đẹp.** `/qc-automation-assess` (Đợt 2 · b3) **loại**
348
349
  > khỏi lượt mọi TC chưa `APPROVED`. Đổi chuỗi này là làm trạm đó mù — nên nếu phải đổi, đổi ở cả
@@ -401,9 +402,9 @@ Output Artifacts · Next) cho report cuối, kèm khối bên dưới.
401
402
  ```
402
403
  /qc-review-testcase Hoàn tất — {UC-ID} vòng #{N}
403
404
  Điểm : {XX}/100 ({fail} FAIL × −5đ · {warn} WARN × −2đ){nếu có vòng trước: " ← vòng #{N-1}: {YY}/100"}
404
- Verdict: {APPROVED | NEEDS_FIX} — {n} findings ({crit} chặn)
405
+ Verdict: {APPROVED | APPROVED_WITH_SUGGESTIONS | REVISION_REQUIRED | REJECTED} — {n} findings ({blk} BLOCKER · {maj} MAJOR · {min} MINOR · {sug} SUGGESTION)
405
406
  File : {qc_artifact_dir}test-cases/REVIEW_<FEATURE>.md (thêm 1 hàng vào bảng Tổng quan)
406
407
  Self-review: {✅ sạch | ⚠️ {n} điểm cần chú ý — liệt kê}
407
- Next (APPROVED) : /qc-design-script {UC-ID}
408
- (NEEDS_FIX → sửa TC bị gắn cờ bằng /qc-design-test {UC-ID}, rồi chạy lại lệnh này)
408
+ Next (≥ APPROVED_WITH_SUGGESTIONS) : /qc-design-script {UC-ID}
409
+ (REVISION_REQUIRED | REJECTED → sửa TC bị gắn cờ bằng /qc-design-test {UC-ID}, rồi chạy lại lệnh này)
409
410
  ```
@@ -5,7 +5,7 @@ updated: 2026-09-16
5
5
 
6
6
  # /qc-run-manualtest — Ghi kết quả test TAY vào sổ trace
7
7
 
8
- > Stage 7b. QC chạy tay các TC mang `Automatable: N`, lệnh **hỏi từng TC** rồi ghi `qc_status`
8
+ > Trạm 8b/9 của dây chuyền QC automation — song song với trạm 8. QC chạy tay các TC mang `Automatable: N`, lệnh **hỏi từng TC** rồi ghi `qc_status`
9
9
  > vào sổ trace. Không có lệnh này thì những scenario ấy nằm `not_run` vĩnh viễn — và `/qc-report`
10
10
  > sẽ chấm cả PRD là **FAIL**, không cách nào sửa.
11
11
 
@@ -6,7 +6,7 @@ ported_from: ai-automation-qc-base
6
6
 
7
7
  # /qc-run-script — Chạy automation script (ghi qc_status)
8
8
 
9
- > Stage 7. Chạy script **đã `APPROVED`**, phân loại mỗi FAIL, rồi ghi `qc_status` **chính thức**
9
+ > Trạm 8/9 của dây chuyền QC automation. Chạy script **đã `APPROVED`**, phân loại mỗi FAIL, rồi ghi `qc_status` **chính thức**
10
10
  > vào sổ trace. **Không sinh script** — đó là `/qc-design-script`.
11
11
 
12
12
  ## Gate
@@ -200,8 +200,8 @@ cả hai đều xảy ra trong im lặng, không có bước nào phía sau bắ
200
200
 
201
201
  | Đọc được | Làm gì |
202
202
  |---|---|
203
- | `APPROVED` | đi tiếp |
204
- | `NEEDS_FIX` | **DỪNG** — `❌ Script chưa đạt. Sửa rồi soát lại bằng /qc-review-script {UC-ID}.` |
203
+ | `APPROVED` · `APPROVED_WITH_SUGGESTIONS` | **đi tiếp** — in một dòng bằng chứng:<br/>`✅ Cổng script đã soát: {verdict} — {đường dẫn file vừa đọc}` |
204
+ | `REVISION_REQUIRED` · `REJECTED` | **DỪNG** — `❌ Script chưa đạt. Sửa rồi soát lại bằng /qc-review-script {UC-ID}.` |
205
205
  | Không có file | **DỪNG** — `❌ Chưa soát script. Chạy /qc-review-script {UC-ID} trước.` |
206
206
 
207
207
  > **Cổng này là lý do `/qc-review` phải tách đôi** (Đợt 2 · b1). Biên bản cũ không nói nó soát
@@ -222,15 +222,22 @@ cả hai đều xảy ra trong im lặng, không có bước nào phía sau bắ
222
222
  > hoặc **chạy 0 test mà vẫn báo xanh** — rồi con số đó đi thẳng vào `/qc-report` thành số liệu
223
223
  > người ta tin. Đây là kiểu hỏng tệ nhất: một báo cáo xanh trên một lần chạy **không tồn tại**.
224
224
 
225
- ## Role & stack (theo module qc-playwright)
225
+ ## Role & stack (module theo nền — bảng §2b của `steps/qc-scope.md`)
226
226
 
227
- Bạn là **QC Script Runner**. Chạy pytest-playwright script đã có, thu bằng chứng, phân loại FAIL,
227
+ Bạn là **QC Script Runner**. Chạy script đã **theo nền đã phân giải ở §2b**, thu bằng chứng, phân loại FAIL,
228
228
  ghi kết quả theo từng scenario. **KHÔNG sửa script, KHÔNG sinh script.**
229
229
 
230
- ## Skills — chọn layer, nạp MỘT file (`{paths.qc_skills_dir}/qa-runner/`)
230
+ ## Skills — chọn NỀN, nạp MỘT file (`{paths.qc_skills_dir}/qa-script-runner/`)
231
231
 
232
- `functional/{gui-screen,gui-feature,api}.md`, `integration.md`, `e2e.md`,
233
- `non-functional.md`, `exploratory/session.md`.
232
+ **Nạp theo nền đã phân giải ở `steps/qc-scope.md` §2b:**
233
+
234
+ | `active_platform` | File |
235
+ |---|---|
236
+ | `web` · `webview` · `system` | `web/run.md` |
237
+ | `app` · `app-ios` · `app-android` | `mobile/run.md` |
238
+
239
+ Báo cáo sau lượt chạy: `report.md` — reporter **theo nền** *(Playwright HTML Report cho
240
+ web·system, Allure v2.x cho app)*.
234
241
 
235
242
  ---
236
243
 
@@ -0,0 +1,13 @@
1
+ name: "QC Playwright (TypeScript)"
2
+ version: "1.0.0"
3
+ description: "QC automation — Playwright + TypeScript. Phục vụ HAI nền: web (automation/) và API/system (api-automation/)"
4
+ language: "TypeScript"
5
+ framework: "Playwright Test"
6
+ stack_type: "qc-automation"
7
+ default_layer_order:
8
+ - Test case Markdown (.Test.md) — nguồn sự thật, review xong mới sinh code
9
+ - Test data (data/*.data.ts)
10
+ - Page Object (pages/*.page.ts) · API Object (api/*.api.ts)
11
+ - Fixture (fixtures/*.fixture.ts)
12
+ - Spec (tests/[feature]/*.spec.ts)
13
+ test_framework: "Playwright Test + expect"
@@ -0,0 +1,99 @@
1
+ # QC automation module — Playwright + TypeScript.
2
+ #
3
+ # Nguồn: upstream/qc-base-new/Automation-Standards.md (Approved) §1 §2.3 §3 §6.1 §9.2
4
+ # upstream/qc-base-new/API-Testing-Standards.md (Approved) §1 §2.1 §7.2 §7.3
5
+ #
6
+ # Module này phục vụ HAI nền — web và system(API) — vì cả hai dùng CÙNG stack
7
+ # (AD-API-001: "Playwright API mode thay vì framework riêng, để tái dùng infrastructure
8
+ # với Web testing"). Tách làm hai module là khai dãy phiên bản Playwright/TS hai lần.
9
+ # Nền mobile ở modules/qc-wdio-appium (stack khác hẳn: WebdriverIO + Appium).
10
+ #
11
+ # CHỌN NỀN LÚC CHẠY: theo `active_platform` đã phân giải ở trạm 1 (steps/qc-scope.md).
12
+ # KHÔNG có key cấu hình riêng cho việc này — một pass QC đã khoá đúng một nền, hỏi lại
13
+ # bằng một field thứ hai là tạo hai đáp án cho một câu.
14
+ #
15
+ # web · webview → layout.web app · app-ios · … → qc-wdio-appium
16
+ # system → layout.api
17
+
18
+ versions:
19
+ playwright: "latest" # Playwright Test — runner + assertion + reporter, không thêm Jest/Mocha
20
+ typescript: "v5.x" # strict mode
21
+
22
+ build:
23
+ web:
24
+ test: "npx playwright test"
25
+ e2e: "npx playwright test tests/ --grep @e2e"
26
+ report: "npx playwright show-report"
27
+ show_trace: "npx playwright show-trace test-results/<test>/trace.zip"
28
+ api:
29
+ test: "npx playwright test --config=api-automation/playwright.config.ts"
30
+ report: "npx playwright show-report"
31
+
32
+ layout:
33
+ # §2.3 của Automation-Standards — mirror test-suites/, KHÔNG đổi tên thư mục.
34
+ web: |
35
+ automation/
36
+ ├── playwright.config.ts
37
+ ├── package.json · tsconfig.json
38
+ ├── pages/ ← Page Object: base.page.ts · <feature>.page.ts
39
+ ├── tests/ ← spec, mirror test-suites/: {TICKET-ID}/<feature>-happy-path.spec.ts
40
+ ├── data/ ← <feature>.data.ts (ref TDS artifact)
41
+ ├── fixtures/ ← base.fixture.ts
42
+ ├── helpers/ ← <helper>.ts
43
+ └── reports/ ← sinh ra, gitignored
44
+
45
+ # §2.1 của API-Testing-Standards — thư mục gốc RIÊNG, "tách biệt với automation/ (web)
46
+ # để tránh xung đột config và dependency". api/ thay cho pages/; không có Page Object.
47
+ api: |
48
+ api-automation/
49
+ ├── playwright.config.ts ← config riêng của API mode
50
+ ├── package.json · tsconfig.json
51
+ ├── api/ ← API Object: base.api.ts · <resource>.api.ts
52
+ ├── tests/ ← {TICKET-ID}/<feature>-{happy-path,negative,security}.spec.ts
53
+ ├── data/ ← <resource>.data.ts
54
+ ├── fixtures/ ← api.fixture.ts (shared API context, auth token)
55
+ ├── helpers/ ← schema.helper.ts · auth.helper.ts
56
+ └── reports/ ← sinh ra, gitignored
57
+
58
+ naming:
59
+ # §9.2 (web) · §7.2 (api). File kebab-case; class PascalCase; method camelCase verb-first.
60
+ page_object: "pages/<feature>.page.ts → class <Feature>Page extends BasePage"
61
+ api_object: "api/<resource>.api.ts → class <Resource>API extends BaseAPI"
62
+ spec: "tests/{TICKET-ID}/<feature>-<scenario>.spec.ts"
63
+ test_data: "data/<resource>.data.ts"
64
+ fixture: "fixtures/<name>.fixture.ts"
65
+ helper: "helpers/<name>.helper.ts"
66
+ test_case_md: "{qc_artifact_dir}test-cases/TC_<FEATURE>.Test.md"
67
+
68
+ locator_priority:
69
+ # §6.1 — chỉ áp cho nền web. API không có locator.
70
+ web: "getByRole → getByLabel → getByPlaceholder → getByTestId → getByText → locator('[css]') (last resort, ghi lý do)"
71
+ note: "Giá trị test-id lấy từ bảng Test Selectors §4.5.6 của tech-doc, KHÔNG scan runtime.
72
+ Tên thuộc tính đọc từ `@trace.testid_attr`; nếu ≠ data-testid thì phải gọi
73
+ `expect.configure`/`selectors.setTestIdAttribute` trước khi dùng getByTestId."
74
+
75
+ reporting:
76
+ web: "Playwright HTML Report" # §1 + OQ-01 đã đóng 2026-06-02: Phase 1 KHÔNG cần Allure
77
+ api: "Playwright HTML Report" # Allure defer Phase 2
78
+
79
+ trace_tags:
80
+ # Dấu comment là `//` (TypeScript) — stack cũ dùng `#`. Bộ parse bám chuỗi `@trace.*`,
81
+ # không bám dấu comment (bin/lint-trace.js:733), nên đổi dấu là an toàn; lane DEV đã
82
+ # dùng `//` từ trước.
83
+ verifies: "// @trace.verifies={UC-ID}-SC{N}"
84
+ source: "// @trace.source=specs/{domain}/{prd-slug}/bdd/{platform}/{UC-ID}-{slug}.feature"
85
+ test_type: "// @trace.test_type=functional|integration|e2e|non-functional"
86
+
87
+ artifact_id_prefix:
88
+ # §7.3 API-Testing-Standards — dãy API độc lập với web/mobile.
89
+ api: "TS-API · SCN-API · TC-API · AUT-API · TDS-API"
90
+
91
+ # Luật VIẾT CODE (Page Object 3 lớp, assertion, wait, anti-pattern, flaky policy) KHÔNG ở
92
+ # đây — chúng ở skills/qc/qa-script-designer/_shared/web-conventions.md.
93
+ # Ranh giới: hồ sơ này trả lời "chạy ở đâu, đặt tên gì"; skill trả lời "viết thế nào".
94
+ # Vì sao tách: hồ sơ được đọc NGUYÊN vào ngữ cảnh mỗi lần chạy lệnh, còn skill nạp MỘT
95
+ # file theo lane — nhồi luật vào đây bắt mọi lần làm web phải đọc cả luật của nền khác.
96
+
97
+ # qc_status: /qc-run-script ghi pass|fail|skip|not_run + qc_run_at vào
98
+ # {trace_dir}/{domain}/{prd-slug}/{UC-ID}-{active_platform}.tsv — song song với dev_selftest,
99
+ # và đây là kết quả QC CHÍNH THỨC hiện trên Living Docs.
@@ -0,0 +1,20 @@
1
+ name: "QC WebdriverIO + Appium (mobile)"
2
+ version: "1.0.0"
3
+ description: "QC automation cho nền app — WebdriverIO v9 + Appium v2 + UiAutomator2, TypeScript"
4
+ language: "TypeScript"
5
+ framework: "WebdriverIO + Appium"
6
+ stack_type: "qc-automation"
7
+ default_layer_order:
8
+ - Test case Markdown (.Test.md) — nguồn sự thật, review xong mới sinh code
9
+ - Test data (data/*.data.ts)
10
+ - Screen Object (screens/*.screen.ts)
11
+ - Helper (api · device · gesture)
12
+ - Spec (tests/[feature]/*.spec.ts)
13
+ test_framework: "WebdriverIO + Appium + Allure"
14
+
15
+ # ⚠️ PHẠM VI HẸP — KHAI RÕ (PLAN_v2 §8 luật 4).
16
+ # Module này được port theo KHUNG từ Mobile-Automation-Standards.md (Approved) ở Bước S,
17
+ # và CHƯA được chạy thử trên một dự án mobile thật. Ba mục riêng của nền mobile (§6 API
18
+ # Helper · §9 Gesture Helper · §12 Environment Validation) đã có mặt, nhưng các con số
19
+ # trong đó (toạ độ swipe, timeout) là giá trị mặc định của chuẩn, chưa hiệu chỉnh theo
20
+ # thiết bị thật. Lần đầu chạy thật: đối chiếu lại §12 trước khi tin kết quả.
@@ -0,0 +1,107 @@
1
+ # QC automation module — WebdriverIO + Appium, nền app (mobile).
2
+ #
3
+ # Nguồn: upstream/qc-base-new/Mobile-Automation-Standards.md (Approved)
4
+ # §1 §2 §3 §6 §7.1 §9 §10.2 §12
5
+ #
6
+ # ⚠️ ĐÂY KHÔNG PHẢI BẢN COPY CỦA qc-playwright-ts. Chuẩn mobile dài hơn chuẩn web 129 dòng,
7
+ # và phần dôi ra không phải văn vẻ: §6 API Helper · §9 Gesture Helper · §12 Environment
8
+ # Validation Checklist. Một hồ sơ mobile copy từ web sẽ im lặng thiếu ba mục đó, và cái
9
+ # thiếu chỉ lộ ra khi có người chạy thật trên máy thật — tức SAU khi đã tin là xong.
10
+ #
11
+ # CHỌN NỀN LÚC CHẠY: theo `active_platform` ở trạm 1 (steps/qc-scope.md).
12
+ # app · app-ios · app-android → module này
13
+ # web · webview · system → qc-playwright-ts
14
+
15
+ versions:
16
+ appium: "v2.x" # latest
17
+ webdriverio: "v9.x" # latest — test runner
18
+ typescript: "v5.x"
19
+ android_driver: "UiAutomator2" # driver@latest
20
+ emulator: "Genymotion" # trial, latest
21
+
22
+ build:
23
+ test: "npx wdio ./wdio.config.ts"
24
+ android: "npx wdio ./wdio.android.config.ts"
25
+ dry_run: "npx wdio ./wdio.config.ts --dry-run"
26
+ appium: "npx appium"
27
+ report: "npx allure generate reports/allure-results --clean && npx allure open"
28
+
29
+ layout:
30
+ mobile: |
31
+ projects/[ProjectName]/mobile-automation/
32
+ ├── wdio.config.ts ← WebdriverIO + Appium
33
+ ├── wdio.android.config.ts ← override riêng Android
34
+ ├── package.json ← dependency mobile RIÊNG
35
+ ├── tsconfig.json · .env.example
36
+ ├── screens/ ← Screen Object (≈ Page Object): base.screen.ts · <feature>.screen.ts
37
+ ├── tests/ ← {TICKET-ID}/<feature>-{happy-path,negative,api-sync}.spec.ts
38
+ ├── data/ ← <feature>.data.ts (dùng chung chuẩn với web)
39
+ ├── fixtures/ ← base.fixture.ts
40
+ ├── helpers/ ← api.helper.ts · device.helper.ts · gesture.helper.ts
41
+ └── reports/ ← Allure output, gitignored
42
+
43
+ naming:
44
+ # §10.2 — khác web: hậu tố "Screen", không phải "Page".
45
+ screen_object: "screens/<feature>.screen.ts → class <Feature>Screen extends BaseScreen"
46
+ spec: "tests/{TICKET-ID}/<feature>-<scenario>.spec.ts"
47
+ test_data: "data/<feature>.data.ts"
48
+ helper: "helpers/<name>.helper.ts"
49
+ test_case_md: "{qc_artifact_dir}test-cases/TC_<FEATURE>.Test.md"
50
+
51
+ locator_priority:
52
+ # §7.1 — KHÁC HẲN web. Không có getByRole/getByLabel.
53
+ order: "~accessibilityId → id (resource-id) → xpath (last resort, ghi lý do)"
54
+ note: "`~accessibilityId` dùng Android content-desc và YÊU CẦU dev gán. Giá trị lấy từ
55
+ bảng Test Selectors §4.5.6 của tech-doc, tên thuộc tính đọc từ `@trace.testid_attr`
56
+ (RN: testID · Flutter: Key/Semantics(identifier:) · native iOS: accessibilityIdentifier)."
57
+
58
+ # ── Ba mục CHỈ mobile mới có. Thiếu bất kỳ mục nào là hồ sơ chưa xong. ──
59
+
60
+ api_helper:
61
+ # §6 — mobile verify dữ liệu server bằng Playwright request, TÁI DÙNG từ automation/ (web).
62
+ file: "helpers/api.helper.ts"
63
+ impl: "class ApiHelper dùng `request`/`APIRequestContext` của @playwright/test;
64
+ baseUrl = process.env.API_BASE_URL"
65
+ why: "spec `*-api-sync.spec.ts` đối chiếu thứ hiện trên màn hình với thứ server thật có —
66
+ một màn hình hiển thị đúng dữ liệu CŨ vẫn là bug, và UI assertion không bắt được."
67
+
68
+ gesture_helper:
69
+ # §9 — web không cần mục này.
70
+ file: "helpers/gesture.helper.ts"
71
+ impl: "class GestureHelper — scrollDown · swipeLeft · … dựng bằng
72
+ browser.action('pointer', { parameters: { pointerType: 'touch' } })"
73
+ note: "Toạ độ mặc định trong chuẩn (x=540, startY=800, endY=300, duration=500) là giá trị
74
+ của MỘT cấu hình màn hình. Hiệu chỉnh theo thiết bị thật trước khi tin kết quả."
75
+
76
+ environment_validation:
77
+ # §12 — Gate 6B. Chạy TRƯỚC mọi lần execute mobile.
78
+ gate: "6B"
79
+ checklist:
80
+ - "Genymotion emulator đang chạy và `adb devices` thấy thiết bị"
81
+ - "APK đúng version đã install trên emulator"
82
+ - "App khởi động thành công (smoke check bằng tay)"
83
+ - "API_BASE_URL gọi được TỪ emulator: `adb shell curl ${API_BASE_URL}/health`"
84
+ - "Test data đã seed trên server (nếu cần)"
85
+ - ".env đã cấu hình đúng environment hiện tại"
86
+ - "Appium server connect được: `npx appium` chạy không lỗi"
87
+ - "WDIO dry-run pass: `npx wdio ./wdio.config.ts --dry-run`"
88
+ why: "Tám mục này là ranh giới giữa 'test đỏ' và 'môi trường chưa sẵn sàng'. Bỏ qua thì
89
+ mọi FAIL đều trông như product-gap, và QC đi mở bug cho một cái emulator chưa bật."
90
+
91
+ reporting:
92
+ # §1 — ⚠️ NGƯỢC với luật "No Allure" của stack cũ và của nền web.
93
+ tool: "Allure Report v2.x"
94
+ note: "Nền web dùng Playwright HTML Report (OQ-01 đóng 2026-06-02: Allure defer Phase 2).
95
+ Nền mobile thì Allure là BẮT BUỘC theo §1. Hai nền khác nhau ở điểm này — đừng
96
+ 'thống nhất' chúng lại; đó là quyết định của chuẩn, không phải chỗ sót."
97
+
98
+ trace_tags:
99
+ verifies: "// @trace.verifies={UC-ID}-SC{N}"
100
+ source: "// @trace.source=specs/{domain}/{prd-slug}/bdd/{platform}/{UC-ID}-{slug}.feature"
101
+ test_type: "// @trace.test_type=functional|integration|e2e|non-functional"
102
+
103
+ # Luật VIẾT CODE ở skills/qc/qa-script-designer/_shared/mobile-conventions.md.
104
+ # Ranh giới: hồ sơ này trả lời "chạy ở đâu, đặt tên gì"; skill trả lời "viết thế nào".
105
+
106
+ # qc_status: /qc-run-script ghi pass|fail|skip|not_run + qc_run_at vào
107
+ # {trace_dir}/{domain}/{prd-slug}/{UC-ID}-{active_platform}.tsv
@@ -60,7 +60,7 @@ Ghi vào **mục Data Flow** của `{qc_artifact_dir}REQUIREMENT_ANALYSIS.md`
60
60
  - Sơ đồ/list luồng dữ liệu cho mỗi kịch bản chính.
61
61
  - Danh sách integration point + state change + failure point.
62
62
  - Gợi ý loại test cần cho từng điểm (gui-feature / integration / e2e) khi sang qa-designer.
63
- - Dữ liệu/trạng thái cần chuẩn bị & cleanup → đầu vào fixture cho qa-runner.
63
+ - Dữ liệu/trạng thái cần chuẩn bị & cleanup → đầu vào fixture cho `qa-script-designer`.
64
64
 
65
65
  Chặng nào luồng/hành vi chưa rõ (vd lỗi xử lý ra sao, retry, partial commit) →
66
66
  ghi vào `{qc_artifact_dir}DOC_GAP.md` (loại MISSING / OPEN QUESTION).
@@ -99,9 +99,12 @@ biến một TC đang `Y` thành `N`.
99
99
  tag `@trace.verifies`. Không có cột này thì `/qc-run-script` phải suy đường dẫn từ quy ước đặt
100
100
  tên — suy sai thì chạy sai bộ test, hoặc **chạy 0 test mà vẫn báo xanh**.
101
101
 
102
- > **Đường dẫn theo stack HIỆN TẠI** module `qc-playwright` (Python + pytest-playwright):
103
- > `tests/<project>/test_<feature>.py` + `pages/<feature>_page.py`, theo
104
- > `modules/qc-playwright/stack-profile.yaml` §layout.
102
+ > **Đường dẫn theo module đã phân giải `steps/qc-scope.md` §2b** `qc-playwright-ts`
103
+ > *(web · system)* hoặc `qc-wdio-appium` *(app)*, mục `§layout.{web|api|mobile}` của
104
+ > `stack-profile.yaml` tương ứng. **Đừng viết cứng tên module ở đây.**
105
+ >
106
+ > *(Tên file theo `§naming` của module: `<feature>.page.ts` + `<feature>-<scenario>.spec.ts`
107
+ > (web) · `<resource>.api.ts` (system) · `<feature>.screen.ts` (app).)*
105
108
  >
106
109
  > *(Đề xuất gốc của đội QC viết theo TypeScript + Playwright Test / WebdriverIO. Việc đổi stack
107
110
  > là một bước RIÊNG, cố ý tách khỏi đợt tách lệnh — xem quyết định F3, Đợt 2 · b2. Khi stack
@@ -28,9 +28,15 @@ expected/actual) · `#QUESTION`, `#IDEA` placeholder · summary cuối session.
28
28
  ## Mode 2 — Convert Findings
29
29
  Input: session note (#BUG + #IDEA).
30
30
  - **Bug report** mỗi #BUG: title, severity, priority, steps to reproduce, expected/actual, hypothesis root cause.
31
- - **Functional TC mới:** mỗi #BUG đã fix 1–2 TC regression; mỗi #IDEA TC nếu đủ (hoặc backlog).
32
- Đặt đúng layer; bám format TC (Test Data list, Trace BR, 🚫 Block); trace "Origin: Exploratory session <date>".
31
+ - **Functional TC mới → KHÔNG viết luật đây.** Dùng `explore-to-functional.md` Phase 4
32
+ format `TC_<FEATURE>.Test.md` đầy đủ (metadata list, Trace BR, 🚫 Block, Test Data, Steps,
33
+ Expected 1 bullet, Trace matrix). Chỉ thêm một điều riêng của đường này: mỗi TC sinh từ session
34
+ phải mang `Origin: Exploratory session <date>`.
33
35
  - **Weekly summary** (nếu yêu cầu): overview, top findings, coverage gap, recommendations.
34
36
 
37
+ > **Vì sao Mode 2 trỏ đi chứ không tự viết** *(Bước S · S2, 2026-09-17)*: bản cũ mô tả lại format TC
38
+ > bằng một câu rút gọn, trong khi `explore-to-functional.md` Phase 4 đã có bản đủ. Hai bản của một
39
+ > format thì bản ngắn sẽ lạc hậu trước — và người đọc bản ngắn không biết mình đang đọc bản cũ.
40
+
35
41
  ## Output
36
42
  Mode 1: file session note. Mode 2: bug reports + file TC trong `{qc_artifact_dir}test-cases/` + summary.
@@ -16,7 +16,7 @@ Nạp cùng `shared/` (khuôn + độ chính xác + từ điển hành động)
16
16
 
17
17
  ## Khi KHÔNG trigger
18
18
  - Test qua giao diện → `functional/gui-screen`/`gui-feature`
19
- - Luồng dữ liệu API ↔ DB/service khác → `integration/api` · message/event → `integration/kafka`
19
+ - Luồng dữ liệu API ↔ DB/service khác → `integration/api` · message/event → `integration/queue`
20
20
 
21
21
  ---
22
22
 
@@ -0,0 +1,128 @@
1
+ ---
2
+ version: 1.0
3
+ updated: 2026-09-17
4
+ ---
5
+
6
+ # Test Case — Job chạy ngầm *(tự chạy theo lịch hoặc điều kiện)*
7
+
8
+ Skill **tự chứa** để viết TC cho một việc **không ai gọi**: nó tự thức dậy theo lịch, theo ngưỡng,
9
+ hoặc theo một cờ trong dữ liệu. Chỉ cần load file này.
10
+
11
+ ## Khi nào trigger
12
+ - Nền `system`, và hình dạng đã chốt là **job** *(xem `/qc-design-test` §Nền `system`)*.
13
+ - Ví dụ: dọn dữ liệu quá hạn lúc 2h sáng · tổng hợp báo cáo cuối ngày · gửi nhắc hạn ·
14
+ đồng bộ định kỳ với hệ ngoài · batch/ETL.
15
+
16
+ ## Khi KHÔNG trigger
17
+ - Có endpoint, ai đó gọi vào → `functional/api.md`
18
+ - Nằm chờ message rồi xử lý → `integration/queue.md`
19
+ - Chỉ verify bản ghi DB sau **một thao tác của người** → `integration/db.md`
20
+
21
+ ---
22
+
23
+ ## Format file TC
24
+
25
+ > **Nạp `{paths.qc_skills_dir}/qa-designer/shared/tc-metadata-format.md`** — khuôn TC, luật
26
+ > ATOMIC (1 kết cục = 1 TC), phân nhóm, Trace + `@trace.verifies`, `🚫 Block`.
27
+ > **Không lặp lại luật format ở đây.**
28
+ >
29
+ > Khi viết Expected Result / Test Data: nạp thêm `shared/precision-rules.md` +
30
+ > `shared/action-keywords-glossary.md`.
31
+
32
+ **`Tags` của mọi TC ở đây mang lane `job`.** Trạm 5 và trạm 6 đọc nó để không phải hỏi lại.
33
+
34
+ ---
35
+
36
+ ## 1 · Ba thứ phải chốt TRƯỚC khi viết TC
37
+
38
+ Job khác API ở chỗ **không có request để mô tả**. Thay vào đó phải chốt ba thứ, và **thiếu cái
39
+ nào thì dừng hỏi, đừng đoán**:
40
+
41
+ | | Chốt gì | Nếu thiếu |
42
+ |---|---|---|
43
+ | **Kích hoạt** | Trong môi trường test, job được làm cho chạy bằng cách nào? *(lịch bắn thật · gọi tay qua CLI/endpoint quản trị · cắm cờ trong DB · đẩy một message)* | Ghi `🚫 Block: [GAP-…]` — không có cách kích hoạt thì **không TC nào chạy được** |
44
+ | **Cửa sổ dữ liệu** | Lượt chạy này **nhặt những bản ghi nào**? *(tạo trước mốc nào · trạng thái nào · giới hạn bao nhiêu bản ghi một lượt)* | Không biết cửa sổ thì không dựng được Test Data, và Expected Result thành *"xử lý đúng"* — một cụm bị cấm |
45
+ | **Dấu vết quan sát được** | Sau khi chạy xong, **nhìn vào đâu** để biết nó đã làm? *(bản ghi đổi trạng thái · file sinh ra · message phát đi · thông báo gửi đi · số liệu/log)* | Không có dấu vết thì TC không có oracle — nó không đỗ/trượt được |
46
+
47
+ > **Đây là chỗ job hay bị viết hụt nhất.** Người viết quen với API: có request, có response, oracle
48
+ > hiển nhiên. Job **không trả gì cả** — oracle nằm ở **thay đổi trạng thái**, và nếu không chốt
49
+ > trước thì Expected Result sẽ trôi về *"job chạy thành công"*, một câu không kiểm được.
50
+
51
+ ---
52
+
53
+ ## 2 · Chín nhóm TC bắt buộc soi
54
+
55
+ Sáu nhóm từ **4** trở xuống là **rủi ro riêng của job** — không skill nào khác trong framework
56
+ phủ chúng. Bỏ nhóm nào thì nêu rõ **vì sao bỏ**, đừng im lặng.
57
+
58
+ ### 1 · Đường thuận
59
+ Có dữ liệu đúng trong cửa sổ → chạy → **từng dấu vết ở §1 đổi đúng như mong đợi**.
60
+ Assert cả ba mặt nếu có: bản ghi · message phát ra · thông báo.
61
+
62
+ ### 2 · Không nhặt thứ ngoài cửa sổ
63
+ Bản ghi **ngoài** điều kiện *(sai trạng thái, tạo sau mốc)* → chạy → **bản ghi đó KHÔNG đổi**.
64
+ Đây là assert **phủ định**, và là nhóm hay bị đánh rơi nhất khi rút gọn TC.
65
+
66
+ ### 3 · Lượt chạy rỗng
67
+ Không có bản ghi nào để làm → chạy → **không lỗi, không phát message, không gửi thông báo**.
68
+ Job báo lỗi khi rỗng là bug; job gửi thông báo *"đã xử lý 0 bản ghi"* mỗi đêm cũng là bug.
69
+
70
+ ### 4 · Chạy lại lần hai cùng dữ liệu *(idempotency)*
71
+ Chạy xong lần 1 → chạy lại ngay lần 2 trên cùng dữ liệu → **hiệu ứng chỉ xảy ra một lần**:
72
+ không trừ tiền hai lần, không gửi mail hai lần, không tạo bản ghi trùng.
73
+
74
+ > **Đây là bug kinh điển nhất của job chạy ngầm.** Nó xuất hiện thật khi lịch chạy chồng, khi
75
+ > có người kích tay lúc job đang chạy, hoặc khi hệ thống khởi động lại giữa chừng.
76
+
77
+ ### 5 · Hỏng giữa chừng
78
+ Cho lỗi ở bản ghi thứ **k** của **n** *(k nằm giữa)* → phải trả lời được **hai** câu, và TC phải
79
+ ghi rõ thiết kế chọn đường nào:
80
+
81
+ | Đường | Kỳ vọng |
82
+ |---|---|
83
+ | **Dừng cả lượt** | k−1 bản ghi đầu **đã xong** phải giữ nguyên, hay bị rollback hết? |
84
+ | **Bỏ qua bản lỗi, chạy tiếp** | bản thứ k có được ghi lại ở đâu không? Lượt sau có nhặt lại nó không? |
85
+
86
+ Chạy lại sau khi hỏng: **k−1 bản đầu KHÔNG được xử lý lần thứ hai** *(nối với nhóm 4)*.
87
+
88
+ ### 6 · Hai tiến trình cùng lúc
89
+ Kích hai lượt chạy chồng nhau → **không bản ghi nào bị xử lý hai lần**. Hoặc job phải **từ chối**
90
+ lượt thứ hai *(có khoá)*, hoặc hai lượt chia nhau bản ghi — **thiết kế chọn đường nào phải ghi
91
+ trong TC**, vì hai đường có Expected Result khác hẳn.
92
+
93
+ ### 7 · Biên của cửa sổ
94
+ Bản ghi tạo **đúng mốc** · **trước mốc một đơn vị** · **sau mốc một đơn vị** → nhặt đúng cái phải
95
+ nhặt. Và ca khó hơn: bản ghi **được tạo trong lúc job đang chạy** — lượt này lấy hay để lượt sau?
96
+
97
+ > Nêu **đơn vị** tường minh *(giây? ngày? theo múi giờ nào?)* — `precision-rules.md` cấm mốc mơ hồ.
98
+
99
+ ### 8 · Bản ghi độc
100
+ Một bản ghi hỏng *(dữ liệu sai định dạng, tham chiếu chết)* → nó **không được làm chết cả lượt**,
101
+ trừ khi thiết kế cố ý thế. Ghi rõ đường nào, và bản ghi độc đi đâu.
102
+
103
+ ### 9 · Thử lại và trần
104
+ Job gọi ra ngoài mà bên kia lỗi → thử lại mấy lần, cách nhau bao lâu, **trần ở đâu**?
105
+ Không có trần là job treo tới khi có người tắt.
106
+
107
+ ---
108
+
109
+ ## 3 · Phân nhóm trong file TC
110
+
111
+ ```
112
+ 1 Đường thuận ← nhóm 1
113
+ 2 Cửa sổ & biên ← nhóm 2, 7
114
+ 3 Chạy lặp & đồng thời ← nhóm 4, 6
115
+ 4 Hỏng & phục hồi ← nhóm 5, 8, 9
116
+ 5 Lượt rỗng ← nhóm 3
117
+ ```
118
+
119
+ ---
120
+
121
+ ## 4 · Test Data — khác API ở chỗ nào
122
+
123
+ Job **không nhận payload**; dữ liệu của nó là **trạng thái có sẵn trong hệ thống**. Nên Test Data
124
+ của TC job là một **bảng bản ghi phải seed trước**, kèm ba cột tối thiểu: định danh · trạng thái ·
125
+ mốc thời gian liên quan tới cửa sổ.
126
+
127
+ Và phải nêu **dọn thế nào** — job đổi trạng thái thật, nên chạy hai lần liên tiếp mà không dọn
128
+ thì lượt sau đã không còn ở điều kiện ban đầu *(và đó chính là nhóm 4 nếu cố ý, là nhiễu nếu vô ý)*.
@@ -15,7 +15,7 @@ verify luồng dữ liệu & contract giữa các thành phần. Chỉ cần loa
15
15
 
16
16
  ## Khi KHÔNG trigger
17
17
  - Chỉ verify request/response 1 endpoint → `functional/api`
18
- - Verify riêng trạng thái DB → `integration/db` · message/event → `integration/kafka`
18
+ - Verify riêng trạng thái DB → `integration/db` · message/event → `integration/queue`
19
19
 
20
20
  ---
21
21
 
@@ -13,7 +13,7 @@ insert/update/soft-delete đúng giá trị, side-effect, toàn vẹn. Chỉ c
13
13
  - Kiểm tra bản ghi DB sau thao tác (tạo ticket → ghi đúng bảng/cột); soft-delete, default, audit log
14
14
 
15
15
  ## Khi KHÔNG trigger
16
- - Chỉ verify response API → `functional/api`/`integration/api` · message/event → `integration/kafka`
16
+ - Chỉ verify response API → `functional/api`/`integration/api` · message/event → `integration/queue`
17
17
 
18
18
  ---
19
19
 
@@ -4,16 +4,32 @@ updated: 2026-06-11
4
4
  ported_from: ui-automation-testing
5
5
  ---
6
6
 
7
- # Test Case — Integration Kafka (Message/Event)
7
+ # Test Case — Integration hàng đợi (Message/Event)
8
8
 
9
- Skill **tự chứa** để viết TC tích hợp qua Kafka: producer phát event đúng, consumer xử
10
- đúng, đảm bảo ordering/idempotency/retry. Chỉ cần load file này.
9
+ Skill **tự chứa** để viết TC tích hợp qua hàng đợi/message bus Kafka, RabbitMQ, SQS, hay bất
10
+ kỳ chế nào **người gửi** **người nhận** tách rời: producer phát event đúng, consumer xử
11
+ lý đúng, đảm bảo ordering/idempotency/retry. Chỉ cần load file này.
12
+
13
+ > **Tên file đổi từ `kafka.md` (2026-09-17):** nội dung chưa bao giờ phụ thuộc Kafka — nó nói về
14
+ > **hình dạng hàng đợi**. Giữ tên một công nghệ cụ thể làm người dùng RabbitMQ/SQS tưởng không
15
+ > áp dụng được.
11
16
 
12
17
  ## Khi nào trigger
13
- - Action sinh event Kafka (vd tạo ticket → phát event sang service/CRM); verify topic/payload/thứ tự/khử trùng
18
+
19
+ Hai phía, **cùng một file** — nêu rõ TC đang đứng ở phía nào:
20
+
21
+ | Phía | Khi nào | Ví dụ |
22
+ |---|---|---|
23
+ | **Người gửi** *(producer)* | một action sinh ra event | tạo ticket → phát event sang CRM; verify topic · key · payload · điều kiện phát |
24
+ | **Người nhận** *(consumer)* | service **nằm chờ**, có message tới thì xử lý — **không action nào của người đứng trước** | đơn hàng mới vào hàng đợi → service kho trừ tồn; verify xử lý đúng · khử trùng · lỗi thì đi đâu |
25
+
26
+ > **Phía người nhận là chỗ hay bị bỏ sót.** Khung cũ chỉ viết *"Action sinh event"* — tức luôn
27
+ > giả định có một thao tác đứng trước. Một consumer thuần thì **không có thao tác đó**, và TC
28
+ > phải bắt đầu bằng *"có message X trên hàng đợi Y"*, không phải bằng một hành động của người.
14
29
 
15
30
  ## Khi KHÔNG trigger
16
31
  - Tích hợp đồng bộ qua API → `integration/api` · verify DB → `integration/db`
32
+ - **Tự chạy theo lịch, không có message nào kích** → `functional/job.md`
17
33
 
18
34
  ---
19
35
 
@@ -11,6 +11,21 @@ upstream_sha: 57125f0c21512f2abcc55d00420e92c84c95fc8f
11
11
 
12
12
  ---
13
13
 
14
+ ## Bước 0 — TC đã có lane chưa? *(hỏi TRƯỚC mọi câu khác)*
15
+
16
+ Nếu `Tags` của TC đã mang một `<lane>` — `ui` · `api` · `job` · `queue` · `db` · `e2e` · `nfr` —
17
+ thì **ĐỌC nó, dừng ở đây, không suy lại**. Bảng lane ↔ skill ở
18
+ `shared/tc-metadata-format.md` §Tags.
19
+
20
+ > **Vì sao dừng chứ không "kiểm tra lại cho chắc".** Với nền `system`, lane là **câu trả lời của
21
+ > QC** ở trạm 3 cho một câu mà máy không suy được *(xem `/qc-design-test` §Nền `system`)*. Suy lại
22
+ > là đặt phán đoán của máy lên trên câu trả lời của người — và khi hai bên lệch, TC và script sẽ
23
+ > kiểm hai thứ khác nhau mà **cả hai đều chạy được**.
24
+ >
25
+ > Chưa có lane → đi tiếp Bước 1.
26
+
27
+ ---
28
+
14
29
  ## Bước 1 — Đối tượng test là gì?
15
30
 
16
31
  ```
@@ -18,6 +33,8 @@ upstream_sha: 57125f0c21512f2abcc55d00420e92c84c95fc8f
18
33
  ├── Hiển thị / validation / state của 1 screen → [A] Xét tiếp Bước 2 (UI vs Integration GUI)
19
34
  ├── User thực hiện workflow có mục tiêu nghiệp vụ → [B] Xét tiếp Bước 3 (E2E vs Integration)
20
35
  ├── 1 API endpoint (request/response/mã lỗi) → api-testcase-designer
36
+ ├── Việc TỰ CHẠY theo lịch/điều kiện, không ai gọi → functional/job.md
37
+ ├── Nằm chờ message rồi xử lý → integration/queue.md
21
38
  ├── NFR (performance/security/a11y/i18n) → nfr-testcase-designer
22
39
  └── Luồng đa màn nằm trong 1 feature, không xuyên hệ thống → ui-testcase-designer (gui-feature)
23
40
  ```