Skip to content

PRD: QR Self-order

ModuleBán hàngPRD IDPRD-SLF-001
Trạng tháiChưa tạo itemFEATSLF · BANA-1432
EpicBANA-1325PlaneBANA-1562
Ngày2026-07-15Phiên bảnv0.2
Gói@nx/sale · @nx/commerceURDSLF
SurfaceSale · POS
Phụ tráchHải Cao · Khoa Nguyễn · Phát Nguyễn

TL;DR

  • Khách ngồi bàn quét QR, xem menu đã lọc theo policy (giờ/kênh) ngay trên điện thoại - không cần cài app - chọn món rồi gửi.
  • Mỗi lượt gửi tạo một card gọi món riêng, nhưng cả bàn dùng chung một đơn: năm khách cùng bàn gửi năm lượt vẫn chỉ có một đơn của bàn 5 với năm card bên trong.
  • Nhân viên xác nhận hoặc từ chối từng card trên POS; card được xác nhận in phiếu bếp như đơn nhân viên tự nhập.
  • Chưa có gì trong số này tồn tại hôm nay - toàn bộ tính năng là 🚧 forward-spec.

1. Bối cảnh & Vấn đề

Giờ cao điểm, phục vụ bàn nghẽn ở khâu ghi món - mỗi bàn phải chờ nhân viên rảnh tay tới ghi order trước khi bếp nhận được gì. Hiện tại không có đường đi nào khác: không có trang gọi món cho khách, không có mã QR gắn theo bàn, không có menu lọc theo giờ/kênh (policy), và luồng nhận-xác nhận đơn trên POS cho đơn không do nhân viên tự gõ cũng chưa tồn tại.

Ba mảnh ghép mà tính năng này cần, nhìn từ code hiện có:

  • Bàn & chiếm dụng đã có sẵn qua Table & floor allocation - mỗi bàn (AllocationUnit) chiếm dụng qua một AllocationUsage (reserved/active/success = bận, completed/cancelled = trống), và Sale POS đã có sơ đồ bàn trực tiếp đọc đúng trạng thái này. SLF không dựng lại cơ chế chiếm bàn - nó gắn đơn khách tự gọi vào usage đã có của bàn.
  • Vòng đời đơn (SaleOrderStatuses: DRAFT/PROCESSING/PARTIAL/COMPLETED/CANCELLED) cũng đã có sẵn ở Sale ORD. SLF cần định nghĩa "xác nhận"/"từ chối" một card gọi món ánh xạ vào enum này thế nào (xem §6, §9) - đây là phần vòng đời mới, chưa tồn tại.
  • Xóa đơn của bàn hiện KHÔNG có bước chặn nào ngoài việc kiểm tra đơn chưa ở trạng thái terminal - PRD-SLF-002 đóng lỗ hổng này độc lập, đi trước SLF, và định nghĩa quy tắc "đơn khách chỉ từ chối, không xóa" (URD-SLF-009) mà PRD này phải tuân theo chứ không định nghĩa lại.

Còn thiếu hoàn toàn: trang khách gọi món, mã QR theo bàn, engine menu-theo-policy (kế hoạch riêng, epic BANA-902…907, chưa bắt đầu), và luồng xác nhận/từ chối trên POS cho đơn khách tự gửi.

2. Mục tiêu & Loại trừ

Mục tiêu

  • Khách quét QR của đúng bàn, xem menu trên điện thoại, không cần cài app hay đăng nhập (URD-SLF-001).
  • Menu hiển thị đúng theo policy đang áp dụng cho thời điểm/kênh hiện tại (URD-SLF-002).
  • Khách tạo giỏ và gửi đơn cho bàn; mỗi lượt gửi là một card riêng, nhiều lượt/nhiều khách cùng bàn gộp vào một đơn của bàn (URD-SLF-003, URD-SLF-008).
  • POS nhận từng card gắn đúng bàn; nhân viên xác nhận hoặc từ chối từng card - không có hành động xóa (URD-SLF-004).
  • Card đã xác nhận in phiếu bếp giống hệt đơn nhân viên tự nhập (URD-SLF-005).
  • Khách thấy trạng thái từng card cập nhật theo thời gian thực (URD-SLF-006).
  • Món hết hàng bị ẩn hoặc không gọi được trên menu khách (URD-SLF-007).

