@educa-corp/sdd-framework 0.2.6 → 0.2.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 (77) hide show
  1. package/commands/debug.md +4 -1
  2. package/commands/define-product.md +38 -1
  3. package/commands/define-product.tmpl +34 -0
  4. package/commands/dev-gen-test.md +4 -1
  5. package/commands/dev-run-test.md +4 -1
  6. package/commands/dev-smoke-test.md +4 -1
  7. package/commands/fix-bug.md +4 -1
  8. package/commands/generate-architecture.md +4 -1
  9. package/commands/generate-bdd.md +4 -1
  10. package/commands/generate-code.md +80 -26
  11. package/commands/generate-code.tmpl +76 -25
  12. package/commands/generate-design-spec.md +4 -1
  13. package/commands/generate-prd.md +4 -1
  14. package/commands/generate-spec-manifest.md +4 -1
  15. package/commands/generate-tech-docs.md +4 -1
  16. package/commands/learn.md +4 -1
  17. package/commands/map-testids.md +4 -1
  18. package/commands/propose-scenario.md +4 -1
  19. package/commands/qc-analyze.md +4 -1
  20. package/commands/qc-design-test.md +4 -1
  21. package/commands/qc-plan.md +4 -1
  22. package/commands/qc-report.md +4 -1
  23. package/commands/qc-review.md +4 -1
  24. package/commands/qc-run-test.md +4 -1
  25. package/commands/refine-prd.md +4 -1
  26. package/commands/report-bug.md +4 -1
  27. package/commands/review-code.md +4 -1
  28. package/commands/review-context.md +4 -1
  29. package/commands/review-tech-docs.md +4 -1
  30. package/commands/setup-ai-first.md +2 -1
  31. package/commands/validate-traces.md +4 -1
  32. package/core/FRAMEWORK_VERSION +1 -1
  33. package/core/commands/debug.md +4 -1
  34. package/core/commands/define-product.md +38 -1
  35. package/core/commands/dev-gen-test.md +4 -1
  36. package/core/commands/dev-run-test.md +4 -1
  37. package/core/commands/dev-smoke-test.md +4 -1
  38. package/core/commands/fix-bug.md +4 -1
  39. package/core/commands/generate-architecture.md +4 -1
  40. package/core/commands/generate-bdd.md +4 -1
  41. package/core/commands/generate-code.md +80 -26
  42. package/core/commands/generate-design-spec.md +4 -1
  43. package/core/commands/generate-prd.md +4 -1
  44. package/core/commands/generate-spec-manifest.md +4 -1
  45. package/core/commands/generate-tech-docs.md +4 -1
  46. package/core/commands/learn.md +4 -1
  47. package/core/commands/map-testids.md +4 -1
  48. package/core/commands/propose-scenario.md +4 -1
  49. package/core/commands/qc-analyze.md +4 -1
  50. package/core/commands/qc-design-test.md +4 -1
  51. package/core/commands/qc-plan.md +4 -1
  52. package/core/commands/qc-report.md +4 -1
  53. package/core/commands/qc-review.md +4 -1
  54. package/core/commands/qc-run-test.md +4 -1
  55. package/core/commands/refine-prd.md +4 -1
  56. package/core/commands/report-bug.md +4 -1
  57. package/core/commands/review-code.md +4 -1
  58. package/core/commands/review-context.md +4 -1
  59. package/core/commands/review-tech-docs.md +4 -1
  60. package/core/commands/setup-ai-first.md +2 -1
  61. package/core/commands/validate-traces.md +4 -1
  62. package/core/modules/phaser-game/architecture-snippets/phaser-scene-patterns.md +646 -0
  63. package/core/modules/phaser-game/module.yaml +15 -0
  64. package/core/modules/phaser-game/stack-profile.yaml +90 -0
  65. package/core/steps/context-loader.md +2 -0
  66. package/core/steps/gate.md +2 -1
  67. package/core/templates/project-context.yaml +6 -0
  68. package/docs/02-concepts/pipeline-steps/06-code.md +7 -4
  69. package/docs/03-guides/developer.md +6 -3
  70. package/docs/explain/09-generate-code.md +41 -3
  71. package/modules/phaser-game/architecture-snippets/phaser-scene-patterns.md +646 -0
  72. package/modules/phaser-game/module.yaml +15 -0
  73. package/modules/phaser-game/stack-profile.yaml +90 -0
  74. package/package.json +1 -1
  75. package/steps/context-loader.md +2 -0
  76. package/steps/gate.md +2 -1
  77. package/templates/project-context.yaml +6 -0
@@ -52,7 +52,8 @@ Hiển thị và chờ phản hồi:
52
52
 
53
53
  ## Bước 1 — Xác định Target File
54
54
 
55
- 1. Nếu `$ARGUMENTS` được cung cấp trỏ tới một file tồn tại dùng trực tiếp làm target.
55
+ 0. **Tách cờ trước khi resolve target.** `$ARGUMENTS` thể lẫn các `--flag` (vd `--phase=integration`, `--comment`, `--fix`). **Loại bỏ mọi token bắt đầu bằng `--`** ra khỏi phần dùng để tìm target — chỉ giữ phần path/UC-ID/ticket. (Các flag đó do phần logic riêng của lệnh parse ở bước sau, KHÔNG phải tên file.)
56
+ 1. Nếu `$ARGUMENTS` (đã tách cờ) được cung cấp và trỏ tới một file tồn tại → dùng trực tiếp làm target.
56
57
  2. Nếu `$ARGUMENTS` là một **UC-ID / ticket ID / tên rút gọn** (không có path) → phân giải thành file bằng cách glob theo bố cục feature-package. `{prd-slug}` lúc này **chưa biết**, nên dùng wildcard `*` cho segment đó, và `**` đệ quy dưới `bdd/` để phủ hết các thư mục con theo platform (`bdd/web/`, `bdd/app/`, `bdd/system/`):
57
58
  - **Lệnh BDD** (target là `.feature`): `{specs_dir}/{domain}/*/bdd/**/{UC-ID}*.feature` — hoặc `{specs_dir}/*/*/bdd/**/{UC-ID}*.feature` nếu domain cũng chưa biết. Nếu lệnh ngụ ý một platform/scope cụ thể (vd: system tech-doc cần BDD `system/`), ưu tiên kết quả trong thư mục con platform đó.
58
59
  - **Lệnh PRD** (target là file PRD `{TICKET-ID}-{prd-slug}.md` — file `.md` duy nhất ở gốc feature folder, cạnh `bdd/`): `{specs_dir}/{domain}/*/{TICKET-ID}*.md` nếu biết TICKET-ID; nếu không, `{specs_dir}/{domain}/*/*.md` (khớp feature folder có id tương ứng), hoặc `{specs_dir}/*/*/*.md` nếu domain cũng chưa biết. *(Glob `*/*.md` ở cấp gốc folder chỉ khớp PRD — tech-docs/design-spec `.md` nằm sâu hơn trong thư mục con.)*
@@ -138,6 +139,7 @@ Thực hiện các bước theo đúng thứ tự. Lưu mọi thứ vào bộ nh
138
139
  - `paths.business_dictionary` → path tới business-dictionary.md
139
140
  - `paths.core_entities` → path tới core-entities.md
140
141
  - `paths.tech_docs_dir` → gốc tài liệu kỹ thuật (gộp với specs_dir trong bố cục feature-package — tech-docs nằm dưới `{specs_dir}/{domain}/{prd-slug}/tech-docs/`)
142
+ - `paths.src_dir` → gốc mã nguồn (nơi generate-code đặt & quét code; nguồn chính cho FE + phạm vi reuse-scan của DS5)
141
143
  - `paths.trace_dir` → thư mục trạng thái trace; cấu trúc: `.trace/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv` (mỗi UC × platform một sổ)
142
144
 
143
145
  Nếu không có section `paths`, dùng các giá trị mặc định:
@@ -150,6 +152,7 @@ Nếu không có section `paths`, dùng các giá trị mặc định:
150
152
  - `business_dictionary` = `specs/domain-knowledge/business-dictionary.md`
151
153
  - `core_entities` = `specs/domain-knowledge/core-entities.md`
152
154
  - `tech_docs_dir` = `specs`
155
+ - `src_dir` = `src`
153
156
  - `trace_dir` = `.trace`
154
157
 
155
158
  Lưu ý: Trong bố cục feature-package, `specs_dir` là gốc thống nhất. Mọi loại spec artifact (PRD, BDD, tech-docs, design-spec) đều nằm dưới `{specs_dir}/{domain}/{prd-slug}/`. `prd-slug` là tên folder feature-package, không phải một biến config riêng.
@@ -439,7 +442,7 @@ Lệnh này giới hạn nghiêm ngặt trong **một file feature** được tr
439
442
 
440
443
  Đọc:
441
444
  1. Chỉ file `.feature` đã giới hạn scope
442
- 2. Tech-doc gộp của PRD tại `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md` (nếu tồn tại) — **tra §10 UC Coverage làm mục lục** để định vị scenario/section của UC đang sinh; **endpoint liên quan = §4.1 entries mà §5 lane của UC này gọi tới** (đừng lấy endpoint/section của UC khác). Từ đó đọc §4 API, §4.5 client, §5 flow của đúng UC này
445
+ 2. Tech-doc gộp của PRD tại `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md` (nếu tồn tại) — **tra §10 UC Coverage làm mục lục** để định vị scenario/section của UC đang sinh; **endpoint liên quan = §4.1 entries mà §5 lane của UC này gọi tới** (đừng lấy endpoint/section của UC khác). Từ đó đọc §4 API, §4.5 client, §5 flow của đúng UC này. **Đọc thêm §7 (Security & Authorization)** — luật phân quyền/enforce của UC → áp vào code; **và §8 (Error Handling & Edge Cases)** — mỗi row lỗi/biên phải có nhánh xử lý tương ứng trong code (khớp §4.3 error code), đừng chỉ code happy-path.
443
446
  3. CLAUDE.md §architecture + §coding_standards
