# /generate-prd — Sinh Product Requirements Document

## Gate
{{include:steps/gate.md}}

*Lưu ý: Với lệnh này, target file ở Bước 1 là một file product-definition trong `{paths.product_definitions_dir}/`. Phân giải từ `$ARGUMENTS` hoặc liệt kê thư mục và hỏi.*

## Context
{{include:steps/context-loader.md}}

*Context bổ sung cho lệnh này: Đọc toàn bộ file product-definition. Trích xuất: **TICKET-ID**, **domain**, **tên feature**, **tên PO** (field `PO` ở Metadata), dữ liệu Phase 1-7, và bảng **Chuẩn hoá thuật ngữ** (Terminology Map ở Phase 0 — các cặp `thuật ngữ PO → thuật ngữ chuẩn`). Lưu bản đồ này để áp dụng ở bước Quy tắc thuật ngữ. **Nếu Phase 7 (Validation Report) còn `Xung đột phát hiện` / `Mục còn thiếu` khác "None" → diễn đạt lại mỗi mục thành một câu hỏi theo format `Q… — [AI DRAFT]` của section "Giả định AI" (nêu rõ độ vênh + cần PO chốt điều gì), thay vì dán thô. AI không tự quyết thay PO.***

**Map "Phụ thuộc liên service"** (Phase 1 câu 8 của product-definition) → **§1c "Phụ thuộc liên service"** của PRD, giữ nguyên mức nghiệp vụ (cần dữ liệu/năng lực gì, từ ai, vì sao — KHÔNG thêm chi tiết API/kỹ thuật). Nếu discovery ghi "Không có" → §1c ghi "Không có".

**Map "Màn hình & thành phần chính"** (Phase 2 của product-definition) → **§4b Wireframe** của PRD: mỗi màn hình thành một Screen với Components/Actions tương ứng. Đây là nguồn coverage cho `/generate-bdd` (C.1). Nếu phải **suy thêm** Screen/component mà discovery chưa nêu → đánh dấu rõ `*(AI đề xuất — PO review)*` cạnh phần đó, đừng để âm thầm thành chân lý coverage.

**Phân giải PO** (đọc trước, hỏi sau): lấy `PO` từ Metadata của product-definition. Nếu đã có giá trị → dùng luôn, KHÔNG hỏi lại. Nếu trống/thiếu → hỏi PO ngay ở CHECKPOINT dưới. Điền giá trị này vào field `PO` của PRD Metadata.

**Phân giải link tracker (hỏi cho MỌI ticket):** `TICKET-ID` là **định danh nội bộ** PO tự đặt lúc discovery — **KHÔNG đảm bảo** là một Jira key có thật, nên **TUYỆT ĐỐI KHÔNG tự dựng URL** kiểu `{base}/browse/{TICKET-ID}` (sẽ ra link rác trỏ tới ticket không tồn tại). Field `Ticket` **luôn giữ TICKET-ID dạng plain text**; link Jira (nếu có) chỉ **đặt thêm bên cạnh**. **Luôn hỏi PO**: *"Ticket {TICKET-ID} có link tracker thật (Jira/khác) không? Nếu có, dán vào."*
- PO **có** link → điền field `Ticket` dạng: `{TICKET-ID} ([Jira]({tracker_url}))` — plain ID đứng trước, link trong ngoặc bên cạnh.
- PO **không** có / để trống → điền plain text `{TICKET-ID}` (KHÔNG link, KHÔNG placeholder `{...}` lủng lẳng).

**Phân giải `slug`** (kế thừa, KHÔNG tái sinh): đọc `TICKET-ID` từ Metadata `Ticket` của product-definition, rồi lấy `slug` = phần tên file **sau khi strip đúng chuỗi `{TICKET-ID}-` ở đầu**. **KHÔNG tách theo dấu `-` đầu tiên** — vì TICKET-ID có thể chứa `-` (vd Jira key `LOYAL-29`): `LOYAL-29-loyalty-points.md` với TICKET-ID `LOYAL-29` → `slug = loyalty-points` (KHÔNG phải `29-loyalty-points`). Đặt `prd-slug = slug` này cho feature-package PRD, để folder `{specs_dir}/{domain}/{prd-slug}/` khớp 1-1 với product-definition. KHÔNG tự bịa slug mới — nếu tên file không bắt đầu bằng `{TICKET-ID}-`, dừng và hỏi người dùng.

