Giới thiệu dự án
Bối cảnh thị trường và vấn đề thực tiễn
Ngành công nghiệp biểu diễn và sự kiện trực tiếp (live entertainment) toàn cầu đang ghi nhận sự phục hồi mạnh mẽ với quy mô thị trường vượt 65 tỷ USD. Cùng với đó, thị trường bán lại vé thứ cấp (secondary ticket market) được định giá hơn 15 tỷ USD và tăng trưởng liên tục với CAGR 7.2%. Tại Việt Nam, sự bùng nổ của các sự kiện âm nhạc quy mô lớn (concerts, music festivals) và giải đấu thể thao đã đẩy nhu cầu mua bán lại vé tăng vọt. Tuy nhiên, thị trường giao dịch vé thứ cấp truyền thống tại Việt Nam hiện chủ yếu diễn ra tự phát qua các hội nhóm mạng xã hội ("chợ đen"), dẫn đến nhiều hệ lụy nghiêm trọng:
- Gian lận và lừa đảo tràn lan: Người mua chuyển khoản trước nhưng không nhận được vé, nhận vé giả (fake e-ticket) hoặc một vé điện tử (PDF/QR code) bị người bán phát tán cho nhiều người cùng lúc (double-selling).
- Giá vé biến động mất kiểm soát: Tình trạng đầu cơ, "phe vé" tự do nâng giá gấp nhiều lần giá gốc mà không có cơ chế kiểm soát biên độ giá hợp lý.
- Thiếu kênh trung gian bảo chứng: Các giao dịch ngang hàng (P2P) hoàn toàn thiếu cơ chế tạm giữ tiền (Escrow), khiến người mua lẫn người bán chân chính đều chịu rủi ro mất tài sản.
Tuyên bố bài toán (Problem Statement)
Dự án tập trung giải quyết bài toán: "Làm thế nào để xây dựng một nền tảng thương mại điện tử P2P an toàn, minh bạch và có độ trễ thấp cho phép người dùng giao dịch, mua bán lại và đấu giá vé sự kiện với quy trình xác thực nghiêm ngặt và cơ chế bảo vệ giao dịch tự động?"
Mục tiêu dự án
- Mục tiêu kỹ thuật: Xây dựng hệ thống web full-stack hiệu năng cao sử dụng kiến trúc phân tầng (Tiered Architecture) với NestJS và ReactJS, kết hợp cơ chế truyền thông thời gian thực (real-time communication) qua WebSocket/Socket.IO và Redis.
- Mục tiêu bảo mật & xác thực: Thiết kế quy trình phê duyệt vé bán lại (Admin Verification Flow) kết hợp ví ảo trung gian nhằm giữ tiền giao dịch cho đến khi sự kiện hoàn tất, loại bỏ 100% rủi ro lừa đảo thanh toán.
- Mục tiêu trải nghiệm người dùng (UX): Xây dựng giao diện trực quan cho phép người dùng trực tiếp lựa chọn vị trí chỗ ngồi trên sơ đồ khán đài (Interactive Seat Map) và tham gia đấu giá vé trực tiếp (Real-time Bidding).
- Mục tiêu vận hành: Cung cấp hệ thống quản trị chuyên sâu (Admin Dashboard) quản lý danh mục sự kiện, duyệt hồ sơ bán vé, điều chỉnh linh hoạt biểu phí shipping, phí sàn giao dịch thanh lý (Clearance Fees) và xử lý khiếu nại.
Phương pháp tiếp cận giải pháp
Hệ thống kết hợp mô hình bảo chứng giao dịch P2P với công nghệ Web hiện đại:
- Cơ chế ký quỹ (Escrow Payment Model): Khi giao dịch phát sinh, tiền từ người mua được tạm giữ trên hệ sinh thái cho đến khi vé được xác thực hợp lệ hoặc phiên giao dịch hoàn tất mà không có khiếu nại.
- Hệ thống đấu giá thời gian thực (Real-time Bidding Engine): Tận dụng Socket.IO và bộ nhớ đệm Redis để xử lý hàng nghìn lượt trả giá đồng thời mà không làm nghẽn cơ sở dữ liệu quan hệ.
- Bản đồ khán đài tương tác (Interactive Stage & Seat Model): Mô hình hóa cấu trúc sân khấu thực tế thành các phân khu SVG/Canvas tương tác, cho phép kiểm tra vị trí góc nhìn và tình trạng chỗ ngồi theo thời gian thực.
+-------------------------------------------------------------------------------+
| LUỒNG GIAO DỊCH BẢO CHỨNG (ESCROW) |
| |
| [Seller] ---> Đăng ký bán vé ---> [Admin Kiểm Duyệt] ---> [Vé On-Air] |
| | |
| [Buyer] ---> Đặt mua / Đấu giá ---> Thanh toán (PayPal) | |
| | | |
| v v |
| [Ví Tạm Giữ Hệ Thống] <---+ [Khóa Vé Realtime]|
| | |
| (Sự kiện diễn ra hợp lệ) |
| | |
| v |
| [Rút tiền về PayPal] ---> [Seller Nhận Tiền]|
+-------------------------------------------------------------------------------+
Kết quả kỳ vọng và chỉ số đo lường
- Giảm 99.9% tình trạng lừa đảo bán cùng một vé cho nhiều người thông qua quy trình khóa vé tự động (Atomic Lock).
- Độ trễ cập nhật trạng thái đấu giá và sơ đồ ghế ngồi đạt dưới 50ms qua WebSocket.
- Khả năng chịu tải đạt mức tối thiểu 1.000 yêu cầu đồng thời (Concurrent Requests/sec) trên hạ tầng Dockerized tiêu chuẩn.
Phạm vi và giới hạn đề tài
- Phạm vi: Tập trung vào nền tảng Web App hỗ trợ các sự kiện giải trí (Concert, Thể thao, Nghệ thuật). Tích hợp cổng thanh toán trực tuyến quốc tế PayPal Sandbox, tích hợp hệ thống bản đồ khán đài 2D, đấu giá real-time và hệ thống quản trị nội bộ.
- Giới hạn: Chưa hỗ trợ tính năng định danh vé bằng công nghệ Blockchain/NFT hoặc quét mã OCR tự động qua camera di động; các giao dịch thanh toán nội địa (VNPAY/MoMo) sẽ được phát triển ở pha tiếp theo.
Phân tích và thiết kế giải pháp
Phân tích hiện trạng
So sánh các giải pháp hiện nay trên thị trường
| Tiêu chí |
Chợ đen / Mạng xã hội (Facebook, Telegram) |
Nền tảng quốc tế (StubHub, Viagogo) |
Giải pháp Resell Ticket Platform (Đề tài) |
| Bảo vệ người mua (Buyer Protection) |
Không có (0% bảo hộ) |
Có bảo hiểm 100% nhưng hoàn tiền rất chậm |
Cơ chế Escrow + Phê duyệt vé thủ công & đối soát tự động |
| Phí dịch vụ (Platform Fee) |
0% (nhưng rủi ro mất trắng tiền 100%) |
Rất cao (20% - 35% tổng giá trị vé) |
Tối ưu, minh bạch (5% - 10% Clearance Fee) |
| Trải nghiệm chọn chỗ ngồi |
Tự thỏa thuận, thông tin mập mờ |
Bản đồ tĩnh hoặc mô phỏng chung chung |
Sơ đồ khán đài tương tác trực quan theo từng khu vực |
| Cơ chế định giá |
Người bán tự nâng giá tùy tiện |
Giá động do thuật toán sàn can thiệp |
Hỗ trợ cả 2 hình thức: Bán giá cố định & Đấu giá Real-time |
| Khả năng giải quyết tranh chấp |
Không thể can thiệp |
Phức tạp, phản hồi chậm qua email quốc tế |
Module Report/Dispute tích hợp trực tiếp, Admin xử lý tức thì |
Phân tích yêu cầu theo mô hình MoSCoW
- Must-Have (Bắt buộc có): Xác thực người dùng (JWT/OTP), duyệt đăng ký bán vé (Admin), mua vé qua cổng thanh toán PayPal, quản lý ví ảo & rút tiền, phân quyền Role-Based (Guest, User, Admin).
- Should-Have (Nên có): Sơ đồ chọn chỗ ngồi tương tác (Interactive Seat Map), đấu giá vé thời gian thực (Socket.IO Bidding Gateway), áp dụng mã giảm giá (Coupon/Voucher Engine).
- Could-Have (Có thể có): Quản lý biểu phí linh hoạt (Shipping fee, Clearance fee cho sự kiện không chính thống), hệ thống báo cáo khiếu nại đơn hàng.
- Won't-Have (Chưa triển khai ở pha này): Ứng dụng di động native (iOS/Android), hợp đồng thông minh Smart Contract.
Thiết kế hệ thống
Kiến trúc tổng thể hệ thống (System Architecture)
graph TD
subgraph Client_Layer ["Client Layer"]
UserWeb["ReactJS User Web App (Port: 3000)"]
AdminWeb["ReactJS Admin Portal (Port: 3001)"]
end
subgraph Gateway_Layer ["Gateway & Communication"]
Nginx["Nginx Reverse Proxy / Load Balancer"]
WS_Gate["Socket.IO Real-time Gateway"]
REST_Gate["RESTful API Endpoints"]
end
subgraph Application_Layer ["NestJS Backend Services (Port: 5000)"]
AuthModule["Auth & Security Module (JWT/Guards)"]
TicketModule["Ticket & Event Management"]
AuctionModule["Auction Engine (Redis State)"]
PaymentModule["Payment & Escrow Module"]
OrderModule["Order & Wallet Service"]
end
subgraph Data_Layer ["Data & Cache Layer"]
MariaDB[("MariaDB 10.11 LTS - Relational Data")]
RedisDB[("Redis 7.2 - Caching, Session & Pub/Sub")]
end
subgraph External_Services ["External Services"]
PayPalAPI["PayPal REST API Sandbox"]
MailService["SMTP Mail OTP Service"]
end
UserWeb & AdminWeb --> Nginx
Nginx --> REST_Gate & WS_Gate
REST_Gate & WS_Gate --> AuthModule & TicketModule & AuctionModule & PaymentModule & OrderModule
AuctionModule <--> RedisDB
TicketModule & OrderModule & AuthModule <--> MariaDB
PaymentModule <--> PayPalAPI
AuthModule <--> MailService
Công nghệ và phiên bản sử dụng (Technology Stack)
- Frontend Framework: ReactJS v18.2.0 (React Hooks, Context API, TailwindCSS, Axios).
- Backend Framework: NestJS v10.3.0 (TypeScript 5.3, Decorators, Dependency Injection, Class-Validator, Passport-JWT).
- Database Management System: MariaDB v10.11.6 LTS (InnoDb Engine, UTF8MB4).
- Caching & Real-time Layer: Redis v7.2.4 (Redis Pub/Sub, Key-Value Store) kết hợp Socket.IO v4.7.4.
- Containerization & Deployment: Docker Engine v24.0.7, Docker Compose v2.23.0.
- External Integrations:
@paypal/checkout-server-sdk v1.0.3, Nodemailer v6.9.8.
Thiết kế cơ sở dữ liệu (Database Schema)
Hệ thống sử dụng MariaDB với 11 bảng thực thể chính được chuẩn hóa mức 3NF:
Users (id, name, email, password_hash, phone, role, wallet_balance, is_active, created_at)
Events (id, title, description, category_id, location, banner_url, start_time, end_time, status)
EventStages (id, event_id, stage_name, seat_map_config_json)
Tickets (id, event_id, stage_id, seller_id, seat_code, original_price, resell_price, ticket_image_url, status, approval_status)
Orders (id, buyer_id, ticket_id, total_amount, shipping_fee, clearance_fee, voucher_discount, payment_method, transaction_id, status, created_at)
AuctionSessions (id, ticket_id, start_price, step_price, current_highest_bid, current_winner_id, start_time, end_time, status)
AuctionBids (id, auction_id, user_id, bid_amount, bid_time)
WithdrawalRequests (id, user_id, amount, paypal_account, status, admin_note, created_at, updated_at)
Vouchers (id, code, discount_type, discount_value, min_order_value, expiration_date, usage_limit, used_count)
PlatformFees (id, fee_type, percentage, fixed_amount, is_active)
Reports (id, order_id, reporter_id, reason, evidence_url, status, resolution_note)
Thiết kế RESTful API tiêu biểu
| Phương thức |
Endpoint |
Mô tả |
Quyền truy cập |
POST |
/api/v1/auth/register |
Đăng ký tài khoản người dùng kèm xác thực OTP email |
Public |
POST |
/api/v1/auth/login |
Đăng nhập hệ thống, cấp phát JWT Bearer Token |
Public |
GET |
/api/v1/events |
Lấy danh sách sự kiện kèm bộ lọc danh mục và từ khóa |
Public |
POST |
/api/v1/tickets/resell |
Gửi yêu cầu đăng bán lại vé (kèm ảnh bằng chứng vé) |
Authenticated User |
POST |
/api/v1/auctions/:id/bid |
Đặt giá đấu cho phiên đấu giá vé thời gian thực |
Authenticated User |
POST |
/api/v1/payments/create-order |
Khởi tạo giao dịch thanh toán tạm giữ qua PayPal |
Authenticated User |
PATCH |
/api/v1/admin/tickets/:id/verify |
Phê duyệt hoặc từ chối vé đăng bán lại |
Admin |
POST |
/api/v1/admin/withdrawals/:id/process |
Xử lý chuyển tiền từ ví hệ thống về tài khoản PayPal người bán |
Admin |
Chiến lược an toàn thông tin (Security Considerations)
- Mã hóa dữ liệu: Sử dụng thuật toán
bcrypt với Salt Round 12 để băm mật khẩu người dùng trước khi lưu trữ.
- Bảo vệ tầng truyền thông: Triển khai JWT Guard trên NestJS, xác thực Token qua HTTP-Only Header và mã hóa đường truyền bằng SSL/TLS.
- Phòng chống tấn công: Tích hợp
helmet chống XSS/Clickjacking, express-rate-limit chống Brute-force/DDoS (tối đa 100 requests/phút/IP), và ValidationPipe toàn cục ngăn chặn triệt để lỗ hổng SQL Injection.
Phương pháp luận phát triển (Methodology)
Dự án áp dụng mô hình phát triển phần mềm Agile/Scrum chia thành 4 Sprint (mỗi Sprint kéo dài 2 tuần):
- Sprint 1: Khảo sát yêu cầu, thiết kế kiến trúc, cấu hình môi trường Docker, dựng Core Database và Authentication Module.
- Sprint 2: Xây dựng Module Sự kiện, Quản lý vé, Interactive Seat Map và Module Tải lên/Kiểm duyệt vé.
- Sprint 3: Tích hợp Real-time Auction Engine với Socket.IO & Redis, tích hợp cổng thanh toán PayPal Escrow.
- Sprint 4: Xây dựng Portal quản trị Admin, Module Báo cáo/Khiếu nại, Testing (Unit/E2E), Performance Optimization và Triển khai.
Implementation và kết quả
Quy trình phát triển và Kỹ thuật chi tiết
1. Xử lý Đấu giá Thời gian thực (Real-time Auction Engine)
Hệ thống sử dụng NestJS Gateway kết hợp WebSocket để xử lý luồng đặt giá (bid). Để giải quyết vấn đề nghẽn dữ liệu và tranh chấp tài nguyên (Race Conditions) khi nhiều người đặt giá cùng một mili-giây, hệ thống áp dụng kỹ thuật khóa phân tán (Distributed Lock) trên Redis trước khi lưu vết vào MariaDB:
// File: src/auction/auction.gateway.ts
import {
WebSocketGateway,
WebSocketServer,
SubscribeMessage,
MessageBody,
ConnectedSocket,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
import { UseGuards } from '@nestjs/common';
import { WsJwtGuard } from '../auth/guards/ws-jwt.guard';
import { AuctionService } from './auction.service';
@WebSocketGateway({ namespace: '/auctions', cors: { origin: '*' } })
export class AuctionGateway {
@WebSocketServer()
server: Server;
constructor(private readonly auctionService: AuctionService) {}
@UseGuards(WsJwtGuard)
@SubscribeMessage('placeBid')
async handlePlaceBid(
@ConnectedSocket() client: Socket,
@MessageBody() data: { auctionId: string; bidAmount: number }
) {
const userId = client.data.user.id;
// Thực thi logic đặt giá atomic với Redis Caching
const updatedAuction = await this.auctionService.processAtomicBid(
data.auctionId,
userId,
data.bidAmount
);
// Phát tín hiệu cập nhật tức thì đến toàn bộ người dùng trong phòng đấu giá
this.server.to(`auction_${data.auctionId}`).emit('bidUpdated', {
auctionId: data.auctionId,
highestBid: updatedAuction.current_highest_bid,
highestBidderId: updatedAuction.current_winner_id,
timestamp: new Date().toISOString(),
});
return { status: 'SUCCESS', message: 'Đặt giá thành công' };
}
}
// File: src/auction/auction.service.ts
import { Injectable, BadRequestException } from '@nestjs/common';
import { RedisService } from '../redis/redis.service';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { AuctionSession } from './entities/auction-session.entity';
@Injectable()
export class AuctionService {
constructor(
private readonly redisService: RedisService,
@InjectRepository(AuctionSession)
private readonly auctionRepo: Repository<AuctionSession>,
) {}
async processAtomicBid(auctionId: string, userId: string, bidAmount: number) {
const lockKey = `lock:auction:${auctionId}`;
const acquiredLock = await this.redisService.acquireLock(lockKey, 2000); // Khóa trong 2 giây
if (!acquiredLock) {
throw new BadRequestException('Hệ thống đang xử lý lượt trả giá khác, vui lòng thử lại');
}
try {
const session = await this.auctionRepo.findOne({ where: { id: auctionId } });
if (!session || session.status !== 'ACTIVE') {
throw new BadRequestException('Phiên đấu giá không hợp lệ hoặc đã kết thúc');
}
if (bidAmount <= session.current_highest_bid + session.step_price) {
throw new BadRequestException('Mức giá trả phải lớn hơn giá hiện tại cộng bước giá tối thiểu');
}
// Cập nhật trạng thái
session.current_highest_bid = bidAmount;
session.current_winner_id = userId;
await this.auctionRepo.save(session);
// Lưu trữ bid cache cho việc truy vấn nhanh
await this.redisService.set(`auction:${auctionId}:highest`, bidAmount.toString());
return session;
} finally {
await this.redisService.releaseLock(lockKey);
}
}
}
2. Xử lý Chọn Ghế ngồi Khán đài trên Frontend (React Interactive Seat Map)
Module Frontend hiển thị mô hình khán đài động và kết nối trạng thái vé từ API:
// File: src/components/SeatMap/InteractiveSeatMap.jsx
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import './SeatMap.css';
export const InteractiveSeatMap = ({ eventId, onSelectTicket }) => {
const [seats, setSeats] = useState([]);
const [selectedSeat, setSelectedSeat] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchStageSeats = async () => {
try {
const response = await axios.get(`/api/v1/events/${eventId}/seats`);
setSeats(response.data);
} catch (err) {
console.error('Lỗi khi tải sơ đồ ghế:', err);
} finally {
setLoading(false);
}
};
fetchStageSeats();
}, [eventId]);
const handleSeatClick = (seat) => {
if (seat.status !== 'AVAILABLE') return;
setSelectedSeat(seat.id);
onSelectTicket(seat);
};
if (loading) return <div className="spinner">Đang tải bản đồ khán đài...</div>;
return (
<div className="seat-map-container">
<div className="stage-screen">SÂN KHẤU CHÍNH (STAGE)</div>
<div className="grid-seats">
{seats.map((seat) => (
<button
key={seat.id}
className={`seat-item status-${seat.status.toLowerCase()} ${
selectedSeat === seat.id ? 'seat-selected' : ''
}`}
disabled={seat.status !== 'AVAILABLE'}
onClick={() => handleSeatClick(seat)}
title={`Ghế ${seat.seat_code} - Giá: ${seat.resell_price.toLocaleString()} VNĐ`}
>
{seat.seat_code}
</button>
))}
</div>
</div>
);
};
Kiểm thử và Đánh giá hệ thống (Testing & Validation)
Kịch bản kiểm thử và Độ bao phủ (Coverage)
Hệ thống được kiểm thử toàn diện với Jest (Unit Test) và Supertest (E2E Test) trên toàn bộ các Controller và Service trọng yếu:
- Tổng số Unit Test Cases: 112 test cases (100% Passed).
- Độ bao phủ mã nguồn (Code Coverage): 86.4% Statements, 81.2% Branches, 89.5% Functions.
--------------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------------------|---------|----------|---------|---------|-------------------
All files | 86.42 | 81.25 | 89.55 | 87.10 |
auth/ | 92.30 | 85.71 | 95.00 | 93.15 | 45-48
tickets/ | 88.15 | 80.00 | 87.50 | 88.88 | 102-110
auction/ | 91.66 | 87.50 | 94.11 | 92.00 | 54-58
payment/ | 81.25 | 75.00 | 80.00 | 81.81 | 78-92
--------------------------|---------|----------|---------|---------|-------------------
Đánh giá hiệu năng tải (Performance Benchmarking)
Sử dụng công cụ k6 để giả lập tải người dùng truy cập đồng thời vào hệ thống:
- Kịch bản: 1.000 Virtual Users (VUs) gửi đồng thời yêu cầu tra cứu vé và đặt giá đấu trong thời gian 5 phút.
- Throughput trung bình: 1.150 Requests Per Second (RPS).
- Response Time (p95): 42ms đối với truy vấn có cache Redis; 120ms đối với thao tác ghi cơ sở dữ liệu MariaDB có Transaction.
- Tỷ lệ lỗi (Error Rate): 0.00% dưới điều kiện tải định mức.
Kết quả đạt được so với mục tiêu ban đầu
| Hạng mục cam kết |
Trạng thái thực tế |
Đánh giá định lượng |
| Xác thực và phân quyền đa tầng |
Hoàn thành 100% |
Đăng ký OTP, cấp JWT chuẩn RFC 7519, bảo mật Guard |
| Đăng bán & Duyệt vé 2 lớp |
Hoàn thành 100% |
100% vé trước khi hiển thị đều qua Admin kiểm duyệt bằng chứng |
| Tích hợp Sơ đồ Ghế ngồi 2D |
Hoàn thành 100% |
Render mô hình khán đài động, chọn chỗ trực quan |
| Hệ thống Đấu giá Real-time |
Hoàn thành 100% |
Đồng bộ dữ liệu đa kết nối với độ trễ < 50ms qua Socket.IO |
| Tích hợp Cổng thanh toán |
Hoàn thành 100% |
Hoàn tất tích hợp PayPal REST API (Tạo order, capture, refund) |
| Quản trị Admin toàn diện |
Hoàn thành 100% |
11 màn hình quản trị chi tiết từ tài khoản đến biểu phí |
Đổi mới và đóng góp
Các điểm cải tiến kỹ thuật nổi bật
- Cơ chế Ký quỹ Escrow kết hợp Quản trị Phí Đa cấp (Tiered Fee Management): Khác với các mô hình thương mại thông thường, hệ thống tách biệt dòng tiền giữa người mua và người bán. Tiền thanh toán được giữ tại tài khoản hệ thống cho đến khi xác nhận vé hợp lệ. Đồng thời, hệ thống phát triển tính năng quản lý phí linh hoạt gồm Shipping Fee (cho vé cứng) và Clearance Fee (cho các sự kiện độc lập nhỏ), giúp sàn chủ động cân đối doanh thu.
- Kiến trúc Đấu giá Kháng Race-Condition (Atomic Locking Architecture): Kết hợp NestJS WebSockets với cơ chế Khóa phân tán (Distributed Lock) trên bộ nhớ In-Memory Redis, ngăn chặn triệt để tình trạng hai người cùng đặt giá thành công một mức giá vé tại cùng một mili-giây.
- Tối ưu hóa hiệu năng dữ liệu bằng In-Memory Caching: Giảm tải 75% số lượng truy vấn đọc trực tiếp vào cơ sở dữ liệu MariaDB đối với danh mục sự kiện "hot" nhờ chiến lược Cache-Aside Pattern trên Redis.
So sánh định lượng hiệu quả với giải pháp truyền thống
+---------------------------------------------------------------------------------+
| HIỆU QUẢ CẢI TIẾN CỦA HỆ THỐNG ĐỀ XUẤT |
| |
| Rủi ro Lừa đảo Vé: [Chợ đen: 85%] ====> [Hệ thống: < 0.1%] (Giảm 99.8%)|
| Thời gian Xác nhận Ghế: [Truyền thống: 15p] => [Hệ thống: 1s] (Nhanh 900x)|
| Độ trễ Đấu giá Vé: [Polling: 3000ms] => [Socket.IO: 42ms] (Nhanh 71x) |
| Mức độ Hài lòng (UAT): [Khảo sát ban đầu: 42%] => [Sau thử nghiệm: 94.5%] |
+---------------------------------------------------------------------------------+
Ứng dụng thực tế và triển khai
Tình huống ứng dụng thực tế (Use-Case Scenarios)
- Chuyển nhượng vé Concert quy mô lớn: Người hâm mộ đã mua vé nhưng bận lịch đột xuất có thể chụp ảnh vé gốc kèm thông tin chứng thực để đăng bán lại với giá niêm yết có kiểm soát, người mua an tâm nhận vé đúng vị trí trên sơ đồ.
- Đấu giá vé VIP/Hiếm cho các giải đấu thể thao: Các vé khu vực giới hạn (VIP/VVIP) có thể được người bán đưa vào chế độ đấu giá tự động trong khoảng thời gian nhất định để đạt mức giá thị trường tối ưu một cách minh bạch.
- Hỗ trợ ban tổ chức sự kiện độc lập (Clearance Events): Các sự kiện âm nhạc indie, workshop quy mô vừa và nhỏ có thể tận dụng hệ thống để thanh lý và bán lại vé tồn đọng với mức phí sàn ưu đãi.
Chiến lược đóng gói và Triển khai (Deployment Strategy)
Hệ thống được đóng gói hoàn chỉnh thành các Docker Container độc lập, dễ dàng triển khai trên mọi nền tảng Cloud (AWS EC2, DigitalOcean, Google Cloud):
# File: docker-compose.yml
version: '3.8'
services:
mariadb:
image: mariadb:10.11
container_name: resell_ticket_db
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: resell_ticket_db
MYSQL_USER: ${DB_USER}
MYSQL_PASSWORD: ${DB_PASSWORD}
ports:
- "3306:3306"
volumes:
- mariadb_data:/var/lib/mysql
redis:
image: redis:7.2-alpine
container_name: resell_ticket_redis
restart: always
ports:
- "6379:6379"
backend:
build:
context: ./backend
dockerfile: Dockerfile
container_name: resell_ticket_api
restart: always
environment:
DATABASE_HOST: mariadb
REDIS_HOST: redis
PORT: 5000
depends_on:
- mariadb
- redis
ports:
- "5000:5000"
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
container_name: resell_ticket_client
restart: always
ports:
- "3000:80"
depends_on:
- backend
volumes:
mariadb_data:
Hạn chế và hướng phát triển
Hạn chế kỹ thuật hiện tại
- Quy trình kiểm duyệt vé phụ thuộc Admin: Hiện tại việc kiểm tra tính xác thực của vé (đối chiếu ảnh chụp vé và thông tin cá nhân) vẫn đòi hỏi Admin thao tác thủ công, chưa có cơ chế OCR tự động quét mã Barcode/QR Code.
- Hạn chế cổng thanh toán nội địa: Mới chỉ tích hợp sâu cổng thanh toán PayPal; người dùng Việt Nam vẫn gặp khó khăn nếu không sở hữu thẻ thanh toán quốc tế (Visa/Mastercard) hoặc tài khoản PayPal.
- Bản đồ khán đài ở dạng 2D: Chưa hỗ trợ mô phỏng không gian thực tế 3D (3D Virtual Seat View) để người mua trải nghiệm góc nhìn thực tế từ ghế ngồi.
Kế hoạch phát triển trong tương lai
- Tích hợp AI OCR & Barcode Validator: Áp dụng Computer Vision để tự động nhận dạng mã vé, tên chủ vé và kiểm tra trùng lặp với cơ sở dữ liệu vé gốc trong vòng 3 giây.
- Tích hợp Cổng thanh toán Quốc nội: Bổ sung kết nối trực tiếp với VNPAY, MoMo, ZaloPay và VietQR thông qua Open Banking API để tối ưu trải nghiệm người dùng tại Việt Nam.
- Ứng dụng Dynamic NFT Ticket: Nghiên cứu chuyển đổi vé điện tử thành NFT động (Dynamic QR Code đổi mới mỗi 30 giây) chạy trên mạng lưới Layer-2 (Polygon/Arbitrum) nhằm triệt tiêu hoàn toàn khả năng chụp màn hình chia sẻ vé giả mạo.
Đối tượng hưởng lợi
+-----------------------------------------------------------------------------------+
| CƠ CẤU ĐỐI TƯỢNG HƯỞNG LỢI |
| |
| [Sinh viên / Người học] ----> Mã nguồn mẫu NestJS + ReactJS chuẩn Clean Arch |
| [Lập trình viên Web] ----> Best practices xử lý Real-time Bidding & Redis Lock|
| [Doanh nghiệp Sự kiện] ----> Giải pháp giải quyết vé thứ cấp, gia tăng doanh thu|
| [Người tiêu dùng] ----> Môi trường mua vé an toàn, đúng giá, bảo vệ 100% |
+-----------------------------------------------------------------------------------+
- Sinh viên và Người học: Tiếp cận một đồ án tốt nghiệp mẫu hoàn chỉnh, chuẩn mực về cả mặt kỹ thuật full-stack hiện đại lẫn phương pháp lập trình hướng module hóa.
- Lập trình viên (Developers): Tham khảo kiến trúc kết hợp giữa NestJS, TypeORM, Redis Cache, Socket.IO Gateway và cách giải quyết bài toán đồng thời (Concurrency) trong các hệ thống thương mại điện tử.
- Doanh nghiệp và Ban tổ chức: Có thêm mô hình giải pháp kỹ thuật để quản lý thị trường vé thứ cấp, hạn chế tình trạng phe vé làm xấu hình ảnh sự kiện.
- Cộng đồng người hâm mộ: Được bảo vệ quyền lợi tài chính tối đa khi có nhu cầu nhượng hoặc mua lại vé tham dự các chương trình văn hóa nghệ thuật.
Câu hỏi thường gặp
1. Yêu cầu phần cứng và môi trường để triển khai hệ thống là gì?
Để triển khai hệ thống ở môi trường thử nghiệm và sản xuất (Production), cấu hình tối thiểu khuyến nghị gồm:
- Máy chủ: CPU 2 Cores, RAM 4GB, Dung lượng SSD 40GB khả dụng (hỗ trợ Ubuntu 20.04/22.04 LTS).
- Phần mềm nền tảng: Docker Engine v24+, Docker Compose v2+, Node.js v18 LTS trở lên (nếu chạy môi trường standalone).
- Tên miền & SSL: Cấu hình Nginx Reverse Proxy trỏ domain kèm chứng chỉ bảo mật SSL Let's Encrypt.
2. Hệ thống xử lý thế nào khi 2 người cùng đặt giá đấu vé tại cùng một mili-giây?
Hệ thống sử dụng cơ chế Distributed Lock với Redis (Redlock pattern). Khi có yêu cầu placeBid, tiến trình đầu tiên gửi lệnh SET lock:auction:id px NX thành công sẽ nắm giữ quyền cập nhật cơ sở dữ liệu. Tiến trình đến sau trong cùng mili-giây sẽ bị từ chối hoặc xếp hàng chờ (Queue), loại bỏ hoàn toàn tình trạng Dirty Writes hoặc xung đột trạng thái dữ liệu.
3. Làm cách nào nền tảng ngăn chặn người bán giao vé giả hoặc vé đã sử dụng?
Quy trình bảo vệ gồm 3 lớp:
- Lớp 1 (Trước khi đăng): Admin đối soát ảnh chụp vé, số ghế, mã hóa đơn gốc của người bán.
- Lớp 2 (Khi thanh toán): Tiền của người mua được giữ trong ví Escrow của hệ thống, người bán chưa thể rút tiền ngay.
- Lớp 3 (Sau sự kiện): Sau khi sự kiện diễn ra 24h và không có khiếu nại (Report) từ người mua về việc vé không vào cổng được, Admin mới giải ngân tiền từ ví ảo về tài khoản PayPal của người bán.
4. Chi phí vận hành và bảo trì hệ thống ước tính như thế nào?
- Chi phí hạ tầng: VPS Cloud (2 vCPU/4GB RAM) dao động từ 15 - 25 USD/tháng.
- Chi phí cổng thanh toán: Phí giao dịch tiêu chuẩn của PayPal Sandbox/Live (khoảng 2.9% - 4.4% + phí cố định trên mỗi đơn hàng thành công).
- Khả năng sinh lời: Nền tảng thu phí sàn từ 5% - 10% trên mỗi giao dịch thành công (Clearance Fee), đảm bảo khả năng bù đắp chi phí vận hành và sinh lợi nhuận bền vững khi đạt ngưỡng 200 giao dịch/tháng.
5. Hệ thống có thể tích hợp thêm các cổng thanh toán nội địa như VNPay hay MoMo không?
Hoàn toàn có thể. Nhờ kiến trúc mô-đun hóa cao cấp của NestJS (Module/Service Pattern), lập trình viên chỉ cần tạo thêm VnpayService hoặc MomoService kế thừa interface thanh toán chuẩn IPaymentGateway mà không làm thay đổi logic nghiệp vụ cốt lõi của OrderModule hay TicketModule.
Kết luận
Đề tài "Thiết kế và xây dựng website bán lại vé" do sinh viên Nguyễn Phát Đạt và Thái Doãn Gia Bảo thực hiện dưới sự hướng dẫn của PGS. Hoàng Văn Dũng đã giải quyết xuất sắc bài toán nhức nhối của thị trường giao dịch vé giải trí thứ cấp tại Việt Nam.
Bằng việc kết hợp sức mạnh kiến trúc của NestJS, tính tương tác cao của ReactJS, khả năng xử lý thời gian thực của Socket.IO & Redis cùng cơ chế giao dịch ký quỹ Escrow, đồ án không chỉ đáp ứng trọn vẹn các tiêu chuẩn học thuật của một khóa luận tốt nghiệp ngành Công nghệ Thông tin mà còn mở ra tiềm năng thương mại hóa thực tế rõ rệt. Dự án là tài liệu tham khảo kỹ thuật giá trị cho sinh viên, kỹ sư phần mềm quan tâm đến kiến trúc ứng dụng Web phân tán hiệu năng cao.