Sẽ mở trong thẻ mới
PDL AIAI Worker — trợ lý AI trực 24/7: trả lời khách, xử lý yêu cầu, báo cáo tự động

Kỹ sư phần mềm thời AITờ 03-06 / 112

Viết PRD và spec mà cả người lẫn AI đều hiểu

Bộ hồ sơ bản vẽ có tờ tóm tắt và các tờ chi tiết đã đóng dấu duyệt, ví cho PRD và spec
Tờ
03-06 / 112
Hạng mục
M03 · Từ ý tưởng đến yêu cầu
Cấp độ
Trung cấp
Thời gian đọc
15 phút
Giai đoạn công trình
0 · Khám phá
Cập nhật
Bản đồ công trìnhTờ này lắp: PRD & spec, Giao diện app, API
Bản đồ công trình Mộc OMSBài này: PRD & spec, Giao diện app, API. Đã học: Coding agent, Khách hàng, Kênh bán, Sheet & sổ tay. Chưa tới: Repo & CI, Kiểm thử, Hosting & tên miền, Giám sát lỗi, Database, Dashboard, báo cáo, Trợ lý AI nhận đơn, Màn hình bếp, Đăng nhập, vai trò, Thanh toán VietQR, Thông báo khách, Nhiều tiệm (MộcOS), Kế toán, hoá đơn.Thi công & hạ tầngDòng đơn hàngNghiệp vụ & dịch vụMở rộng MộcOSPRD & specspecCoding agentagentRepo & CIrepo-ciKiểm thửtestsHosting & tên miềnhostingGiám sát lỗimonitoringKhách hàngcustomerKênh bánchannelsGiao diện appapp-uiAPIapiDatabasedatabaseDashboard, báo cáoreportsSheet & sổ taysheetTrợ lý AI nhận đơnai-assistantMàn hình bếpkitchenĐăng nhập, vai tròauthThanh toán VietQRpaymentsThông báo kháchnotificationsNhiều tiệm (MộcOS)tenantsKế toán, hoá đơnintegrations0 Khám phá1 MVP2 Ra mắt3 Thêm AI4 Mở rộng
Bản đồ công trình Mộc OMSBài này: PRD & spec, Giao diện app, API. Đã học: Coding agent, Khách hàng, Kênh bán, Sheet & sổ tay. Chưa tới: Repo & CI, Kiểm thử, Hosting & tên miền, Giám sát lỗi, Database, Dashboard, báo cáo, Trợ lý AI nhận đơn, Màn hình bếp, Đăng nhập, vai trò, Thanh toán VietQR, Thông báo khách, Nhiều tiệm (MộcOS), Kế toán, hoá đơn.Dòng đơn hàngKhách hàngKênh bánGiao diệnAPIDatabaseBáo cáoNghiệp vụ & dịch vụSheet, sổ tayTrợ lý AIMàn hình bếpĐăng nhậpThanh toánThông báoThi công & hạ tầngPRD & specCoding agentRepo & CIKiểm thửHostingGiám sátMở rộng MộcOSNhiều tiệmKế toán0 Khám phá1234

Bài nàyĐã họcChưa tớiĐã thay thế

Bạn sẽ học được gì

Tiêu chí nghiệm thu

Vì sao tài liệu quan trọng hơn khi có AI?

Hãy so sánh hai cách giao việc cho một thợ bánh mới vào làm. Cách thứ nhất: “Làm cho chị cái bánh sinh nhật nhé.” Cách thứ hai: một phiếu đặt bánh ghi rõ size 20cm, vị chanh dây, chữ “Mừng sinh nhật Mẹ Ánh” (có dấu), nến số 6, giao trước 17:00, không dùng hạt vì khách dị ứng. Thợ giỏi đến mấy, cách thứ nhất cũng đòi hỏi họ đoán hàng chục điều — và mỗi lần đoán sai, bạn chỉ phát hiện ra khi bánh đã xong.

Coding agent là “thợ mới vào làm” mỗi khi bạn mở phiên mới: nó giỏi kỹ thuật, nhưng không nhớ gì về cuộc trò chuyện hôm qua, không biết anh Tuấn sắp bánh theo chuyến xe, không biết Hà hay bấm nút hai lần khi mạng chậm. Một prompt mơ hồ buộc mô hình đoán hàng loạt yêu cầu ngầm, và những lần đoán sai thường lộ ra rất muộn. Spec là phiếu đặt bánh của phần mềm.

Thêm một lý do: ngữ cảnh là tài nguyên quý nhất của agent (xem bài context engineering02-05). Một spec cô đọng 2–4 trang chứa đúng những gì cần cho một tính năng tốt hơn rất nhiều so với việc để agent đọc lại 50 tin nhắn trao đổi hoặc tự khám phá hàng chục file.

PRD tổng thể và spec tính năng

PRD (Product Requirements Document) Spec tính năng
Phạm vi Toàn bộ sản phẩm hoặc một giai đoạn (ví dụ MVP Mộc OMS) Một tính năng (ví dụ “Tạo đơn hàng”)
Câu hỏi chính Làm gì, cho ai, vì sao, thành công là gì, không làm gì Chính xác hành vi nào, quy tắc nào, dữ liệu nào, kiểm chứng ra sao
Độ dài gợi ý 1–3 trang 2–5 trang
Người đọc Chủ doanh nghiệp, team, đối tác, agent (làm bối cảnh) Agent thực thi, người review, người kiểm thử
Tần suất thay đổi Ít, theo giai đoạn Thường xuyên trong lúc làm tính năng
Vị trí trong repo docs/PRD.md docs/specs/tao-don-hang.md
Có nói về công nghệ? Chỉ ràng buộc lớn (stack đã chọn, ngân sách) Có thể chỉ ra file, interface, bảng dữ liệu liên quan

Quan hệ giữa các tài liệu bạn đã tạo trong module này:

Vuốt ngang để xem hết sơ đồ

phát hiện điều chưa rõ

Problem statement
(bài 03-01)

docs/PRD.md

Nghiên cứu, quy tắc nghiệp vụ
(bài 03-02)

MoSCoW, non-goals
(bài 03-04)

docs/specs/tao-don-hang.md