**Guard — discovery phải hoàn tất:** đọc `Status` và `Completed Phase` từ Metadata của product-definition.
- Nếu `Status: completed` (Completed Phase = 7) → tiếp tục bình thường.
- Nếu `Status: in-progress` (Completed Phase < 7) → **DỪNG**, KHÔNG sinh PRD, báo:
  ```
  ❌ Product-definition chưa hoàn tất (Status: in-progress, Completed Phase: {N}/7).
     /generate-prd cần discovery đủ Phase 1-7 (BR, Business Logic, AC, Validation Report).
     Chạy lại /define-product {file} để resume từ Phase {N+1}, rồi mới sinh PRD.
  ```
  PRD là artifact ký duyệt — không sinh từ nguồn discovery chưa chốt.

**Phân giải `API Source` (brownfield / greenfield / partner song song):** hỏi PO **một** câu để chốt **loại** nguồn API — PO CHỈ chốt loại, **không bao giờ gõ chi tiết contract**:

> "API của feature này thuộc loại nào?
>   1. **existing** — API đã chạy production, contract cố định
>   2. **greenfield** — mình tự thiết kế contract mới
>   3. **partner** — đối tác đang phát triển song song, contract chưa có"

- **(1) existing** → set Metadata `API Source: existing`. Xin PO **con trỏ nguồn** contract (1 trong: file openapi/swagger, URL swagger, path service/repo BE, hoặc doc đính kèm). AI **trích as-is** vào Appendix "Existing API Contract" (ghi rõ nguồn từng row — KHÔNG bịa, KHÔNG thiết kế mới). *Người điền detail là AI từ artifact thật, KHÔNG phải PO.*
  - Nếu con trỏ **không truy cập được** từ context hiện tại → KHÔNG fabricate: ghi block `⛔ PENDING: contract chưa trích — nguồn: {pointer}; phải trích as-is trước /generate-bdd` vào section đó, vẫn giữ `API Source: existing`. Coi phần contract của PRD chưa hoàn tất tới khi bảng đủ.
- **(2) greenfield** → để trống `API Source`. **Xoá** Appendix "Existing API Contract" (template đã dặn). Contract sẽ được thiết kế ở `/generate-tech-docs`.
- **(3) partner song song** → ĐI LUỒNG greenfield (`API Source` để trống, **xoá** section Existing API Contract), **KHÔNG** set `existing`. Thêm:
  - Ghi phụ thuộc partner vào **§1c "Phụ thuộc liên service"** của PRD (mức nghiệp vụ): cần contract/năng lực gì từ partner nào, vì sao.
  - Một mục trong "Giả định AI": *"Contract do partner {X} phát triển song song; bản tech-docs sinh sau là ĐỀ XUẤT của ta để đàm phán (qua cổng T7 cross-team sign-off), chốt khi partner confirm — có thể thay đổi."*
  - Lý do KHÔNG dùng `existing`: `existing` làm `/review-tech-docs` **skip T7** — nhưng partner song song chính là lúc CẦN T7 để đàm phán contract.

> **`API Source` là field có vòng đời:** có thể bắt đầu greenfield/partner rồi **chuyển thành `existing`** khi contract được chốt (vd partner áp contract của họ và ta phải theo). Khi đó: chạy `/refine-prd` đổi `API Source → existing` + điền Existing API Contract từ nguồn partner (trích as-is) + bump Version; `/generate-bdd` (Version drift) và `/generate-tech-docs` (reverse-document) sẽ tự realign system BDD + tech-doc theo contract mới. FE/App BDD phần lớn không vỡ nhờ luật declarative (assert outcome quan sát được, không assert shape JSON).

