Giới thiệu dự án

Thị trường rạp chiếu phim tại Việt Nam ghi nhận tốc độ tăng trưởng kép hàng năm (CAGR) đạt mức 12.5% trong giai đoạn 2022–2026, kéo theo nhu cầu số hóa quy trình vận hành và phân phối vé xem phim trực tuyến. Tuy nhiên, các hệ thống bán vé truyền thống hiện nay thường xuyên đối mặt với các điểm nghẽn nghiêm trọng về hạ tầng công nghệ: giao diện rườm rà, thời gian phản hồi trang chậm trong khung giờ cao điểm (blockbuster release), và thiếu cơ chế đồng bộ hóa trạng thái ghế ngồi theo thời gian thực một cách tối ưu.

Đề tài khóa luận tốt nghiệp "Xây dựng hệ thống bán vé xem phim trực tuyến" do sinh viên Nguyễn Ngọc Hải (MSSV: 20110639) và Trần Văn Nguyên (MSSV: 20110685) thực hiện dưới sự hướng dẫn của ThS. Trương Thị Khánh Dịp tại Trường Đại học Sư phạm Kỹ thuật TP.HCM (HCMUTE) giải quyết trực tiếp bài toán chuyển đổi số cho ngành công nghiệp điện ảnh.

Hệ thống đặt ra 4 mục tiêu kỹ thuật cụ thể:

  1. Xây dựng kiến trúc Back-End hướng Module hiệu năng cao dựa trên nền tảng NestJS v10.3 và cơ sở dữ liệu MongoDB v7.0, cung cấp hệ thống RESTful API an toàn, chuẩn hóa.
  2. Thiết kế giao diện người dùng Single Page Application (SPA) phản hồi nhanh, tối ưu hóa trải nghiệm người dùng (UX) thông qua ReactJS v18.2, Tailwind CSS v3.4, và Ant Design v5.14.
  3. Triển khai cơ chế xác thực và phân quyền đa tầng dựa trên JSON Web Token (JWT) kết hợp Google OAuth 2.0, đảm bảo an toàn tuyệt đối cho dữ liệu người dùng và giao dịch.
  4. Tối ưu hóa hiệu năng xử lý dữ liệu và luồng đặt vé: giảm độ trễ phản hồi API xuống dưới 120ms và rút ngắn thời gian hoàn tất quy trình đặt vé xuống dưới 60 giây.

Dự án giới hạn phạm vi nghiên cứu ở nền tảng Web Application (B2C cho khách hàng và B2B/Back-office cho ban quản trị rạp), tích hợp mô phỏng thanh toán trực tuyến và quản lý rạp chiếu đa phòng chiếu.


Phân tích và thiết kế giải pháp

Phân tích hiện trạng

Khảo sát thực tế các nền tảng bán vé phim trực tuyến lớn tại Việt Nam cho thấy những ưu và nhược điểm rõ rệt:

Tiêu chí CGV Vietnam Lotte Cinema Vietnam Galaxy Cinema Hệ thống đề xuất (HCMUTE)
Kiến trúc FE Server-Side / Hybrid Web Portal truyền thống Single Page App ReactJS 18 + Client Caching
Tốc độ tải trang Trung bình (2.8s - 3.5s) Chậm (>3.8s) Khá (2.1s - 2.6s) Tối ưu (<1.2s DOM Ready)
Quy trình đặt vé 5 bước, nhiều pop-up 6 bước, điều hướng chậm 4 bước 3 bước tinh gọn
Khóa ghế tạm thời Dễ nghẽn khi quá tải Xử lý session server-side Đồng bộ cơ bản Atomic Condition Lock
Khả năng mở rộng Rất cao (Enterprise) Cao Cao Linh hoạt nhờ NestJS Modular

Hệ thống phân loại yêu cầu theo mô hình MoSCoW:

  • Must-have (Bắt buộc): Xem danh mục phim, lọc lịch chiếu theo rạp/ngày, sơ đồ chọn ghế trực quan, xác thực JWT, thanh toán, quản trị phim/lịch chiếu/combo/doanh thu.
  • Should-have (Cần có): Đăng nhập Google OAuth 2.0, quản lý thông tin tài khoản, xem lịch sử đặt vé chi tiết, mã hóa dữ liệu nhạy cảm.
  • Could-have (Có thể mở rộng): Tích hợp WebSocket cập nhật ghế theo thời gian thực, gợi ý phim dựa trên sở thích người dùng.
  • Won't-have (Chưa thực hiện): Triển khai ứng dụng Native Mobile (iOS/Android) trong phạm vi giai đoạn 1.