docs/specs/man-hinh-bep.md

User story + Given–When–Then
(bài 03-05)

Kế hoạch kỹ thuật (plan)

Danh sách task

Code + test

Hình 1 Sơ đồ luồng
Đọc sơ đồ dạng chữ
  1. Problem statement (bài 03-01) → docs/PRD.md
  2. Nghiên cứu, quy tắc nghiệp vụ (bài 03-02) → docs/PRD.md
  3. MoSCoW, non-goals (bài 03-04) → docs/PRD.md
  4. docs/PRD.md → docs/specs/tao-don-hang.md
  5. docs/PRD.md → docs/specs/man-hinh-bep.md
  6. User story + Given–When–Then (bài 03-05) → docs/specs/tao-don-hang.md
  7. User story + Given–When–Then (bài 03-05) → docs/specs/man-hinh-bep.md
  8. docs/specs/tao-don-hang.md → Kế hoạch kỹ thuật (plan)
  9. Kế hoạch kỹ thuật (plan) → Danh sách task
  10. Danh sách task → Code + test
  11. Code + test → docs/specs/tao-don-hang.md (phát hiện điều chưa rõ)

Mũi tên nét đứt cuối cùng là chỗ nhiều người bỏ qua: khi làm, bạn sẽ phát hiện điều spec chưa nói. Đường đúng là quay lại cập nhật spec, không phải “sửa nhanh trong code rồi tính sau”.

Mẫu PRD 1–3 trang

Một PRD cho dự án nhỏ không cần 40 trang. Nó cần đủ để một người mới (hoặc một agent) đọc trong 10 phút là hiểu sản phẩm này tồn tại để làm gì và ranh giới nằm ở đâu. Đây là PRD của Mộc OMS, rút gọn từ các bài trước:

MARKDOWN
# PRD — Mộc OMS (giai đoạn 1: MVP)

- Phiên bản: 1.2 | Cập nhật: 2026-01-19 | Chủ sở hữu: Nguyễn Thị Lan (owner)
- Trạng thái: Đã duyệt

## 1. Tóm tắt
Mộc OMS là hệ thống quản lý đơn nội bộ cho chuỗi 3 tiệm Bánh Mộc (Phú Nhuận, Thảo Điền, Gò Vấp)
và bếp trung tâm. Mục tiêu giai đoạn 1: mọi đơn đặt trước được nhập MỘT LẦN tại nguồn,
bếp và chi nhánh đọc từ cùng một chỗ, tiền cọc gắn với đơn.

## 2. Vấn đề
Xem problem statement đầy đủ ở phần Phụ lục A. Tóm tắt: đơn bị chép lại 2–3 lần qua Sheet, sổ tay,
ảnh chụp Zalo; ước tính thiệt hại trực tiếp 13–24 triệu đồng/tháng (giả định, đang đo baseline).

## 3. Mục tiêu và chỉ số thành công (sau 3 tháng dùng ở cả 3 tiệm)
- Tỷ lệ bánh kem làm lại do sai thông tin giảm ≥ 50% so với baseline.
- Thời gian đối soát cuối ngày ≤ 30 phút/tiệm.
- ≥ 95% đơn đặt trước được tạo trong Mộc OMS (không còn đơn chỉ nằm trên Sheet/Zalo).
- Chỉ số định hướng và kế hoạch đo: docs/metrics.md.

## 4. Người dùng
- staff: Hà (bán hàng online), nhân viên quầy — tạo, sửa đơn; ghi cọc.
- manager: quản lý chi nhánh, anh Tuấn (bếp trung tâm) — như staff + hủy đơn đang làm, sửa giá, tạo đơn gấp.
- owner: chị Lan — xem toàn chuỗi, quản lý nhân viên và danh mục.
- Persona chi tiết: docs/research/personas.md.

## 5. Phạm vi MVP
| Mã | Tính năng | Story | Spec |
|---|---|---|---|
| F1 | Tạo đơn hàng (kèm tìm/tạo khách, ghi cọc khi tạo) | US-01, US-02, US-03 | specs/tao-don-hang.md |
| F2 | Sửa, hủy đơn; chuyển trạng thái | US-03, US-05 | specs/cap-nhat-don.md |
| F3 | Màn hình bếp theo chuyến xe | US-04 | specs/man-hinh-bep.md |
| F4 | Khách hàng và lịch sử mua | US-02 | specs/khach-hang.md |
| F5 | Danh mục sản phẩm, bánh kem tùy chỉnh | — | specs/san-pham.md |
| F6 | Đăng nhập theo vai trò, phân quyền theo chi nhánh | — | specs/phan-quyen.md |
| F7 | Dashboard đơn hôm nay | US-06 | specs/dashboard.md |

## 6. Ngoài phạm vi (non-goals)
Website cho khách tự đặt; chatbot/trợ lý AI; thay máy tính tiền, hóa đơn điện tử; tự xác nhận chuyển khoản;
thông báo tự động cho khách; kho nguyên liệu; tích điểm, khuyến mãi; app di động cài đặt;
tự tính phí giao hàng; multi-tenant. Lý do và thời điểm xem lại: Phụ lục B.

## 7. Ràng buộc và giả định
- Stack: Next.js + TypeScript + Supabase (PostgreSQL, Auth) + Drizzle + Zod; host Vercel.
- Tiền lưu số nguyên VNĐ; thời gian lưu timestamptz, hiển thị Asia/Ho_Chi_Minh.
- Dữ liệu cá nhân khách (tên, SĐT, địa chỉ, sinh nhật) chỉ dùng cho mục đích phục vụ đơn hàng;
  tuân thủ quy định bảo vệ dữ liệu cá nhân hiện hành (cần tư vấn pháp lý khi mở rộng sử dụng).
- Thiết bị: laptop ở quầy, máy tính bảng ở bếp, điện thoại của người giao. Chỉ tiếng Việt.
- Nguồn lực: chị Lan ~8–10 giờ/tuần cùng coding agent; review bảo mật thuê ngoài trước khi ra mắt.