444
447
  4. **(chỉ FE/App)** Design Spec — nạp qua **Guard** bên dưới (gate approved/độ-tươi + sanity), là nguồn của màn hình, component inventory, và link Figma frame từng-màn.
445
448
 
@@ -462,7 +465,7 @@ Lệnh này giới hạn nghiêm ngặt trong **một file feature** được tr
462
465
  - **Sanity-scan** (như generate-bdd bước 2.5): màn thiếu state loading/error/empty, AC-UI không testable, component `[NEW]`/`[TODO]` chưa chốt, còn ❌ Missing frame → cảnh báo trong cùng CHECKPOINT.
463
466
  - `Status: approved` VÀ `Built from PRD` khớp PRD hiện tại VÀ sạch cờ đỏ → dùng làm nguồn màn hình / component / Figma.
464
467
 
465
- **Tech-doc contract (chỉ backend/system) — DS3:** *áp dụng khi lần sinh này tạo code **backend** — `@trace.platform = system`, HOẶC chế độ default (không `--phase`) với `platform_type = backend`. Bỏ qua FE `--phase=ui`/`--phase=integration` (đã có nguồn shape riêng ở Phase Detection).*
468
+ **Tech-doc contract (chỉ backend/system) — DS3:** *áp dụng khi lần sinh này tạo code **backend** — `@trace.platform = system` (nguồn chuẩn quyết BE/FE, xem Phase Detection). Bỏ qua FE (`@trace.platform` = `web`/`app`) FE có nguồn shape riêng ở Phase Detection.*
466
469
 
467
470
  Định vị tech-doc gộp `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md`, kiểm phần backend của UC này (§4.1 Endpoints / §4.2 Request-Response / §4.3 Error):
468
471
  - **Brownfield** — nếu PRD Metadata `API Source: existing`: contract nằm ở Appendix "Existing API Contract" của PRD → nguồn hợp lệ, **bỏ qua DS3** (không cảnh báo).
@@ -481,13 +484,17 @@ Lệnh này giới hạn nghiêm ngặt trong **một file feature** được tr
481
484
 
482
485
  ## Phase Detection
483
486
 
487
+ > **Nguồn chuẩn quyết BE/FE = `@trace.platform` của FILE FEATURE** (`system` → BE · `web`/`app` → FE). KHÔNG dùng `platform_type` (suy từ module) để quyết BE/FE — nó chỉ dùng cho **idiom stack/module** (cú pháp, layer, thư viện). Lý do: repo fullstack một-module (vd Next.js có API route) có `platform_type` cố định một giá trị, nhưng vẫn có cả feature `system` (BE) lẫn `web` (FE) — chỉ tag của chính feature mới đúng.
488
+
484
489
  Parse `$ARGUMENTS` tìm flag `--phase`:
485
490
 
486
491
  | Flag | Ý nghĩa |
487
492
  |---|---|
488
493
  | `--phase=ui` | FE Phase 1 — sinh UI + layer mock API từ System BDD contract |
489
494
  | `--phase=integration` | FE Phase 2 — thay mock adapter bằng lời gọi API thật từ tech docs |
490
- | *(không có)* | Default — full implementation (BE hoặc full-stack không tách mock) |
495
+ | *(không có)* | Default — full: **BE/`system`** → full backend; **FE (`web`/`app`)** **FE full** (sinh UI + wire API thật trong một lần, không qua bước mock) |
496
+
497
+ **Xác định `fe_full`:** khi **KHÔNG** có `--phase` VÀ `@trace.platform` là `web`/`app` → đây là **FE full mode**. Sinh UI **và** wire API thật trong cùng một lần chạy, **bỏ qua** layer mock. Cụ thể: các section **sinh UI** chạy · **Mock API Layer** bị bỏ (chỉ dành `--phase=ui`) · **DS4** và **Integration Phase** VẪN chạy (xem điều kiện của từng section). BE/`system` ở default vẫn là full backend như trước.
491
498
 
492
499
  **Nếu `--phase` được set — xác nhận platform:**
493
500
  Đọc `@trace.platform` từ header file feature.
@@ -551,14 +558,21 @@ selection context, và code snippet — những thứ một URL web đơn không
551
558
  qua Figma MCP và ground UI trên layout, variable, và mapping Code Connect trả về. Ưu tiên
552
559
  component được map Code-Connect hơn là bịa markup; dùng tên token thật, không phải giá trị hardcode.
553
560
 
554
- **Nếu `--phase=integration`:**
561
+ ---
562
+
563
+ ## Integration Gates — DS4 (contract) · DS5 (reuse)
564
+
565
+ *Áp dụng khi wire API thật: `--phase=integration` **HOẶC** `fe_full`. Bỏ qua `--phase=ui` và default BE.*
566
+
567
+ > **Sequencing ở `fe_full`:** hai cổng này chạy **trước** khi UI/adapter được sinh trong cùng lần chạy, nên chúng suy luận từ **BẢN THIẾT KẾ** (design-spec + tech-doc §4.5) — tức *kế hoạch*, KHÔNG phải code đã sinh. "Port do UI định nghĩa" và "mock adapter có sẵn" chỉ tồn tại ở luồng 2-pha (`--phase=integration` chạy sau `--phase=ui`); ở `fe_full` port thật được chốt tại bước Generate về sau.
568
+
555
569
  Phân giải design điều khiển adapter từ **tech-doc gộp của PRD** `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md`:
556
570
  - **Mapping port→endpoint→DTO→error** (ưu tiên): §4.5.4 (API Integration Layer của platform này) — mỗi client method → endpoint có thật.
557
571
  - **Nguồn endpoint/shape**: §4.1 Endpoints + §4.2 Request-Response + §4.3 Error của cùng doc.
558
572
 
559
- **Client contract gate — DS4** *(chỉ `--phase=integration`; KHÔNG áp dụng `--phase=ui` — UI vẫn degrade êm qua mock).* Đối xứng với DS3 của BE: soi §4.5.4 **đủ chưa** cho UC/platform này *trước khi* wire adapter thật.
573
+ **Client contract gate — DS4** *(áp dụng khi `--phase=integration` **HOẶC** `fe_full`; KHÔNG áp dụng `--phase=ui` — UI vẫn degrade êm qua mock).* Đối xứng với DS3 của BE: soi §4.5.4 **đủ chưa** cho UC/platform này *trước khi* wire adapter thật.
560
574
 
561
- 1. **Xác định phạm vi cần:** các client method mà UC NÀY dùng — lấy từ §10 (định vị scenario của UC) → §4.5.4 rows / interface `{UC-ID}ApiPort` của mock adapter (`--phase=ui`).
575
+ 1. **Xác định phạm vi cần:** các client method mà UC NÀY dùng — lấy từ §10 (định vị scenario của UC) → §4.5.4 rows. Nguồn interface port: `{UC-ID}ApiPort` của mock adapter (`--phase=integration`, đã có từ lần `--phase=ui` trước) HOẶC, ở `fe_full`, port do chính lần chạy này định nghĩa lúc sinh UI (§4.5.3 state + §4.5.4) — chưa có mock adapter.
562
576
  2. **Kiểm tính đủ của §4.5.4 cho từng method:** có endpoint (resolve được ở §4.1) + map request + response→model + error→UI. *(Khác cảnh báo cũ: cái cũ chỉ bắt "thiếu HẲN §4.5.4"; DS4 bắt cả "thiếu MỘT PHẦN".)*
563
577
  3. **Phân loại (giống DS3):**
564
578
  - **Đủ + `@trace.status: approved` + 0 🔴 blocker-GAP (§12) chạm §4.5.4/UC này** → dùng làm nguồn, KHÔNG hỏi.
@@ -575,8 +589,24 @@ Phân giải design điều khiển adapter từ **tech-doc gộp của PRD** `{
575
589
  Vẫn wire bây giờ? (Y = best-effort/giữ mock cho phần thiếu · N = dừng, đi hoàn thiện tech-docs)
576
590
  ```
577
591
  Chỉ tiếp khi Y. *(Đây là "tư thế BE": trỏ ngược tech-docs thay vì hỏi live từng câu.)*
578
- Định vị mock adapter sẵn từ lần chạy `--phase=ui` (tìm `{UC-ID}MockApiAdapter` trong `{paths.src_dir}/{domain}/`).
579
- Nếu không tìm thấy → cảnh báo: "Không tìm thấy mock adapter — sinh real API adapter từ đầu dùng contract tech-doc."
592
+ **FE component/service reuse gate DS5** *(áp dụng khi `--phase=integration` **HOẶC** `fe_full`; KHÔNG áp dụng `--phase=ui`).* **Phát hiện & tái dùng** code FE đang tồn tại trước khi dựng mới — chống đẻ adapter/service **song song, mồ côi**, không nối vào app đang chạy.
593
+
594
+ 1. **Định vị mock adapter framework:** tìm `{UC-ID}MockApiAdapter` trong `{paths.src_dir}/{domain}/` (output `--phase=ui`).
595
+ 2. **Discovery code FE có sẵn:** quét `{paths.src_dir}` (phạm vi domain/feature) tìm **component / service / hook / api-client** mà các màn của UC này dùng — đối chiếu: component inventory của **design-spec**, path ở tech-doc **§4.5.2**, tên màn/UC. Lập danh sách "đã tồn tại" vs "chưa có".
596
+ 3. **Quyết định reuse-or-new:**
597
+ - **CÓ mock adapter** (luồng 2-pha chuẩn) → tái dùng port/wiring của nó như cũ; **KHÔNG hỏi**.
598
+ - **KHÔNG có mock adapter NHƯNG discovery thấy component/service có sẵn** (brownfield / chạy integration một mình trên app đang chạy) → **CHECKPOINT hỏi, KHÔNG tự dựng mới:**
599
+ ```
600
+ 🔎 Thấy {N} phần FE đang tồn tại cho màn của {UC-ID}/{platform}:
601
+ - {path} ({component | service | hook | api-client})
602
+ Wire API thật vào code CÓ SẴN này, hay dựng mới?
603
+ R (reuse) — EXTEND/wire adapter vào component/service đang chạy (khuyến nghị)
604
+ N (new) — dựng adapter/service mới (chỉ khi code cũ không tái dùng được — ghi lý do)
605
+ ```
606
+ - **R** → set `reuse_target` = các file có sẵn; Integration Phase **EXTEND/wire vào chúng** (áp Quy tắc EXTEND phi-phá-huỷ + Guard sau-ghi ở §File Scan), KHÔNG tạo file song song.
607
+ - **N** → dựng mới, ghi lý do vào report.
608
+ - **KHÔNG có mock adapter VÀ discovery KHÔNG thấy gì** → greenfield thật → sinh real adapter từ đầu dùng contract tech-doc (không cần hỏi).
609
+ 4. Lưu `reuse_target` (hoặc `none`) cho Integration Phase dùng ở bước wire-up.
580
610
 
