--- name: ba-3-specification description: Giai đoạn 3 của quy trình BA — viết đặc tả chi tiết tới mức dev code được và QA test được. Viết SRS/FRD cho một hoặc nhiều User Story, với PART 2 thay đổi theo loại sản phẩm - màn hình và bảng field (screen), endpoint và hợp đồng dữ liệu (api-service), luồng dữ liệu và data contract (data-pipeline), metric và ngưỡng chấp nhận (ml-model), lịch và idempotency (batch-job) - cộng acceptance criteria Given/When/Then đủ cả luồng lỗi, bảng mã lỗi, yêu cầu phi chức năng, API contract; với sản phẩm có giao diện còn sinh quy ước giao diện cấp project (UICONV) và wireframe low-fi (WF markdown + HTML) đối chiếu với prototype nếu có. Kích hoạt khi người dùng nói "viết SRS", "đặc tả US này", "viết acceptance criteria", "field spec", "bảng mã lỗi", "NFR", "API contract", "data contract", "spec cho dev", "ngưỡng chấp nhận cho mô hình", "wireframe", "bố cục màn hình", "đối chiếu prototype", "quy ước UI". Input là BACKLOG đã qua G2 (+ prototype/design system nếu có); output vào ba-output//03-specification/ và phải qua Gate G3 (Ready for Dev) trước khi dev bắt đầu. --- # GĐ3 · SPECIFICATION — Đặc tả chi tiết Mục tiêu: **viết tới mức dev code được mà không phải đoán, QA test được mà không phải hỏi.** Đây là sản phẩm chính của nghề BA và là gate nghiêm nhất. Một chỗ mơ hồ lọt qua G3 sẽ thành một bug hoặc một CR — với chi phí gấp nhiều lần chi phí làm rõ ở đây. Output: `SRS` · `AC` · `NFR` · `API` trong `ba-output//03-specification/`. Khi `PRODUCT = screen` thêm: `UICONV` (một lần cho cả project, ở `00-index/`) và `WF` (mỗi US, gồm `.md` + `.html` low-fi) — hai artifact này là phần **thay vai trò design ở mức bố cục và trạng thái** khi dự án có prototype tham chiếu, và là **đề xuất chờ Designer duyệt** khi không có. ## Bốn nguyên tắc bất di bất dịch 1. **Không bịa yêu cầu** — thiếu ⇒ `OQ-nnn`. Ở giai đoạn này bịa một giá trị "hợp lý" (độ dài 255, timeout 30s) là cách phổ biến nhất tạo ra bug. 2. **Không quyết định thay PO.** 3. **Mọi phát biểu truy vết được** — mỗi AC chỉ về `US`, mỗi field chỉ về `BR`. 4. **Không ghi đè tài liệu đã qua gate.** Nạp bắt buộc trước khi viết: `../ba-lifecycle/references/domain-profiles.md` (quyết định PART 2 viết cái gì và gate chặt tới đâu) · `../ba-lifecycle/references/writing-rules.md` (W1–W13 — giai đoạn này áp dụng chặt nhất) · `../ba-lifecycle/references/artifact-map.md` §2 · `../ba-lifecycle/references/diagram-rules.md` (sơ đồ điều hướng, sequence, lineage). 🔴 **Mọi sơ đồ theo chuẩn Archify** (`W13`, `../ba-lifecycle/references/diagram-rules.md`): spec JSON `diagrams/_..json` (`quality_profile: showcase`, validate 0 lỗi) **+** mermaid có marker `` (hoặc `mermaid-only` cho ERD/use case/2×2) **+** bảng đi kèm. Một đường chính, ≤ 12 node, nhãn cạnh là điều kiện/giao thức, không màu. Không có Bash ⇒ ghi `humanInputNeeded` "chạy archify validate/deliver + diagram-check", không tự nhận đã validate. Điều hướng, phụ thuộc job → `workflow` · luồng nhiều bên → `sequence` · lineage → `dataflow`. Riêng ở GĐ3: mọi `sequenceDiagram` **bắt buộc vẽ cả nhánh lỗi** (`alt`/`else`, spec dùng `segments` "Nhánh lỗi") — sequence chỉ có luồng thành công vi phạm W4, và đó chính là nhánh dev hay tự bịa. Spec mẫu đã pass: `templates/diagrams/SRS_lineage.dataflow.json`, `../sa-2-architecture/templates/diagrams/SAD_luong-chinh.sequence.json`. Ví dụ minh hoạ cho từng bước, ở nhiều domain khác nhau: `examples.md`. ## Bước 0 — Chốt input rồi dừng lại **Chưa được ghi file.** Làm bảy việc rồi **dừng chờ trả lời**: 1. **Profile** — đọc `00-index/PROFILE_.md`. Chưa có ⇒ suy ra từ tài liệu, **nêu rõ là suy đoán** và hỏi xác nhận. Nêu đích danh `PRODUCT · LIFECYCLE · RIGOR`. 2. **Input dùng được** — bảng `File | Vai trò | Version | Status`. Bắt buộc tìm: `BACKLOG` (US cần đặc tả), `BR`, `RBAC`, `IMPACT`, `PROCESS` từ GĐ2. 3. **Gate G2 đã qua chưa** — đọc `Approved by`. Chưa qua ⇒ nêu rủi ro (SRS sẽ phải viết lại nếu backlog đổi) rồi hỏi có làm tiếp không. 4. **Phạm vi lần chạy** — liệt kê đích danh `US` sẽ đặc tả. **Quá 3 US một lần chạy thì chất lượng giảm rõ rệt** — đề xuất chia. 5. **Biến thể PART 2 sẽ nạp** — theo `PRODUCT` (Bước 2). US có nhiều loại ⇒ nêu đủ. 6. **Guideline dự án cần tuân thủ** — tìm và nêu: `00-index/UICONV_.md`, quy ước UI sẵn có của dự án (vd `GLOBAL_UI_CONVENTION.md`), bộ NFR chuẩn, glossary, danh sách mã lỗi đã dùng. **Chưa có `UICONV` mà `PRODUCT = screen` ⇒ lần chạy này phải sinh nó trước (Bước 8)** và nêu ai duyệt (Designer + PO). 7. **Ngôn ngữ hiển thị** — chỉ hỏi khi `PRODUCT` có giao diện cho người. Không có ⇒ ghi N/A. 8. **Prototype / design system tham chiếu** — chỉ khi `PRODUCT = screen`. Tìm theo thứ tự: tham số `--proto`, thư mục `design/` hoặc `prototype/` trong repo, mục *Thiết kế giao diện* của SAD (`docs/sections/07-*.md`, `docs/SAD.md` §7), file Figma/HTML/ảnh người dùng đưa. Trình bảng `Nguồn | Định dạng | Phiên bản | Phủ màn hình nào`. Không có ⇒ nói rõ **WF sẽ là đề xuất của BA và cần Designer duyệt trước G3**; có ⇒ prototype là nguồn sự thật về bố cục. Rồi **hỏi xác nhận** tám điểm trên. Bỏ qua khi lệnh có `go`. ## Thực hiện — 9 bước Bước 1–7 cho mọi `PRODUCT`. Bước 8–9 chỉ khi `PRODUCT = screen`; loại khác ghi "N/A" trong báo cáo cuối, không bỏ im lặng. ### Bước 1 — Khung SRS và tóm tắt nghiệp vụ Dùng `templates/srs.md`. **Không bỏ mục nào** — mục không áp dụng thì ghi "N/A" kèm lý do, đừng xoá; xoá mục làm người đọc không biết là đã cân nhắc hay đã quên. Với `PRODUCT = screen`: §2.3.6 (trạng thái), §4.3 (định dạng) và mọi quy ước phân trang, toast, vị trí nút **tham chiếu `UICONV`** thay vì định nghĩa lại. Muốn khác ⇒ ghi vào `UICONV` §12. Viết mục **Tóm tắt nghiệp vụ** cho PO đọc: US này giải quyết `RQ` nào, người dùng được gì, khác hiện tại chỗ nào. Ngôn ngữ nghiệp vụ, không có tên bảng dữ liệu, không có tên component. Đây là hiện thực hoá quy tắc W10 — một tài liệu, ba người đọc. ### Bước 2 — Chọn và nạp biến thể PART 2 🔴 **PART 2 thay đổi theo `PRODUCT`.** Không viết PART 2 từ đầu — nạp biến thể: | `PRODUCT` | Nạp | PART 2 mô tả | |---|---|---| | `screen` | `templates/srs-part2/screen.md` | Màn hình, bảng thành phần, bảng field | | `api-service` | `templates/srs-part2/api-service.md` | Người tiêu thụ, khả năng, hợp đồng dữ liệu | | `data-pipeline` | `templates/srs-part2/data-pipeline.md` | Luồng, data contract, chất lượng, đối soát | | `ml-model` | `templates/srs-part2/ml-model.md` | Bài toán, nhãn, metric + ngưỡng, fallback | | `batch-job` | `templates/srs-part2/batch-job.md` | Job, lịch, idempotency, cảnh báo | | `process-only` | — | Không có PART 2; nội dung ở `PROCESS` của GĐ2 | **Một US thường có nhiều loại** (màn hình + API, hoặc màn hình + job đêm) ⇒ nạp nhiều biến thể, mỗi cái một mục con `2.A`, `2.B`, `2.C`. Ghi vào dòng **Biến thể PART 2** ở header. **Loại chưa có biến thể** (nhúng/IoT/firmware) ⇒ nói thẳng với người dùng là PART 2 phải tự viết, và đề xuất khung dựa trên biến thể gần nhất — **không im lặng nhét vào biến thể sai**. `Read` file biến thể trước khi làm tiếp. Mỗi biến thể có **tiêu chí G3 riêng** ghi ở đầu file — đó là thứ thay cho dòng "bảng field" / "wireframe" trong checklist G3 chung. ### Bước 3 — Điền biến thể **Đây là phần dev đọc nhiều nhất.** Ba quy tắc áp cho **mọi** biến thể, bất kể loại sản phẩm: **① Bảng ràng buộc phải cụ thể tới mức không cần hỏi lại.** Mỗi biến thể có một bảng đóng vai trò "bảng field": `screen` → bảng field 10 cột · `api-service` → bảng tham số/schema · `data-pipeline` → bảng ánh xạ trường · `batch-job` → bảng quy tắc xử lý bản ghi · `ml-model` → bảng metric + ngưỡng. Bốn thứ không được để trống ở bất kỳ bảng nào: | Thiếu | Hậu quả thực tế | |---|---| | **Giới hạn** (độ dài, khoảng, ngưỡng) | Chặn ở một tầng, không chặn ở tầng kia ⇒ lỗi 500 hoặc dữ liệu bẩn | | **Giá trị mặc định** | Mỗi chỗ một kiểu; báo cáo lệch vì bản ghi cũ null | | **Nguồn giá trị** | Lấy từ đâu, lọc theo gì, sắp xếp thế nào — dev tự quyết mỗi chỗ một kiểu | | **Hành vi khi sai** | Dev tự quyết ⇒ mỗi chỗ một kiểu, không nhất quán, không dịch được | Mọi con số phải có **đơn vị và nguồn** (quy tắc W3): `40 ký tự (code point UTF-8)` chứ không phải `40`. Tiếng Hàn/Việt có dấu làm số byte khác số ký tự. **② Ba trạng thái, không được gộp** (quy tắc W7). Với `screen`: không hiển thị · disable · read-only. Với `api-service`: 404 · 403 · 200 kèm cờ. Với `batch-job`: bỏ qua · quarantine · dừng job. Ghi "tuỳ trường hợp" là chưa đặc tả xong. **③ Phân biệt "không có gì" với "không lấy được".** Mọi biến thể đều có mục này và mọi biến thể đều hay bỏ nó: hai tình huống trông giống nhau (danh sách rỗng, 0 bản ghi, mảng rỗng) nhưng ý nghĩa ngược nhau. Gộp chúng khiến sự cố bị bỏ qua nhiều ngày. ### Bước 4 — Acceptance Criteria Dùng `templates/acceptance-criteria.md`. Viết theo Given/When/Then. 🔴 **Với `PRODUCT = ml-model`, chia đôi trước khi viết AC.** Given/When/Then không mô tả được yêu cầu xác suất. Phần **hệ thống bao quanh** (API, lưu kết quả, hiển thị, xử lý lỗi) viết AC bình thường đủ 4 nhóm; phần **chất lượng dự đoán** dùng **metric + ngưỡng chấp nhận** ở PART 2 §2.4. Nhầm hai phần này là lỗi kinh điển — QA sẽ viết test đòi mô hình đúng 100% trên vài mẫu tự chọn rồi kết luận fail. **Mỗi US phải có đủ bốn nhóm AC** (quy tắc W4). Chỉ có nhóm 1 là spec chưa viết xong: | Nhóm | Nội dung | Tối thiểu | |---|---|---| | 1. Luồng thành công | Đường đi đúng | 1 AC/hành động | | 2. Validation | Từng rule kiểm tra dữ liệu | 1 AC/rule | | 3. Lỗi hệ thống | Timeout, 5xx, mất mạng giữa chừng | ≥1 AC | | 4. Phân quyền | Không đủ quyền, sai trạng thái | ≥1 AC/vai trò bị chặn | Kèm **bảng dữ liệu biên** cho mỗi field có ràng buộc — đây là thứ QA dùng trực tiếp: | Field | Dưới ngưỡng | Ngưỡng dưới | Trong khoảng | Ngưỡng trên | Trên ngưỡng | Rỗng | Ký tự đặc biệt | |---|---|---|---|---|---|---|---| **Kiểm tra tính test được** — đọc từng AC và tự hỏi: *"tôi ngồi trước màn hình, tôi làm gì để kiểm chứng câu này?"* Không trả lời được ⇒ AC chưa viết xong. AC kiểu "hệ thống hoạt động ổn định" không phải AC. ### Bước 5 — Bảng mã lỗi và text hiển thị **① Bảng mã lỗi — bắt buộc với mọi `PRODUCT`:** | Mã | Khi nào xảy ra | Thông điệp | Đi tới đâu | Người/hệ thống nhận nên làm gì | BR/AC | |---|---|---|---|---|---| Cột **"Đi tới đâu"** và **"nên làm gì"** đổi theo loại sản phẩm — đây là chỗ hay bị bỏ nhất ở loại không có giao diện: | `PRODUCT` | Đi tới đâu | Nên làm gì | |---|---|---| | `screen` | Toast / dưới field / trang lỗi | Người dùng sửa gì | | `api-service` | Mã HTTP + `code` trong body | 🔴 Người gọi có được retry không | | `data-pipeline` | Log / bảng quarantine / cảnh báo | Ai điều tra, bản ghi đi đâu | | `batch-job` | Log + kênh cảnh báo | Người trực làm gì, có chạy lại được không | | `ml-model` | Log + fallback | Hệ thống dùng giá trị gì thay thế | Đặt mã theo `E--<4 số>`, **không tái sử dụng**. Dự án đã có dãy mã ⇒ dùng tiếp số. **② Text hiển thị — chỉ khi `PRODUCT` có giao diện cho người.** Không có ⇒ ghi "N/A", đừng xoá mục. **BA sở hữu mọi chuỗi hiển thị** (quy tắc W5), viết nguyên văn từng ký tự: | Khoá | Ngữ cảnh | Text (VI) | Text (EN) | Text (KO) | Giới hạn ký tự | |---|---|---|---|---|---| **③ "Không có gì" ≠ "không lấy được" — bắt buộc với mọi `PRODUCT`:** | `PRODUCT` | Hai tình huống phải phân biệt | |---|---| | `screen` | Chưa có bản ghi nào *(nút Tạo mới)* ↔ bộ lọc không khớp *(nút Xoá lọc)* | | `api-service` | Mảng rỗng + `total: 0` *(200)* ↔ tài nguyên không tồn tại *(404)* | | `data-pipeline` | Ngày không phát sinh giao dịch ↔ nguồn không phản hồi | | `batch-job` | Không có bản ghi thoả điều kiện ↔ đầu vào chưa sẵn sàng | Gộp hai tình huống này là lỗi kinh điển: với `screen` người dùng tưởng mất dữ liệu; với ba loại còn lại, sự cố im lặng nhiều ngày không ai biết. ### Bước 6 — Yêu cầu phi chức năng Dùng `templates/nfr-checklist.md`. Chỉ viết **NFR áp dụng cho US này**, không copy cả bộ tiêu chuẩn công ty vào. Mỗi NFR bắt buộc ba thứ: **con số đo được** · **điều kiện đo** · **cách verify**. ❌ "Hệ thống phải nhanh." ✅ "Danh sách chênh lệch trả về ≤ 2 giây ở p95, với 100.000 bản ghi và 20 người dùng đồng thời. Verify: chạy k6 kịch bản S1 trên môi trường staging." Bảy nhóm cần rà, ghi "N/A + lý do" cho nhóm không áp dụng: hiệu năng · dung lượng/tăng trưởng · bảo mật & quyền riêng tư · lưu vết · khả dụng & xử lý sự cố · đa ngữ & định dạng · khả năng truy cập. 🔴 **Nhóm đa ngữ & định dạng hay bị bỏ:** múi giờ hiển thị, định dạng ngày, dấu phân cách số, đơn vị tiền, sắp xếp chuỗi có dấu. Đây toàn là thứ gây bug ở môi trường thật. ### Bước 7 — API contract (nếu cần) Dùng `templates/api-contract.md`. 🔴 **Với `PRODUCT = api-service`, đây là artifact chính, không phải bước cuối.** Làm nó song song với Bước 3, và PART 2 chỉ mô tả hợp đồng nhìn từ phía người tiêu thụ — đừng chép trùng. 🔴 **Ghi rõ ngay đầu tài liệu API là contract này do BA đề xuất hay do BE cung cấp.** Hai thứ có độ tin cậy khác hẳn nhau. BA đề xuất ⇒ đánh dấu `⚠️ Đề xuất — chờ BE xác nhận` và liệt kê điểm cần BE chốt. Với mỗi endpoint: method · path · quyền · request (kèm ràng buộc) · response thành công · response lỗi (map về bảng mã lỗi ở Bước 5) · phân trang · sắp xếp. Ba điểm phải chốt, hay bị bỏ: - **Số lớn** (id, số tiền) truyền dạng string hay number? Vượt `2^53` thì JS làm tròn sai. - **Thời gian** dạng gì, múi giờ nào — UTC hay giờ địa phương? - **Phân trang** offset hay cursor, có `hasNext`/`total` không? ### Bước 8 — Quy ước giao diện cấp project (`UICONV`) — chỉ `screen` Dùng `templates/ui-convention.md`, ghi vào `00-index/UICONV_.md`. **Sinh một lần** ở lần chạy ba-3 đầu tiên của project; các lần sau chỉ đọc và bổ sung §10 (dãy mã lỗi), §11 (từ vựng thành phần), §12 (ngoại lệ). Nguồn điền, theo thứ tự ưu tiên: design system của dự án > prototype tham chiếu > guideline sẵn có > **hỏi** (ghi `OQ`, không tự chọn). Mọi ô "chọn một" phải chọn xong — còn dấu `/` giữa các phương án là chưa làm. 🔴 `UICONV` là **hợp đồng giữa BA và Design**: BA sở hữu text và trạng thái, Design sở hữu layout và từ vựng thành phần. Cả hai ký. Dự án không có Designer ⇒ PO ký thay và ghi `DEC-nn`. ### Bước 9 — Wireframe & bố cục (`WF`) — chỉ `screen` Dùng `templates/wireframe.md` (bảng) + `templates/wireframe.html` (render low-fi). Ghi `WF__v1.0.md` và `WF__v1.0.html` vào `03-specification/`. Làm **sau** Bước 3 và 5, vì WF chỉ sắp xếp những thành phần và text đã có trong SRS. **Hai chế độ, phải khai rõ ở dòng `Nguồn bố cục` của header:** | Chế độ | Khi nào | WF là gì | Ai duyệt | |---|---|---|---| | 🎨 **Prototype tham chiếu** | Có Figma / HTML / ảnh / mô tả UI đã duyệt | **Bản ghi lại** bố cục của prototype bằng bảng + đối chiếu với SRS | PO (Designer đã duyệt prototype) | | ✏️ **BA tự dựng** | Không có prototype | **Đề xuất** bố cục theo `UICONV` | **Designer bắt buộc** ở `standard`+ | Bốn việc, theo thứ tự: 1. **Bản đồ prototype ↔ SCR** (§1): mỗi màn hình trong `SRS` §2.1 có trong prototype không, ở frame/trang nào. Màn hình prototype không có ⇒ BA tự dựng phần đó và đánh dấu. 2. **Bảng vùng + vị trí thành phần** (§3.x.1–2) cho **mọi** `SCR`, kể cả modal và trang lỗi. 🔴 Tập `C-id` phải **khớp hai chiều** với bảng thành phần `SRS` §2.3.1 — chạy `grep -o "C[0-9][0-9]"` trên cả hai file và so tập. Thành phần có trong prototype mà SRS không có ⇒ **không tự thêm vào SRS**, ghi lệch ở §5 cho PO quyết. 3. **Trạng thái, responsive, tương tác trình bày** (§3.x.3–6): hai trạng thái rỗng phải **trông** khác nhau; mọi con số (ms, s, px) có nguồn `UICONV`/prototype, không có ⇒ `OQ`. 4. **Sinh HTML** từ bảng: mỗi `SCR` một `
`, mỗi vùng `data-zone`, mỗi thành phần `data-c` đúng C-id, mỗi trạng thái một khối `data-state`. Thành phần **chỉ có ở prototype** (lệch loại Tồn tại ở §5) vẽ đúng chỗ prototype đặt nó bằng ``, **không gán `data-c`** — khung đỏ đứt để PO nhìn thấy ngay quyết định còn thiếu. Giữ nguyên `