Loại trừ

  • Thanh toán online trong v1 - khách vẫn thanh toán tại quầy/bàn qua nhân viên như hiện tại.
  • Tích hợp loyalty.
  • Hoạt động offline - trang khách và POS đều cần kết nối mạng.
  • Mỗi khách có đơn/tab thanh toán riêng - không có; toàn bộ card của một bàn cộng dồn vào một đơn tổng duy nhất, thanh toán vẫn tính theo bàn như hiện tại (xem §6 FR-004).
  • Bản thân engine menu-theo-policy (tạo/sửa policy, gán theo giờ/kênh) - thuộc epic riêng BANA-902…907; PRD này chỉ tiêu thụ policy đã có, không định nghĩa màn quản trị policy.
  • Luồng xác nhận-vs-xóa và log kiểm toán khi xóa đơn của bàn - thuộc PRD-SLF-002 (URD-SLF-009); PRD này chỉ tuân theo quy tắc "từ chối, không xóa" mà PRD đó đặt ra, không định nghĩa lại.

3. Thước đo thành công

Thước đoMục tiêu / tín hiệu
Quán pilot chạy thật1-2 quán F&B, tháng 8
Đơn khách → bếpChạy end-to-end với bước xác nhận của nhân viên, không phát sinh phiếu bếp cho card bị từ chối
Tỷ lệ card bị từ chốiTheo dõi theo quán pilot - tỷ lệ cao bất thường là tín hiệu menu/giá hiển thị sai hoặc quy trình xác nhận có vấn đề
Độ trễ xác nhậnThời gian từ lúc card xuất hiện trên POS tới lúc nhân viên xác nhận/từ chối - theo dõi để phát hiện bàn "bị bỏ quên"

4. Persona & Tình huống

PersonaMục tiêu trong tính năng này
KháchGọi món bằng điện thoại của mình, không cần app, không cần chờ phục vụ rảnh tay; biết chắc món đã gửi được xác nhận, từ chối kèm lý do, hay vẫn đang chờ
Phục vụ / Thu ngânNhận đơn khách đúng bàn trên POS, xác nhận hoặc từ chối từng lượt gọi, giữ toàn quyền kiểm soát trước khi món xuống bếp
BếpNhận phiếu bếp cho card đã xác nhận giống hệt phiếu của đơn nhân viên tự nhập - không cần học quy trình mới

Tình huống chính: một bàn 5 khách, mỗi người tự quét QR trên điện thoại của mình và gửi một lượt gọi món riêng. Cả 5 lượt gộp vào một đơn của bàn 5, hiện thành 5 card chờ trên POS. Phục vụ xác nhận lần lượt từng card; bếp nhận 5 phiếu tương ứng, không lẫn sang bàn khác.

5. User Stories

  • khách, tôi quét QR bàn, xem menu, gọi 2 món và thấy khi nào món được xác nhận - để không phải vẫy tay gọi phục vụ.
  • khách ngồi cùng bàn với bạn bè, mỗi người tự gọi món trên điện thoại riêng, và biết cả bàn vẫn tính chung một đơn khi thanh toán.
  • phục vụ, đơn của khách hiện trên POS đúng bàn dưới dạng từng card riêng; tôi xác nhận hoặc từ chối từng card, giữ quyền kiểm soát trước khi món xuống bếp.
  • bếp, tôi nhận phiếu cho card đã xác nhận y hệt phiếu của đơn nhân viên tự nhập - không cần phân biệt nguồn gốc đơn.

6. Yêu cầu chức năng