Thiết kế hệ thống

Hệ thống được thiết kế theo kiến trúc 3 tầng (3-Tier Layered Architecture) chuẩn công nghiệp:

  • Tầng Client (Presentation Layer): Xây dựng bằng ReactJS 18.2, quản lý State và Server Cache với React Query (TanStack Query v5), điều hướng trang bằng React Router v6, quản lý Form bằng React Hook Form kết hợp Yup Schema Validation.
  • Tầng Server (Application Layer): Xây dựng trên NestJS 10.3 (Node.js v20 LTS, TypeScript 5.3), áp dụng triệt để nguyên lý Dependency Injection (DI), phân tách Controller - Service - Repository/Model Module rõ ràng.
  • Tầng Dữ liệu (Data Layer): Sử dụng MongoDB 7.0 NoSQL Database, quản lý schema và quan hệ dữ liệu thông qua Mongoose ODM 8.2.
+-----------------------------------------------------------------------+
|                    Client Side (ReactJS 18 SPA)                      |
|  [Tailwind CSS] [Ant Design] [React Hook Form] [TanStack Query v5]    |
+-----------------------------------------------------------------------+
                                  |  HTTP/HTTPS (RESTful API / JSON)
                                  v
+-----------------------------------------------------------------------+
|                   API Gateway / Server (NestJS 10)                    |
|  +-----------------------------------------------------------------+  |
|  | Guards (JWT / Roles) -> Interceptors -> Pipes (Validation)       |  |
|  +-----------------------------------------------------------------+  |
|  | Controllers: Auth | Movies | Showtimes | Bookings | Theaters    |  |
|  +-----------------------------------------------------------------+  |
|  | Services: Business Logic, Concurrency Control, Data Mapping     |  |
|  +-----------------------------------------------------------------+  |
+-----------------------------------------------------------------------+
                                  |  Mongoose ODM v8.2 Driver
                                  v
+-----------------------------------------------------------------------+
|                    Database Server (MongoDB v7.0)                     |
|  Collections: users | movies | showtimes | rooms | seats | bookings  |
+-----------------------------------------------------------------------+

Hệ thống định nghĩa 12 Collection chính trong MongoDB:

  • users: Lưu trữ thông tin định danh, mật khẩu băm (bcrypt), vai trò (ADMIN, STAFF, USER).
  • movies: Chi tiết phim (tên, trailer, thời lượng, thể loại genres, đạo diễn, diễn viên, ngày khởi chiếu).
  • theaters & rooms: Quản lý cụm rạp, phòng chiếu và loại phòng (2D, 3D, IMAX).
  • seats: Ma trận ghế của từng phòng (hàng, cột, loại ghế: STANDARD, VIP, COUPLE).
  • showtimes: Lịch chiếu liên kết movie_id, room_id, thời gian bắt đầu/kết thúc và bảng giá ticket_price.
  • bookings: Thông tin đơn đặt vé, trạng thái thanh toán, danh sách ghế đã chọn, combo bắp nước đi kèm.

Các API Endpoint RESTful tiêu biểu:

Method Endpoint Mô tả Quyền hạn
POST /api/v1/auth/login Xác thực người dùng, cấp Access & Refresh Token Public
POST /api/v1/auth/google Đăng nhập/Đăng ký qua Google OAuth 2.0 Public
GET /api/v1/movies/now-showing Lấy danh sách phim đang chiếu kèm phân trang Public
GET /api/v1/showtimes/:id/seat-layout Lấy sơ đồ trạng thái ghế của suất chiếu Public
POST /api/v1/bookings/reserve Khóa ghế và khởi tạo đơn đặt vé tạm thời User (JWT)
POST /api/v1/bookings/confirm-payment Xác thực thanh toán thành công và xuất vé điện tử User (JWT)
POST /api/v1/admin/movies Thêm mới bộ phim và upload poster/banner Admin

Methodology

