RestaurantOS.

Hệ thống POS cho nhà hàng đa chi nhánh — khách quét QR tại bàn để đặt món, nhân viên nhận và xử lý order realtime, bill in tại quầy khi thanh toán. Toàn bộ luồng vận hành chạy trên một backend duy nhất, phục vụ đồng thời API NestJS, dashboard quản trị và web đặt món của khách — cả hai đều được xây bằng Next.js.

Year2024
RoleSolo · fullstack (API + admin + guest)
Timeline42 tuần
Status● Live · production

01.Overview

Tổng quan

RestaurantOS ra đời từ thực tế của một chuỗi quán nhỏ 3 chi nhánh. Giờ cao điểm buổi trưa, nhân viên ghi order bằng giấy rồi đọc lại cho bếp — mỗi lần đổi món, nhầm bàn, hay khách muốn thêm một dĩa rau là một lần chạy qua chạy lại giữa bàn, bếp và quầy thu ngân. Cuối ngày ngồi đối sổ thì con số luôn lệch, không rõ lệch ở đâu.

Giải pháp là ba app dùng chung một API: web cho khách — quét QR tại bàn để xem menu và đặt món thẳng vào hệ thống, không cần gọi nhân viên; dashboard quản trị cho nhân viên, bếp và quản lý — duyệt order, cập nhật trạng thái từng món, in bill khi thanh toán; và API NestJS đa tenant chạy multi-chi-nhánh với RBAC scope riêng theo từng chi nhánh, audit log chi tiết đến từng order item, và Socket.IO đồng bộ realtime mọi thay đổi xuyên suốt hệ thống.

02.Features

Tính năng
  • 01
    Đặt món qua QRGuest scans · no app, no signup

    Mỗi bàn được gắn một QR riêng tương ứng với session đang mở. Khách quét bằng camera điện thoại, web khách Next.js mở ra ngay — không cần tải app, không cần đăng nhập. Từ đó khách xem menu theo từng category, thêm món, ghi chú nếu cần, rồi submit. Order đi về backend qua HTTP và được broadcast lập tức tới dashboard quản trị qua Socket.IO — nhân viên và bếp thấy order mới ngay khi khách vừa bấm xác nhận.

  • 02
    Multi-tenant theo chi nhánhOrg → branches · per-branch RBAC

    Hệ thống tổ chức theo mô hình organizations → branches: một công ty quản lý nhiều chi nhánh độc lập. Phân quyền được xử lý qua bảng user_branch_roles — cùng một tài khoản có thể đóng vai quản lý ở chi nhánh A và thu ngân ở chi nhánh B, với dữ liệu hoàn toàn tách biệt giữa hai nơi. Mỗi người chỉ thấy đúng những gì họ được phép thấy tại chi nhánh họ đang làm việc.

  • 03
    Order lifecycle realtimepending → preparing → served · per item

    Mỗi order đều có vòng đời pending → confirmed → preparing → served hoặc rẽ sang cancelled nếu cần. Không chỉ order — mỗi order_item cũng mang status riêng, cho phép bếp tick từng món độc lập thay vì phải chờ cả bàn xong mới cập nhật. Mọi lần chuyển trạng thái đều được ghi vào order_audit_logs và push realtime qua Socket.IO room riêng theo từng chi nhánh — quản lý, thu ngân và bếp luôn nhìn thấy cùng một trạng thái tại cùng một thời điểm.

  • 04
    Bill + print trackingSnapshot · print count · void with reason

    Bill được chốt từ session theo công thức subtotal − discount + tax = total, ghi lại đầy đủ paymentMethod, paidBypaidAt tại thời điểm thanh toán. Mỗi lần in được đếm vào printCount và hệ thống tự lưu firstPrintedAt / lastPrintedAt — đủ để truy vết nếu có tranh chấp. Trường hợp huỷ bill bắt buộc phải kèm voidReason, không cho phép void trống lý do. Front-end xử lý in trực tiếp qua react-to-print, không cần qua driver hay phần mềm trung gian.

  • 05
    Menu CMS + drag-dropCategories · items · sort · soft delete

    Trang quản trị menu dùng dnd-kit để kéo thả sắp xếp thứ tự category và món — không cần nhập số thứ tự thủ công. Mỗi món hỗ trợ upload nhiều ảnh, toggle isAvailable để ẩn tạm thời khi hết nguyên liệu mà không cần xoá. Thay vì xoá cứng, hệ thống dùng soft delete với deletedAt — món bị xoá vẫn được giữ lại trong lịch sử order, đảm bảo dữ liệu thanh toán và báo cáo không bị mất theo.

03.Tech stack