#Yêu cầuTrạng tháiURD ref
FR-001Khách quét mã QR gắn theo bàn và mở được menu trên trình duyệt điện thoại - không cần cài app, không cần đăng nhập. QR hết hạn hoặc không hợp lệ hiển thị thông báo yêu cầu gọi nhân viên, không hiện menu cũ hay lỗi trắng trang.🚧URD-SLF-001
FR-002Menu hiển thị cho khách được lọc theo policy đang áp dụng tại thời điểm quét: khung giờ (theo ngày trong tuần), kênh bán (liên kết SaleChannel hiện có), và phạm vi áp dụng (toàn menu / theo category / theo món). Món hoặc category ngoài khung giờ hoặc sai kênh không xuất hiện trên menu khách.🚧 - phụ thuộc cứng vào engine policy (BANA-902…907), hiện chưa bắt đầuURD-SLF-002
FR-003Khách thêm/bớt món và số lượng vào giỏ, ghi chú tự do theo món (không bắt buộc), xem tổng tạm tính cập nhật trực tiếp, rồi gửi giỏ cho bàn đang ngồi. Giỏ rỗng không gửi được.🚧URD-SLF-003
FR-004Mỗi lượt gửi giỏ tạo một card gọi món riêng. Một bàn tại một thời điểm chỉ có một đơn tổng; card của mọi lượt gửi - dù từ cùng một khách gửi nhiều lần hay từ nhiều khách khác nhau cùng bàn - đều gắn vào đơn tổng đó, không tạo đơn con riêng và không chiếm dụng bàn thêm lần nữa.🚧URD-SLF-003 · URD-SLF-008
FR-005Mỗi card hiện trên POS gắn đúng bàn, hiển thị danh sách món/số lượng/ghi chú và thời điểm gửi. Nhân viên có đúng hai hành động trên một card: Xác nhận hoặc Từ chối (bắt buộc nhập lý do) - không có hành động xóa (theo quy tắc URD-SLF-009, định nghĩa đầy đủ tại PRD-SLF-002).🚧URD-SLF-004
FR-006Xác nhận một card cộng món của card đó vào đơn tổng của bàn và tạo phiếu bếp ngay lập tức, cùng cấu trúc và trạm bếp như phiếu của đơn nhân viên tự nhập.🚧URD-SLF-005
FR-007Khách xem trạng thái từng card của mình theo thời gian thực: Đã gửi → Đã xác nhận (→ Đang phục vụ, nếu bật) hoặc Đã gửi → Bị từ chối kèm lý do - không cần tự làm mới trang.🚧URD-SLF-006
FR-008Món hoặc variant đang hết hàng không xuất hiện trên menu khách, hoặc hiện mờ và không cho thêm vào giỏ. Nếu món bị đánh hết hàng sau khi đã nằm trong giỏ nhưng trước khi gửi, món đó tự động bị loại khỏi giỏ kèm thông báo.🚧URD-SLF-007
FR-009Trong cùng một phiên (QR chưa hết hạn), khách gửi thêm giỏ mới bất kỳ lúc nào; mỗi lượt gửi thêm tạo một card mới gắn vào đơn tổng của bàn theo đúng quy tắc FR-004, không giới hạn số lượt gửi trong v1.🚧URD-SLF-008

6.1 Tiêu chí nghiệm thu

  • Khách quét QR hợp lệ của bàn 5 → mở được trang menu ngay trên trình duyệt điện thoại, không cần đăng nhập/cài app; đầu trang hiện tên quán và "Bàn 5". 🚧
  • QR của bàn đã hết hạn → trang hiện thông báo "Mã QR đã hết hạn - gọi nhân viên hỗ trợ", không hiện menu cache cũ. 🚧
  • Ngoài khung giờ hoặc sai kênh của policy đang áp dụng → món/category tương ứng không xuất hiện trong menu khách (khác với món hết hàng - không có badge riêng, món coi như không tồn tại tại thời điểm đó). 🚧 - phụ thuộc engine policy chưa xây
  • Khách thêm 3 món vào giỏ và bấm gửi → một card mới xuất hiện trên POS gắn đúng bàn 5, liệt kê đủ 3 món, số lượng và thời điểm gửi. 🚧
  • 5 khách khác nhau cùng ngồi bàn 5, mỗi người tự quét QR và gửi giỏ riêng → 5 card riêng biệt xuất hiện trên POS, tất cả gắn vào cùng một đơn tổng của bàn 5 - không có 5 đơn riêng, không có 5 lượt chiếm bàn (AllocationUsage) mới. 🚧
  • Một khách gửi thêm giỏ lần hai trong cùng phiên → một card mới được thêm vào đơn tổng của bàn 5; đơn tổng và lượt chiếm bàn hiện có không bị tạo lại. 🚧
  • Nhân viên xác nhận một card → món của card được cộng vào đơn tổng của bàn, phiếu bếp được tạo ngay, khách thấy trạng thái card chuyển "Đã xác nhận" mà không cần tải lại trang. 🚧
  • Nhân viên bấm từ chối một card mà không nhập lý do → hệ thống chặn, buộc nhập lý do trước khi xác nhận từ chối; khách được báo "Bị từ chối" kèm lý do (hành vi xác nhận/từ chối/audit log đầy đủ theo PRD-SLF-002, URD-SLF-009 - không định nghĩa lại ở đây). 🚧
  • Một món trong giỏ của khách bị đánh hết hàng trước khi khách bấm gửi → món tự động bị loại khỏi giỏ kèm thông báo; nếu giỏ rỗng sau khi loại, nút gửi bị vô hiệu. 🚧