CHECKPOINT trước khi sinh: "Sinh PRD cho **{TICKET-ID} — {feature}** (domain: {domain}), PO: **{tên PO — hoặc hỏi nếu product-definition để trống}**. API Source: **{existing — nguồn {pointer} | greenfield | partner song song}**. Link tracker: **{URL — hoặc 'không có, dùng plain ID'}**. Nguồn: discovery hoàn tất (Phase 7/7). Tiếp tục? (Y/N)"

---

## Quy tắc thuật ngữ *(áp dụng nếu business-dictionary.md tồn tại)*

- **Áp dụng Terminology Map từ product-definition**: với mỗi cặp `thuật ngữ PO → thuật ngữ chuẩn` trong bảng **Chuẩn hoá thuật ngữ** (Phase 0 của product-definition), dùng **thuật ngữ chuẩn** khi viết PRD. Đây là bản đồ PO đã xác nhận ở discovery — luôn ưu tiên áp dụng kể cả khi business-dictionary.md vắng mặt, để PRD nhất quán với product-definition. Nếu bảng trống/không có → bỏ qua âm thầm.
- **Thay banned term**: thay mọi banned term bằng bản chuẩn tương đương (xem dictionary § Banned Terms).
- **Dùng canonical term**: chỉ dùng các thuật ngữ được định nghĩa trong dictionary.
- **NEW TERM DETECTION (lưới an toàn — define-product lẽ ra đã bắt ở discovery Phase 3)**: Nếu vẫn còn thuật ngữ trong input PO xuất hiện ≥2 lần và KHÔNG có trong dictionary → **DỪNG** và hỏi PO:
  - Thuật ngữ đó nghĩa là gì trong ngữ cảnh hệ thống?
  - English canonical term nên dùng là gì?
  - Có cần bổ sung vào business-dictionary.md không?
  Sau khi PO confirm → cập nhật `business-dictionary.md` (nếu đồng ý) → tiếp tục sinh.
- Nếu không có banned term và tất cả thuật ngữ đều chuẩn → tiếp tục không gián đoạn.

## Ngôn ngữ nghiệp vụ
{{include:steps/business-language.md}}

## Quy tắc Cross-Reference

Bất kỳ chỗ nào nhắc tới một TICKET-ID khác trong PRD (pre-condition, BR, ghi chú, appendix) → **PHẢI** là inline link. Mỗi PRD sống trong feature-package riêng (`{paths.specs_dir}/{domain}/{prd-slug-khác}/`), nên link trỏ sang folder anh em:
```
[TICKET-ID khác](../{prd-slug-khác}/{TICKET-ID-khác}-{prd-slug-khác}.md)
```
Không bao giờ để TICKET-ID dạng plain text nếu file PRD tương ứng tồn tại trong `{paths.specs_dir}/{domain}/`.

## Quy ước đánh số UC và BR

- **UC ID**: `{TICKET-ID}-UC{N}` — N bắt đầu từ 1, tăng theo từng use case.
- **BR ID**: `{TICKET-ID}-UC{N}-BR{M}` — **M tăng liên tục trên toàn PRD** (KHÔNG reset theo từng UC).
  - Ví dụ: UC1 → BR1, BR2; UC2 → BR3, BR4 (KHÔNG phải BR1, BR2 lại từ đầu).

## Traceability AC ↔ BR ↔ UC