Công nghệ sử dụng
APINestJS 11 · TypeScript · TypeORM (migrations + seeds) · Passport JWT · class-validator · Swagger · Throttler · Terminus health
AdminNext.js 16 · React 19 · TypeScript · Redux Toolkit · TanStack Query + Table · react-hook-form + zod · dnd-kit · recharts · react-to-print · Tailwind 4
GuestNext.js 16 (cổng 3002) · React 19 · TanStack Query · socket.io-client · Tailwind 4 — không Redux, không form heavy
DatabasePostgresql (organizations, branches, menus, sessions, qr_codes, orders, order_items, bills, audit_logs) · soft delete · decimal cho giá
RealtimeSocket.IO (OrderGateway + GuestGateway) · Redis adapter cho multi-instance · room theo branch / session
InfraDocker · GitHub Actions · QR generation server-side (qrcode) · Excel export (exceljs)

04.How it works

Kiến trúc tổng thể

Trung tâm của hệ thống là table session. Khi nhân viên mở bàn, backend tạo một table_sessions mới (status=open) kèm một qr_codes gắn 1-1 với session đó. QR mã hoá URL chứa token của session — khách quét xong là mở thẳng vào đúng session, mọi order gửi lên đều được validate qua token này. Đóng session → token vô hiệu hoá ngay, không thể quét lại.

Mỗi session có flag order_mode để linh hoạt theo tình huống: false (mặc định) — order của khách vào trạng thái pending, chờ nhân viên duyệt trước khi xuống bếp; true — auto-confirm, dùng cho giờ cao điểm khi quầy không kịp xử lý từng order một. Khi order được tạo hoặc đổi trạng thái, SocketService emit vào room branch:{branchId} để mọi màn hình bếp và quầy trong cùng chi nhánh nhận update <120ms. Mỗi item bị huỷ hay đổi giá đều để lại một dòng trong order_audit_logs — không có thay đổi nào mất dấu.

Design decision

"Trung tâm của RestaurantOS là tableModule — mỗi bàn không chỉ là một vị trí vật lý, mà là điểm khởi đầu của toàn bộ luồng vận hành. Khi nhân viên mở bàn, tableModule kết nối trực tiếp với sessionModule để tạo một session mới, và ngay lúc đó một mã QR mới được sinh ra gắn 1-1 với session đó. Khách quét QR là bước vào đúng session đang mở của bàn mình — không nhầm lẫn, không xung đột với lượt khách trước."

05.Bình luận

Ý kiến của bạn

Chưa có bình luận nào.

Xem tiep
hotel preview
H
Hotel management

Hotel Management là phần mềm quản trị khách sạn nội bộ, xây cho đội ngũ lễ tân và quản lý vận hành hàng ngày. Toàn bộ luồng cốt lõi được xử lý trong một hệ thống: nhận đặt phòng walk-in tại quầy hoặc từ kênh online, check-in và check-out, ghi nhận dịch vụ phát sinh trong quá trình lưu trú, và xuất hoá đơn tự động khi khách trả phòng. Phân quyền chi tiết đến từng thao tác — nhân viên lễ tân, thu ngân và quản lý có màn hình và quyền hạn khác nhau. Mọi thay đổi trên hệ thống đều được ghi vào audit log đầy đủ, đủ để truy vết khi cần.

bank-notify-bridge preview
B
Bank Notify

BankNotify biến một chiếc điện thoại Android cũ thành cổng thanh toán DIY cho merchant nhỏ. App Flutter + Kotlin chạy nền trên điện thoại, đọc thông báo biến động số dư từ app ngân hàng và forward ngay về backend qua HTTP. Backend nhận thông báo, match với đơn hàng đang pending, rồi gọi callback để hoàn thành thanh toán — tất cả xảy ra trong vài giây, không cần tích hợp cổng thanh toán chính thức, không cần phí hàng tháng.

chatgpt-auto-login preview
G
GPT Login

API NestJS tự đăng nhập ChatGPT bằng puppeteer-real-browser (bypass Cloudflare anti-bot), hỗ trợ OTP qua email, lưu session để dùng lại cho route /ask để promt, và cron job mỗi giờ kiểm tra session — gửi cảnh báo qua Telegram khi hết hạn. Điều này giúp tôi promt và nhận câu trả lời trực tiếp từ api mà không cần mở trình duyệt.

trading-signals preview
T
Trading Signals

TradingSignals là công cụ phân tích tín hiệu mua/bán cá nhân cho crypto và chứng khoán — không phải bot copy trade đại trà, mà là hệ thống được xây riêng để phục vụ đúng một người, với dữ liệu kiểm chứng thực tế 2–5 năm trở lại. NestJS scan đồng thời trên nhiều khung thời gian từ 15 phút đến 1 tháng, chạy song song qua 4 engine độc lập: candlestick pattern, indicator, price action và volume analysis. Tín hiệu chỉ được ghi nhận khi nhiều khung đồng thuận — loại bỏ nhiễu, chỉ giữ lại những điểm vào lệnh thực sự đáng chú ý. Sau 10 ngày, hệ thống tự nhìn lại từng tín hiệu — đúng hay sai — tích lũy dần độ chính xác theo thời gian sử dụng. Kết quả được đẩy thẳng về Telegram cá nhân ngay khi có tín hiệu, pattern hiển thị realtime trên TradingView tích hợp trong Next.js.