7. Yêu cầu phi chức năng

Khía cạnhYêu cầu
Hiệu năngTrang khách hiển thị được menu trong ≤3 giây ở mốc p95 trên kết nối chậm (~150kbps, tương đương 3G yếu) - 🚧 con số đề xuất, chốt chính thức sau khi đo thực tế tại quán pilot
Bảo mật QRToken gắn theo bàn là chuỗi ngẫu nhiên tối thiểu 128-bit, không suy đoán được từ số bàn hay thời gian quét; đề xuất TTL 12 giờ (phủ một ca hoạt động) rồi yêu cầu quét lại - 🚧 con số đề xuất, chờ Thiết kế (T7) và rà soát bảo mật chốt chính thức
Tenancy & authzTrang khách chỉ đọc menu/policy của đúng merchant và đúng bàn mã hóa trong token; không có quyền ghi nào ngoài gửi giỏ cho chính bàn đó
Thời gian thựcTrạng thái card (xác nhận/từ chối) đẩy tới trang khách và tới mọi máy POS qua kênh cập nhật trực tiếp đã dùng cho sơ đồ bàn (Table & floor allocation), không cần làm mới thủ công
Đa ngôn ngữMenu khách và nội dung xác nhận/từ chối song ngữ (Anh/Việt), theo ngôn ngữ ưu tiên của merchant

8. UX & Luồng

Một khách gọi món, xác nhận, xuống bếp

Nhiều khách cùng bàn - một đơn, nhiều card

Bề mặt chính: trang khách (menu → giỏ → trạng thái) chạy trên trình duyệt điện thoại, không cần cài đặt gì; POS thêm một khu vực "chờ xác nhận" theo bàn, mỗi card là một dòng riêng với hai nút Xác nhận/Từ chối - không có nút xóa trên card khách gửi.

9. Dữ liệu & Miền nghiệp vụ

Khái niệmVai trò
AllocationUnit / AllocationUsageBàn và lượt chiếm dụng đã có sẵn từ Table & floor allocation; SLF không tạo cơ chế chiếm bàn mới, chỉ gắn đơn khách vào usage hiện có của bàn (reserved/active/success = bàn đang bận)
SaleOrder (đơn tổng của bàn)Đơn hiện có, mang SaleOrderStatuses (DRAFT/PROCESSING/PARTIAL/COMPLETED/CANCELLED); một bàn tại một thời điểm chỉ có tối đa một đơn tổng đang mở cho luồng khách tự gọi
Card gọi món (mới, khái niệm)Một lượt gửi giỏ của khách; nhiều card gắn vào cùng một đơn tổng của bàn; mỗi card mang trạng thái riêng (chờ / đã xác nhận / bị từ chối kèm lý do) độc lập với trạng thái đơn tổng
Token QR theo bàn (mới)Chuỗi định danh bàn dùng để mở trang khách, có hạn dùng (TTL) - xem NFR
Policy menu (ngoài phạm vi, tiêu thụ qua API)Xác định món/category nào hiển thị theo giờ/kênh; thuộc epic BANA-902…907, chưa bắt đầu - PRD này chỉ tiêu thụ kết quả, không định nghĩa policy

Chỉ mang tính khái niệm - "card gọi món" và "token QR" là mô hình đề xuất, schema thật chờ Thiết kế/BE chốt ở T7-T8.

10. Phụ thuộc & Giả định

Phụ thuộc vào

  • Engine menu theo policy (BANA-902…907) - là menu khách nhìn thấy (FR-002). 🚧 Chưa bắt đầu.
  • Table & floor allocation - AllocationUsage là nguồn sự thật cho việc bàn nào đang mở; đơn khách gắn vào usage này. ✅ Built, ngoại trừ FR-006 (giới hạn số lượng tầng/phòng/bàn/ghế) hiện 🔶 một phần.
  • PRD-SLF-002 (chặn xóa đơn của bàn) - định nghĩa quy tắc "card/đơn khách chỉ từ chối, không xóa" (URD-SLF-009) mà FR-005 của PRD này phải khớp vào. 🚧 Đang lên kế hoạch, có thể ra mắt trước SLF.
  • Vòng đời đơn hàng (SaleOrderStatuses, ORD) - card xác nhận/từ chối phải ánh xạ vào enum trạng thái đơn có sẵn. ✅ Built.
  • Thiết kế (T7) - UI trang khách + UX xác nhận/từ chối trên POS, số liệu NFR còn 🚧 (TTL token, SLA tải trang). Chưa bắt đầu.