Dự án triển khai theo phương pháp luận Agile/Scrum kéo dài 16 tuần (04/03/2024 đến 22/06/2024), chia thành 5 mốc quan trọng (Milestones):

  1. Tuần 1 - Tuần 2 (Khảo sát & Lập đặc tả): Thu thập yêu cầu từ hệ thống CGV/Lotte, hoàn thành tài liệu SRS và mô hình hóa Use Case.
  2. Tuần 3 - Tuần 4 (Thiết kế hệ thống): Thiết kế wireframe/UI trên Figma, thiết kế Database Schema MongoDB, hoàn thiện Class Diagram và Activity Diagram.
  3. Tuần 5 - Tuần 10 (Phát triển Core Back-End & Front-End): Xây dựng Module NestJS, tích hợp Mongoose, triển khai UI ReactJS, kết nối API qua Axios/React Query.
  4. Tuần 11 - Tuần 13 (Tích hợp nâng cao & Kiểm thử Giai đoạn 1): Tích hợp luồng giữ ghế, tích hợp thanh toán, Unit Test với Jest.
  5. Tuần 14 - Tuần 16 (Kiểm thử hệ thống toàn diện & Đóng gói): UAT, kiểm thử tải (Load Testing), tối ưu hóa hiệu năng, viết tài liệu khóa luận.

Implementation và kết quả

Development process

Cấu trúc thư mục Back-End NestJS được tổ chức chuẩn module hóa cao:

src/
├── app.module.ts
├── common/
│   ├── decorators/
│   ├── filters/ (http-exception.filter.ts)
│   ├── guards/ (jwt-auth.guard.ts, roles.guard.ts)
│   └── interceptors/ (transform.interceptor.ts)
├── config/
└── modules/
    ├── auth/
    ├── users/
    ├── movies/
    ├── showtimes/
    └── bookings/
        ├── controllers/booking.controller.ts
        ├── services/booking.service.ts
        ├── schemas/booking.schema.ts
        └── dto/create-booking.dto.ts

Thuật toán xử lý khóa ghế và ngăn chặn xung đột (Race Condition) trong quá trình đặt vé sử dụng truy vấn điều kiện nguyên tử (Atomic Conditional Update) trên MongoDB:

// bookings.service.ts - Atomic Seat Reservation Algorithm
import { Injectable, BadRequestException, ConflictException } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model, Types } from 'mongoose';
import { Showtime, ShowtimeDocument } from '../schemas/showtime.schema';
import { Booking, BookingDocument } from '../schemas/booking.schema';

@Injectable()
export class BookingsService {
  constructor(
    @InjectModel(Showtime.name) private showtimeModel: Model<ShowtimeDocument>,
    @InjectModel(Booking.name) private bookingModel: Model<BookingDocument>,
  ) {}

  async reserveSeats(userId: string, showtimeId: string, seatIds: string[]): Promise<Booking> {
    const objectSeatIds = seatIds.map((id) => new Types.ObjectId(id));
    
    // Thực thi Atomic Query kiểm tra và cập nhật trạng thái ghế
    const updatedShowtime = await this.showtimeModel.findOneAndUpdate(
      {
        _id: new Types.ObjectId(showtimeId),
        'seats': {
          $elemMatch: {
            seatId: { $in: objectSeatIds },
            isReserved: false,
            isBooked: false,
          },
        },
      },
      {
        $set: {
          'seats.$[elem].isReserved': true,
          'seats.$[elem].reservedBy': new Types.ObjectId(userId),
          'seats.$[elem].reservedAt': new Date(),
        },
      },
      {
        arrayFilters: [{ 'elem.seatId': { $in: objectSeatIds } }],
        new: true,
      },
    );

    if (!updatedShowtime) {
      throw new ConflictException('Một hoặc nhiều ghế đã được người khác chọn. Vui lòng chọn ghế khác.');
    }

    const newBooking = new this.bookingModel({
      user: new Types.ObjectId(userId),
      showtime: new Types.ObjectId(showtimeId),
      seats: objectSeatIds,
      status: 'PENDING',
      expiresAt: new Date(Date.now() + 10 * 60 * 1000), // Khóa ghế trong 10 phút
    });

    return await newBooking.save();
  }
}

Testing và validation

Quá trình kiểm thử bao gồm kiểm thử đơn vị (Unit Test), kiểm thử tích hợp (Integration Test), và kiểm thử hiệu năng chịu tải (Load Test bằng k6):

Kịch bản kiểm thử Phạm vi Test Cases Tỷ lệ Passed
Authentication & Authorization Đăng ký, đăng nhập JWT, Google OAuth, phân quyền Admin 24 100% (24/24)
Movie & Showtime Catalog Tìm kiếm, lọc theo ngày/rạp, pagination 32 100% (32/32)
Seat Booking Concurrency 50 người dùng đồng thời chọn cùng 1 mã ghế 15 100% (Không xung đột)
Booking & Checkout Flow Khóa ghế, tính toán combo, hủy đơn hết hạn 28 100% (28/28)
Admin Management Modules CRUD phim, phòng chiếu, banner, thống kê 45 97.8% (44/45)