581
611
  ---
582
612
 
@@ -606,6 +636,11 @@ Trước khi định vị file, chốt **package đích** theo **Package Layout
606
636
 
607
637
  **Quét module TÁI DÙNG trước khi tạo:** với mỗi layer, kiểm `{code_base_package}.{layer}` đã tồn tại trên disk chưa. Nếu đã có class phục vụ cùng entity/nghiệp vụ → **đặt member mới vào class đó (EXTEND)**, KHÔNG dựng cây layer / class song song. Chỉ tạo mới khi thực sự chưa có.
608
638
 
639
+ **Đặt code FE (`@trace.platform` = web/app):** quy tắc trên là cho BE (Java-style `{package}.{layer}`). FE đặt file theo thứ tự ưu tiên:
640
+ 1. **Path ở tech-doc §4.5.2 (Component File Mapping)** — nếu có, dùng **nguyên văn** đường dẫn cột `Path` (đây là contract đặt file của FE).
641
+ 2. **Else** → gốc `{paths.src_dir}` + quy ước thư mục của module/framework (vd `src/features/{domain}/…` React · `lib/{domain}/…` Flutter). Component/hook/service/adapter của cùng feature nằm gần nhau; **KHÔNG** rải mỗi file một nơi.
642
+ Adapter API mặc định tại `{paths.src_dir}/{domain}/` (khi §4.5.2 không chỉ định). Luôn **quét `{paths.src_dir}` tái dùng** như BE trước khi tạo mới (đồng bộ DS5).
643
+
609
644
  ---
610
645
 
611
646
  ## Seam & Stub Ledger — nối/lấp chỗ chưa implement *(chống mồ côi)*
@@ -737,9 +772,10 @@ Domain : {domain}
737
772
  UC : chỉ {UC-ID} ← các file feature khác trong folder này KHÔNG được đọc
738
773
  Tech : {language} / {framework}
739
774
  Package : {code_base_package}.{layer} · {by-layer | by-feature} ← feature/UC ở TÊN CLASS, KHÔNG thành package (nếu by-layer)
740
- Phase : {UI — mock layer | Integration — real API | Default — full} ← bỏ nếu không flag --phase
775
+ Phase : {UI — mock layer | Integration — real API | FE full UI + real API | BE full} ← FE full = default trên web/app; bỏ dòng này với default BE
741
776
  Scenarios: {N} total ({X} new, {Y} drifted, {Z} synced-skip)
742
777
  Layer : {từ CLAUDE.md §2}
778
+ Client : {chỉ integration/fe_full — reuse: {reuse_target hoặc "dựng mới"} · gaps §4.5.4: {n còn trống hoặc "đủ"}} ← bỏ dòng này với BE / --phase=ui
743
779
 
744
780
  Files:
745
781
  CREATE {N} file mới
@@ -809,7 +845,7 @@ DTOs → Entity/Model → Repository → Service interface → Service impl →
809
845
  Mỗi element **có action** (button, input, link, select, toggle, form-submit) PHẢI mang một **test-id ổn định** để QC định vị trực tiếp (không scan runtime):
810
846
 
811
847
  1. **Nguồn id.** Nếu tech-doc gộp `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md` có **§4.5.6 Test Selectors** cho platform này, lấy id **nguyên văn** từ bảng đó (contract). Nếu chưa có (vd `--phase=ui` trước khi §4.5 được vẽ), **sinh id theo quy ước** `{uc-lower}-{screen}-{element}-{type}` (vd `ft001-login-submit-btn`) để QC vẫn có handle ổn định — chúng sẽ được đối chiếu với §4.5.6 của tech-design lúc integration.
812
- 2. **Emit qua attribute platform** (từ `@trace.testid_attr`, hoặc theo module):
848
+ 2. **Emit qua attribute platform** — chọn attribute theo **`active_module`** (bảng dưới, mặc định). Chỉ override khi header `.feature` khai tường minh `@trace.testid_attr={attr}` (hiếm; dùng cho stack lai). Không có khai báo → theo module:
813
849
  - web (`react`/`nextjs`/`vue`/`angular`) → `data-testid="..."`
814
850
  - React Native → `testID="..."`
815
851
  - Flutter → `Key('...')` (+ `Semantics(identifier: '...')` khi action cần)
@@ -849,24 +885,32 @@ Dựng mock từ `mock_source` đã phân giải ở Phase Detection — **shape
849
885
 
850
886
  ---
851
887
 
852
- ## Integration Phase (chỉ `--phase=integration`)
888
+ ## Integration Phase (`--phase=integration` HOẶC `fe_full`)
853
889
 
854
- *Bỏ qua hoàn toàn section này nếu `--phase` không phải `integration`.*
890
+ *Bỏ qua hoàn toàn section này nếu KHÔNG phải `--phase=integration` KHÔNG phải `fe_full` (vd `--phase=ui`, hoặc default BE/`system`).*
891
+
892
+ *Hai chế độ vào section này:*
893
+ - **`--phase=integration`** — đã có mock adapter + UI từ lần `--phase=ui` trước → **thay** mock bằng real (có lật wire-up).
894
+ - **`fe_full`** — UI vừa được sinh trong CHÍNH lần chạy này, **không có bước mock** → wire real adapter **thẳng** (không có mock để thay/lật).
855
895
 
856
896
  1. **Đọc integration design.** Trong tech-doc gộp `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md`: ưu tiên §4.5.4 (mapping port→endpoint→DTO→error của platform), dùng §4.1/§4.2/§4.3 làm nguồn endpoint / request-response / error-code. Nếu doc chưa có §4.5.4 cho platform này, trích endpoint + shape + error code trực tiếp từ §4.1–§4.3.
857
- - **Tính đủ của §4.5.4 đã được cửa DS4 (Phase Detection) kiểm + vét SRC-CHAIN + gộp-hỏi TỪ TRƯỚC.** Ở bước này dùng thẳng kết quả đã phân giải của DS4 — **KHÔNG mở checkpoint/hỏi lại**. Nếu DS4 kết luận một mapping vẫn trống mà người đã chọn Y (best-effort) → giữ mock cho đúng phần đó, tag `@trace.stub`, ghi sổ seam; đừng bịa giá trị.
858
- 2. **Đọc mock adapter có sẵn** interface (`{UC-ID}ApiPort`) từ output `--phase=ui`. Real adapter implements **cùng** interface này → shape port/DTO đã cố định từ mock; **không hỏi lại shape** đã có ở đây.
859
- 3. **Sinh real API adapter** tại `{paths.src_dir}/{domain}/{UC-ID}ApiAdapter.{ext}`:
860
- - Implements cùng interface `{UC-ID}ApiPort` như mock adapter
861
- - Gọi HTTP thật tới endpoint từ contract tech-doc
862
- - Map field response sang cùng shape mock adapter trả về
863
- - Tag traceability:
897
+ - **Tính đủ của §4.5.4 đã được cửa DS4 kiểm + vét SRC-CHAIN + gộp-hỏi TỪ TRƯỚC.** Ở bước này dùng thẳng kết quả đã phân giải của DS4 — **KHÔNG mở checkpoint/hỏi lại**. Nếu DS4 kết luận một mapping vẫn trống mà người đã chọn Y (best-effort) → ở `--phase=integration` giữ mock cho phần đó; ở `fe_full` để adapter trả stub, tag `@trace.stub`, ghi sổ seam; đừng bịa giá trị.
898
+ 2. **Nguồn interface port `{UC-ID}ApiPort`:**
899
+ - `--phase=integration` (có mock) → đọc từ mock adapter sẵn (output `--phase=ui`). Real adapter implements **cùng** interface → shape port/DTO đã cố định, **không hỏi lại shape**.
900
+ - `reuse_target` (DS5 chọn **R**) → dùng interface/kiểu **service/hook sẵn** đang khai báo; adapter mới phải khớp chữ ký chúng đang gọi (không đổi hợp đồng của code đang chạy).
901
+ - `fe_full` greenfield port do UI vừa sinh trong lần này định nghĩa (§4.5.3/§4.5.4). Không có mock adapter để đọc.
902
+ 3. **Sinh / lắp real API adapter** theo kết quả **DS5**:
903
+ - **`reuse_target` = none** (greenfield / DS5 chọn N) → sinh file mới `{paths.src_dir}/{domain}/{UC-ID}ApiAdapter.{ext}`, implements `{UC-ID}ApiPort`.
904
+ - **`reuse_target` có file** (DS5 chọn R) → **EXTEND vào service/api-client/hook đang chạy** (áp Quy tắc EXTEND phi-phá-huỷ + Guard sau-ghi ở §File Scan): thay lời gọi mock/placeholder bằng lời gọi HTTP thật **tại chỗ**, giữ nguyên mọi member cũ; **KHÔNG** tạo `{UC-ID}ApiAdapter` song song.
905
+ - Chung: gọi HTTP thật tới endpoint từ contract tech-doc; map field response sang shape port/service khai báo; tag:
864
906
  ```
865
907
  @trace.implements={UC-ID}-SC{N}
866
908
  @trace.tech_doc_revision={đọc từ header tech-doc}
867
909
  ```