Giả định

  • Tại một thời điểm, một bàn có tối đa một AllocationUsage hiệu lực (theo mô hình FLR) - nên "đơn tổng của bàn nào" luôn rõ ràng, không mơ hồ khi gộp nhiều card.
  • Engine policy (BANA-902…907) khi hoàn thành sẽ lộ ra một API đọc "menu khả dụng theo merchant + thời điểm + kênh" mà SLF tiêu thụ trực tiếp, không cần xây lại logic lọc.
  • Quán pilot có nhân viên trực đủ để xác nhận/từ chối card trong thời gian hợp lý - PRD không đặt SLA cứng cho thời gian phản hồi ở v1 (xem Rủi ro).

11. Rủi ro & Câu hỏi mở

Rủi ro / câu hỏiGiảm thiểu / trạng thái
Đơn rác/phá từ kháchBước xác nhận của nhân viên trên từng card là chốt chặn v1 - không có card nào xuống bếp mà chưa qua xác nhận
Số lượt gửi không giới hạn trong một phiên (FR-009) có thể bị spamChưa có giới hạn cứng ở v1; theo dõi qua thước đo "tỷ lệ card bị từ chối" (§3), xem lại nếu pilot phát sinh vấn đề thật
TTL token QR và SLA tải trang chưa chốt số chính thứcĐề xuất giữ ở §7 NFR; chờ Thiết kế T7 và đo thực tế pilot để chốt
Nhân viên không phản hồi một card trong thời gian dàiNgoài phạm vi v1 - chưa có SLA/nhắc tự động; nếu vận hành pilot cần, bổ sung ở increment sau
Engine policy (BANA-902…907) chưa bắt đầu, có thể trễ so với mốc T7-T8 của SLFFR-002 phụ thuộc cứng; nếu policy trễ, menu khách có thể tạm thời chạy không lọc (toàn bộ menu hiển thị) như một phương án dự phòng - cần Thiết kế xác nhận trước khi build

12. Kế hoạch phát hành & Tiêu chí

Khía cạnhKế hoạch
Giai đoạnP2 (T7-T8) - SLF trong URD feature catalog
RolloutQuán pilot F&B trước (1-2 quán, tháng 8), mở rộng sau khi qua tiêu chí ra mắt
MigrationKhông cần dữ liệu cũ - đơn tổng của bàn dùng lại mô hình SaleOrder/AllocationUsage có sẵn; card gọi món là dữ liệu bổ sung mới
Tiêu chí ra mắtAC-SLF-01 (URD) pass tại quán pilot: khách gửi đơn 2 món → POS hiện đúng bàn chờ xác nhận → xác nhận xong bếp nhận phiếu; món hết hàng không gọi được; nhiều khách cùng bàn gộp đúng một đơn nhiều card
Giám sátTỷ lệ card bị từ chối, độ trễ xác nhận theo bàn/quán, tỷ lệ lỗi tải trang khách (QR hết hạn/không hợp lệ), số lượt gửi trung bình mỗi bàn mỗi phiên

13. FAQ

  • Khách có thanh toán online không? V1 chưa - chỉ gọi món; thanh toán vẫn qua nhân viên tại quầy/bàn như hiện tại.
  • Nhiều khách cùng bàn gọi món cùng lúc thì sao? Mỗi lượt gửi tạo một card riêng, nhưng toàn bộ card của bàn đó gộp vào một đơn tổng duy nhất - không có đơn/tab riêng cho từng khách, thanh toán vẫn tính theo bàn (xem FR-004).
  • Nhân viên có xóa được một card gọi món khách gửi nhầm không? Không - hành động duy nhất là từ chối kèm lý do; xóa không áp dụng cho đơn/card khách tự gửi, theo quy tắc của PRD-SLF-002 (URD-SLF-009).
  • Nếu engine menu-theo-policy chưa xong khi SLF tới hạn build thì sao? FR-002 phụ thuộc cứng vào BANA-902…907; nếu trễ, cần Thiết kế xác nhận phương án dự phòng (ví dụ hiển thị toàn bộ menu, không lọc) trước khi build, không tự ý bỏ qua bước lọc.

Tham chiếu

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.