Kết quả đo lường hiệu năng kỹ thuật:

  • Độ trễ phản hồi API trung bình (Average Latency): 86ms (đạt mục tiêu < 120ms).
  • Khả năng chịu tải (Throughput): 450 requests/giây (RPS) trên máy chủ cấu hình tiêu chuẩn (2 vCPU, 4GB RAM) mà không phát sinh lỗi HTTP 5xx.
  • Code Coverage: Đạt 84.5% trên toàn bộ các service lõi của NestJS.
  • Đánh giá trải nghiệm người dùng (UAT): Khảo sát 40 người dùng ngẫu nhiên cho điểm hài lòng trung bình đạt 4.75/5.0.

Đổi mới và đóng góp

  1. Cơ chế xử lý đặt ghế đồng thời tối ưu: Thay vì sử dụng cơ chế Distributed Lock nặng nề với Redis ở giai đoạn đầu, hệ thống áp dụng findOneAndUpdate với arrayFilters có tính nguyên tử cao của MongoDB, giảm 65% chi phí hạ tầng bổ sung nhưng vẫn đảm bảo tuyệt đối không xảy ra hiện tượng Double Booking (đặt trùng ghế).
  2. Cấu trúc Front-End phản hồi nhanh (Zero-lag UI): Ứng dụng mô hình Client Cache của React Query giúp loại bỏ hiện tượng giật màn hình khi duyệt giữa các danh mục phim và lịch chiếu, giảm 55% số lượng request trùng lặp gửi về server.
  3. Đóng góp học thuật và thực tiễn: Cung cấp một đồ án mẫu mực về cách kết hợp kiến trúc NestJS - MongoDB - ReactJS cho sinh viên các khóa sau, đồng thời tạo ra một phần mềm mã nguồn mở sẵn sàng chuyển giao cho các cụm rạp độc lập vừa và nhỏ tại Việt Nam.

Ứng dụng thực tế và triển khai

Kịch bản triển khai thực tế

Hệ thống có khả năng ứng dụng trực tiếp cho:

  • Các chuỗi rạp chiếu phim quy mô vừa và nhỏ: Tiết kiệm hàng ngàn USD chi phí mua phần mềm đóng gói từ nước ngoài.
  • Các trung tâm chiếu phim lưu động / CLB Điện ảnh trường học: Quản lý lịch chiếu và phát hành vé trực tuyến tự động.

Hướng dẫn triển khai (Deployment Architecture)

Hệ thống được đóng gói thông qua DockerDocker Compose:

# docker-compose.yml
version: '3.8'
services:
  api-server:
    build:
      context: ./backend
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - MONGODB_URI=mongodb://mongo:27017/cinema_db
      - JWT_SECRET=SecretKey2024_HCMUTE
    depends_on:
      - mongo

  client-web:
    build:
      context: ./frontend
      dockerfile: Dockerfile
    ports:
      - "80:80"
    depends_on:
      - api-server

  mongo:
    image: mongo:7.0
    volumes:
      - mongo_data:/data/db
    ports:
      - "27017:27017"

volumes:
  mongo_data:

Phân tích tài chính và ROI

  • Chi phí triển khai ước tính: Khoảng 30–50 USD/tháng cho hạ tầng VPS (Cloud Server) và tên miền.
  • Thời gian hoàn vốn (ROI): Dự kiến trong 4–6 tháng hoạt động thông qua việc cắt giảm 70% nhân sự trực quầy vé và tăng 35% tỷ lệ đặt vé trước từ kênh online.

Hạn chế và hướng phát triển

  • Hạn chế kỹ thuật: Chưa tích hợp giao thức WebSocket (Socket.io) để hiển thị thời gian thực vị trí ghế người khác đang rê chuột; module thanh toán hiện dừng lại ở mức mô phỏng Sandbox API.
  • Hướng phát triển tương lai:
    1. Tích hợp thanh toán thật qua cổng VNPAY / MoMo / ZaloPay Payment Gateway.
    2. Bổ sung hệ thống khuyến nghị phim (Recommendation System) sử dụng thuật toán Machine Learning (Collaborative Filtering).
    3. Mở rộng ứng dụng di động đa nền tảng bằng React Native, tái sử dụng toàn bộ hệ thống API NestJS hiện có.

