PRD: Nguyên vật liệu
| Module | Kho (CORE-06) | PRD ID | PRD-MAT-001 |
| Status | Shipped | Owner | Inventory squad |
| Date | 2026-05-18 | Version | v1.0 |
| Packages | @nx/inventory · @nx/core · apps/client | URD | MAT |
TL;DR
Mang lại cho merchant F&B một danh mục Material hạng nhất - nguyên liệu thô và bán thành phẩm được theo dõi tách biệt với sản phẩm bán được. Mỗi material mang một tên i18n, một system identifier, và nhiều scheme identifier (SKU, barcode, QR) để có thể tra cứu lúc nhận hàng và kiểm kê. Material là principal mà công thức (BOM) tiêu thụ, biến ghi chú nguyên liệu rời rạc thành một kho được quản lý, quét được.
1. Bối cảnh & Vấn đề
Merchant F&B mua và tiêu thụ nguyên liệu thô - bột, sữa, siro - vốn không bao giờ bán trực tiếp nhưng cần để sản xuất sản phẩm bán được. Mô hình kho hiện tại chỉ theo dõi biến thể sản phẩm, nên không có nơi nào để ghi nhận các đầu vào này hay để dẫn động việc trừ theo bill-of-materials tại bếp. Khi thiếu một thực thể material, tồn nguyên liệu không thể được kiểm đếm, tra cứu bằng barcode, hay được tiêu thụ bởi một công thức, điều này chặn việc theo dõi chi phí chính xác và tự động hóa bếp cho mảng dọc F&B mà KICKO nhắm tới.
Nguyên vật liệu giới thiệu một danh mục theo từng merchant gồm nguyên liệu thô và bán thành phẩm, giữ tách biệt với danh mục sản phẩm. Đây là principal mà công thức (tính năng REC) tiêu thụ, và nó mang scheme identifier riêng để có thể được tìm bằng SKU, barcode, hay QR code.
2. Mục tiêu & Ngoài phạm vi
Mục tiêu
- Một thực thể danh mục Material theo từng merchant, được cô lập theo từng merchant, tách biệt với biến thể sản phẩm.
- Một tên material i18n (nhiều locale) và một mô tả có thể sửa.
- Một system identifier (
MAT_YYYYMMDD_id), tự sinh và người dùng không sửa được. - Một vòng đời hỗ trợ deactivate và archive (đã archive là trạng thái cuối / chỉ-đọc).
- Một sub-entity MaterialIdentifier hỗ trợ scheme SYSTEM, SLUG, SKU, BARCODE, QRCODE, với SYSTEM là mặc định và
(scheme, code)là duy nhất xuyên suốt các material. - Nhiều identifier thuộc các scheme khác nhau trên một material, cộng với tìm kiếm barcode.
- Một aggregate API cho material (create/update với identifier và chiều vendor) hậu thuẫn cho các màn hình quản lý phía client.
Ngoài phạm vi
- Công thức material / BOM và phân rã bếp - thuộc về tính năng
REC. - BOM đa cấp (material làm principal cho cụm lắp ráp con) - Ngoài phạm vi của URD.
- Sản lượng công thức và phần trăm hao hụt - Ngoài phạm vi của URD.
- Tích hợp quét barcode đầy đủ cho kiểm kê - Ngoài phạm vi của URD.
3. Success Metrics
| Metric | Mục tiêu / tín hiệu |
|---|---|
| Mức áp dụng danh mục | Merchant F&B duy trì nguyên liệu thô dưới dạng material thay vì ghi chú văn bản tự do |
| Tính duy nhất của identifier | Không có cặp (scheme, code) trùng lặp xuyên suốt các material của một merchant |
| Độ phủ tra cứu | Material có một BARCODE đã đăng ký được tìm thấy qua tìm kiếm barcode lúc nhận hàng/kiểm kê |
| Sẵn sàng cho BOM | Material sẵn dùng làm principal mà công thức (REC) có thể tiêu thụ |
4. Personas & Use Cases
| Persona | Mục tiêu trong tính năng này |
|---|---|
| Chủ | Duy trì danh mục nguyên liệu thô, gán SKU/barcode, archive các material lỗi thời |
| Nhân viên kho | Tìm một material bằng barcode/QR lúc nhận hàng và kiểm kê |
| Bếp (qua Công thức) | Tham chiếu material làm thành phần công thức để trừ BOM |
Kịch bản cốt lõi: tạo một material với tên i18n và chiều vendor → đính kèm identifier SKU/barcode/QR → tra cứu nó bằng barcode lúc nhận hàng → deactivate hoặc archive khi không còn dùng.
5. User Stories
- Với vai trò chủ, tôi muốn tạo một material với một tên i18n và mô tả, để nguyên liệu thô của tôi được lập danh mục tách biệt với sản phẩm bán được.
- Với vai trò chủ, tôi muốn mỗi material tự nhận một system identifier duy nhất, để tôi không bao giờ phải nghĩ ra hay đụng độ mã.
- Với vai trò chủ, tôi muốn đính kèm identifier SKU, barcode, và QR vào một material, để nó có thể được quét và tra cứu lúc nhận hàng và kiểm kê.
- Với vai trò nhân viên kho, tôi muốn tìm một material bằng barcode đã đăng ký của nó, để tìm nhanh ngay tại sàn.
- Với vai trò chủ, tôi muốn deactivate hoặc archive một material, để nguyên liệu lỗi thời rời khỏi danh mục đang dùng mà không mất lịch sử.
- Với vai trò chủ, tôi muốn tạo và cập nhật một material cùng với identifier và chiều vendor của nó trong một aggregate call duy nhất, để màn hình quản lý lưu một bản ghi đầy đủ trong một lần.
6. Functional Requirements
| # | Yêu cầu | URD ref |
|---|---|---|
| FR-1 | Tạo một material theo từng merchant, cô lập theo từng merchant, tách biệt với biến thể sản phẩm | URD-MAT-001 |
| FR-2 | Material có một system identifier tự sinh (MAT_YYYYMMDD_id) và một tên i18n hỗ trợ nhiều locale | URD-MAT-002..003 |
| FR-3 | Mô tả material có thể sửa | URD-MAT-004 |
| FR-4 | Vòng đời material hỗ trợ deactivate và archive (đã archive là trạng thái cuối / chỉ-đọc) | URD-MAT-005..006 |
| FR-5 | Identifier của material là duy nhất | URD-MAT-007 |
| FR-6 | Chủ có thể đính kèm một identifier BARCODE vào một material | URD-MAT-101 |
| FR-7 | Identifier hỗ trợ scheme SYSTEM, SLUG, SKU, BARCODE, QRCODE; scheme mặc định là SYSTEM khi không chỉ định | URD-MAT-102 · URD-MAT-104 |
| FR-8 | Một cặp (scheme, code) là duy nhất xuyên suốt các material | URD-MAT-103 |
| FR-9 | Nhiều identifier thuộc các scheme khác nhau có thể cùng tồn tại trên một material | URD-MAT-105 |
| FR-10 | Material có thể tìm kiếm bằng barcode đã đăng ký | URD-MAT-106 |
| FR-11 | Aggregate create/update của material chấp nhận identifier và chiều vendor; payload update sai định dạng bị từ chối | URD-MAT-001..007 |
Toàn văn yêu cầu và tiêu chí chấp nhận nằm trong URD Kho. PRD này tham chiếu chúng thay vì lặp lại.
7. Non-Functional Requirements
| Khía cạnh | Yêu cầu |
|---|---|
| Toàn vẹn dữ liệu | Tính duy nhất (scheme, code) được áp đặt xuyên suốt các material của một merchant; xung đột identifier bị từ chối |
| Tenancy & authz | Material được cô lập theo từng merchant (x-merchant-id) và được gác bởi permission của inventory |
| An toàn vòng đời | Material đã archive là trạng thái cuối / chỉ-đọc; soft-delete giữ lại lịch sử |
| i18n | Tên material được lưu dưới dạng một object i18n ({ en, vi, … }) hỗ trợ nhiều locale |
| Liên kết vendor | Liên kết vendor đi qua VendorItem, không bao giờ qua một cột vendorId trên material |
| Nhất quán | Aggregate create/update (material + identifier + chiều vendor) là transactional; payload sai định dạng bị từ chối mà không ghi một phần |
8. UX & Flows
Màn hình chính (trong apps/client): màn hình quản lý material với hỗ trợ đơn vị đo lường, validation form, vendor multi-select, nhập identifier, và một overview với widget tóm tắt.
9. Data & Domain
| Thực thể | Vai trò |
|---|---|
Material | Principal danh mục - tên i18n, mô tả, system identifier, trạng thái, metadata jsonb có kiểu |
MaterialIdentifier | Một sub-entity giữ một identifier (scheme, code); scheme SYSTEM / SLUG / SKU / BARCODE / QRCODE |
VendorItem | Liên kết giữa một material và các vendor của nó (nguồn sự thật duy nhất cho liên kết vendor) |
InventoryItem / stock | Liên kết tồn tùy chọn được tạo cùng với material |
Chỉ là khái niệm - toàn bộ schema và bất biến nằm trong domain model của inventory.
10. Dependencies & Assumptions
Phụ thuộc vào
- Mục kho & tồn (URD-ITM · URD-STK) - một material có thể được tạo cùng với liên kết inventory item/stock của nó.
- Vendor (URD-VEN) - chiều vendor trên một material liên kết qua VendorItem.
@nx/core- schema/model của material và material-identifier nằm dưới các schema inventory tập trung của core.
Giả định
- Merchant tồn tại và có một địa điểm kho mặc định cho bất kỳ liên kết tồn nào.
- Mã identifier là duy nhất theo từng
(scheme, code)trong phạm vi các material của merchant.
11. Risks & Open Questions
| Rủi ro / câu hỏi | Giảm thiểu / trạng thái |
|---|---|
(scheme, code) trùng lặp sẽ phá vỡ tra cứu | Tính duy nhất được áp đặt xuyên suốt các material; ghi xung đột bị từ chối |
| Liên kết vendor có thể trôi nếu lưu trên material | Liên kết vendor chỉ đi qua VendorItem - không có cột vendorId |
| Material đã archive vẫn được công thức tham chiếu | Archive là trạng thái cuối/chỉ-đọc; công thức (REC) chỉ tiêu thụ material đang hoạt động |
| Tích hợp quét barcode đầy đủ cho kiểm kê | Ngoài phạm vi increment này; tìm kiếm barcode được hỗ trợ, luồng quét phần cứng để sau |
12. Release Plan & Launch Criteria
| Khía cạnh | Kế hoạch |
|---|---|
| Phase | P3 (BOM + Nâng cao) - xem danh mục tính năng URD |
| Rollout | Tất cả merchant; không feature flag (mảng dọc F&B là người dùng chính) |
| Migration | Không - thực thể mới dưới các schema inventory của @nx/core |
| Tiêu chí ra mắt | Tạo material → đính kèm SKU/barcode/QR → tra cứu barcode trả về nó → tính duy nhất (scheme, code) từ chối khi xung đột → aggregate create/update được kiểm chứng đầu-cuối |
| Giám sát | Số material theo từng merchant, tỉ lệ từ chối xung đột identifier, tỉ lệ trúng tìm kiếm barcode |
13. FAQ
Material khác sản phẩm như thế nào? Một material là một đầu vào thô hoặc bán thành phẩm không bao giờ bán trực tiếp; một biến thể sản phẩm thì bán được. Material được lập danh mục tách biệt và được công thức (BOM) tiêu thụ.
Một material có thể có nhiều barcode không? Có - nhiều identifier thuộc các scheme khác nhau (SKU, BARCODE, QRCODE) có thể cùng tồn tại trên một material, miễn là mỗi cặp (scheme, code) là duy nhất xuyên suốt các material.
Dùng scheme nào nếu tôi không chọn? Scheme identifier mặc định là SYSTEM, và một system identifier (MAT_YYYYMMDD_id) được sinh tự động.
Tôi có thể xóa một material không? Material dùng soft-delete và có thể được deactivate hoặc archive; đã archive là trạng thái cuối và chỉ-đọc, nên lịch sử được giữ lại.
Tôi liên kết một vendor với một material như thế nào? Liên kết vendor đi qua VendorItem (vendor multi-select trên màn hình quản lý), không bao giờ qua một cột trên chính material.
References
- URD: Kho - Nguyên vật liệu (
MAT) - yêu cầu + chấp nhận - Liên quan: Công thức / BOM (
REC) - tiêu thụ material làm principal - Module: Kho - tổng quan + truy vết
- Developer: @nx/inventory · domain model