Hệ thống đặt hàng qua mã QR cho nhà hàng (QR-based restaurant ordering system) – đa tenant, thời gian thực, với tích hợp thanh toán.
- Tổng quan
- Kiến trúc & Thành phần
- Yêu cầu hệ thống
- Hướng dẫn cài đặt & chạy localhost
- Hướng dẫn sử dụng môi trường đã deploy
- Khắc phục sự cố
- CI/CD Pipeline
- Cấu trúc dự án
- Tính năng chính
- Tài liệu
- Trạng thái dự án
- Phát triển
- Bảo mật
- Hỗ trợ & Đóng góp
| Yêu cầu | Phiên bản tối thiểu | Ghi chú |
|---|---|---|
| Node.js | ≥18.0.0 | Khuyến nghị 20 LTS hoặc cao hơn |
| pnpm | ≥8.0.0 | Package manager cho monorepo |
| Docker | ≥24.0 | Cho PostgreSQL & Redis (recommended) |
| Docker Compose | ≥2.20 | Bundled với Docker Desktop |
# Kiểm tra Node.js
node --version # Should output v18.0.0 or higher
# Kiểm tra pnpm
pnpm --version # Should output 8.0.0 or higher
# Kiểm tra Docker
docker --version
docker compose version- Google OAuth: Chỉ cần cấu hình
.envnếu muốn login qua Google (không bắt buộc cho localhost) - SePay Payment: Chỉ cần khóa API nếu muốn test thanh toán thực (không bắt buộc cho localhost)
TKQR-in Ordering Platform (tên dự án: TKOB_QROrderSystem) là một nền tảng tạo hóa đơn đầy đủ cho nhà hàng cho phép:
- 🔐 Khách hàng: Quét mã QR → xem menu → thêm vào giỏ → thanh toán trực tiếp
- 📱 Chủ nhà hàng/Admin: Quản lý menu, bàn, QR, đơn hàng, nhân viên, phân tích, đăng ký
- 👨💼 Nhân viên: Quản lý bàn, dịch vụ, xem đơn hàng
- 👨🍳 Bếp (KDS): Xem đơn hàng theo ưu tiên, cập nhật trạng thái
Tính năng chính:
- ✅ Multi-tenant isolation (application-level)
- ✅ WebSocket thời gian thực cho cập nhật đơn hàng
- ✅ Tích hợp thanh toán SePay QR + webhook
- ✅ RBAC (Role-Based Access Control): OWNER, STAFF, KITCHEN
- ✅ Xác thực Google OAuth cho chủ nhà hàng/nhân viên
- ✅ Yêu cầu hóa đơn từ khách hàng + thông báo thời gian thực cho nhân viên
- ✅ Hệ thống đánh giá & xếp hạng, khuyến mãi
- ✅ Analytics: doanh thu, đơn hàng, mục phổ biến
- ✅ Database audit logs, hóa đơn
Monorepo pnpm workspace với 3 ứng dụng chính + 1 UI package dùng chung:
| Ứng dụng | Loại | Vị trí | Mô tả | Port | Dev Script |
|---|---|---|---|---|---|
| API | NestJS | source/apps/api |
Backend REST API (~140+ endpoints) | 3000 | pnpm dev (from root) |
| Web Tenant | Next.js 15 | source/apps/web-tenant |
Dashboard admin/staff/kitchen | 3002 | pnpm dev:web-tenant |
| Web Customer | Next.js 15 | source/apps/web-customer |
Ứng dụng gọi món khách hàng | 3001 | pnpm dev:web-customer |
| UI Package | Shared | packages/ui |
Shared UI components (TailwindCSS) | — | — |
- Framework: NestJS 10+
- Database: PostgreSQL 16 + Prisma ORM (21 migrations)
- Cache: Redis (menu, session, queue)
- Real-time: WebSocket via Socket.IO
- Payment: SePay QR integration
- Validation: Zod, class-validator
- Framework: Next.js 15 (App Router)
- UI: React 19, TailwindCSS v4, Shadcn/ui
- State: TanStack Query v5 (server state), Zustand (client state)
- API Client: Axios + interceptors
- Icons: lucide-react
- PostgreSQL 16 (Docker Compose) – Primary database
- Redis 7 (Docker Compose) – Cache & session storage
- MinIO (Optional) – S3 mock cho upload ảnh menu
git clone https://github.com/tkob-team/TKOB_QROrderSystem
cd TKOB_QROrderSystempnpm installLưu ý: Lệnh này cài tất cả packages cho tất cả ứng dụng (API, web-customer, web-tenant, UI).
Bạn cần tạo file .env cho mỗi ứng dụng. Mỗi ứng dụng đã có .env.example làm mẫu.
cd source/apps/api
# Copy template
cp .env.example .env
# Edit .env và điền các giá trị sau (tối thiểu):Các biến bắt buộc (giá trị mẫu cho localhost):
# API
API_PORT=3000
# Database (sử dụng PostgreSQL từ Docker Compose)
DATABASE_URL=postgresql://postgres:tkob_bathangkho123@localhost:5432/qr_ordering
# Logging
LOG_LEVEL=debug
NODE_ENV=development
# JWT (tạo chuỗi ngẫu nhiên, ví dụ: openssl rand -base64 32)
JWT_SECRET=your-super-secret-key-here
JWT_ACCESS_TOKEN_EXPIRES_IN=1h
JWT_REFRESH_TOKEN_EXPIRES_IN=7d
# Redis (từ Docker Compose)
REDIS_HOST=localhost
REDIS_PORT=6379
# Email (tuỳ chọn cho localhost)
EMAIL_PROVIDER=sendgrid
SENDGRID_API_KEY=your-sendgrid-key
# OTP
OTP_LENGTH=6
OTP_EXPIRY_SECONDS=600
# Storage
STORAGE_DRIVER=local
MAX_FILE_SIZE=5242880
ALLOWED_MIME_TYPES=image/jpeg,image/png,image/webp
# CORS
CORS_ORIGINS=http://localhost:3001,http://localhost:3002,http://localhost:3000
# Optional: SePay Payment (chỉ khi muốn test thanh toán)
# PAYMENT_PROVIDER=sepay
# SEPAY_API_URL=https://api.sepay.vn/v1
# SEPAY_SECRET_KEY=your-sepay-keyFile tham khảo: source/apps/api/.env.example
cd ../.. # Quay về rootcd source/apps/web-tenant
# Copy template
cp .env.example .env.local
# Edit .env.local và điền:NEXT_PUBLIC_API_URL=http://localhost:3000/api/v1
NEXT_PUBLIC_CUSTOMER_APP_URL=http://localhost:3001
NEXT_PUBLIC_APP_NAME=TKQR Admin
# Optional: Logging (development only)
NEXT_PUBLIC_USE_LOGGING=falseFile tham khảo: source/apps/web-tenant/.env.example
cd ../..cd source/apps/web-customer
# Copy template
cp .env.example .env.local
# Edit .env.local và điền:NEXT_PUBLIC_API_URL=http://localhost:3000/api/v1
NEXT_PUBLIC_APP_NAME=TKQR Order
# Optional: Logging (development only)
NEXT_PUBLIC_USE_LOGGING=falseFile tham khảo: source/apps/web-customer/.env.example
cd ../..cd source/docker
# Khởi động containers
docker compose up -d
# Kiểm tra status
docker compose ps
# Expected output: PostgreSQL + Redis running
# Logs: docker compose logs -f postgres redisServices khởi động:
- PostgreSQL:
localhost:5432(user:postgres, password:tkob_bathangkho123) - Redis:
localhost:6379
cd ../.. # Quay về rootcd source/apps/api
# Generate Prisma Client
pnpm prisma:generate
# Run migrations
pnpm db:migrate
# Optional: Seed database (nếu không có, migration sẽ tạo schema cơ bản)
# (Hiện tại repo không cung cấp seed script mẫu)
cd ../..Kiểm tra:
# Mở Prisma Studio (giao diện quản lý database)
cd source/apps/api
pnpm db:studio
# Mở browser: http://localhost:5555
cd ../..Mở 3 terminal riêng từ thư mục root và chạy các lệnh dưới đây:
pnpm dev
# Hoặc chỉ API:
# cd source/apps/api && pnpm start:devOutput mong đợi:
🚀 Application is running on port 3000
📚 API Documentation: http://localhost:3000/api-docs
Kiểm tra health:
curl http://localhost:3000/health
# Expected response: { "status": "ok" }pnpm dev:web-customerOutput mong đợi:
▲ Next.js 15.x
- Local: http://localhost:3001
pnpm dev:web-tenantOutput mong đợi:
▲ Next.js 15.x
- Local: http://localhost:3002
Mở browser và kiểm tra:
| Ứng dụng | URL | Mô tả |
|---|---|---|
| API Health | http://localhost:3000/health | Health check |
| Swagger Docs | http://localhost:3000/api-docs | REST API documentation |
| Customer App | http://localhost:3001 | Ứng dụng gọi món khách hàng |
| Tenant Dashboard | http://localhost:3002 | Bảng điều khiển admin/staff |
Test flow đơn giản:
- Truy cập http://localhost:3002 (Tenant app)
- Đăng ký tài khoản chủ nhà hàng
- Tạo menu & bàn
- Tạo QR code cho bàn
- Truy cập http://localhost:3001 (Customer app)
- Quét QR code (hoặc copy URL từ QR)
- Xem menu & thêm vào giỏ
- Checkout
Khi hệ thống được deploy lên production, bạn có thể truy cập các URL sau:
| Ứng dụng | URL | Mô tả |
|---|---|---|
| Customer App | https://tkob-qr-order-system-web-customer.vercel.app |
Ứng dụng gọi món khách hàng |
| Tenant/Admin App | https://tkob-qrorder-system.vercel.app |
Dashboard quản lý nhà hàng |
| API Base URL | https://tkob.nphoang.me/ |
REST API |
| API Swagger Docs | https://tkob.nphoang.me/api-docs |
Tài liệu API |
Ghi chú: Thay example.com bằng tên miền thực tế của bạn.
- Truy cập Tenant Dashboard:
https://tkob-qrorder-system.vercel.app - Đăng ký / Đăng nhập với email hoặc Google
- Thiết lập menu:
- Vào phần "Menu"
- Tạo danh mục (Phở, Bánh mì, Đồ uống, v.v.)
- Thêm mục vào mỗi danh mục với giá
- Tạo bàn:
- Vào phần "Tables" → "Create"
- Tạo bàn (ví dụ: T01, T02, T03)
- Tạo / tạo lại QR code → Tải xuống (PNG/SVG/PDF/ZIP)
- In QR codes hoặc dán trên bàn
- Quét QR code tại bàn (hoặc nhập URL thủ công)
- Truy cập Customer App:
https://tkob-qr-order-system-web-customer.vercel.app/t/{qrToken} - Duyệt menu theo danh mục
- Thêm mục vào giỏ:
- Chọn số lượng
- Chọn modifier (nếu có: size, topping, v.v.)
- Xem giỏ → Checkout
- Thanh toán:
- Quét QR code SePay với app ngân hàng hỗ trợ
- Hoặc nhập số tiền thủ công (tùy setup)
- Chờ – Đơn hàng được gửi đến bếp
- Truy cập KDS (Kitchen Display System):
https://tkob-qrorder-system.vercel.app/kds - Xem danh sách đơn hàng → Sắp xếp theo ưu tiên
- Cập nhật trạng thái:
- "Preparing" → "Ready" → "Completed"
- Thông báo real-time được gửi tới khách hàng
Khách hàng nhìn thấy cập nhật trạng thái real-time trên app và nhận thông báo:
- Đơn hàng đã nhận
- Đang chuẩn bị
- Sẵn sàng phục vụ
Lưu ý: Nếu production có seed demo accounts, liệt kê dưới đây:
| Vai trò | Mật khẩu | Ghi chú | |
|---|---|---|---|
| Admin/Owner | owner@example.com |
DemoPass123! |
Nhà hàng mẫu |
| Staff | staff@example.com |
DemoPass123! |
Phục vụ viên mẫu |
| Kitchen | kitchen@example.com |
DemoPass123! |
Bếp mẫu |
Hoặc: Nếu không có demo accounts, tạo tài khoản mới tại https://tkob-qrorder-system.vercel.app/auth/signup
| Vai trò | Quyền hạn |
|---|---|
| Admin/Owner | Quản lý tất cả (menu, bàn, nhân viên, thanh toán, analytics) |
| Staff | Quản lý bàn, xem đơn hàng, phục vụ |
| Kitchen | Xem đơn hàng KDS, cập nhật trạng thái |
| Customer | Đặt hàng qua QR, thanh toán, xem trạng thái |
Nếu deployed config hỗ trợ Google Login:
- Chủ nhà hàng có thể đăng nhập qua Google
- Cần email Google hợp lệ
- (Secrets được lưu trữ an toàn trên server, không hiển thị)
- Khách hàng quét QR code với ứng dụng ngân hàng
- Hỗ trợ các ngân hàng Việt Nam qua VietQR
- Thanh toán được xác nhận tự động hoặc qua webhook
Vấn đề: "Port 3000/3001/3002 already in use"
Giải pháp:
# Tìm process đang dùng port
lsof -i :3000 # macOS/Linux
netstat -ano | findstr :3000 # Windows
# Giết process
kill -9 <PID> # macOS/Linux
taskkill /PID <PID> /F # Windows
# Hoặc chạy trên port khác
cd source/apps/api && PORT=3005 pnpm start:devVấn đề: "ConnectionRefusedError: connect ECONNREFUSED 127.0.0.1:5432"
Giải pháp:
# Kiểm tra Docker containers
docker compose ps
# Nếu PostgreSQL không running
cd source/docker
docker compose up -d postgres
docker compose logs postgres
# Chờ 10-15 giây để PostgreSQL sẵn sàng
# Check health
docker compose exec postgres pg_isreadyVấn đề: "Error: connect ECONNREFUSED 127.0.0.1:6379"
Giải pháp:
cd source/docker
# Khởi động Redis
docker compose up -d redis
docker compose logs redis
# Test kết nối
docker compose exec redis redis-cli ping
# Expected: PONGVấn đề: "Migration pending" hoặc "Schema not up to date"
Giải pháp:
cd source/apps/api
# Xem migrations
pnpm prisma:generate
pnpm db:migrate
# Nếu vẫn lỗi, reset database (mất dữ liệu!)
pnpm db:resetVấn đề: "Error: JWT_SECRET is not defined"
Giải pháp:
- Kiểm tra file
.envtồn tại - Điền tất cả biến bắt buộc (xem Bước 3)
- Khởi động lại ứng dụng
Vấn đề: "Redirect URI mismatch" khi đăng nhập qua Google
Giải pháp:
- Vào Google Cloud Console: https://console.cloud.google.com
- Chọn dự án
- Vào "Credentials" → "OAuth 2.0 Client IDs"
- Thêm redirect URI:
- Localhost:
http://localhost:3002/auth/google/callback - Production:
https://tkob-qrorder-system.vercel.app/auth/google/callback
- Localhost:
- Lưu và khởi động lại
Vấn đề: "Real-time updates không hoạt động"
Giải pháp:
- Kiểm tra API chạy trên cùng host/port (3000)
- Kiểm tra CORS config:
# In source/apps/api/src/main.ts # CORS_ORIGINS phải bao gồm frontend URL
- Kiểm tra browser console (F12 → Network → WS)
Vấn đề: "Type error" hoặc build fail
Giải pháp:
# Type check
pnpm type-check
# Rebuild all
pnpm clean
pnpm install
pnpm build
# Hoặc từng app
cd source/apps/api && pnpm buildRepo sử dụng GitHub Actions để tự động test, build, và deploy.
Workflow File: .github/workflows/deploy.yml
| Trigger | Chi tiết |
|---|---|
Push to main |
Chạy test → build Docker image → deploy |
| Pull Request | Chạy test → linting |
| Manual | Có thể trigger từ GitHub Actions tab |
-
Test (CI): Chạy
pnpm testtrên API- Prisma migration check
- Unit tests (nếu có)
-
Build (CD): Build Docker image
- Tag:
latest,sha-{commit},pr-{number} - Push to GitHub Container Registry
- Tag:
-
Deploy (CD): Deploy lên AWS EC2
- Copy
docker-compose.prod.yml - Pull image mới
- Restart services (zero-downtime)
- Cleanup old images
- Copy
Vào: https://github.com/{owner}/{repo}/actions
pnpm lint pnpm type-check
---
## Tính năng chính (Chi tiết)
### 👥 Khách hàng (Customer)
- Quét QR tại bàn → thiết lập phiên
- Duyệt menu theo danh mục, tìm kiếm
- Thêm mục với modifier (SINGLE/MULTI choice)
- Giỏ hàng + thanh toán qua SePay QR
- Theo dõi trạng thái đơn hàng theo thời gian thực
- Hủy đơn hàng (cửa sổ 5 phút)
- Đánh giá & xếp hạng
### 🏪 Chủ nhà hàng / Admin
- **Hồ sơ & Cài đặt**: Thông tin nhà hàng, logo, email
- **Menu**: Tạo danh mục → mục → modifier (ảnh tải hàng loạt)
- **Bàn & QR**: CRUD, tạo/tạo lại QR (PNG/SVG/PDF/ZIP)
- **Nhân viên**: Lời mời email, gán vai trò (STAFF/KITCHEN), giới hạn theo gói
- **Đơn hàng**: Xem chi tiết, lịch sử, thêm mục
- **Thanh toán**: Cấu hình khóa SePay, xem webhook log
- **Khuyến mãi**: Tạo mã giảm giá (PERCENTAGE/FIXED)
- **Hóa đơn**: Tạo từ đơn hàng, xuất PDF
- **Analytics**: Doanh thu, mục phổ biến, phân bố theo giờ, hiệu suất bàn
- **Đăng ký**: FREE/BASIC/PREMIUM, theo dõi sử dụng, nâng cấp qua SePay
### 👨💼 Nhân viên (Staff)
- Xem bàn, trạng thái phiên
- Xem đơn hàng, phục vụ khách hàng
- Ghi chú, chuyển yêu cầu bếp
### 👨🍳 Bếp (KDS – Kitchen Display System)
- Xem danh sách đơn hàng theo ưu tiên (Thường/Cao/Khẩn cấp)
- Cập nhật trạng thái: Chuẩn bị → Hoàn thành → Phục vụ
- Thống kê thực tế
- WebSocket cập nhật ngay lập tức
---
## 📚 Tài liệu
**Tài liệu chính:**
- [Setup Guide](docs/common/SETUP.md) – Cài đặt env, database migration, troubleshooting
- [Architecture](docs/common/ARCHITECTURE.md) – Kiến trúc toàn hệ thống, tech stack, security
- [User Guide](docs/common/USER_GUIDE.md) – Hướng dẫn cho từng vai trò (customer, admin, staff, kitchen)
- [OpenAPI Spec](docs/common/OPENAPI.md) – Tài liệu REST API (~140+ operations)
- [Contributing Guide](docs/common/CONTRIBUTING.md) – Quy trình đóng góp, code standards
**Tài liệu Frontend:**
- [Web Tenant README](docs/frontend/web-tenant/README.md) – Architecture, features, setup
- [Web Customer README](docs/frontend/web-customer/README.md) – Architecture, features, setup
- [RBAC Guide](docs/frontend/RBAC_GUIDE.md) – Role-based access control patterns
**Tài liệu Backend:**
- [Backend README](docs/backend/README.md)
- [Database Schema](docs/backend/database/description.md) – Tất cả bảng, trường, quan hệ
- [ER Diagram](docs/backend/database/er_diagram.md)
- [WebSocket Guide](docs/backend/websocket-client.md)
---
## Trạng thái dự án
### ✅ Đã triển khai (MVP)
| Module | Trạng thái |
|--------|-----------|
| Xác thực (JWT + OTP) | ✅ |
| Google OAuth (Owner/Staff) | ✅ |
| Multi-tenant | ✅ |
| Quản lý menu & danh mục | ✅ |
| Bàn & QR Code (tạo/tạo lại/tải xuống) | ✅ |
| Giỏ hàng & checkout | ✅ |
| Đơn hàng (tạo, hủy, theo dõi) | ✅ |
| Yêu cầu hóa đơn + thông báo staff | ✅ |
| Thanh toán (SePay QR) | ✅ |
| WebSocket (real-time updates) | ✅ |
| KDS (Kitchen Display System) | ✅ |
| Quản lý nhân viên + RBAC | ✅ |
| Đăng ký (gói FREE/BASIC/PREMIUM) | ✅ |
| Analytics & Reports | ✅ |
| Đánh giá & Xếp hạng | ✅ |
| Khuyến mãi & Mã giảm giá | ✅ |
| Hóa đơn | ✅ |
| CI/CD Pipeline (GitHub Actions) | ⚠️ Không hoàn chỉnh* |
*Xem [CI_CD.md](docs/common/CI_CD.md) cho chi tiết. Blocker: `docker-compose.prod.yml` bị thiếu.
### 📋 Dự định (Planned)
- Thanh toán thẻ (Card online) – Dự tính Q2 2026
- Tích hợp Facebook Orders
- Mobile app (React Native) – Tối ưu hóa mobile
- Advanced analytics (Predictive)
- Loyalty program
---
## 🛠️ Phát triển
### Folder Structure
TKOB_QROrderSystem/
├── docs/
│ ├── common/ # Shared documentation
│ ├── backend/ # Backend-specific docs
│ └── frontend/ # Frontend-specific docs
├── source/
│ ├── apps/
│ │ ├── api/ # NestJS backend
│ │ ├── web-customer/ # Customer app (Next.js)
│ │ └── web-tenant/ # Tenant dashboard (Next.js)
│ ├── packages/ # Shared packages
│ │ └── ui/ # Shared UI components
│ └── docker/ # docker-compose.yaml
├── packages/
│ └── ui/ # Root UI package (aliases)
├── package.json # Root workspace
├── pnpm-workspace.yaml # Workspace config
└── README.md # This file
Cả frontend lẫn backend tuân theo Clean Architecture:
Frontend (web-customer, web-tenant):
app/– Presentation Layer (routing)src/features/– Domain Layer (business logic)src/shared/– Shared Layer (reusable UI, hooks)src/lib/– Infrastructure Layer (API client)
Backend (api):
src/modules/– Feature modules (auth, menu, orders, etc.)src/common/– Shared utilities, decorators, guardssrc/database/– Prisma schema, migrationssrc/main.ts– App bootstrap
- Authentication: JWT bearer tokens + refresh token rotation
- Authorization: Role-based access control (OWNER, STAFF, KITCHEN)
- Multi-tenancy: Tenant isolation via
tenantId(application-level) - Payment: Webhook validation + polling fallback
- Database: Audit logs cho thay đổi quan trọng
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Contributing: Xem CONTRIBUTING.md
MIT License © 2025 TonKnight – Xem LICENSE