868
- 4. **Lật wire-up**: chuyển DI binding / env flag để service/hook dùng `{UC-ID}ApiAdapter` (thật) thay vì mock.
869
- 5. **KHÔNG xoá mock adapter** — giữ lại cho unit test.
910
+ 4. **Wire-up:**
911
+ - `--phase=integration` (có mock) → **lật** DI binding / env flag để service/hook dùng adapter thật thay vì mock. **KHÔNG xoá mock adapter** — giữ cho unit test.
912
+ - `reuse_target` (DS5 chọn R) → wiring đã nằm trong chính component/service có sẵn (đã EXTEND ở bước 3) → **không thêm binding song song**; chỉ chỉnh cấu hình bật đường thật nếu code cũ có cờ mock.
913
+ - `fe_full` greenfield → wire service/hook thẳng vào `{UC-ID}ApiAdapter` (thật); không sinh mock adapter (unit test dùng stub/fake tại chỗ khi cần).
870
914
 
871
915
  ---
872
916
 
@@ -885,6 +929,16 @@ Dựng mock từ `mock_source` đã phân giải ở Phase Detection — **shape
885
929
  {conventions.build_command} # từ project-context.yaml, tối đa 3 retry
886
930
  ```
887
931
 
932
+ > **GATE build (BẮT BUỘC):** chỉ khi build **SUCCESS** mới được đi tiếp sang **Write Trace State** và **Commit**.
933
+ > - Fail → sửa lỗi rồi retry (tối đa 3 lần).
934
+ > - **Vẫn fail sau 3 retry → DỪNG.** KHÔNG ghi trace, KHÔNG commit (trace/repo không được nói "đã xong" khi chưa build được). Xuất:
935
+ > ```
936
+ > ❌ Build FAIL sau 3 lần thử — không ghi trace, không commit.
937
+ > Lỗi cuối: {tóm tắt}
938
+ > File đã sinh giữ nguyên trên working tree để bạn sửa tay hoặc chạy /debug.
939
+ > ```
940
+ > Đặt Status badge = ❌ ở report cuối và dừng (bỏ qua Write Trace / Refresh Panel / Commit).
941
+
888
942
  ## Write Trace State
889
943
 
890
944
  Cập nhật `{paths.trace_dir}/{domain}/{prd-slug}/{UC-ID}-{@trace.platform}.tsv` — với mỗi scenario đã implement, tìm row có sẵn theo `sc_id` và chỉ cập nhật các cột sau. *(Umbrella + `spec_source`: `trace_dir` phân giải về `{spec_source}/.trace` — lệnh này chạy từ `service_root` nhưng ghi trace row vào **spec repo** (liên-repo); commit/push spec submodule cho lần cập nhật trace, cùng với push code 2 tầng.)*
@@ -895,8 +949,8 @@ Cập nhật `{paths.trace_dir}/{domain}/{prd-slug}/{UC-ID}-{@trace.platform}.ts
895
949
  | `implemented_by` | `{ControllerClass}.{methodName}` |
896
950
  | `bdd_version` | `@trace.bdd_version` từ header `.feature` |
897
951
  | `tech_doc_revision` | `@trace.revision` từ tech-doc gộp `{TICKET-ID}-tech-design.md` (§4 backend đã điều khiển codegen của UC này), hoặc `—` nếu chưa có doc |
898
- | `fe_tech_doc_revision` | `@trace.revision` của cùng tech-doc gộp, ghi khi sinh FE với `--phase=integration` (adapter được wire theo §4.5.4); `—` cho BE, hoặc cho FE `--phase=ui` / chưa có §4.5.4 |
899
- | `fe_phase` | `ui` nếu `--phase=ui` \| `integrated` nếu `--phase=integration` \| `—` nếu không flag phase |
952
+ | `fe_tech_doc_revision` | `@trace.revision` của cùng tech-doc gộp, ghi khi sinh FE wire adapter theo §4.5.4 (`--phase=integration` **hoặc** `fe_full`); `—` cho BE, hoặc cho FE `--phase=ui` / chưa có §4.5.4 |
953
+ | `fe_phase` | `ui` nếu `--phase=ui` \| `integrated` nếu `--phase=integration` **hoặc** `fe_full` (đều đã wire real adapter) \| `—` cho BE |
900
954
  | `last_updated` | hôm nay `YYYY-MM-DD` |
901
955
 
902
956
  Giữ nguyên mọi cột khác (`sc_title`, `spec_ver`, `prd_version`, `prd_status`, `uc_status`, `test_count`, `test_classes`, `dev_selftest`, `dev_selftest_at`, `qc_status`, `qc_run_at`, `qc_owner`, `qc_blocked_by`).
@@ -1050,8 +1104,8 @@ Next : {lệnh gợi ý kèm ví dụ tham số}
1050
1104
  /generate-code Hoàn tất — {UC-ID}
1051
1105
  Files: created={N}, extended={M}, filled={F} stub, skipped={K} | Build: SUCCESS
1052
1106
  Branch: feature/{TICKET_ID}-{slug}
1053
- Phase : {UI (mock layer) | Integration (real API) | Default (full)}
1054
- fe_phase : {ui | integrated | —}
1107
+ Phase : {UI (mock layer) | Integration (real API) | FE full (UI + real API) | BE full}
1108
+ fe_phase : {ui | integrated (—phase=integration | fe_full) | —}
1055
1109
  Figma : {Dev Mode MCP local (grounded) | ⚠️ chỉ link web + text spec (không có MCP local) | n/a cho BE} ← chỉ UI FE/App
1056
1110
 
1057
1111
  Next:
@@ -27,7 +27,7 @@ Lệnh này giới hạn nghiêm ngặt trong **một file feature** được tr
27
27
 
28
28
  Đọc:
29
29
  1. Chỉ file `.feature` đã giới hạn scope
30
- 2. Tech-doc gộp của PRD tại `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md` (nếu tồn tại) — **tra §10 UC Coverage làm mục lục** để định vị scenario/section của UC đang sinh; **endpoint liên quan = §4.1 entries mà §5 lane của UC này gọi tới** (đừng lấy endpoint/section của UC khác). Từ đó đọc §4 API, §4.5 client, §5 flow của đúng UC này
30
+ 2. Tech-doc gộp của PRD tại `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md` (nếu tồn tại) — **tra §10 UC Coverage làm mục lục** để định vị scenario/section của UC đang sinh; **endpoint liên quan = §4.1 entries mà §5 lane của UC này gọi tới** (đừng lấy endpoint/section của UC khác). Từ đó đọc §4 API, §4.5 client, §5 flow của đúng UC này. **Đọc thêm §7 (Security & Authorization)** — luật phân quyền/enforce của UC → áp vào code; **và §8 (Error Handling & Edge Cases)** — mỗi row lỗi/biên phải có nhánh xử lý tương ứng trong code (khớp §4.3 error code), đừng chỉ code happy-path.
31
31
  3. CLAUDE.md §architecture + §coding_standards
32
32
  4. **(chỉ FE/App)** Design Spec — nạp qua **Guard** bên dưới (gate approved/độ-tươi + sanity), là nguồn của màn hình, component inventory, và link Figma frame từng-màn.
33
33
 
@@ -50,7 +50,7 @@ Lệnh này giới hạn nghiêm ngặt trong **một file feature** được tr
50
50
  - **Sanity-scan** (như generate-bdd bước 2.5): màn thiếu state loading/error/empty, AC-UI không testable, component `[NEW]`/`[TODO]` chưa chốt, còn ❌ Missing frame → cảnh báo trong cùng CHECKPOINT.
51
51
  - `Status: approved` VÀ `Built from PRD` khớp PRD hiện tại VÀ sạch cờ đỏ → dùng làm nguồn màn hình / component / Figma.
52
52
 
53
- **Tech-doc contract (chỉ backend/system) — DS3:** *áp dụng khi lần sinh này tạo code **backend** — `@trace.platform = system`, HOẶC chế độ default (không `--phase`) với `platform_type = backend`. Bỏ qua FE `--phase=ui`/`--phase=integration` (đã có nguồn shape riêng ở Phase Detection).*
53
+ **Tech-doc contract (chỉ backend/system) — DS3:** *áp dụng khi lần sinh này tạo code **backend** — `@trace.platform = system` (nguồn chuẩn quyết BE/FE, xem Phase Detection). Bỏ qua FE (`@trace.platform` = `web`/`app`) FE có nguồn shape riêng ở Phase Detection.*
54
54
 
55
55
  Định vị tech-doc gộp `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md`, kiểm phần backend của UC này (§4.1 Endpoints / §4.2 Request-Response / §4.3 Error):
56
56
  - **Brownfield** — nếu PRD Metadata `API Source: existing`: contract nằm ở Appendix "Existing API Contract" của PRD → nguồn hợp lệ, **bỏ qua DS3** (không cảnh báo).
@@ -69,13 +69,17 @@ Lệnh này giới hạn nghiêm ngặt trong **một file feature** được tr
69
69
 
70
70
  ## Phase Detection
71
71
 
72
+ > **Nguồn chuẩn quyết BE/FE = `@trace.platform` của FILE FEATURE** (`system` → BE · `web`/`app` → FE). KHÔNG dùng `platform_type` (suy từ module) để quyết BE/FE — nó chỉ dùng cho **idiom stack/module** (cú pháp, layer, thư viện). Lý do: repo fullstack một-module (vd Next.js có API route) có `platform_type` cố định một giá trị, nhưng vẫn có cả feature `system` (BE) lẫn `web` (FE) — chỉ tag của chính feature mới đúng.
73
+
72
74
  Parse `$ARGUMENTS` tìm flag `--phase`:
73
75
 
74
76
  | Flag | Ý nghĩa |
75
77
  |---|---|
76
78
  | `--phase=ui` | FE Phase 1 — sinh UI + layer mock API từ System BDD contract |
77
79
  | `--phase=integration` | FE Phase 2 — thay mock adapter bằng lời gọi API thật từ tech docs |
78
- | *(không có)* | Default — full implementation (BE hoặc full-stack không tách mock) |
80
+ | *(không có)* | Default — full: **BE/`system`** → full backend; **FE (`web`/`app`)** **FE full** (sinh UI + wire API thật trong một lần, không qua bước mock) |
81
+
82
+ **Xác định `fe_full`:** khi **KHÔNG** có `--phase` VÀ `@trace.platform` là `web`/`app` → đây là **FE full mode**. Sinh UI **và** wire API thật trong cùng một lần chạy, **bỏ qua** layer mock. Cụ thể: các section **sinh UI** chạy · **Mock API Layer** bị bỏ (chỉ dành `--phase=ui`) · **DS4** và **Integration Phase** VẪN chạy (xem điều kiện của từng section). BE/`system` ở default vẫn là full backend như trước.
79
83
 
80
84
  **Nếu `--phase` được set — xác nhận platform:**
81
85
  Đọc `@trace.platform` từ header file feature.
@@ -139,14 +143,21 @@ selection context, và code snippet — những thứ một URL web đơn không
139
143
  qua Figma MCP và ground UI trên layout, variable, và mapping Code Connect trả về. Ưu tiên
140
144
  component được map Code-Connect hơn là bịa markup; dùng tên token thật, không phải giá trị hardcode.
141
145
 
142
- **Nếu `--phase=integration`:**
146
+ ---
147
+
148
+ ## Integration Gates — DS4 (contract) · DS5 (reuse)
149
+
150
+ *Áp dụng khi wire API thật: `--phase=integration` **HOẶC** `fe_full`. Bỏ qua `--phase=ui` và default BE.*
151
+
152
+ > **Sequencing ở `fe_full`:** hai cổng này chạy **trước** khi UI/adapter được sinh trong cùng lần chạy, nên chúng suy luận từ **BẢN THIẾT KẾ** (design-spec + tech-doc §4.5) — tức *kế hoạch*, KHÔNG phải code đã sinh. "Port do UI định nghĩa" và "mock adapter có sẵn" chỉ tồn tại ở luồng 2-pha (`--phase=integration` chạy sau `--phase=ui`); ở `fe_full` port thật được chốt tại bước Generate về sau.
153
+
143
154
  Phân giải design điều khiển adapter từ **tech-doc gộp của PRD** `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md`:
144
155
  - **Mapping port→endpoint→DTO→error** (ưu tiên): §4.5.4 (API Integration Layer của platform này) — mỗi client method → endpoint có thật.
145
156
  - **Nguồn endpoint/shape**: §4.1 Endpoints + §4.2 Request-Response + §4.3 Error của cùng doc.
146
157
 
147
- **Client contract gate — DS4** *(chỉ `--phase=integration`; KHÔNG áp dụng `--phase=ui` — UI vẫn degrade êm qua mock).* Đối xứng với DS3 của BE: soi §4.5.4 **đủ chưa** cho UC/platform này *trước khi* wire adapter thật.
158
+ **Client contract gate — DS4** *(áp dụng khi `--phase=integration` **HOẶC** `fe_full`; KHÔNG áp dụng `--phase=ui` — UI vẫn degrade êm qua mock).* Đối xứng với DS3 của BE: soi §4.5.4 **đủ chưa** cho UC/platform này *trước khi* wire adapter thật.
148
159
 
149
- 1. **Xác định phạm vi cần:** các client method mà UC NÀY dùng — lấy từ §10 (định vị scenario của UC) → §4.5.4 rows / interface `{UC-ID}ApiPort` của mock adapter (`--phase=ui`).
160
+ 1. **Xác định phạm vi cần:** các client method mà UC NÀY dùng — lấy từ §10 (định vị scenario của UC) → §4.5.4 rows. Nguồn interface port: `{UC-ID}ApiPort` của mock adapter (`--phase=integration`, đã có từ lần `--phase=ui` trước) HOẶC, ở `fe_full`, port do chính lần chạy này định nghĩa lúc sinh UI (§4.5.3 state + §4.5.4) — chưa có mock adapter.
150
161
  2. **Kiểm tính đủ của §4.5.4 cho từng method:** có endpoint (resolve được ở §4.1) + map request + response→model + error→UI. *(Khác cảnh báo cũ: cái cũ chỉ bắt "thiếu HẲN §4.5.4"; DS4 bắt cả "thiếu MỘT PHẦN".)*
151
162
  3. **Phân loại (giống DS3):**
152
163
  - **Đủ + `@trace.status: approved` + 0 🔴 blocker-GAP (§12) chạm §4.5.4/UC này** → dùng làm nguồn, KHÔNG hỏi.
@@ -163,8 +174,24 @@ Phân giải design điều khiển adapter từ **tech-doc gộp của PRD** `{
163
174
  Vẫn wire bây giờ? (Y = best-effort/giữ mock cho phần thiếu · N = dừng, đi hoàn thiện tech-docs)
164
175
  ```
165
176
  Chỉ tiếp khi Y. *(Đây là "tư thế BE": trỏ ngược tech-docs thay vì hỏi live từng câu.)*
166
- Định vị mock adapter sẵn từ lần chạy `--phase=ui` (tìm `{UC-ID}MockApiAdapter` trong `{paths.src_dir}/{domain}/`).
167
- Nếu không tìm thấy → cảnh báo: "Không tìm thấy mock adapter — sinh real API adapter từ đầu dùng contract tech-doc."
177
+ **FE component/service reuse gate DS5** *(áp dụng khi `--phase=integration` **HOẶC** `fe_full`; KHÔNG áp dụng `--phase=ui`).* **Phát hiện & tái dùng** code FE đang tồn tại trước khi dựng mới — chống đẻ adapter/service **song song, mồ côi**, không nối vào app đang chạy.
178
+
179
+ 1. **Định vị mock adapter framework:** tìm `{UC-ID}MockApiAdapter` trong `{paths.src_dir}/{domain}/` (output `--phase=ui`).
180
+ 2. **Discovery code FE có sẵn:** quét `{paths.src_dir}` (phạm vi domain/feature) tìm **component / service / hook / api-client** mà các màn của UC này dùng — đối chiếu: component inventory của **design-spec**, path ở tech-doc **§4.5.2**, tên màn/UC. Lập danh sách "đã tồn tại" vs "chưa có".
181
+ 3. **Quyết định reuse-or-new:**
182
+ - **CÓ mock adapter** (luồng 2-pha chuẩn) → tái dùng port/wiring của nó như cũ; **KHÔNG hỏi**.
183
+ - **KHÔNG có mock adapter NHƯNG discovery thấy component/service có sẵn** (brownfield / chạy integration một mình trên app đang chạy) → **CHECKPOINT hỏi, KHÔNG tự dựng mới:**
184
+ ```
185
+ 🔎 Thấy {N} phần FE đang tồn tại cho màn của {UC-ID}/{platform}:
186
+ - {path} ({component | service | hook | api-client})
187
+ Wire API thật vào code CÓ SẴN này, hay dựng mới?
188
+ R (reuse) — EXTEND/wire adapter vào component/service đang chạy (khuyến nghị)
189
+ N (new) — dựng adapter/service mới (chỉ khi code cũ không tái dùng được — ghi lý do)
190
+ ```
191
+ - **R** → set `reuse_target` = các file có sẵn; Integration Phase **EXTEND/wire vào chúng** (áp Quy tắc EXTEND phi-phá-huỷ + Guard sau-ghi ở §File Scan), KHÔNG tạo file song song.
192
+ - **N** → dựng mới, ghi lý do vào report.
193
+ - **KHÔNG có mock adapter VÀ discovery KHÔNG thấy gì** → greenfield thật → sinh real adapter từ đầu dùng contract tech-doc (không cần hỏi).
194
+ 4. Lưu `reuse_target` (hoặc `none`) cho Integration Phase dùng ở bước wire-up.
168
195
 
169
196
  ---
170
197
 
@@ -194,6 +221,11 @@ Trước khi định vị file, chốt **package đích** theo **Package Layout
194
221
 
195
222
  **Quét module TÁI DÙNG trước khi tạo:** với mỗi layer, kiểm `{code_base_package}.{layer}` đã tồn tại trên disk chưa. Nếu đã có class phục vụ cùng entity/nghiệp vụ → **đặt member mới vào class đó (EXTEND)**, KHÔNG dựng cây layer / class song song. Chỉ tạo mới khi thực sự chưa có.
196
223
 
224
+ **Đặt code FE (`@trace.platform` = web/app):** quy tắc trên là cho BE (Java-style `{package}.{layer}`). FE đặt file theo thứ tự ưu tiên:
225
+ 1. **Path ở tech-doc §4.5.2 (Component File Mapping)** — nếu có, dùng **nguyên văn** đường dẫn cột `Path` (đây là contract đặt file của FE).
226
+ 2. **Else** → gốc `{paths.src_dir}` + quy ước thư mục của module/framework (vd `src/features/{domain}/…` React · `lib/{domain}/…` Flutter). Component/hook/service/adapter của cùng feature nằm gần nhau; **KHÔNG** rải mỗi file một nơi.
227
+ Adapter API mặc định tại `{paths.src_dir}/{domain}/` (khi §4.5.2 không chỉ định). Luôn **quét `{paths.src_dir}` tái dùng** như BE trước khi tạo mới (đồng bộ DS5).
228
+
197
229
  ---