## 8. Rủi ro chính
- Nhân viên quay lại Sheet nếu tạo đơn chậm hơn cách cũ -> mục tiêu tạo đơn ≤ 90 giây.
- Sai phân quyền làm lộ dữ liệu khách giữa chi nhánh -> test phân quyền bắt buộc.
- Ngày lễ quá tải -> chạy thử trước mùa cao điểm ít nhất 2 tuần.

## 9. Mốc
- Lát 1 chạy thử ở Phú Nhuận + bếp trung tâm: 2 tuần.
- Lát 2, mở cho 3 tiệm: sau khi lát 1 đạt tiêu chí go/no-go.

## 10. Câu hỏi mở
- Bánh nhận trước 08:00 đi chuyến nào? (chờ anh Tuấn xác nhận)

## 11. Lịch sử thay đổi
- 1.2 (2026-01-19): thêm quy tắc chuyến xe QT-07 sau shadowing bếp.
- 1.1: thêm F4 lịch sử mua vào lát 2 theo kết quả phỏng vấn khách.

Mẫu spec tính năng

Spec tính năng tốt có bốn đặc điểm, rút ra từ kinh nghiệm làm việc với coding agent:

  1. Tự chứa (self-contained): một agent ở phiên mới đọc spec (cùng các file nó trỏ tới) là đủ để làm, không cần lịch sử trò chuyện.
  2. Chỉ ra file và interface liên quan: bảng dữ liệu nào, thư mục nào, hàm nào đã có để tái sử dụng — giúp agent khỏi “khám phá vô hạn” codebase.
  3. Nói rõ ngoài phạm vi: hàng rào chống “tiện tay làm thêm”.
  4. Kết thúc bằng cách kiểm chứng end-to-end: lệnh test nào, kịch bản thủ công nào, bằng chứng nào cần nộp.

Khung mẫu bạn có thể lưu thành docs/specs/_template.md:

MARKDOWN
# Spec: [Tên tính năng]
- Mã: SPEC-xxx | Trạng thái: Nháp / Đang review / Đã duyệt / Đã triển khai | Phiên bản: x.y
- Cập nhật: YYYY-MM-DD | Người phụ trách: ...
- Liên quan: PRD mục ..., user story ..., spec khác ...

## 1. Mục tiêu
Một đoạn: tính năng này giải phần nào của vấn đề trong PRD; thành công trông như thế nào.

## 2. Người dùng và quyền
Ai dùng, ở thiết bị nào; mỗi vai trò được làm gì, không được làm gì.

## 3. Trong phạm vi
Danh sách hành vi cụ thể.

## 4. Ngoài phạm vi
Những gì KHÔNG làm trong spec này (kể cả những thứ "tiện thể").

## 5. Luồng chính
Các bước người dùng đi qua, từ điểm vào đến kết quả.

## 6. Quy tắc nghiệp vụ
Đánh mã (QT-xx), mỗi quy tắc kiểm tra được.

## 7. Dữ liệu
Bảng/cột đọc và ghi; giá trị mặc định; ràng buộc; những gì phải ghi lịch sử.

## 8. Giao diện
Màn hình, đường dẫn, các trường và thứ tự; trạng thái rỗng/đang tải/lỗi/thành công.

## 9. Hợp đồng phía máy chủ
Tên hàm/endpoint, đầu vào, đầu ra, mã lỗi.

## 10. Lỗi và thông báo
Bảng: tình huống -> thông báo hiển thị (tiếng Việt, tử tế, chỉ cách sửa).

## 11. Tiêu chí chấp nhận
Given–When–Then hoặc trỏ tới file story.

## 12. Kiểm chứng end-to-end
Lệnh chạy test; kịch bản thủ công; bằng chứng cần nộp (output test, ảnh chụp).

## 13. Câu hỏi mở
Điều chưa quyết định; đánh dấu [CẦN XÁC NHẬN].

## 14. Lịch sử thay đổi

Spec hoàn chỉnh: “Tạo đơn hàng”

Đây là spec mà chị Lan dùng để giao cho agent. Bạn sẽ thấy nó được thực thi từng bước ở bài case study 06-1006-10. Hãy đọc kỹ cách spec nói rất rõ “cái gì” nhưng để ngỏ “làm thế nào” ở những chỗ thuộc về kế hoạch kỹ thuật (ví dụ cách sinh mã đơn an toàn khi tạo đồng thời).

MARKDOWN
# Spec: Tạo đơn hàng
- Mã: SPEC-001 | Trạng thái: Đã duyệt | Phiên bản: 1.1
- Cập nhật: 2026-01-26 | Người phụ trách: Nguyễn Thị Lan
- Liên quan: docs/PRD.md (F1); docs/specs/user-stories.md (US-01, US-02, US-03 phần ghi cọc khi tạo)

## 1. Mục tiêu
Cho phép nhân viên ghi một đơn (đặc biệt đơn bánh kem tùy chỉnh) MỘT LẦN, đầy đủ thông tin bếp cần,
trong ≤ 90 giây với khách đã có. Thay thế việc gõ Google Sheet và chụp màn hình gửi bếp.

## 2. Người dùng và quyền
- staff (Hà, nhân viên quầy): tạo đơn cho chi nhánh của mình; KHÔNG sửa đơn giá; KHÔNG tạo đơn gấp.
- manager: như staff + sửa đơn giá + tạo đơn gấp (bắt buộc lý do).
- owner: như manager, cho mọi chi nhánh.
- Thiết bị chính: laptop ở quầy (màn hình ≥ 1280px); phải dùng được trên máy tính bảng.

## 3. Trong phạm vi
- Tìm khách theo số điện thoại; tạo khách mới (họ tên, SĐT bắt buộc; địa chỉ, sinh nhật tùy chọn).
- Thêm 1..n dòng sản phẩm; với sản phẩm is_custom_cake: chọn vị, chữ trên bánh (hoặc "không chữ"), ghi chú cho bếp.
- Chọn kênh (facebook | zalo | phone | walk_in | website), chi nhánh nhận, nhận tại tiệm hoặc giao hàng,
  giờ nhận/giao, địa chỉ giao (nếu giao), phí giao (nhập tay), ghi chú đơn.