- **Giữ link AC→BR từ discovery (KHÔNG vứt khi flatten):** Product Definition Phase 6 có cột "Bắt nguồn từ BR-{N}". Khi viết AC §2, **remap** mỗi `BR-{N}` (số discovery) sang **BR ID của PRD** (`{TICKET-ID}-UC{n}-BR{m}` sau khi đã phân BR vào UC) và gắn vào cuối AC: `_(BR: {ids})_`. Mỗi AC PHẢI có ≥1 ref BR.
- **Điền "AC liên quan" cho mỗi UC §3 (chiều ngược):** với mỗi UC, liệt kê các AC mà nó thoả.
- **Nhất quán 2 chiều (bắt buộc):** tập "AC liên quan" của UC{n} phải **đúng bằng** tập AC có ref BR trỏ về UC{n}. Vì BR ID đã chứa số UC, hai chiều này suy ra lẫn nhau — lệch là lỗi traceability, sửa trước khi ghi.

---

## Platform Strategy — PRD là tài liệu nghiệp vụ (không technical)

PRD mô tả **WHAT** (yêu cầu nghiệp vụ) — không nhét chi tiết **kỹ thuật** (API, token, endpoint, HTTP status, tên class/bảng/cột DB, query). Những thứ đó thuộc **Tech Docs**.
PRD **được phép** có User Flow + Wireframe ở mức nghiệp vụ (§4) để BA/QC/Dev cùng hình dung; chỉ **chi tiết visual** (màu sắc, layout pixel, animation, micro-interaction) mới thuộc **Design Spec**.

> **Ngoại lệ DUY NHẤT (brownfield):** khi `API Source: existing`, Appendix "Existing API Contract" ĐƯỢC PHÉP chứa chi tiết kỹ thuật (method, path, request/response shape, HTTP status, error code) — vì đó là contract **đã tồn tại**, AI chỉ **trích as-is** làm input cho trước, KHÔNG phải thiết kế mới. Ngoại lệ này CHỈ áp cho riêng section đó; AC, BR, và toàn bộ thân PRD vẫn thuần nghiệp vụ.

| ✅ Viết trong PRD (nghiệp vụ) | ❌ KHÔNG viết trong PRD |
|---|---|
| "Đăng nhập thành công → truy cập được tính năng" | "API trả về JWT token" ← Tech Docs |
| "Sai mật khẩu 5 lần → khoá tài khoản 30 phút" | "Hiển thị spinner khi loading" ← Design Spec |
| Wireframe mức nghiệp vụ: màn hình có gì, hành động ra kết quả gì | "Animation fade 300ms, màu #FF0000" ← Design Spec |

**Một PRD phục vụ tất cả platform:**
- **FE/App team** → đọc PRD + Design Spec → `/generate-bdd` (UI-level scenarios)
- **BE team** → đọc PRD trực tiếp → `/generate-bdd` (API-level scenarios)
- Design Spec là tài liệu **chi tiết visual** riêng cho FE/App — Wireframe nghiệp vụ trong PRD chỉ là khung.

Khi viết AC, nếu PO đề cập chi tiết visual (màu sắc, animation, layout pixel) → nhắc nhở:
*"Chi tiết visual này thuộc về Design Spec, không thuộc PRD. Ghi nhận lại để tạo Design Spec sau."*

---

## Generate

Ghi `{paths.specs_dir}/{domain}/{prd-slug}/{TICKET-ID}-{prd-slug}.md` theo cấu trúc dưới đây.

> **Quy ước tên file PRD:** `{TICKET-ID}-{prd-slug}.md` — vd `SEG01-segment-scoring-service.md`. KHÔNG đặt tên `prd.md`. Mỗi feature-package có đúng **một** file PRD ở cấp gốc folder (cạnh `bdd/`, `tech-docs/`, `design-spec/`); tính duy nhất nằm ở cả tên folder lẫn TICKET-ID trong tên file.

---

````markdown
{{include:templates/prd.template.md}}
````

---

## Quality Checklist *(kiểm tra trước khi ghi)*

