PRD: Tùy chọn sản phẩm & biến thể
| Module | Sản phẩm | PRD ID | PRD-OPT-001 |
| Trạng thái | Sẵn sàng dev | FEAT | OPT |
| Epic | — | Plane | BANA-1553 |
| Ngày | 2026-06-12 | Phiên bản | v1.0 |
| Gói | @nx/commerce · @nx/core | URD | OPT |
| Surface | Client · Chủ/QLSale · POS | ||
| Phụ trách | Phát Nguyễn | ||
Tùy chọn sản phẩm & biến thể là gì
Biến thể (Variant) cho biết một sản phẩm có nhiều dạng bán được, nhưng không nói vì sao chúng khác nhau. Chỉ với tên dạng chữ tự do, không gì chặn hai biến thể trùng nhau, POS không phân biệt được size với mức đá, và không có khóa ổn định nào để đối chiếu với listing bên ngoài.
PRD này biến tùy chọn (Option), giá trị tùy chọn (Option value) và tổ hợp (Combination) của từng biến thể thành thông tin tường minh - do Owner khai báo, hệ thống giữ nhất quán. Owner mô tả một sản phẩm biến đổi ra sao - các tùy chọn như size, mức đá, màu sắc, mỗi tùy chọn có danh sách giá trị riêng - và mỗi biến thể bán được chọn một giá trị cho mỗi tùy chọn.
Hai luật giữ mọi thứ chặt chẽ
| Luật | Nghĩa là |
|---|---|
| Giá trị phải thuộc về sản phẩm | Một biến thể không dùng được giá trị của tùy chọn thuộc sản phẩm khác |
| Không hai biến thể nào trùng tổ hợp | Cùng một tập giá trị đã chọn thì chỉ có một biến thể mang tổ hợp đó trong sản phẩm |
Nhờ hai luật này, POS, kênh online và báo cáo đều coi tổ hợp là danh tính của biến thể - lấy tổ hợp ra là biết chính xác biến thể nào.
Một sản phẩm, từ khai tùy chọn tới chọn món
Owner dựng món trà sữa với size (S/M/L) và mức đá (100/50/0), rồi khai báo năm tổ hợp thực bán. Thu ngân sau đó chọn biến thể bằng cách bấm size rồi mức đá - không lục một danh sách dài.
Thêm biến thể "Lớn, 50%" thứ hai sẽ bị từ chối vì tổ hợp đã tồn tại; chọn hai size cho một biến thể cũng bị từ chối vì một biến thể chỉ chọn tối đa một giá trị mỗi tùy chọn.
Chỗ dễ sai nhất
Hệ thống không tự sinh mọi tổ hợp giúp Owner
Phần lớn merchant không bán hết ma trận. Owner chỉ khai báo những tổ hợp mình thực bán; hệ thống không tự bung Size × Mức đá thành mọi khả năng rồi bắt Owner xóa bớt. Khai báo chỉ đúng những gì thực bán giữ danh mục đúng bằng những gì bán được - không có biến thể ma phải ẩn, định giá hay theo dõi tồn.
1. Mục tiêu & Loại trừ
Mục tiêu
- Mỗi sản phẩm có tùy chọn riêng, mỗi tùy chọn là danh sách giá trị sắp thứ tự, hiển thị theo thứ tự chủ chọn.
- Mỗi biến thể chọn một giá trị cho mỗi tùy chọn nó dùng.
- Hệ thống bảo đảm mọi tổ hợp đều hợp lệ và duy nhất trong phạm vi sản phẩm.
- Một cài đặt merchant quyết định mọi biến thể có bắt buộc dùng tùy chọn hay được phép không có tùy chọn.
Loại trừ
- Không tự sinh toàn bộ ma trận - chủ chỉ khai báo những biến thể thực sự bán.
- Không gắn giá hay tồn kho vào giá trị - giá nằm ở fare (FAR), tồn kho nằm ở Kho.
2. Thước đo thành công
| Chỉ số | Mục tiêu |
|---|---|
| Tổ hợp trùng | Bằng không - tổ hợp lặp lại luôn bị từ chối |
| Tổ hợp không hợp lệ | Bằng không - giá trị không thuộc sản phẩm không bao giờ được nhận |
| Thực thi bắt buộc tùy chọn | Khi cài đặt bật, không thể tạo biến thể không tùy chọn |
3. Persona & Tình huống
| Persona | Mục tiêu |
|---|---|
| Owner / Quản lý | Định nghĩa sản phẩm biến đổi ra sao và các lựa chọn cung cấp, theo thứ tự hiển thị |
| Thu ngân | Chọn biến thể bằng cách bấm size rồi mức đá - không lục một danh sách dài |
| Tích hợp kênh bán | Khớp listing bên ngoài về đúng biến thể qua tổ hợp của nó |
Tình huống lõi: Owner dựng món trà sữa với size (S/M/L) và mức đá (100/50/0), rồi khai báo năm tổ hợp thực bán. Thêm biến thể "Lớn, 50%" thứ hai sẽ bị từ chối; chọn hai size cho một biến thể cũng vậy.
4. User Stories
| # | Là một | Tôi muốn | Để |
|---|---|---|---|
| 01 | Owner | định nghĩa tùy chọn và giá trị của sản phẩm một lần | mọi biến thể chỉ việc chọn từ đó |
| 02 | Owner | tổ hợp đã có bị từ chối | danh mục không bao giờ có hai mục cho cùng một thứ |
| 03 | Owner | quyết định biến thể không tùy chọn có được phép hay không | sản phẩm đơn giản vẫn đơn giản còn menu phức tạp vẫn kỷ luật |
| 04 | thu ngân | thấy biến thể gom theo tùy chọn | đặt món chỉ vài lần bấm |
5. Yêu cầu chức năng
| # | Yêu cầu | Trạng thái | URD ref |
|---|---|---|---|
FR-001 | Chủ định nghĩa các tùy chọn của sản phẩm. Mỗi tùy chọn hiển thị theo thứ tự đã chọn. | ✅ | URD-OPT-001 |
FR-002 | Mỗi tùy chọn mang một danh sách giá trị được sắp thứ tự. | ✅ | URD-OPT-002 |
FR-003 | Một tùy chọn và các giá trị của nó được tạo hoặc đổi cùng nhau trong một bước. | ✅ | URD-OPT-003 |
FR-004 | Biến thể khai báo giá trị trên mỗi tùy chọn nó dùng. Tùy chọn hoặc giá trị lạ bị từ chối. | ✅ | URD-OPT-004 |
FR-005 | Một biến thể chọn tối đa một giá trị mỗi tùy chọn. | ✅ | URD-OPT-005 |
FR-006 | Mọi giá trị một biến thể dùng phải thuộc về sản phẩm và về tùy chọn của nó. | ✅ | URD-OPT-006 |
FR-007 | Không hai biến thể nào của một sản phẩm trùng tổ hợp. Biến thể không tùy chọn được miễn. | ✅ | URD-OPT-007 |
FR-008 | Một cài đặt merchant có thể buộc mọi biến thể dùng tùy chọn. Biến thể không tùy chọn bị từ chối. | 🔶 | URD-OPT-008 |
FR-009 | Chủ có thể đổi các tùy chọn mà một biến thể dùng. | ✅ | URD-OPT-009 |
FR-010 | Một tùy chọn không có giá trị bị từ chối. Một lựa chọn trùng bị từ chối. | 🔶 | URD-OPT-010 |
5.1 Tiêu chí nghiệm thu
- Định nghĩa một tùy chọn mới cho sản phẩm cùng danh sách giá trị của nó trong một lần gọi → tùy chọn và toàn bộ giá trị được lưu cùng nhau, hiển thị đúng thứ tự đã khai báo.
- Sửa một tùy chọn đã có, thêm một giá trị mới và xóa một giá trị cũ trong cùng một lần gọi → cả hai thay đổi lên hiệu lực cùng lúc.
- Khai báo một biến thể chọn một giá trị cho mỗi tùy chọn nó dùng → biến thể được lưu, gắn đúng những giá trị đã chọn.
- Khai báo một biến thể dùng một tùy chọn hoặc một giá trị không thuộc sản phẩm → bị từ chối.
- Khai báo hai giá trị cho cùng một tùy chọn trên một biến thể → bị từ chối.
- Khai báo một biến thể thứ hai với đúng tổ hợp giá trị của một biến thể đã có → bị từ chối; đổi một giá trị bất kỳ trong tổ hợp thì được chấp nhận.
- Bật cài đặt bắt buộc dùng tùy chọn, rồi tạo một sản phẩm mới với một biến thể không chọn tùy chọn nào → bị từ chối. Cùng cài đặt đang bật, nhưng thêm một biến thể không tùy chọn vào một sản phẩm đã tồn tại - qua màn sửa sản phẩm hoặc qua tạo biến thể riêng - thì hiện vẫn được chấp nhận, cài đặt chưa được áp dụng ở hai đường này.
- Sửa một biến thể đã có để đổi sang một tùy chọn khác → tổ hợp mới được kiểm tra thuộc sản phẩm và không trùng biến thể nào khác, rồi mới lưu.
- Tạo một tùy chọn mới cho sản phẩm nhưng không kèm giá trị nào, hoặc tạo hai giá trị trùng tên trong cùng một tùy chọn, ngay trong lúc tạo sản phẩm → bị từ chối. Cùng thao tác đó nhưng tạo tùy chọn qua màn quản lý tùy chọn riêng (không qua tạo sản phẩm) → tùy chọn không giá trị hiện vẫn được tạo, giá trị trùng tên vẫn bị chặn.
6. Yêu cầu phi chức năng
| Khía cạnh | Yêu cầu |
|---|---|
| Trọn gói | Một tùy chọn và giá trị của một biến thể được lưu thành một khối: hoặc lưu hết, hoặc không lưu gì |
| Tách biệt theo merchant | Tùy chọn thuộc về một sản phẩm dưới một merchant; không bao giờ dùng chung giữa các sản phẩm hay merchant |
| Đa ngôn ngữ | Tên tùy chọn và giá trị hiển thị nhiều ngôn ngữ |
| Không phụ thuộc thứ tự | Một tổ hợp là như nhau bất kể thứ tự liệt kê giá trị |
7. UX & Luồng
8. Dữ liệu & Miền nghiệp vụ
| Khái niệm | Vai trò |
|---|---|
| Tùy chọn (Option) | Một cách một sản phẩm biến đổi (size, mức đá), với danh sách giá trị sắp thứ tự |
| Giá trị tùy chọn (Option value) | Một lựa chọn trên một tùy chọn (S / M / L) |
| Tổ hợp (Combination) | Tập giá trị một biến thể chọn - danh tính của nó trong sản phẩm |
Key của một tùy chọn là duy nhất trong sản phẩm (ràng buộc duy nhất áp trên key, không phải tên hiển thị); một giá trị duy nhất trong tùy chọn của nó; một tổ hợp duy nhất giữa các biến thể của sản phẩm.
9. Phụ thuộc & Giả định
Phụ thuộc vào
| # | Feature | Phụ thuộc điều gì |
|---|---|---|
| 01 | Biến thể (PRD-PRD-001) | tùy chọn gắn vào biến thể, không thay thế biến thể. |
Giả định
| # | Giả định | Sai thì sao |
|---|---|---|
| 01 | Cài đặt bắt buộc tùy chọn được đọc khi một biến thể được lưu; bật về sau không kiểm tra lại các biến thể đã có. | Nếu hệ thống hồi tố kiểm tra toàn bộ biến thể cũ mỗi khi cài đặt đổi, một merchant từng cho phép biến thể không tùy chọn sẽ đột ngột có biến thể "vi phạm" dù không ai sửa gì - bật cài đặt bắt buộc chỉ chặn thay đổi MỚI, không động tới dữ liệu cũ. |
10. Kế hoạch phát hành & Tiêu chí
| Khía cạnh | Kế hoạch |
|---|---|
| Phase | P1 - xem feature catalog của URD |
| Rollout | Phát hành cùng năng lực biến thể; toàn bộ merchant, không feature flag |
| Migration | Không - tùy chọn và tổ hợp là logic validate trên đường tạo/sửa biến thể hiện có, không có dữ liệu cũ cần chuyển đổi |
| Tiêu chí phát hành | Tổ hợp không hợp lệ và trùng bị từ chối kèm lý do rõ ràng; tính duy nhất giữ vững kể cả khi biến thể được tạo cùng lúc; POS hiển thị tùy chọn theo thứ tự của Owner |
| Theo dõi | Tỷ lệ tổ hợp trùng hoặc không hợp lệ bị từ chối khi tạo biến thể |
Tham khảo
- URD: OPT - Tùy chọn Sản phẩm · VAR - Biến thể
- PRD anh em: Danh mục sản phẩm, biến thể & định danh · Hệ thống Fare & Định giá
- Developer: @nx/commerce
Rủi ro & Câu hỏi mở
| # | Rủi ro / câu hỏi | Giảm thiểu / trạng thái |
|---|---|---|
| 01 | Xóa một giá trị còn được một biến thể dùng có thể phá vỡ biến thể đang tồn tại | Tuân theo chính sách xóa của merchant, không xóa tự do |
| 02 | Bật cài đặt bắt buộc tùy chọn không hồi tố các biến thể không tùy chọn đã có, có thể gây hiểu nhầm là cài đặt chưa hoạt động | Chỉ thay đổi mới bị kiểm tra - biến thể cũ giữ nguyên, đây là hành vi có chủ đích |
Câu hỏi thường gặp
| # | Câu hỏi | Trả lời |
|---|---|---|
| 01 | Vì sao không tự sinh mọi tổ hợp giúp tôi? | Phần lớn merchant không bán hết ma trận. Chỉ khai báo những gì thực bán giữ danh mục đúng bằng những gì bán được - không có biến thể ma phải ẩn, định giá hay theo dõi tồn. |
| 02 | Hai sản phẩm có dùng chung tùy chọn được không? | Không - tùy chọn thuộc về một sản phẩm. Template dùng chung có thể đến sau nếu việc trùng lặp trở nên phiền. |
| 03 | Giá phụ thuộc tùy chọn đặt ở đâu? | Trên fare của biến thể. Tổ hợp định danh biến thể; fare định giá nó. |