- Ghi nhận tiền cọc ngay khi tạo (tùy chọn): phương thức, số tiền, mã giao dịch.
- Sinh mã đơn; lưu đơn ở trạng thái moi; ghi dòng đầu tiên vào lịch sử trạng thái.
- Sau khi tạo: hiển thị mã đơn và nút "Sao chép tóm tắt" để gửi khách xác nhận.

## 4. Ngoài phạm vi
- Sửa, hủy, chuyển trạng thái đơn (SPEC-002).
- Hiển thị ở màn hình bếp (SPEC-003) — spec này chỉ cần đảm bảo dữ liệu đủ cho bếp.
- Gửi tin nhắn/email/Zalo tự động cho khách; tạo mã VietQR; xác nhận chuyển khoản tự động.
- Tự tính phí giao hàng; mã giảm giá; tích điểm; xuất hóa đơn.
- Trang quản trị danh mục sản phẩm (dùng dữ liệu seed).
- KHÔNG tự thêm tính năng ngoài danh sách trên; đề xuất ghi vào mục 13.

## 5. Luồng chính
1. Nhân viên mở /orders/new.
2. Nhập SĐT -> hệ thống chuẩn hóa và tìm khách. Thấy: hiện tên + 3 đơn gần nhất. Không thấy: form khách mới, SĐT điền sẵn.
3. Thêm sản phẩm. Nếu là bánh kem tùy chỉnh: hiện thêm trường vị, chữ trên bánh, ghi chú bếp.
4. Chọn kênh, chi nhánh (mặc định chi nhánh của nhân viên), nhận/giao, giờ nhận.
5. (Tùy chọn) ghi nhận cọc.
6. Xem tóm tắt: tạm tính, phí giao, tổng, đã cọc, còn lại. Bấm "Tạo đơn".
7. Thành công: hiện mã đơn, tóm tắt; nút "Sao chép tóm tắt", "Tạo đơn mới".

## 6. Quy tắc nghiệp vụ
- QT-01: bánh kem tùy chỉnh bắt buộc vị; size xác định bởi sản phẩm (ví dụ "Bánh kem tùy chỉnh 20cm");
  chữ trên bánh tối đa 40 ký tự, giữ nguyên dấu; không chấp nhận emoji (bếp không viết được);
  nếu khách không muốn chữ: chọn "Không chữ" (cake_message = null).
- QT-02: bánh kem tùy chỉnh: delivery_at ≥ thời điểm tạo + 24 giờ. staff bị chặn.
  manager/owner được tạo "đơn gấp" khi nhập lý do; lý do lưu đầu trường note dạng "[ĐƠN GẤP] <lý do>".
- QT-03: delivery_at trong khung 07:00–21:00 giờ Việt Nam, không ở quá khứ.
- QT-05: SĐT chuẩn hóa về 10 chữ số bắt đầu bằng 0 trước khi tìm/lưu; customers.phone là UNIQUE.
- QT-06: unit_price lấy từ products.price tại thời điểm tạo; chỉ manager/owner sửa được.
- QT-09: mã đơn dạng BM-YYMMDD-XXX theo NGÀY TẠO giờ Việt Nam; XXX tăng dần từ 001 trong ngày, toàn chuỗi;
  không bao giờ trùng, kể cả khi nhiều người tạo cùng lúc.
- QT-10: tiền là số nguyên VNĐ. subtotal = tổng(quantity × unit_price); total = subtotal + shipping_fee.
- QT-11: cọc khi tạo: 0 < số tiền ≤ total. Nếu số tiền = total -> payment_status = paid; nếu > 0 -> deposit;
  không cọc -> unpaid. Ghi một dòng vào payments.
- QT-12: delivery_type = delivery thì bắt buộc delivery_address.
- QT-13: bấm "Tạo đơn" nhiều lần (hoặc gửi lại do mạng) chỉ tạo đúng một đơn.

## 7. Dữ liệu
- Đọc: customers (tìm theo phone), products (is_active = true), staff (vai trò, branch_id của người dùng).
- Ghi trong MỘT giao dịch (tất cả hoặc không gì cả):
  - customers: tạo mới nếu chưa có.
  - orders: code, customer_id, branch_id, channel, status = 'moi', delivery_type, delivery_at, delivery_address,
    subtotal, shipping_fee, total, deposit (tổng đã cọc), payment_status, note, created_by = staff.id.
  - order_items: product_id, quantity, unit_price, cake_message,
    options JSONB ví dụ {"flavor": "chanh_day", "kitchen_note": "ít ngọt"}.
  - payments (nếu có cọc): method (cash | bank_transfer | vietqr), amount, paid_at, reference.
  - order_status_history: from_status = null, to_status = 'moi', changed_by, changed_at.
- Không thay đổi schema trong spec này. Nếu thấy cần, dừng lại và ghi vào mục 13.

## 8. Giao diện
- Đường dẫn: /orders/new. Một trang, chia 4 khối theo thứ tự: Khách hàng -> Sản phẩm -> Nhận hàng -> Thanh toán,
  bên phải là khối Tóm tắt luôn hiển thị.
- Thứ tự trường bánh kem theo mẫu tin nhắn Hà đang dùng: Sản phẩm (size) -> Vị -> Chữ trên bánh -> Ghi chú bếp.
- Bộ đếm ký tự cho chữ trên bánh (x/40).
- Trạng thái: đang tìm khách; không tìm thấy; đang lưu (nút bị vô hiệu hóa, chữ "Đang tạo đơn..."); lỗi; thành công.
- Lỗi hiện ngay dưới trường liên quan; không xóa dữ liệu đã nhập khi lỗi.
- Dùng component có sẵn trong src/components/ui (shadcn/ui); không thêm thư viện giao diện mới.

## 9. Hợp đồng phía máy chủ
- Server action createOrder(input) trong src/features/orders/actions.ts.
- Schema Zod createOrderSchema trong src/features/orders/schema.ts, dùng chung cho client và server.
- Quy tắc thuần (QT-02, QT-03, QT-10, QT-11) đặt trong src/features/orders/rules.ts, có unit test.
- normalizePhone đã có ở src/lib/phone.ts — tái sử dụng, không viết lại.
- Đầu vào: thông tin khách (customerId hoặc khách mới), danh sách dòng, kênh, chi nhánh, nhận/giao, giờ nhận,
  phí giao, ghi chú, cọc (tùy chọn), rushReason (tùy chọn), idempotencyKey (chuỗi do client sinh mỗi lần mở form).