198
230
 
199
231
  ## Seam & Stub Ledger — nối/lấp chỗ chưa implement *(chống mồ côi)*
@@ -325,9 +357,10 @@ Domain : {domain}
325
357
  UC : chỉ {UC-ID} ← các file feature khác trong folder này KHÔNG được đọc
326
358
  Tech : {language} / {framework}
327
359
  Package : {code_base_package}.{layer} · {by-layer | by-feature} ← feature/UC ở TÊN CLASS, KHÔNG thành package (nếu by-layer)
328
- Phase : {UI — mock layer | Integration — real API | Default — full} ← bỏ nếu không flag --phase
360
+ Phase : {UI — mock layer | Integration — real API | FE full UI + real API | BE full} ← FE full = default trên web/app; bỏ dòng này với default BE
329
361
  Scenarios: {N} total ({X} new, {Y} drifted, {Z} synced-skip)
330
362
  Layer : {từ CLAUDE.md §2}
363
+ Client : {chỉ integration/fe_full — reuse: {reuse_target hoặc "dựng mới"} · gaps §4.5.4: {n còn trống hoặc "đủ"}} ← bỏ dòng này với BE / --phase=ui
331
364
 
332
365
  Files:
333
366
  CREATE {N} file mới
@@ -397,7 +430,7 @@ DTOs → Entity/Model → Repository → Service interface → Service impl →
397
430
  Mỗi element **có action** (button, input, link, select, toggle, form-submit) PHẢI mang một **test-id ổn định** để QC định vị trực tiếp (không scan runtime):
398
431
 
399
432
  1. **Nguồn id.** Nếu tech-doc gộp `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md` có **§4.5.6 Test Selectors** cho platform này, lấy id **nguyên văn** từ bảng đó (contract). Nếu chưa có (vd `--phase=ui` trước khi §4.5 được vẽ), **sinh id theo quy ước** `{uc-lower}-{screen}-{element}-{type}` (vd `ft001-login-submit-btn`) để QC vẫn có handle ổn định — chúng sẽ được đối chiếu với §4.5.6 của tech-design lúc integration.
400
- 2. **Emit qua attribute platform** (từ `@trace.testid_attr`, hoặc theo module):
433
+ 2. **Emit qua attribute platform** — chọn attribute theo **`active_module`** (bảng dưới, mặc định). Chỉ override khi header `.feature` khai tường minh `@trace.testid_attr={attr}` (hiếm; dùng cho stack lai). Không có khai báo → theo module:
401
434
  - web (`react`/`nextjs`/`vue`/`angular`) → `data-testid="..."`
402
435
  - React Native → `testID="..."`
403
436
  - Flutter → `Key('...')` (+ `Semantics(identifier: '...')` khi action cần)
@@ -437,24 +470,32 @@ Dựng mock từ `mock_source` đã phân giải ở Phase Detection — **shape
437
470
 
438
471
  ---
439
472
 
440
- ## Integration Phase (chỉ `--phase=integration`)
473
+ ## Integration Phase (`--phase=integration` HOẶC `fe_full`)
441
474
 
442
- *Bỏ qua hoàn toàn section này nếu `--phase` không phải `integration`.*
475
+ *Bỏ qua hoàn toàn section này nếu KHÔNG phải `--phase=integration` KHÔNG phải `fe_full` (vd `--phase=ui`, hoặc default BE/`system`).*
476
+
477
+ *Hai chế độ vào section này:*
478
+ - **`--phase=integration`** — đã có mock adapter + UI từ lần `--phase=ui` trước → **thay** mock bằng real (có lật wire-up).
479
+ - **`fe_full`** — UI vừa được sinh trong CHÍNH lần chạy này, **không có bước mock** → wire real adapter **thẳng** (không có mock để thay/lật).
443
480
 
444
481
  1. **Đọc integration design.** Trong tech-doc gộp `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md`: ưu tiên §4.5.4 (mapping port→endpoint→DTO→error của platform), dùng §4.1/§4.2/§4.3 làm nguồn endpoint / request-response / error-code. Nếu doc chưa có §4.5.4 cho platform này, trích endpoint + shape + error code trực tiếp từ §4.1–§4.3.
445
- - **Tính đủ của §4.5.4 đã được cửa DS4 (Phase Detection) kiểm + vét SRC-CHAIN + gộp-hỏi TỪ TRƯỚC.** Ở bước này dùng thẳng kết quả đã phân giải của DS4 — **KHÔNG mở checkpoint/hỏi lại**. Nếu DS4 kết luận một mapping vẫn trống mà người đã chọn Y (best-effort) → giữ mock cho đúng phần đó, tag `@trace.stub`, ghi sổ seam; đừng bịa giá trị.
446
- 2. **Đọc mock adapter có sẵn** interface (`{UC-ID}ApiPort`) từ output `--phase=ui`. Real adapter implements **cùng** interface này → shape port/DTO đã cố định từ mock; **không hỏi lại shape** đã có ở đây.
447
- 3. **Sinh real API adapter** tại `{paths.src_dir}/{domain}/{UC-ID}ApiAdapter.{ext}`:
448
- - Implements cùng interface `{UC-ID}ApiPort` như mock adapter
449
- - Gọi HTTP thật tới endpoint từ contract tech-doc
450
- - Map field response sang cùng shape mock adapter trả về
451
- - Tag traceability:
482
+ - **Tính đủ của §4.5.4 đã được cửa DS4 kiểm + vét SRC-CHAIN + gộp-hỏi TỪ TRƯỚC.** Ở bước này dùng thẳng kết quả đã phân giải của DS4 — **KHÔNG mở checkpoint/hỏi lại**. Nếu DS4 kết luận một mapping vẫn trống mà người đã chọn Y (best-effort) → ở `--phase=integration` giữ mock cho phần đó; ở `fe_full` để adapter trả stub, tag `@trace.stub`, ghi sổ seam; đừng bịa giá trị.
483
+ 2. **Nguồn interface port `{UC-ID}ApiPort`:**
484
+ - `--phase=integration` (có mock) → đọc từ mock adapter sẵn (output `--phase=ui`). Real adapter implements **cùng** interface → shape port/DTO đã cố định, **không hỏi lại shape**.
485
+ - `reuse_target` (DS5 chọn **R**) → dùng interface/kiểu **service/hook sẵn** đang khai báo; adapter mới phải khớp chữ ký chúng đang gọi (không đổi hợp đồng của code đang chạy).
486
+ - `fe_full` greenfield port do UI vừa sinh trong lần này định nghĩa (§4.5.3/§4.5.4). Không có mock adapter để đọc.
487
+ 3. **Sinh / lắp real API adapter** theo kết quả **DS5**:
488
+ - **`reuse_target` = none** (greenfield / DS5 chọn N) → sinh file mới `{paths.src_dir}/{domain}/{UC-ID}ApiAdapter.{ext}`, implements `{UC-ID}ApiPort`.
489
+ - **`reuse_target` có file** (DS5 chọn R) → **EXTEND vào service/api-client/hook đang chạy** (áp Quy tắc EXTEND phi-phá-huỷ + Guard sau-ghi ở §File Scan): thay lời gọi mock/placeholder bằng lời gọi HTTP thật **tại chỗ**, giữ nguyên mọi member cũ; **KHÔNG** tạo `{UC-ID}ApiAdapter` song song.
490
+ - Chung: gọi HTTP thật tới endpoint từ contract tech-doc; map field response sang shape port/service khai báo; tag:
452
491
  ```
453
492
  @trace.implements={UC-ID}-SC{N}
454
493
  @trace.tech_doc_revision={đọc từ header tech-doc}
455
494
  ```
456
- 4. **Lật wire-up**: chuyển DI binding / env flag để service/hook dùng `{UC-ID}ApiAdapter` (thật) thay vì mock.
457
- 5. **KHÔNG xoá mock adapter** — giữ lại cho unit test.
495
+ 4. **Wire-up:**
496
+ - `--phase=integration` (có mock) → **lật** DI binding / env flag để service/hook dùng adapter thật thay vì mock. **KHÔNG xoá mock adapter** — giữ cho unit test.
497
+ - `reuse_target` (DS5 chọn R) → wiring đã nằm trong chính component/service có sẵn (đã EXTEND ở bước 3) → **không thêm binding song song**; chỉ chỉnh cấu hình bật đường thật nếu code cũ có cờ mock.
498
+ - `fe_full` greenfield → wire service/hook thẳng vào `{UC-ID}ApiAdapter` (thật); không sinh mock adapter (unit test dùng stub/fake tại chỗ khi cần).
458
499
 
459
500
  ---
460
501
 
@@ -473,6 +514,16 @@ Dựng mock từ `mock_source` đã phân giải ở Phase Detection — **shape
473
514
  {conventions.build_command} # từ project-context.yaml, tối đa 3 retry
474
515
  ```
475
516
 
517
+ > **GATE build (BẮT BUỘC):** chỉ khi build **SUCCESS** mới được đi tiếp sang **Write Trace State** và **Commit**.
518
+ > - Fail → sửa lỗi rồi retry (tối đa 3 lần).
519
+ > - **Vẫn fail sau 3 retry → DỪNG.** KHÔNG ghi trace, KHÔNG commit (trace/repo không được nói "đã xong" khi chưa build được). Xuất:
520
+ > ```
521
+ > ❌ Build FAIL sau 3 lần thử — không ghi trace, không commit.
522
+ > Lỗi cuối: {tóm tắt}
523
+ > File đã sinh giữ nguyên trên working tree để bạn sửa tay hoặc chạy /debug.
524
+ > ```
525
+ > Đặt Status badge = ❌ ở report cuối và dừng (bỏ qua Write Trace / Refresh Panel / Commit).
526
+
476
527
  ## Write Trace State
477
528
 
478
529
  Cập nhật `{paths.trace_dir}/{domain}/{prd-slug}/{UC-ID}-{@trace.platform}.tsv` — với mỗi scenario đã implement, tìm row có sẵn theo `sc_id` và chỉ cập nhật các cột sau. *(Umbrella + `spec_source`: `trace_dir` phân giải về `{spec_source}/.trace` — lệnh này chạy từ `service_root` nhưng ghi trace row vào **spec repo** (liên-repo); commit/push spec submodule cho lần cập nhật trace, cùng với push code 2 tầng.)*
@@ -483,8 +534,8 @@ Cập nhật `{paths.trace_dir}/{domain}/{prd-slug}/{UC-ID}-{@trace.platform}.ts
483
534
  | `implemented_by` | `{ControllerClass}.{methodName}` |