- [ ] Mọi AC đều testable (pass/fail rõ ràng), không có chi tiết kỹ thuật (API/token/DB) hay visual chi tiết (màu sắc, font, animation)
- [ ] **Altitude (AC vs BR/BL)**: AC chỉ nêu **outcome quan sát/kiểm được + ref BR** — KHÔNG chứa cơ chế (số lần retry, timeout, tên/chủ cờ, nhánh lỗi chi tiết); cơ chế nằm ở **BR/BL** (§3). AC không lặp lại nội dung BR nó ref. **Scope** = ranh giới (KHÔNG định nghĩa thuật ngữ / KHÔNG cơ chế)
- [ ] Mỗi UC có Actor / Description / Pre-condition / Post-condition
- [ ] §1c "Phụ thuộc liên service" có mặt: kế thừa từ discovery Phase 1 câu 8 (hoặc "Không có" nếu discovery trống); case partner song song có ghi phụ thuộc partner ở đây
- [ ] Business Rule (WHAT) và Business Logic (HOW) nằm chung bảng 3 cột `ID | Business Rule | Business Logic`
- [ ] BR ID tăng liên tục trên toàn PRD — không reset theo từng UC
- [ ] **Traceability AC↔BR↔UC**: mỗi AC §2 có ≥1 ref `_(BR: …)_`; mỗi UC §3 có dòng "AC liên quan"; và hai chiều khớp nhau (tập "AC liên quan" của UC = tập AC có ref BR trỏ về UC đó)
- [ ] Mọi cross-reference TICKET-ID đều là inline link `[TICKET-ID](./file.md)`
- [ ] **Tài liệu tham khảo (Appendix)** có mục **BDD** (`./bdd/`) và **Design spec** (`./design-spec/`) — trỏ sẵn dù artifact chưa sinh; giữ nguyên câu chú "không áp dụng với feature thuần backend (không có màn hình)" ở cuối dòng Design spec
- [ ] Không có banned term (nếu dictionary tồn tại)
- [ ] **Ngôn ngữ nghiệp vụ**: 0 thuật ngữ kỹ thuật/UI trong prose (re-render→hiển thị lại, UI→màn, timeout→quá thời gian chờ…) — xem Business Language Guard
- [ ] **API Source nhất quán**: nếu `existing` → bảng "Existing API Contract" đủ method/path/request/response (hoặc mang block ⛔ PENDING kèm con trỏ nguồn); nếu greenfield/partner → section "Existing API Contract" đã bị xoá hẳn (không để bảng rỗng), và case partner có dependency + assumption ghi rõ
- [ ] User Flow có cả luồng lỗi / luồng ngoại lệ
- [ ] Wireframe phủ tất cả màn hình liên quan tới Use Case
- [ ] **Định dạng (readability)**: User Story / AC / các field của UC (Actor, Description, Pre/Post-condition) viết dạng bullet `- **Label:** …` — mỗi ý MỘT dòng, KHÔNG viết các dòng liền nhau (sẽ bị dồn thành 1 đoạn khi render); có một dòng trống trước và sau mỗi bảng

## Output

{{include:steps/report-footer.md}}

Ví dụ footer cho lệnh này:

```
---
Status   : ✅ Complete
Output Artifacts:
  created {paths.specs_dir}/{domain}/{prd-slug}/{TICKET-ID}-{prd-slug}.md (PRD v1.0)
Pipeline : Discovery → [PRD ◀ bạn ở đây] → Design Spec → BDD → Tech Design → Code → Dev Self-Check → QC → Trace Audit
Next     : /refine-prd {paths.specs_dir}/{domain}/{prd-slug}/{TICKET-ID}-{prd-slug}.md
           → rồi /review-context {prd-file}   ← kiểm tra chất lượng PRD trước khi sinh BDD
           → khi sạch critical, PO đặt | **Status** | approved | (PRD mới sinh đang draft):
               • Feature CÓ màn hình (FE/App) → /generate-design-spec {prd-file}  ← sinh + duyệt design-spec TRƯỚC
                 rồi /generate-bdd {prd-file}   (BDD FE/App cần design-spec đã duyệt để phủ Screen States + AC-UI)
               • Feature thuần backend (không màn hình) → /generate-bdd {prd-file} thẳng (bỏ qua design-spec)
```