- Đầu ra thành công: { ok: true, order: { id, code } }.
- Đầu ra lỗi: { ok: false, code, fieldErrors? } với code thuộc:
  VALIDATION_ERROR | LEAD_TIME_TOO_SHORT | OUTSIDE_OPENING_HOURS | DEPOSIT_EXCEEDS_TOTAL | FORBIDDEN | UNKNOWN.
- Mọi kiểm tra quyền và quy tắc thực hiện ở máy chủ; kiểm tra phía client chỉ để phản hồi nhanh.

## 10. Lỗi và thông báo
| Tình huống | Thông báo |
|---|---|
| Thiếu vị bánh | "Vui lòng chọn vị bánh." |
| Chữ > 40 ký tự | "Chữ trên bánh tối đa 40 ký tự (hiện có N)." |
| Chữ có emoji | "Chữ trên bánh không dùng được biểu tượng cảm xúc." |
| Đặt trước < 24 giờ (staff) | "Bánh kem tùy chỉnh cần đặt trước ít nhất 24 giờ. Liên hệ quản lý để tạo đơn gấp." |
| Ngoài giờ mở cửa | "Giờ nhận cần trong khoảng 07:00–21:00." |
| SĐT sai | "Số điện thoại cần 10 chữ số, bắt đầu bằng 0." |
| Cọc > tổng | "Tiền cọc không được lớn hơn tổng đơn." |
| Mất kết nối | "Chưa tạo được đơn do mất kết nối. Thông tin vẫn được giữ, vui lòng thử lại." |

## 11. Tiêu chí chấp nhận
Toàn bộ kịch bản US-01, US-02 trong docs/specs/user-stories.md, cộng thêm:
- Given hai nhân viên bấm "Tạo đơn" cùng lúc, Then hai đơn có mã khác nhau.
- Given đơn tạo lúc 23:59 ngày 12/10 và 00:01 ngày 13/10 (giờ VN), Then mã lần lượt BM-261012-xxx và BM-261013-001 (nếu là đơn đầu ngày).
- Given staff chi nhánh Gò Vấp, When gửi createOrder với branch_id của Phú Nhuận, Then nhận FORBIDDEN.

## 12. Kiểm chứng end-to-end
- Chạy: npm run lint, npm run typecheck, npm test (unit), npm run test:e2e (Playwright).
- Unit test bắt buộc: QT-01, QT-02, QT-03, QT-05, QT-10, QT-11, QT-13 (mỗi test bắt đầu bằng mã quy tắc).
- E2E bắt buộc: luồng chính US-01; khách mới US-02; staff bị chặn đơn gấp.
- Kiểm thử thủ công trên máy tính bảng: tạo 1 đơn bánh kem có chữ "Mừng sinh nhật Mẹ Ánh", chụp màn hình kết quả.
- Bằng chứng nộp kèm PR: output các lệnh trên, 2 ảnh chụp (form đầy đủ, màn hình thành công), danh sách file đã đổi.

## 13. Câu hỏi mở
- [CẦN XÁC NHẬN] Có nên tách lý do đơn gấp thành cột riêng thay vì tiền tố trong note? (ảnh hưởng báo cáo sau này)
- [CẦN XÁC NHẬN] Khách chỉ có Zalo, không cung cấp SĐT: MVP bắt buộc SĐT; xem lại ở giai đoạn trợ lý AI.

## 14. Lịch sử thay đổi
- 1.1 (2026-01-26): thêm QT-13 (chống tạo trùng) và cấm emoji trong chữ trên bánh sau buổi đọc spec với Hà.
- 1.0: bản đầu tiên, viết sau phiên agent phỏng vấn.

Một vài chi tiết đáng chú ý trong spec này:

  • Mục 9 chỉ ra file có sẵn (normalizePhone) và dặn tái sử dụng. Thiếu dòng này, agent rất có thể viết thêm một hàm chuẩn hóa thứ hai hơi khác — và bạn có hai “sự thật” về số điện thoại.
  • QT-09 nói “không bao giờ trùng, kể cả khi tạo cùng lúc” nhưng không nói cách làm. Đó là việc của bước lập kế hoạch kỹ thuật, nơi agent đề xuất phương án (ví dụ dựa vào ràng buộc UNIQUE và cơ chế đếm trong database) để bạn duyệt.
  • “Không thay đổi schema trong spec này” là một hàng rào quan trọng: thay đổi mô hình dữ liệu cần được cân nhắc riêng (xem bài mô hình hóa dữ liệu04-02).
  • Mục 12 yêu cầu bằng chứng, không chỉ “chạy test”. Agent phải nộp output và ảnh chụp, giống như thợ bánh chụp ảnh bánh trước khi giao.

Để agent phỏng vấn bạn rồi viết SPEC.md

Viết spec từ trang trắng rất khó với người mới. Một kỹ thuật hiệu quả mà tài liệu thực hành của nhiều nhà cung cấp coding agent khuyến nghị cho tính năng lớn: đảo vai — để agent phỏng vấn bạn. Agent giỏi đặt những câu hỏi về điểm khó mà bạn chưa nghĩ tới (đồng thời, phân quyền, dữ liệu cũ, múi giờ), còn bạn giỏi trả lời về nghiệp vụ. Kết quả là spec vừa đúng nghiệp vụ, vừa đủ chi tiết kỹ thuật.

Quy trình gồm hai phiên tách biệt:

Vuốt ngang để xem hết sơ đồ

Phiên 2 (sạch): agent thực thidocs/specs/tao-don-hang.mdPhiên 1: agent phỏng vấnChị Lan

loop[Từng nhóm 3–5 câu hỏi]Bối cảnh + yêu cầu phỏng vấn (chế độ chỉ đọc)Đọc PRD, user stories, schemaCâu hỏi (kể cả điểm khó)Trả lời / “chưa biết”Viết spec theo mẫu, đánh dấu [CẦN XÁC NHẬN]Đọc, sửa, đọc cùng Hà, chuyển “Đã duyệt”“Đọc spec, lập kế hoạch trước khi code”Kế hoạch + danh sách taskDuyệt kế hoạch -> thực thi từng task