484
535
  | `bdd_version` | `@trace.bdd_version` từ header `.feature` |
485
536
  | `tech_doc_revision` | `@trace.revision` từ tech-doc gộp `{TICKET-ID}-tech-design.md` (§4 backend đã điều khiển codegen của UC này), hoặc `—` nếu chưa có doc |
486
- | `fe_tech_doc_revision` | `@trace.revision` của cùng tech-doc gộp, ghi khi sinh FE với `--phase=integration` (adapter được wire theo §4.5.4); `—` cho BE, hoặc cho FE `--phase=ui` / chưa có §4.5.4 |
487
- | `fe_phase` | `ui` nếu `--phase=ui` \| `integrated` nếu `--phase=integration` \| `—` nếu không flag phase |
537
+ | `fe_tech_doc_revision` | `@trace.revision` của cùng tech-doc gộp, ghi khi sinh FE wire adapter theo §4.5.4 (`--phase=integration` **hoặc** `fe_full`); `—` cho BE, hoặc cho FE `--phase=ui` / chưa có §4.5.4 |
538
+ | `fe_phase` | `ui` nếu `--phase=ui` \| `integrated` nếu `--phase=integration` **hoặc** `fe_full` (đều đã wire real adapter) \| `—` cho BE |
488
539
  | `last_updated` | hôm nay `YYYY-MM-DD` |
489
540
 
490
541
  Giữ nguyên mọi cột khác (`sc_title`, `spec_ver`, `prd_version`, `prd_status`, `uc_status`, `test_count`, `test_classes`, `dev_selftest`, `dev_selftest_at`, `qc_status`, `qc_run_at`, `qc_owner`, `qc_blocked_by`).
@@ -512,8 +563,8 @@ git commit -m "{commit_format}: {description}"
512
563
  /generate-code Hoàn tất — {UC-ID}
513
564
  Files: created={N}, extended={M}, filled={F} stub, skipped={K} | Build: SUCCESS
514
565
  Branch: feature/{TICKET_ID}-{slug}
515
- Phase : {UI (mock layer) | Integration (real API) | Default (full)}
516
- fe_phase : {ui | integrated | —}
566
+ Phase : {UI (mock layer) | Integration (real API) | FE full (UI + real API) | BE full}
567
+ fe_phase : {ui | integrated (—phase=integration | fe_full) | —}
517
568
  Figma : {Dev Mode MCP local (grounded) | ⚠️ chỉ link web + text spec (không có MCP local) | n/a cho BE} ← chỉ UI FE/App
518
569
 
519
570
  Next:
@@ -52,7 +52,8 @@ Hiển thị và chờ phản hồi:
52
52
 
53
53
  ## Bước 1 — Xác định Target File
54
54
 
55
- 1. Nếu `$ARGUMENTS` được cung cấp trỏ tới một file tồn tại dùng trực tiếp làm target.
55
+ 0. **Tách cờ trước khi resolve target.** `$ARGUMENTS` thể lẫn các `--flag` (vd `--phase=integration`, `--comment`, `--fix`). **Loại bỏ mọi token bắt đầu bằng `--`** ra khỏi phần dùng để tìm target — chỉ giữ phần path/UC-ID/ticket. (Các flag đó do phần logic riêng của lệnh parse ở bước sau, KHÔNG phải tên file.)
56
+ 1. Nếu `$ARGUMENTS` (đã tách cờ) được cung cấp và trỏ tới một file tồn tại → dùng trực tiếp làm target.
56
57
  2. Nếu `$ARGUMENTS` là một **UC-ID / ticket ID / tên rút gọn** (không có path) → phân giải thành file bằng cách glob theo bố cục feature-package. `{prd-slug}` lúc này **chưa biết**, nên dùng wildcard `*` cho segment đó, và `**` đệ quy dưới `bdd/` để phủ hết các thư mục con theo platform (`bdd/web/`, `bdd/app/`, `bdd/system/`):
57
58
  - **Lệnh BDD** (target là `.feature`): `{specs_dir}/{domain}/*/bdd/**/{UC-ID}*.feature` — hoặc `{specs_dir}/*/*/bdd/**/{UC-ID}*.feature` nếu domain cũng chưa biết. Nếu lệnh ngụ ý một platform/scope cụ thể (vd: system tech-doc cần BDD `system/`), ưu tiên kết quả trong thư mục con platform đó.
58
59
  - **Lệnh PRD** (target là file PRD `{TICKET-ID}-{prd-slug}.md` — file `.md` duy nhất ở gốc feature folder, cạnh `bdd/`): `{specs_dir}/{domain}/*/{TICKET-ID}*.md` nếu biết TICKET-ID; nếu không, `{specs_dir}/{domain}/*/*.md` (khớp feature folder có id tương ứng), hoặc `{specs_dir}/*/*/*.md` nếu domain cũng chưa biết. *(Glob `*/*.md` ở cấp gốc folder chỉ khớp PRD — tech-docs/design-spec `.md` nằm sâu hơn trong thư mục con.)*
@@ -138,6 +139,7 @@ Thực hiện các bước theo đúng thứ tự. Lưu mọi thứ vào bộ nh
138
139
  - `paths.business_dictionary` → path tới business-dictionary.md
139
140
  - `paths.core_entities` → path tới core-entities.md
140
141
  - `paths.tech_docs_dir` → gốc tài liệu kỹ thuật (gộp với specs_dir trong bố cục feature-package — tech-docs nằm dưới `{specs_dir}/{domain}/{prd-slug}/tech-docs/`)
142
+ - `paths.src_dir` → gốc mã nguồn (nơi generate-code đặt & quét code; nguồn chính cho FE + phạm vi reuse-scan của DS5)
141
143
  - `paths.trace_dir` → thư mục trạng thái trace; cấu trúc: `.trace/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv` (mỗi UC × platform một sổ)
142
144
 
143
145
  Nếu không có section `paths`, dùng các giá trị mặc định:
@@ -150,6 +152,7 @@ Nếu không có section `paths`, dùng các giá trị mặc định:
150
152
  - `business_dictionary` = `specs/domain-knowledge/business-dictionary.md`
151
153
  - `core_entities` = `specs/domain-knowledge/core-entities.md`
152
154
  - `tech_docs_dir` = `specs`
155
+ - `src_dir` = `src`
153
156
  - `trace_dir` = `.trace`
154
157
 
155
158
  Lưu ý: Trong bố cục feature-package, `specs_dir` là gốc thống nhất. Mọi loại spec artifact (PRD, BDD, tech-docs, design-spec) đều nằm dưới `{specs_dir}/{domain}/{prd-slug}/`. `prd-slug` là tên folder feature-package, không phải một biến config riêng.
@@ -52,7 +52,8 @@ Hiển thị và chờ phản hồi:
52
52
 
53
53
  ## Bước 1 — Xác định Target File
54
54
 
55
- 1. Nếu `$ARGUMENTS` được cung cấp trỏ tới một file tồn tại dùng trực tiếp làm target.
55
+ 0. **Tách cờ trước khi resolve target.** `$ARGUMENTS` thể lẫn các `--flag` (vd `--phase=integration`, `--comment`, `--fix`). **Loại bỏ mọi token bắt đầu bằng `--`** ra khỏi phần dùng để tìm target — chỉ giữ phần path/UC-ID/ticket. (Các flag đó do phần logic riêng của lệnh parse ở bước sau, KHÔNG phải tên file.)
56
+ 1. Nếu `$ARGUMENTS` (đã tách cờ) được cung cấp và trỏ tới một file tồn tại → dùng trực tiếp làm target.
56
57
  2. Nếu `$ARGUMENTS` là một **UC-ID / ticket ID / tên rút gọn** (không có path) → phân giải thành file bằng cách glob theo bố cục feature-package. `{prd-slug}` lúc này **chưa biết**, nên dùng wildcard `*` cho segment đó, và `**` đệ quy dưới `bdd/` để phủ hết các thư mục con theo platform (`bdd/web/`, `bdd/app/`, `bdd/system/`):
57
58
  - **Lệnh BDD** (target là `.feature`): `{specs_dir}/{domain}/*/bdd/**/{UC-ID}*.feature` — hoặc `{specs_dir}/*/*/bdd/**/{UC-ID}*.feature` nếu domain cũng chưa biết. Nếu lệnh ngụ ý một platform/scope cụ thể (vd: system tech-doc cần BDD `system/`), ưu tiên kết quả trong thư mục con platform đó.
58
59
  - **Lệnh PRD** (target là file PRD `{TICKET-ID}-{prd-slug}.md` — file `.md` duy nhất ở gốc feature folder, cạnh `bdd/`): `{specs_dir}/{domain}/*/{TICKET-ID}*.md` nếu biết TICKET-ID; nếu không, `{specs_dir}/{domain}/*/*.md` (khớp feature folder có id tương ứng), hoặc `{specs_dir}/*/*/*.md` nếu domain cũng chưa biết. *(Glob `*/*.md` ở cấp gốc folder chỉ khớp PRD — tech-docs/design-spec `.md` nằm sâu hơn trong thư mục con.)*