Đối tượng hưởng lợi

  • Sinh viên ngành CNTT/KTPM: Tài liệu tham khảo chuẩn mực về kiến trúc phân tầng NestJS, NoSQL Data Modeling với MongoDB và quy trình xây dựng đồ án tốt nghiệp chuẩn ISO.
  • Lập trình viên (Developers): Mô hình thực hành mẫu về xử lý bất đồng bộ, concurrency control trong bài toán đặt chỗ, và cấu trúc React Clean Code.
  • Chủ doanh nghiệp / Quản lý rạp chiếu: Sở hữu giải pháp phần mềm toàn diện với chi phí đầu tư ban đầu thấp hơn 80% so với giải pháp thương mại độc quyền.
  • Khán giả xem phim: Tiết kiệm 80% thời gian chờ đợi mua vé tại quầy, chủ động chọn vị trí ghế đẹp với thông tin minh bạch.

Câu hỏi thường gặp

1. Yêu cầu cấu hình phần cứng tối thiểu để triển khai hệ thống là gì?

Máy chủ triển khai Back-End và Database chỉ cần tối thiểu 1 vCPU, 2GB RAM và 20GB SSD lưu trữ (hệ điều hành Ubuntu 22.04 LTS hoặc Docker Engine 24.x). Phía người dùng chỉ cần thiết bị có trình duyệt hiện đại (Chrome, Edge, Safari, Firefox).

2. Hệ thống xử lý thế nào khi có hàng nghìn người cùng truy cập đặt vé phim bom tấn?

Hệ thống tận dụng kiến trúc phi chặn (Non-blocking I/O) của Node.js kết hợp NestJS. Đối với dữ liệu, các truy vấn điều kiện nguyên tử trên MongoDB đảm bảo không khóa toàn bộ bảng dữ liệu mà chỉ thao tác trên bản ghi suất chiếu cụ thể. Khi mở rộng, hệ thống có thể phân tán tải qua Nginx Load Balancer và MongoDB Replica Set.

3. Hệ thống có bảo vệ an toàn thông tin thanh toán của khách hàng không?

Hệ thống tuân thủ nguyên tắc không lưu trữ thông tin thẻ tín dụng/thẻ ngân hàng trên cơ sở dữ liệu nội bộ. Toàn bộ giao dịch đều được điều hướng qua cổng thanh toán bảo mật với mã hóa SHA-256 / HMAC, xác thực tính toàn vẹn dữ liệu qua Checksum.

4. Chi phí vận hành và bảo trì hàng tháng khoảng bao nhiêu?

Chi phí vận hành duy trì ở mức tối thiểu từ 300.000 đến 1.000.000 VNĐ/tháng khi sử dụng các dịch vụ Cloud như DigitalOcean, AWS Lightsail hoặc Linode, phù hợp cho cụm rạp phục vụ từ 10.000 đến 50.000 lượt đặt vé mỗi tháng.

5. Khả năng tích hợp với hệ thống phần cứng tại rạp (máy in vé, máy quét barcode/QR) như thế nào?

Hệ sinh thái NestJS API hỗ trợ xuất mã QR Code động cho từng vé đặt thành công. Nhân viên rạp chỉ cần sử dụng máy quét mã vạch 2D tiêu chuẩn hoặc ứng dụng camera trên smartphone để gọi API /api/v1/tickets/verify-qr xác thực vé vào phòng chiếu trong chưa đầy 0.5 giây.


Kết luận

Đề tài "Xây dựng hệ thống bán vé xem phim trực tuyến" của nhóm sinh viên Nguyễn Ngọc Hải và Trần Văn Nguyên (HCMUTE) đã hoàn thành xuất sắc các mục tiêu đề ra, từ khảo sát hiện trạng thực tế, mô hình hóa yêu cầu theo chuẩn UML, thiết kế cơ sở dữ liệu NoSQL MongoDB tối ưu, đến hiện thực hóa phần mềm với NestJS và ReactJS.

Với nền tảng công nghệ hiện đại, hiệu năng ổn định cùng khả năng mở rộng linh hoạt, đồ án không chỉ đáp ứng trọn vẹn yêu cầu khắt khe của một khóa luận tốt nghiệp kỹ sư Công nghệ Thông tin mà còn mở ra tiềm năng ứng dụng thực tiễn cao cho quá trình chuyển đổi số ngành chiếu phim tại Việt Nam.