Hình 2 Sơ đồ tuần tự
Đọc sơ đồ dạng chữ
  1. Chị Lan → Phiên 1: agent phỏng vấn: Bối cảnh + yêu cầu phỏng vấn (chế độ chỉ đọc)
  2. Phiên 1: agent phỏng vấn → Phiên 1: agent phỏng vấn: Đọc PRD, user stories, schema
  3. Lặp: Từng nhóm 3–5 câu hỏi
  4. Phiên 1: agent phỏng vấn → Chị Lan: Câu hỏi (kể cả điểm khó)
  5. Chị Lan → Phiên 1: agent phỏng vấn: Trả lời / “chưa biết
  6. Phiên 1: agent phỏng vấn → docs/specs/tao-don-hang.md: Viết spec theo mẫu, đánh dấu [CẦN XÁC NHẬN]
  7. Chị Lan → docs/specs/tao-don-hang.md: Đọc, sửa, đọc cùng Hà, chuyển “Đã duyệt
  8. Chị Lan → Phiên 2 (sạch): agent thực thi: Đọc spec, lập kế hoạch trước khi code
  9. Phiên 2 (sạch): agent thực thi → Chị Lan: Kế hoạch + danh sách task
  10. Chị Lan → Phiên 2 (sạch): agent thực thi: Duyệt kế hoạch -> thực thi từng task

Vì sao phải mở phiên mới để thực thi? Phiên phỏng vấn chứa đầy những câu hỏi, câu trả lời lưỡng lự, ý tưởng bị bỏ — đó là “rác ngữ cảnh”. Nếu thực thi ngay trong phiên đó, agent có thể bị ảnh hưởng bởi một ý bạn đã gạt đi ở câu thứ 7. Phiên mới chỉ đọc spec đã duyệt: sạch, tập trung, và cũng là phép thử xem spec có thật sự tự chứa không. Nếu agent ở phiên mới phải hỏi lại nhiều điều, spec còn thiếu.

Spec là tài liệu sống

Spec không phải hợp đồng đóng dấu rồi cất tủ. Nó thay đổi khi bạn học thêm, và việc quản lý thay đổi đó quyết định spec còn đáng tin hay không.

Hình chữ ký Máy trạng thái
  1. Nháp
  2. Đang review
  3. Đã duyệt
  4. Đang làm
  5. Đã triển khai
  6. phát hiện điều chưa rõ, sửa spec, tăng phiên bản
Xem sơ đồ gốc (Hình 3)

Vuốt ngang để xem hết sơ đồ

tạo từ mẫu / agent phỏng vấn

viết xong bản đầu

cần sửa

người dùng + chủ sở hữu đồng ý

bắt đầu thực thi

phát hiện điều chưa rõ, sửa spec, tăng phiên bản

code khớp spec, kiểm chứng xong

yêu cầu thay đổi mới

lỗi thời / được thay thế

Nháp

Đang review

Đã duyệt

Đang làm

Đã triển khai

Hình 3 Máy trạng thái
Đọc sơ đồ dạng chữ
  1. Bắt đầu → Nhap: tạo từ mẫu / agent phỏng vấn
  2. Nhap → DangReview: viết xong bản đầu
  3. DangReview → Nhap: cần sửa
  4. DangReview → DaDuyet: người dùng + chủ sở hữu đồng ý
  5. DaDuyet → DangLam: bắt đầu thực thi
  6. DangLam → DaDuyet: phát hiện điều chưa rõ, sửa spec, tăng phiên bản
  7. DangLam → DaTrienKhai: code khớp spec, kiểm chứng xong
  8. DaTrienKhai → DaDuyet: yêu cầu thay đổi mới
  9. DaTrienKhai → Kết thúc: lỗi thời / được thay thế

Năm thói quen giữ spec “sống” mà vẫn đáng tin:

  1. Lưu trong Git cùng code. Spec nằm ở docs/specs/, mỗi thay đổi là một commit. Bạn luôn biết spec nói gì ở thời điểm một dòng code được viết.
  2. Thay đổi hành vi bắt đầu từ spec. Hà muốn cho phép chữ trên bánh 50 ký tự? Sửa QT-01 trong spec, tăng phiên bản, ghi lịch sử — rồi mới bảo agent “cập nhật code theo spec phiên bản 1.2”.
  3. Khi code và spec mâu thuẫn, quyết định bên nào đúng. Đôi khi code đúng hơn (agent phát hiện trường hợp hợp lý) — khi đó cập nhật spec cho khớp. Không bao giờ để mâu thuẫn tồn tại.
  4. PR trỏ về spec. Mô tả mỗi pull request ghi “Hiện thực SPEC-001 v1.1, mục 3–6”. Người review đối chiếu được.
  5. Ghi trạng thái rõ ràng. Một spec “Đã triển khai” khác một spec “Nháp”; agent và người đọc cần biết mình đang cầm tài liệu nào.

Áp dụng vào dự án Bánh Mộc

Nhật ký công trình · Bánh Mộc

BM-261013-028

13.10.2026

  • Chị LanChủ chuỗi
  • HàBán hàng online

Chị Lan có sẵn nguyên liệu từ các bài trước: problem statement, sơ đồ as-is/to-be, MoSCoW, non-goals, 6 user story. Việc viết PRD gần như chỉ là ghép lại và cắt gọn; chị hoàn thành bản 1.0 trong một buổi tối, dài khoảng 2 trang.

Spec “Tạo đơn hàng” thì khác. Chị dùng Prompt 1 bên dưới với coding agent ở chế độ chỉ đọc. Agent đọc docs/PRD.md, docs/specs/user-stories.md và file mô tả mô hình dữ liệu, rồi hỏi 4 vòng, tổng cộng 17 câu. Vài câu chị chưa từng nghĩ tới:

  • “Nếu hai nhân viên ở hai chi nhánh tạo đơn cùng một giây, mã đơn có thể trùng không? Chị muốn xử lý thế nào?”
  • “Đơn tạo lúc 23:59 và nhận sau nửa đêm thì mã đơn theo ngày tạo hay ngày nhận?”
  • “Giá bánh kem tùy chỉnh có phụ thu trang trí không? Nếu có, ai được nhập?”
  • “Nếu khách đã tồn tại nhưng nhân viên gõ tên khác, có cập nhật tên khách không?”

