PRD: Tùy chọn sản phẩm & sinh biến thể
| Module | Sản phẩm | PRD ID | PRD-OPT-002 |
| Trạng thái | Sẵn sàng dev | FEAT | OPT |
| Epic | — | Plane | BANA-1555 |
| Ngày | 2026-06-15 | Phiên bản | v1.0 |
| Gói | @nx/commerce · @nx/core | URD | OPT |
| Surface | Client · Chủ/QL | ||
| Phụ trách | Phát Nguyễn | ||
Tùy chọn sản phẩm & sinh biến thể là gì
Mô hình liên kết tùy chọn định nghĩa tổ hợp của một biến thể là gì và giữ cho nó hợp lệ, duy nhất - nhưng không định nghĩa cách một sản phẩm cùng toàn bộ tập biến thể mang tùy chọn ra đời chỉ trong một thao tác của chủ.
PRD này biến các trục tùy chọn của sản phẩm thành đúng những biến thể (Variant) merchant thực bán - chỉ trong một thao tác tạo liền mạch. Chủ khai báo các trục (size, mức đá, màu) và nêu rõ từng biến thể cần sinh cùng lựa chọn trên mỗi trục; hệ thống dựng đồng thời mọi tùy chọn, giá trị, biến thể, liên kết, định danh và thuộc tính kho, chốt một biến thể mặc định, rồi đưa mỗi biến thể vào tìm kiếm để tra theo tùy chọn.
Vì sao cần một đường sinh riêng
Thiếu đường sinh, chủ phải dựng danh mục từng mảnh: tạo sản phẩm trống, thêm từng biến thể, gắn tùy chọn từng cái một. Mỗi lượt qua lại là một dịp để danh mục dở dang - có trục mà không biến thể, biến thể không mặc định, hay barcode trùng mãi đến lần thử thứ ba mới lộ.
| Đặc điểm | Nghĩa là |
|---|---|
| Tường minh | Chỉ những biến thể đã khai báo mới tồn tại, không bao giờ bung trọn ma trận Descartes |
| Liền mạch | Tùy chọn, giá trị, biến thể, liên kết, định danh, thuộc tính kho và một mặc định là một khối - hoặc lưu hết, hoặc không lưu gì |
| Mặc định | Biến thể chủ đánh dấu, hoặc biến thể khai báo đầu tiên nếu không đánh dấu |
Một sản phẩm, từ khai trục tới sẵn sàng bán
Chủ tạo một món trà sữa với trục Size (S/M/L) và Đá (100/50/0), khai báo năm biến thể thực bán, đánh dấu "M, 100% đá" làm mặc định. Chỉ trong một thao tác liền mạch, hệ thống dựng các trục, giá trị, năm biến thể, liên kết, định danh và thuộc tính kho; biến thể được đánh dấu trở thành mặc định; mỗi biến thể tra được ngay trong tìm kiếm theo size và mức đá.
Khai báo hai mặc định, hay hai biến thể trùng barcode, đều bị từ chối trước khi lưu.
Chỗ dễ sai nhất
Màn hình gợi ý ma trận không phải hệ thống lưu ma trận
Màn Sinh biến thể tại trang Client vẫn gợi ý sẵn đủ tổ hợp trục để chủ dễ bớt/thêm trước khi lưu - đó là tiện ích trên màn hình để chủ thao tác nhanh hơn, không phải hệ thống tự lưu cả ma trận xuống. Chỉ những biến thể chủ giữ lại trong lần lưu mới thực sự được tạo; phần bị xóa trên màn hình không bao giờ chạm tới hệ thống.
1. Mục tiêu & Loại trừ
Mục tiêu
- Một thao tác tạo liền mạch nhận trục tùy chọn + biến thể đã khai báo và dựng trọn sản phẩm.
- Chỉ sinh tường minh - đúng những biến thể đã khai báo, không bao giờ là cả ma trận tùy chọn.
- Luôn chốt đúng một mặc định - biến thể được đánh dấu, nếu không thì biến thể khai báo đầu tiên.
- Mang SKU hoặc barcode riêng của từng biến thể, duy nhất trong một yêu cầu và trong một merchant.
- Sinh thuộc tính kho chỉ cho các loại biến thể quản lý tồn; loại không quản lý tồn và combo được tạo ở trạng thái không theo dõi.
- Đưa lựa chọn của mỗi biến thể vào tìm kiếm, luôn cập nhật khi trục, giá trị hay liên kết thay đổi.
Loại trừ
- Tự bung trọn ma trận Descartes ở phía hệ thống - một không-mục-tiêu cố ý trong PRD-OPT-001; chủ chỉ khai báo thứ họ bán. (Màn Sinh biến thể tại trang Client vẫn gợi ý sẵn đủ tổ hợp trục để chủ dễ bớt/thêm trước khi lưu - đó là tiện ích trên màn hình, không phải hệ thống tự lưu cả ma trận xuống.)
- Bản thân các quy tắc của mô hình liên kết (hợp lệ, một-mỗi-trục, tổ hợp duy nhất, bắt buộc tùy chọn) - xem PRD-OPT-001.
- Định giá và mức tồn - giá nằm ở fares (FAR), tồn nằm ở Kho.
- Nhập danh mục hàng loạt / bảng tính (URD-PRD-016) - một đợt riêng.
2. Thước đo thành công
| Chỉ số | Mục tiêu / tín hiệu |
|---|---|
| Tính liền mạch | Bất kỳ bước con nào thất bại (tùy chọn sai, barcode trùng, hai mặc định) đều không để lại gì được lưu |
| Không biến thể ảo | Số biến thể đúng bằng số đã khai báo - không bao giờ bằng kích thước ma trận |
| Toàn vẹn mặc định | Mỗi sản phẩm sinh ra có đúng một mặc định |
| Toàn vẹn barcode | Không hai biến thể nào chung barcode trong một merchant; trùng trong cùng yêu cầu bị từ chối |
| Khả năng tìm | Mỗi biến thể sinh ra đều tra và lọc được theo từng giá trị tùy chọn |
3. Persona & Tình huống
| Persona | Mục tiêu trong tính năng này |
|---|---|
| Chủ / Quản lý | Tạo một sản phẩm cùng mọi biến thể thật của nó trong một bước, tự chọn mặc định |
| Thu ngân | Tra và chọn biến thể theo tùy chọn ngay tại điểm bán |
| Tích hợp kênh | Tìm đúng biến thể bằng cách lọc theo tùy chọn trong tìm kiếm |
Tình huống chính: chủ tạo một món trà sữa với trục Size (S/M/L) và Đá (100/50/0), khai báo năm biến thể thực bán, đánh dấu "M, 100% đá" làm mặc định. Chỉ trong một thao tác liền mạch, hệ thống dựng các trục, giá trị, năm biến thể, liên kết, định danh và thuộc tính kho; biến thể được đánh dấu trở thành mặc định; mỗi biến thể tra được ngay trong tìm kiếm theo size và mức đá. Khai báo hai mặc định, hay hai biến thể trùng barcode, đều bị từ chối trước khi lưu.
4. User Stories
| # | Là một | Tôi muốn | Để |
|---|---|---|---|
| 01 | chủ | khai báo các trục của sản phẩm cùng đúng những biến thể tôi bán trong một yêu cầu | danh mục hoàn chỉnh ngay khi tạo |
| 02 | chủ | chỉ những biến thể tôi nêu mới tồn tại | khỏi phải xóa các tổ hợp không bán |
| 03 | chủ | đánh dấu một biến thể làm mặc định (hoặc để cái đầu tiên giữ vai đó) | POS luôn có lựa chọn hợp lý |
| 04 | chủ | barcode trùng bị bắt trước khi lưu | không bao giờ xuất ra một mã đụng độ |
| 05 | chủ | đổi mặc định về sau mà khỏi dựng lại sản phẩm | thực đơn có thể thay đổi |
| 06 | thu ngân | tìm một biến thể theo size và mức đá | gọi món chỉ trong vài chạm |
5. Yêu cầu chức năng
| # | Yêu cầu | Trạng thái | URD ref |
|---|---|---|---|
FR-001 | Tạo nhận cả các trục tùy chọn lẫn đúng những biến thể cần sinh. Mỗi biến thể nêu lựa chọn trên từng trục. | ✅ | URD-OPT-011 |
FR-002 | Chỉ sinh những biến thể đã khai báo - không tự bung cả ma trận. | ✅ | URD-OPT-012 |
FR-003 | Trục, giá trị và mọi biến thể đã khai báo được sinh cùng sản phẩm trong một thao tác liền mạch. | ✅ | URD-OPT-013 |
FR-004 | Đúng một mặc định được xác định cho mỗi lần tạo. • Biến thể được đánh dấu tường minh sẽ là mặc định. • Nếu không đánh dấu cái nào, biến thể khai báo đầu tiên được nâng lên làm mặc định. | 🔶 | URD-OPT-014 |
FR-005 | Có nhiều hơn một mặc định tường minh trong cùng yêu cầu sẽ bị từ chối. | 🔶 | URD-OPT-015 |
FR-006 | Mặc định có thể đổi sau khi tạo qua một thao tác nâng chuyên biệt. | 🔶 | URD-OPT-016 |
FR-007 | Mỗi biến thể có thể mang SKU hoặc barcode riêng. • Một mã trùng trong cùng yêu cầu sẽ bị từ chối. • Một mã đã dùng trong merchant cũng bị từ chối. | 🔶 | URD-OPT-017 · URD-PID-001 |
FR-008 | Thuộc tính kho chỉ sinh cho loại biến thể quản lý tồn. Combo và loại không quản lý tồn giữ trạng thái không theo dõi. | ✅ | URD-OPT-018 · URD-VAR-006 |
FR-009 | Biến thể sinh ra và lựa chọn tùy chọn của chúng được đưa vào tìm kiếm. Luôn cập nhật khi trục, giá trị hay liên kết thay đổi. | ✅ | URD-OPT-019 |
FR-010 | Trục và giá trị tùy chọn được chuẩn hóa (không phân biệt hoa thường) trên đường chỉnh sửa tùy chọn/giá trị độc lập để các lựa chọn tương đương gộp về một. | 🔶 | URD-OPT-020 |
5.1 Tiêu chí nghiệm thu
- Khai báo trục Size (S/M/L) và Đá (100/50/0) cùng năm biến thể cụ thể khi tạo sản phẩm → đúng năm biến thể đó được lưu, không phải chín tổ hợp đầy đủ của hai trục.
- Trong cùng một yêu cầu tạo, một biến thể khai báo tùy chọn hoặc giá trị không thuộc trục đã khai báo → toàn bộ yêu cầu bị từ chối, không lưu gì.
- Tạo sản phẩm với trục, giá trị và các biến thể khai báo → mọi thứ được lưu cùng lúc; bất kỳ bước con nào lỗi (tùy chọn sai, mã trùng, hai mặc định) thì không dòng nào được lưu.
- Đánh dấu một biến thể là mặc định khi khai báo → biến thể đó được lưu là mặc định; không đánh dấu cái nào → biến thể khai báo đầu tiên tự thành mặc định.
- Đánh dấu hai biến thể cùng là mặc định trong một yêu cầu tạo → bị từ chối trước khi lưu bất cứ gì.
- Sau khi tạo, nâng một biến thể khác lên làm mặc định → biến thể đó thành mặc định, biến thể cũ tự thôi mặc định.
- Khai báo hai biến thể cùng một mã SKU hoặc barcode trong một yêu cầu tạo → bị từ chối; khai báo một mã đã dùng bởi biến thể khác trong cùng merchant → cũng bị từ chối.
- Sinh biến thể cho loại quản lý tồn → thuộc tính kho được tạo cho từng biến thể; sinh biến thể combo hoặc loại không quản lý tồn → biến thể được tạo ở trạng thái không theo dõi.
- Tìm kiếm theo một giá trị tùy chọn của biến thể vừa sinh (ví dụ size=M) → biến thể được trả về và lọc đúng; đổi trục, giá trị hay liên kết sau đó → facet tùy chọn trong tìm kiếm được làm mới theo.
- Ở màn quản lý tùy chọn độc lập, gõ một giá trị khác hoa/thường với giá trị đã có trên cùng trục → hai giá trị tương đương gộp về một, không tạo bản trùng.
6. Yêu cầu phi chức năng
| Lĩnh vực | Yêu cầu |
|---|---|
| Tính liền mạch | Toàn bộ sản phẩm - tùy chọn, giá trị, biến thể, liên kết, định danh, thuộc tính kho, mặc định - là một thao tác toàn-vẹn-hoặc-không |
| Tenancy & truy cập | Mọi thao tác chỉ trong merchant của người dùng và bị chặn bởi quyền sản phẩm |
| Chuẩn hóa | Khóa và giá trị tùy chọn được chuẩn hóa (không phân biệt hoa thường) trên đường chỉnh sửa tùy chọn/giá trị độc lập; đường tạo gộp (generation) hiện chưa chuẩn hóa (lưu nguyên văn) |
| Toàn vẹn định danh | Barcode được kiểm trùng trong cùng yêu cầu và đụng độ với merchant hiện có trước khi lưu |
| Nhất quán tìm kiếm cuối cùng | Dữ liệu tùy chọn tra được làm mới ở chế độ nền sau khi thao tác tạo hoàn tất, không nằm trong đường tới hạn của nó |
| Ngôn ngữ | Tên trục đa ngôn ngữ (tiếng Anh và tiếng Việt); tên hiển thị của một giá trị lùi về giá trị thô khi chưa đặt |
7. UX & Luồng
Bề mặt tạo cho phép chủ định nghĩa các trục và giá trị có thứ tự của chúng, thêm từng biến thể họ bán với lựa chọn trên mỗi trục và một barcode tùy chọn, và đánh dấu một cái là mặc định. Biến thể được sinh sau đó xuất hiện trong tìm kiếm sản phẩm và lọc được theo tùy chọn của chúng.
8. Dữ liệu & Miền nghiệp vụ
| Khái niệm | Vai trò trong việc sinh |
|---|---|
| Tùy chọn (Option) | Một trục tùy chọn sản phẩm biến đổi theo, sinh từ một trục đã khai báo (tên, khóa, thứ tự) |
| Giá trị tùy chọn (Option value) | Một lựa chọn có thứ tự trên một trục, sinh từ các giá trị đã khai báo của trục |
| Biến thể (Variant) | Một đơn vị bán được sinh ra; đúng một cái mỗi sản phẩm là mặc định |
| Liên kết biến thể (Variant binding) | Một liên kết của một biến thể tới một cặp (trục, giá trị) - tập liên kết của biến thể là tổ hợp của nó |
Chỉ là khái niệm - chi tiết và bất biến đầy đủ nằm trong mô hình miền commerce. Liên kết là tham chiếu mềm; toàn vẹn được thực thi trong logic sinh, không bởi ràng buộc cơ sở dữ liệu.
9. Phụ thuộc & Giả định
Phụ thuộc vào
| # | Feature | Phụ thuộc điều gì |
|---|---|---|
| 01 | Mô hình liên kết tùy chọn (PRD-OPT-001, URD-OPT-001..010) | việc sinh tạo ra các liên kết mà mô hình này kiểm. |
| 02 | Biến thể & tạo trọn-gói (VAR, PRD-PRD-001) | biến thể và giá / định danh của chúng được tạo qua thao tác tạo biến thể. |
| 03 | Định danh (PID) | mã hệ thống / slug tự sinh; SKU / barcode riêng theo từng biến thể. |
| 04 | Kho (Kho) | biến thể quản lý tồn sinh ra mục kho ở hạ nguồn. |
| 05 | Tìm kiếm | làm cho tùy chọn và facet của mỗi biến thể tra được để tra cứu. |
Giả định
| # | Giả định | Sai thì sao |
|---|---|---|
| 01 | Chủ khai báo những biến thể họ thực sự bán; hệ thống không suy ra toàn bộ ma trận. | Nếu hệ thống tự suy ra ma trận đầy đủ, mỗi trục thêm sẽ nhân số biến thể lên theo cấp số nhân - sản phẩm có 3 trục 4 giá trị sẽ ra 64 biến thể dù chủ chỉ bán vài kiểu, phải xóa tay phần còn lại thay vì chỉ khai đúng những gì bán. |
| 02 | Cài đặt bắt buộc tùy chọn của merchant (từ PRD-OPT-001) được đọc khi sinh và quyết định liệu biến thể không tùy chọn có được phép. | Nếu đường sinh bỏ qua cài đặt này, một merchant đã bật bắt buộc tùy chọn vẫn có thể sinh ra biến thể không tùy chọn qua đường tạo sản phẩm, phá vỡ chính sách họ đã chọn. |
10. Kế hoạch phát hành & Tiêu chí
| Khía cạnh | Kế hoạch |
|---|---|
| Phase | P2 - OPT trong danh mục feature URD, cùng VAR |
| Triển khai | Mọi merchant; không feature flag |
| Migration | Không - việc sinh chạy trên đường tạo sản phẩm hiện hữu |
| Tiêu chí ra mắt | Tạo sinh đúng những biến thể đã khai báo một cách liền mạch; luôn giải quyết một mặc định; hai mặc định và barcode trùng bị từ chối; thuộc tính kho chỉ xuất hiện cho loại quản lý tồn; biến thể được sinh lọc được theo facet tùy chọn trong tìm kiếm |
| Giám sát | Tỉ lệ lỗi tạo theo lý do (trùng mặc định, đụng độ barcode), độ trễ làm mới facet tìm kiếm |
Tham chiếu
- URD: Sản phẩm - OPT · VAR · PID
- PRD anh em: Tùy chọn sản phẩm & liên kết biến thể · Danh mục sản phẩm, biến thể & định danh · Hệ thống Fare & Định giá
- Module: Sản phẩm - URD
- Lập trình viên: @nx/commerce · @nx/core · @nx/search
Rủi ro & Câu hỏi mở
| # | Rủi ro / câu hỏi | Giảm thiểu / trạng thái |
|---|---|---|
| 01 | Sản phẩm dở dang khi lỗi (có trục nhưng không biến thể, không mặc định) | Toàn bộ sản phẩm là một thao tác liền mạch - bất kỳ lỗi nào rollback trọn vẹn |
| 02 | Hai biến thể đánh dấu mặc định | Từ chối trước khi lưu với lý do rõ ràng, cụ thể |
| 03 | Đụng độ barcode phát hiện muộn | Kiểm hai giai đoạn - trùng trong-yêu-cầu, rồi đụng độ merchant hiện hữu - trước khi lưu bất cứ gì |
| 04 | Tìm kiếm hiện facet tùy chọn cũ | Facet được làm mới ở chế độ nền khi trục, giá trị hay liên kết thay đổi |
| 05 | Chủ kỳ vọng ma trận tự sinh | Không-mục-tiêu cố ý (PRD-OPT-001); chỉ biến thể đã khai báo được sinh |
Câu hỏi thường gặp
| # | Câu hỏi | Trả lời |
|---|---|---|
| 01 | Hệ thống có sinh mọi tổ hợp size × đá cho tôi không? | Bản thân việc lưu là tường minh - chỉ những biến thể bạn giữ lại mới được tạo. Màn Sinh biến thể tại trang Client có gợi ý sẵn đủ tổ hợp trục để bạn dễ bớt bớt trước khi lưu, nhưng đó chỉ là gợi ý trên màn hình; phần bạn xóa đi không hề được lưu xuống hệ thống. (Xem PRD-OPT-001 để biết lý do.) |
| 02 | Nếu tôi không đánh dấu một mặc định? | Biến thể bạn khai báo đầu tiên được nâng thành mặc định tự động, nên một sản phẩm luôn có một cái. |
| 03 | Tôi có thể đánh dấu hai mặc định không? | Không - một yêu cầu với nhiều hơn một mặc định tường minh bị từ chối trước khi lưu bất cứ gì. Đổi mặc định sau bằng thao tác nâng chuyên biệt. |
| 04 | Mọi loại biến thể có được theo dõi tồn không? | Không - chỉ loại quản lý tồn sinh thuộc tính kho. Combo và loại không quản lý tồn (ví dụ dịch vụ) được tạo không theo dõi. |
| 05 | Khi nào tôi tìm được một biến thể mới theo tùy chọn của nó? | Facet tùy chọn của mỗi biến thể tra được trong tìm kiếm ngay sau khi tạo, và luôn được làm mới ở chế độ nền mỗi khi trục, giá trị hay liên kết thay đổi. |