PRD: POS & order bếp
| Module | Đơn hàng (CORE-07) | PRD ID | PRD-KIT-001 |
| Status | Shipped | Owner | Orders squad |
| Date | 2026-03-23 | Version | v1.0 |
| Packages | @nx/sale · @nx/core · apps/sale-renderer | URD | KIT · STA · POS |
TL;DR
Cho phép một quán F&B phục vụ đầy đủ đẩy các món trong đơn xuống bếp dưới dạng phiếu và theo dõi quá trình nấu theo thời gian thực, không ai phải tải lại màn hình. Phiếu được định tuyến tới các trạm chế biến có tên, đi qua các trạng thái nấu theo từng món tự động đẩy trạng thái của phiếu, và dùng void-and-resend để một món đã gửi không bao giờ bị sửa tại chỗ. Kết quả: khu bếp có một hàng đợi công việc trực tiếp, chính xác, còn khu phục vụ thấy trạng thái ngay khi bếp thao tác.
1. Context & Problem
Module Đơn hàng đã bao phủ vòng đời giỏ-tới-checkout-tới-thanh-toán, nhưng một quán F&B phục vụ đầy đủ cần nửa còn lại ở khu bếp: các món trong đơn phải xuống tới bếp, đi qua quá trình nấu, và cập nhật màn hình chế biến mà không ai phải tải lại màn hình. Hiện tại chưa có bất kỳ thực thể nào phía bếp - các món chỉ tồn tại trên sale order, nên bếp không có hàng đợi công việc, không có trạng thái nấu theo từng món, và không có cách đẩy trạng thái ngược lại khu phục vụ. Với các nhà hàng và quán cà phê HKD/SME mà KICKO nhắm tới, khoảng trống này chặn mô hình phục vụ F&B phổ biến nhất (báo bếp, nấu, phục vụ), khiến POS không dùng được ngoài quầy tính tiền nhanh.
Increment này xây dựng quản lý order bếp (KDS) trên nền vòng đời sale order hiện có: phiếu được gửi từ một sale order xuống bếp, các trạm có tên để định tuyến, trạng thái nấu theo từng món, và lan truyền trạng thái trực tiếp qua WebSocket.
2. Goals & Non-Goals
Goals
- Gửi các món trong đơn xuống bếp dưới dạng phiếu có các dòng món, với một lần gửi idempotent để một lần báo bếp lặp lại không bao giờ tạo ra phiếu thứ hai (KIT).
- Một vòng đời phiếu đầy đủ (
PENDING → PROCESSING → READY → COMPLETED / VOIDED) và một vòng đời nấu theo từng món (PENDING → COOKING → READY → SERVED / VOIDED). - Tự động đẩy trạng thái - trạng thái phiếu tiến tự động theo trạng thái các món của nó.
- Cơ chế void-and-resend - một món đã gửi sẽ bị void và gửi lại, không bao giờ sửa tại chỗ.
- Các trạm bếp có tên theo từng merchant với định tuyến theo danh mục sản phẩm và cấu hình máy in cho từng trạm (STA).
- Cập nhật thời gian thực tới màn hình bếp và dashboard khi phiếu được tạo / cập nhật / hoàn thành.
- Đánh dấu một món đã phục vụ kích hoạt việc trừ kho phía sau.
Non-Goals
- Một ứng dụng màn hình bếp riêng biệt - increment này chỉ giao phần backend cùng bề mặt
apps/sale-renderer(Dự kiến). - Luồng hoàn / trả hàng và phần nội tại trừ kho - thuộc về Kho hàng.
- Quản lý sơ đồ bàn / chỗ ngồi (Dự kiến).
- Phiên ca POS (POS) - liệt kê để đầy đủ phạm vi; schema/service phiên không nằm trong increment này.
3. Success Metrics
| Metric | Mục tiêu / tín hiệu |
|---|---|
| Độ tươi thời gian thực | Màn hình bếp phản ánh thay đổi trạng thái mà không cần tải lại thủ công; fan-out qua WebSocket mỗi lần tạo / cập nhật / hoàn thành |
| Tính toàn vẹn khi gửi | Không có phiếu trùng cho một lần báo bếp lặp lại (gửi idempotent giữ vững khi retry) |
| Độ chính xác tự đẩy trạng thái | Trạng thái phiếu luôn khớp với tổng hợp trạng thái các món của nó |
| Độ phủ định tuyến | Các món rơi đúng trạm được map theo danh mục sản phẩm |
| Đúng đắn khi phục vụ | Đánh dấu một món đã phục vụ kích hoạt trừ kho đúng một lần một cách đáng tin |
4. Personas & Use Cases
| Persona | Mục tiêu trong tính năng này |
|---|---|
| Thu ngân | Báo bếp các món trong đơn và thấy khi nào món sẵn sàng phục vụ |
| Nhân viên bếp | Làm việc trên hàng đợi phiếu trực tiếp, đẩy món cooking → ready → served, void món lỗi |
| Quản lý / Chủ | Cấu hình các trạm, định tuyến theo danh mục, và máy in từng trạm |
Core scenarios: thu ngân báo bếp các món → một phiếu hiện trên màn hình của trạm được định tuyến → nhân viên bếp đẩy món cooking → ready → served, phiếu tự đẩy trạng thái, và khu phục vụ thấy trạng thái trực tiếp; một món lỗi bị void và gửi lại thay vì sửa.
5. User Stories
- Là một thu ngân, tôi muốn gửi các món trong đơn xuống bếp bằng một thao tác, để khu bếp nhận phiếu công việc ngay lập tức.
- Là một thu ngân, tôi muốn một lần báo bếp lặp lại là idempotent, để một lần chạm đúp không bao giờ tạo phiếu trùng.
- Là nhân viên bếp, tôi muốn mỗi món mang trạng thái nấu riêng, để tôi theo dõi một phiếu nhiều món một cách chính xác.
- Là nhân viên bếp, tôi muốn phiếu tự đẩy trạng thái theo các món của nó, để tôi không phải duy trì trạng thái phiếu riêng bằng tay.
- Là nhân viên bếp, tôi muốn void và gửi lại một món đã gửi, để các chỉnh sửa không bao giờ ngầm thay đổi một phiếu đang chạy.
- Là một quản lý, tôi muốn định tuyến các danh mục sản phẩm tới các trạm có tên với cấu hình máy in riêng, để mỗi trạm chỉ thấy và in công việc của nó.
- Là một thu ngân, tôi muốn trạng thái bếp cập nhật màn hình theo thời gian thực, để khu phục vụ biết khi nào phục vụ mà không phải hỏi.
6. Functional Requirements
| # | Yêu cầu | URD ref |
|---|---|---|
| FR-1 | Gửi các món trong đơn xuống bếp - tạo một phiếu với các dòng món | URD-KIT-001 |
| FR-2 | Gửi idempotent - một lần gửi trùng tạo ra cùng một phiếu | URD-KIT-002 |
| FR-3 | Vòng đời phiếu PENDING → PROCESSING → READY → COMPLETED / VOIDED | URD-KIT-003 |
| FR-4 | Vòng đời nấu theo từng món PENDING → COOKING → READY → SERVED / VOIDED | URD-KIT-004 |
| FR-5 | Trạng thái phiếu tự đẩy theo trạng thái các món của nó | URD-KIT-005 |
| FR-6 | Các thay đổi dùng void-and-resend - món đã gửi không bị sửa tại chỗ | URD-KIT-006 |
| FR-7 | Cờ rush và số thứ tự theo từng đơn để sắp xếp phiếu | URD-KIT-007 |
| FR-8 | Cập nhật thời gian thực tới màn hình bếp và dashboard | URD-KIT-008 |
| FR-9 | Đánh dấu một món đã phục vụ kích hoạt trừ kho | URD-KIT-009 |
| FR-10 | Tạo các trạm có tên theo từng merchant (i18n) | URD-STA-001 |
| FR-11 | Định tuyến các danh mục sản phẩm tới các trạm | URD-STA-002 |
| FR-12 | Cấu hình máy in cho từng trạm với tự động in | URD-STA-003 |
Toàn bộ nội dung yêu cầu và tiêu chí nghiệm thu nằm trong Orders URD. PRD này tham chiếu chứ không lặp lại chúng.
7. Non-Functional Requirements
| Area | Yêu cầu |
|---|---|
| Thời gian thực | Tạo / cập nhật / hoàn thành phiếu fan-out qua WebSocket; apps/sale-renderer subscribe để nhận trạng thái trực tiếp |
| Idempotency | Việc gửi được keyed để các retry gộp về một phiếu duy nhất; không trùng công việc bếp |
| Tenancy & authz | Mọi thao tác scope theo từng merchant (x-merchant-id); kiểm soát bởi permission sale/bếp |
| Tính toàn vẹn dữ liệu | Trạng thái phiếu luôn là tổng hợp xác định từ trạng thái các món; chỉnh sửa là void-and-resend, không bao giờ sửa tại chỗ |
| Tính nhất quán | Việc gửi và các chuyển trạng thái là transactional; lỗi một phần không để lại phiếu mồ côi |
| i18n | Tên trạm và các trạng thái hiển thị cho người dùng là song ngữ ({ en, vi }) |
8. UX & Flows
Bề mặt chính: các view phiếu bếp nằm trong apps/sale-renderer, subscribe vào luồng WebSocket để nhận trạng thái phiếu/món trực tiếp; cấu hình trạm và định tuyến được quản lý theo từng merchant.
9. Data & Domain
| Entity | Vai trò |
|---|---|
KitchenTicket | Phiếu được gửi xuống bếp - trạng thái, cờ rush, số thứ tự theo từng đơn, gán trạm |
KitchenTicketItem | Một dòng phiếu - tham chiếu order item, mang trạng thái nấu riêng |
KitchenStation | Một khu chế biến có tên (i18n) với định tuyến theo danh mục và cấu hình máy in |
Chỉ mang tính khái niệm - schema và bất biến đầy đủ ở sale domain model.
10. Dependencies & Assumptions
Phụ thuộc vào
- Sale Order (URD-ORD) - phiếu được báo bếp từ các order item.
- Danh mục sản phẩm (Sản phẩm) - định tuyến trạm map danh mục tới trạm.
- Kho hàng (Kho hàng) - một món đã phục vụ kích hoạt trừ kho.
- Vận chuyển thời gian thực (
@nx/saleWebSocket) - để fan-out trạng thái trực tiếp.
Giả định
- Merchant chạy luồng F&B phục vụ đầy đủ (báo bếp), không chỉ quầy tính tiền.
- Các trạm và định tuyến theo danh mục được cấu hình trước khi báo bếp các món.
- Các client (ví dụ
apps/sale-renderer) giữ một subscription WebSocket đang hoạt động để nhận cập nhật trực tiếp.
11. Risks & Open Questions
| Rủi ro / câu hỏi | Giảm thiểu / trạng thái |
|---|---|
| Báo bếp trùng tạo ra hai phiếu | Việc gửi là idempotent qua key; các retry gộp về một phiếu |
| Trạng thái phiếu lệch khỏi trạng thái các món | Trạng thái là tổng hợp tự động xác định, không duy trì bằng tay |
| Sửa một món đã gửi tại chỗ | Bị cấm theo thiết kế - void-and-resend là con đường chỉnh sửa duy nhất |
| Bỏ lỡ một cập nhật WebSocket khiến màn hình cũ | Màn hình subscribe vào tạo / cập nhật / hoàn thành; kết nối lại sẽ đồng bộ lại |
| Chưa có ứng dụng KDS riêng | Backend + bề mặt apps/sale-renderer giao ngay; ứng dụng KDS độc lập là Dự kiến |
12. Release Plan & Launch Criteria
| Aspect | Kế hoạch |
|---|---|
| Phase | P2 - xem danh mục feature Đơn hàng (KIT, STA Built) |
| Rollout | Tất cả merchant; không feature flag |
| Migration | Các migration sale-schema cho các entity bếp mới; không backfill dữ liệu |
| Launch criteria | Báo bếp → phiếu → định tuyến trạm → nấu → phục vụ đã kiểm chứng đầu-cuối; gửi idempotent giữ vững; tự đẩy trạng thái khớp trạng thái các món; cập nhật trực tiếp tới được apps/sale-renderer |
| Monitoring | Số lượng phiếu theo từng merchant, tỉ lệ lỗi / trùng khi gửi, sức khỏe phân phối WebSocket, tính nhất quán giữa phục vụ và trừ kho |
13. FAQ
Một món bếp đã gửi có sửa được không? Không - các món đã gửi không bao giờ bị sửa tại chỗ. Dùng void-and-resend: void món đó và gửi một món mới.
Điều gì xảy ra nếu một lần báo bếp được gửi hai lần? Không có gì bị trùng - việc gửi là idempotent theo key, nên một lần báo bếp lặp lại quy về cùng một phiếu.
Trạng thái phiếu thay đổi như thế nào? Nó tự đẩy theo trạng thái các món của nó; không có trạng thái phiếu riêng duy trì bằng tay.
Phiếu hiện ở đâu? Trên màn hình của trạm được định tuyến trong apps/sale-renderer, cập nhật trực tiếp qua WebSocket - không cần tải lại. Một ứng dụng KDS riêng là Dự kiến.
Phục vụ một món có làm dịch chuyển kho không? Có - đánh dấu một món đã phục vụ kích hoạt trừ kho phía sau (thuộc về Kho hàng).
Đây có phải tính năng phiên ca POS không? Không - phiên POS (URD-POS) thuộc cùng dòng feature nhưng là một increment riêng; PRD này bao phủ phiếu bếp và các trạm.
References
- URD: Đơn hàng - Kitchen Tickets · Kitchen Stations · POS Sessions
- Xây trên: Sale Order
- Module: Đơn hàng - tổng quan + traceability
- Developer: @nx/sale · @nx/core · domain model