Câu cuối khiến chị phải hỏi Hà, và cả hai thống nhất: không tự cập nhật tên khách khi tạo đơn (tránh ghi đè sai), việc sửa thông tin khách là tính năng riêng. Agent ghi điều này vào mục “Ngoài phạm vi”.

Sau khi có bản nháp, chị in ra, đọc cùng Hà. Hà phát hiện hai điều: khách hay gửi chữ kèm biểu tượng trái tim mà bếp không viết được (thành quy tắc cấm emoji), và Hà hay bấm nút hai lần khi mạng ở quầy chậm (thành QT-13). Spec lên phiên bản 1.1, trạng thái “Đã duyệt”.

Cuối cùng, chị mở phiên mới và dùng Prompt 2. Câu đầu tiên agent hỏi lại là “dự án đã có cấu hình Playwright chưa?” — một điều spec giả định nhưng không nói rõ. Chị bổ sung một dòng vào mục 12 và ghi lại bài học: phiên sạch là phép thử tốt nhất cho tính tự chứa của spec.

Prompt mẫu

Prompt 1 — Agent phỏng vấn rồi viết spec (phiên 1, chế độ chỉ đọc/lập kế hoạch)

Giao việc cho agent

Tôi muốn xây tính năng "Tạo đơn hàng" cho Mộc OMS.
Trước tiên hãy đọc: docs/PRD.md, docs/specs/user-stories.md (US-01, US-02, US-03), docs/specs/_template.md,
và schema trong src/db/. Chưa viết code, chưa sửa file nào ngoài file spec ở bước cuối.

Sau đó PHỎNG VẤN tôi để viết spec chi tiết:
- Hỏi theo từng nhóm 3–5 câu, chờ tôi trả lời rồi mới hỏi nhóm tiếp.
- Không hỏi những gì đã có trong tài liệu; nếu tài liệu mâu thuẫn, hỏi tôi chọn bên nào.
- Hỏi cả những điểm khó tôi có thể chưa nghĩ tới: đồng thời (nhiều người cùng thao tác), múi giờ và qua nửa đêm,
  phân quyền theo vai trò/chi nhánh, dữ liệu cũ không chuẩn, lỗi mạng và gửi trùng, giới hạn độ dài, tiền tệ.
- Với mỗi câu hỏi, nêu ngắn gọn vì sao nó quan trọng và đề xuất một lựa chọn mặc định hợp lý.

Khi tôi nói "đủ rồi", viết docs/specs/tao-don-hang.md theo đúng cấu trúc của _template.md:
- Nói rõ "cái gì" và "vì sao"; với "làm thế nào" chỉ nêu ràng buộc, file và interface liên quan.
- Có mục Ngoài phạm vi rõ ràng và mục Kiểm chứng end-to-end có lệnh và bằng chứng cần nộp.
- Điều chưa chắc đánh dấu [CẦN XÁC NHẬN] trong mục Câu hỏi mở, không tự quyết.

Prompt 2 — Thực thi spec ở phiên sạch (phiên 2)

Giao việc cho agent

Đọc docs/specs/tao-don-hang.md (SPEC-001, phiên bản 1.1, trạng thái Đã duyệt) và các file nó tham chiếu.
Ở chế độ lập kế hoạch, chưa sửa code:
1. Liệt kê những điểm trong spec bạn thấy chưa rõ hoặc mâu thuẫn với codebase hiện tại. Nếu có, dừng lại hỏi tôi.
2. Đề xuất kế hoạch kỹ thuật, đặc biệt cách đảm bảo QT-09 (mã đơn không trùng khi tạo đồng thời)
   và QT-13 (chống tạo trùng) — nêu 2 phương án và khuyến nghị.
3. Chia thành các task nhỏ, mỗi task kiểm chứng được độc lập, theo thứ tự: test trước, code sau.
Không làm bất cứ điều gì nằm trong mục "Ngoài phạm vi". Chờ tôi duyệt kế hoạch.

Prompt 3 — Cập nhật spec khi yêu cầu thay đổi

Giao việc cho agent

Yêu cầu thay đổi: cho phép chữ trên bánh tối đa 50 ký tự (thay vì 40) với bánh từ 24cm trở lên.
1. Cập nhật docs/specs/tao-don-hang.md: sửa QT-01, mục 10 (thông báo lỗi), mục 11 nếu cần;
   tăng phiên bản lên 1.2 và ghi một dòng vào Lịch sử thay đổi.
2. Liệt kê các file code và test sẽ phải đổi theo, nhưng CHƯA sửa code.
3. Kiểm tra xem các spec khác trong docs/specs/ có quy tắc liên quan cần cập nhật theo không (ví dụ màn hình bếp).

Sai lầm thường gặp

  1. Sự cố 01

    Viết spec như tiểu thuyết.

    Triệu chứng

    Dài, nhiều đoạn văn kể lể, quy tắc nằm lẫn trong câu chữ. *

    Cách tránh

    * dùng mẫu có mục cố định; quy tắc đánh mã, mỗi quy tắc một dòng kiểm tra được.

  2. Sự cố 02

    Spec không tự chứa.

    Triệu chứng

    “Như đã bàn hôm qua…”. *

    Cách tránh

    * kiểm tra bằng phiên agent mới; mọi điều cần biết phải nằm trong spec hoặc file được trỏ tới.

  3. Sự cố 03

    Thiếu “Ngoài phạm vi”.

    Triệu chứng

    Agent tiện tay làm thêm gửi email, trang quản trị. *

    Cách tránh

    * mục 4 bắt buộc, kèm câu “không tự thêm tính năng ngoài danh sách”.

  4. Sự cố 04

    Trộn “cái gì” với “làm thế nào” quá sớm.

    Triệu chứng

    Spec áp đặt cách cài đặt chi tiết, khóa chặt lựa chọn kỹ thuật chưa được cân nhắc. *

    Cách tránh

    * spec nêu ràng buộc và kết quả; cách làm để bước plan đề xuất, bạn duyệt.

  5. Sự cố 05

    Thực thi ngay trong phiên phỏng vấn.

    Triệu chứng

    Ngữ cảnh lẫn ý đã bỏ. *

    Cách tránh

    * luôn mở phiên sạch để thực thi spec đã duyệt.

  6. Sự cố 06

    Sửa code mà không sửa spec.

    Triệu chứng

    Sau vài tuần, spec thành tài liệu nói dối. *

    Cách tránh

    * quy ước “thay đổi hành vi bắt đầu từ spec”; PR phải trỏ tới phiên bản spec.