@@ -138,6 +139,7 @@ Thực hiện các bước theo đúng thứ tự. Lưu mọi thứ vào bộ nh
138
139
  - `paths.business_dictionary` → path tới business-dictionary.md
139
140
  - `paths.core_entities` → path tới core-entities.md
140
141
  - `paths.tech_docs_dir` → gốc tài liệu kỹ thuật (gộp với specs_dir trong bố cục feature-package — tech-docs nằm dưới `{specs_dir}/{domain}/{prd-slug}/tech-docs/`)
142
+ - `paths.src_dir` → gốc mã nguồn (nơi generate-code đặt & quét code; nguồn chính cho FE + phạm vi reuse-scan của DS5)
141
143
  - `paths.trace_dir` → thư mục trạng thái trace; cấu trúc: `.trace/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv` (mỗi UC × platform một sổ)
142
144
 
143
145
  Nếu không có section `paths`, dùng các giá trị mặc định:
@@ -150,6 +152,7 @@ Nếu không có section `paths`, dùng các giá trị mặc định:
150
152
  - `business_dictionary` = `specs/domain-knowledge/business-dictionary.md`
151
153
  - `core_entities` = `specs/domain-knowledge/core-entities.md`
152
154
  - `tech_docs_dir` = `specs`
155
+ - `src_dir` = `src`
153
156
  - `trace_dir` = `.trace`
154
157
 
155
158
  Lưu ý: Trong bố cục feature-package, `specs_dir` là gốc thống nhất. Mọi loại spec artifact (PRD, BDD, tech-docs, design-spec) đều nằm dưới `{specs_dir}/{domain}/{prd-slug}/`. `prd-slug` là tên folder feature-package, không phải một biến config riêng.
@@ -56,7 +56,8 @@ Hiển thị và chờ phản hồi:
56
56
 
57
57
  ## Bước 1 — Xác định Target File
58
58
 
59
- 1. Nếu `$ARGUMENTS` được cung cấp trỏ tới một file tồn tại dùng trực tiếp làm target.
59
+ 0. **Tách cờ trước khi resolve target.** `$ARGUMENTS` thể lẫn các `--flag` (vd `--phase=integration`, `--comment`, `--fix`). **Loại bỏ mọi token bắt đầu bằng `--`** ra khỏi phần dùng để tìm target — chỉ giữ phần path/UC-ID/ticket. (Các flag đó do phần logic riêng của lệnh parse ở bước sau, KHÔNG phải tên file.)
60
+ 1. Nếu `$ARGUMENTS` (đã tách cờ) được cung cấp và trỏ tới một file tồn tại → dùng trực tiếp làm target.
60
61
  2. Nếu `$ARGUMENTS` là một **UC-ID / ticket ID / tên rút gọn** (không có path) → phân giải thành file bằng cách glob theo bố cục feature-package. `{prd-slug}` lúc này **chưa biết**, nên dùng wildcard `*` cho segment đó, và `**` đệ quy dưới `bdd/` để phủ hết các thư mục con theo platform (`bdd/web/`, `bdd/app/`, `bdd/system/`):
61
62
  - **Lệnh BDD** (target là `.feature`): `{specs_dir}/{domain}/*/bdd/**/{UC-ID}*.feature` — hoặc `{specs_dir}/*/*/bdd/**/{UC-ID}*.feature` nếu domain cũng chưa biết. Nếu lệnh ngụ ý một platform/scope cụ thể (vd: system tech-doc cần BDD `system/`), ưu tiên kết quả trong thư mục con platform đó.
62
63
  - **Lệnh PRD** (target là file PRD `{TICKET-ID}-{prd-slug}.md` — file `.md` duy nhất ở gốc feature folder, cạnh `bdd/`): `{specs_dir}/{domain}/*/{TICKET-ID}*.md` nếu biết TICKET-ID; nếu không, `{specs_dir}/{domain}/*/*.md` (khớp feature folder có id tương ứng), hoặc `{specs_dir}/*/*/*.md` nếu domain cũng chưa biết. *(Glob `*/*.md` ở cấp gốc folder chỉ khớp PRD — tech-docs/design-spec `.md` nằm sâu hơn trong thư mục con.)*
@@ -143,6 +144,7 @@ Thực hiện các bước theo đúng thứ tự. Lưu mọi thứ vào bộ nh
143
144
  - `paths.business_dictionary` → path tới business-dictionary.md
144
145
  - `paths.core_entities` → path tới core-entities.md
145
146
  - `paths.tech_docs_dir` → gốc tài liệu kỹ thuật (gộp với specs_dir trong bố cục feature-package — tech-docs nằm dưới `{specs_dir}/{domain}/{prd-slug}/tech-docs/`)
147
+ - `paths.src_dir` → gốc mã nguồn (nơi generate-code đặt & quét code; nguồn chính cho FE + phạm vi reuse-scan của DS5)
146
148
  - `paths.trace_dir` → thư mục trạng thái trace; cấu trúc: `.trace/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv` (mỗi UC × platform một sổ)
147
149
 
148
150
  Nếu không có section `paths`, dùng các giá trị mặc định:
@@ -155,6 +157,7 @@ Nếu không có section `paths`, dùng các giá trị mặc định:
155
157
  - `business_dictionary` = `specs/domain-knowledge/business-dictionary.md`
156
158
  - `core_entities` = `specs/domain-knowledge/core-entities.md`
157
159
  - `tech_docs_dir` = `specs`
160
+ - `src_dir` = `src`
158
161
  - `trace_dir` = `.trace`
159
162
 
160
163
  Lưu ý: Trong bố cục feature-package, `specs_dir` là gốc thống nhất. Mọi loại spec artifact (PRD, BDD, tech-docs, design-spec) đều nằm dưới `{specs_dir}/{domain}/{prd-slug}/`. `prd-slug` là tên folder feature-package, không phải một biến config riêng.
@@ -64,7 +64,8 @@ Hiển thị và chờ phản hồi:
64
64
 
65
65
  ## Bước 1 — Xác định Target File
66
66
 
67
- 1. Nếu `$ARGUMENTS` được cung cấp trỏ tới một file tồn tại dùng trực tiếp làm target.
67
+ 0. **Tách cờ trước khi resolve target.** `$ARGUMENTS` thể lẫn các `--flag` (vd `--phase=integration`, `--comment`, `--fix`). **Loại bỏ mọi token bắt đầu bằng `--`** ra khỏi phần dùng để tìm target — chỉ giữ phần path/UC-ID/ticket. (Các flag đó do phần logic riêng của lệnh parse ở bước sau, KHÔNG phải tên file.)
68
+ 1. Nếu `$ARGUMENTS` (đã tách cờ) được cung cấp và trỏ tới một file tồn tại → dùng trực tiếp làm target.
68
69
  2. Nếu `$ARGUMENTS` là một **UC-ID / ticket ID / tên rút gọn** (không có path) → phân giải thành file bằng cách glob theo bố cục feature-package. `{prd-slug}` lúc này **chưa biết**, nên dùng wildcard `*` cho segment đó, và `**` đệ quy dưới `bdd/` để phủ hết các thư mục con theo platform (`bdd/web/`, `bdd/app/`, `bdd/system/`):
69
70
  - **Lệnh BDD** (target là `.feature`): `{specs_dir}/{domain}/*/bdd/**/{UC-ID}*.feature` — hoặc `{specs_dir}/*/*/bdd/**/{UC-ID}*.feature` nếu domain cũng chưa biết. Nếu lệnh ngụ ý một platform/scope cụ thể (vd: system tech-doc cần BDD `system/`), ưu tiên kết quả trong thư mục con platform đó.
70
71
  - **Lệnh PRD** (target là file PRD `{TICKET-ID}-{prd-slug}.md` — file `.md` duy nhất ở gốc feature folder, cạnh `bdd/`): `{specs_dir}/{domain}/*/{TICKET-ID}*.md` nếu biết TICKET-ID; nếu không, `{specs_dir}/{domain}/*/*.md` (khớp feature folder có id tương ứng), hoặc `{specs_dir}/*/*/*.md` nếu domain cũng chưa biết. *(Glob `*/*.md` ở cấp gốc folder chỉ khớp PRD — tech-docs/design-spec `.md` nằm sâu hơn trong thư mục con.)*
@@ -150,6 +151,7 @@ Thực hiện các bước theo đúng thứ tự. Lưu mọi thứ vào bộ nh
150
151
  - `paths.business_dictionary` → path tới business-dictionary.md
151
152
  - `paths.core_entities` → path tới core-entities.md
152
153
  - `paths.tech_docs_dir` → gốc tài liệu kỹ thuật (gộp với specs_dir trong bố cục feature-package — tech-docs nằm dưới `{specs_dir}/{domain}/{prd-slug}/tech-docs/`)
154
+ - `paths.src_dir` → gốc mã nguồn (nơi generate-code đặt & quét code; nguồn chính cho FE + phạm vi reuse-scan của DS5)
153
155
  - `paths.trace_dir` → thư mục trạng thái trace; cấu trúc: `.trace/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv` (mỗi UC × platform một sổ)
154
156
 
155
157
  Nếu không có section `paths`, dùng các giá trị mặc định:
@@ -162,6 +164,7 @@ Nếu không có section `paths`, dùng các giá trị mặc định:
162
164
  - `business_dictionary` = `specs/domain-knowledge/business-dictionary.md`
163
165
  - `core_entities` = `specs/domain-knowledge/core-entities.md`
164
166
  - `tech_docs_dir` = `specs`
167
+ - `src_dir` = `src`
165
168
  - `trace_dir` = `.trace`
166
169
 
167
170
  Lưu ý: Trong bố cục feature-package, `specs_dir` là gốc thống nhất. Mọi loại spec artifact (PRD, BDD, tech-docs, design-spec) đều nằm dưới `{specs_dir}/{domain}/{prd-slug}/`. `prd-slug` là tên folder feature-package, không phải một biến config riêng.