Checklist

Phiếu nghiệm thu

Bài tập thực hành

  1. Bài 1

    Cơ bản

    PRD 2 trang

    Viết PRD cho sản phẩm của bạn theo mẫu, tận dụng problem statement, MoSCoW, non-goals từ các bài trước.

    Kết quả mong đợi

    không quá 3 trang; một người ngoài đọc 10 phút trả lời đúng ba câu: giải vấn đề gì, cái gì ngoài phạm vi, thành công đo thế nào.

  2. Bài 2

    Nâng cao

    Agent phỏng vấn

    Dùng Prompt 1 cho một tính năng thật của bạn. Ghi lại các câu hỏi agent đặt ra mà bạn chưa từng nghĩ tới.

    Kết quả mong đợi

    một spec theo mẫu, ít nhất 3 câu hỏi “khó” được trả lời và phản ánh vào quy tắc, ít nhất 1 mục [CẦN XÁC NHẬN] mà bạn phải đi hỏi người làm thật.

  3. Bài 3

    Nâng cao

    Phép thử phiên sạch

    Mở một phiên agent mới, chỉ đưa spec ở bài 2 và yêu cầu: “Liệt kê mọi điều bạn cần hỏi trước khi có thể lập kế hoạch.”

    Kết quả mong đợi

    danh sách câu hỏi; bổ sung vào spec cho tới khi phiên mới gần như không cần hỏi thêm điều gì quan trọng. Tăng phiên bản và ghi lịch sử thay đổi.

Thuật ngữ trong bài

PRD (Product Requirements Document)
Tài liệu yêu cầu sản phẩm tổng thể: vấn đề, mục tiêu, người dùng, phạm vi.
Spec tính năng
Đặc tả chi tiết, tự chứa cho một tính năng.
Tự chứa (self-contained)
Đọc riêng tài liệu là đủ hiểu, không cần lịch sử trò chuyện.
Spec-driven development
Cách làm lấy spec làm nguồn sự thật: Specify → Plan → Tasks → Implement.
Server action
Hàm chạy phía máy chủ được gọi trực tiếp từ giao diện trong Next.js.
Schema Zod
Mô tả cấu trúc và ràng buộc dữ liệu để kiểm tra đầu vào.
Idempotency (bất biến khi lặp)
Gửi cùng một yêu cầu nhiều lần chỉ tạo ra một kết quả.
Phiên sạch
Phiên agent mới, không mang ngữ cảnh cũ.
Tài liệu sống
Tài liệu được cập nhật liên tục, có phiên bản và lịch sử thay đổi.

Đọc thêm

Nghiệm thu tờ 03-06

Đọc xong và tự kiểm theo phiếu nghiệm thu, rồi đánh dấu tờ này.

Tác giả
Phú Digital
Đội ngũ PDL Digital — triển khai website, giải pháp AI và digital marketing cho doanh nghiệp.
Tư vấn 1:1

Muốn dựng phần mềm riêng cho doanh nghiệp của bạn?

Kỹ sư PDL cùng bạn chọn bước đầu tiên phù hợp — phản hồi trong giờ làm việc (T2–T7, 8h–18h).

<script src="https://cdn.jsdelivr.net/npm/page-flip/dist/js/page-flip.browser.js"></script>

<div id="container-flipbook" style="display:flex; justify-content:center;">
    <div id="my-flipbook">
       <div class="page"> <img src="https://pdl.vn/wp-content/uploads/2025/05/AI-Google-Search.jpg" /> </div>
       <div class="page"> <img src="https://pdl.vn/wp-content/uploads/2025/05/wearable-tech-advertising.jpg" /> </div>
       <div class="page"> <img src="https://pdl.vn/wp-content/uploads/2025/05/multimodal-embeddings-digital-marketing.jpg" /> </div>
    </div>
</div>
#my-flipbook {
    box-shadow: 0 0 20px rgba(0,0,0,0.2);
    margin: 20px auto;
    background-color: #f0f0f0;
}

.page {
    background-color: white;
    overflow: hidden;
}

.page img {
    width: 100%;
    height: 100%;
    object-fit: cover; /* Giúp ảnh vừa vặn trang sách */
}
// Đảm bảo thư viện đã sẵn sàng
function initFlipbook() {
    const el = document.getElementById("my-flipbook");
    if (!el || !window.St) return; // Nếu chưa thấy thư viện St thì thoát

    const pageFlip = new St.PageFlip(el, {
        width: 550,
        height: 733,
        size: "stretch",
        minWidth: 315,
        maxWidth: 1000,
        minHeight: 420,
        maxHeight: 1350,
        showCover: true,
        maxShadowOpacity: 0.5,
    });

    pageFlip.loadFromHTML(document.querySelectorAll(".page"));
}

// Chạy khởi tạo
if (document.readyState === 'complete') {
    initFlipbook();
} else {
    window.addEventListener('load', initFlipbook);
}
PDL · Tư vấn 1:1

Nhận tư vấn
miễn phí

Để lại thông tin, chuyên viên PDL sẽ liên hệ để hiểu nhu cầu và đề xuất giải pháp phù hợp ngân sách của bạn.

  • Phân tích nhanh hiện trạng website, quảng cáo, kênh bán hàng
  • Đề xuất lộ trình & báo giá minh bạch, rõ từng hạng mục
  • Không ràng buộc: nghe tư vấn xong mới quyết định
Giờ làm việc T2–T7 · 08:00–18:00

Chỉ mất khoảng 30 giây

Bạn cần tư vấn về

🔒 Thông tin được bảo mật, chỉ dùng để PDL liên hệ tư vấn.