Hệ thống quản lý thương mại điện tử SpringBoot với kiến trúc tách biệt frontend/backend

Hệ thống quản lý thương mại điện tử được xây dựng trên nền tảng SpringBoot kết hợp Vue.js thể hiện một mô hình kiến trúc hiện đại, tập trung vào khả năng mở rộng, bảo mật và hiệu năng. Giải pháp này không chỉ đáp ứng yêu cầu nghiệp vụ cơ bản của sàn giao dịch trực tuyến mà còn tích hợp các thành phần tiên tiến như phân mảnh dữ liệu, triển khai tự động và kiểm soát quyền truy cập theo vai trò.

Trong kiến trúc tổng thể, backend được triển khai bằng SpringBoot 3.x với Spring Data JPA, Spring Security và Spring WebFlux (tùy chọn cho I/O phi đồng bộ). Frontend sử dụng Vue 3 cùng Composition API và Pinia để quản lý trạng thái. Giao tiếp giữa hai tầng được thực hiện thông qua RESTful API tuân thủ nguyên tắc HATEOAS, sử dụng định dạng JSON và mã hóa JWT cho xác thực.

Dưới đây là lược đồ cơ sở dữ liệu được tối ưu hóa cho hệ thống, bao gồm các bảng cốt lõi với ràng buộc toàn vẹn rõ ràng và hỗ trợ index hiệu quả:

-- Bảng người dùng
CREATE TABLE `account` (
  `id` BIGINT PRIMARY KEY AUTO_INCREMENT,
  `login_id` VARCHAR(64) NOT NULL UNIQUE,
  `hashed_password` CHAR(60) NOT NULL,
  `full_name` VARCHAR(128),
  `email` VARCHAR(255) UNIQUE,
  `mobile` VARCHAR(20),
  `status` ENUM('ACTIVE', 'INACTIVE', 'PENDING') DEFAULT 'PENDING',
  `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
  `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  INDEX idx_email (email),
  INDEX idx_mobile (mobile)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- Bảng danh mục sản phẩm
CREATE TABLE `category` (
  `id` BIGINT PRIMARY KEY AUTO_INCREMENT,
  `slug` VARCHAR(128) NOT NULL UNIQUE,
  `display_name` VARCHAR(128) NOT NULL,
  `parent_id` BIGINT NULL,
  `level` TINYINT DEFAULT 0,
  `is_visible` BOOLEAN DEFAULT TRUE,
  `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (`parent_id`) REFERENCES `category`(`id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- Bảng sản phẩm
CREATE TABLE `item` (
  `id` BIGINT PRIMARY KEY AUTO_INCREMENT,
  `sku` VARCHAR(64) NOT NULL UNIQUE,
  `name` VARCHAR(255) NOT NULL,
  `summary` TEXT,
  `base_price` DECIMAL(12,2) NOT NULL,
  `stock_quantity` INT NOT NULL DEFAULT 0,
  `category_id` BIGINT NOT NULL,
  `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
  `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  FOREIGN KEY (`category_id`) REFERENCES `category`(`id`) ON DELETE CASCADE,
  INDEX idx_category (category_id),
  INDEX idx_sku (sku)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- Bảng đơn hàng
CREATE TABLE `transaction` (
  `id` BIGINT PRIMARY KEY AUTO_INCREMENT,
  `ref_number` VARCHAR(32) NOT NULL UNIQUE,
  `account_id` BIGINT NOT NULL,
  `total_amount` DECIMAL(12,2) NOT NULL,
  `currency` CHAR(3) DEFAULT 'VND',
  `status` ENUM('DRAFT', 'CONFIRMED', 'SHIPPED', 'DELIVERED', 'CANCELLED') DEFAULT 'DRAFT',
  `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
  `confirmed_at` DATETIME NULL,
  FOREIGN KEY (`account_id`) REFERENCES `account`(`id`) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- Bảng chi tiết đơn hàng
CREATE TABLE `transaction_line` (
  `id` BIGINT PRIMARY KEY AUTO_INCREMENT,
  `transaction_id` BIGINT NOT NULL,
  `item_id` BIGINT NOT NULL,
  `quantity` INT NOT NULL DEFAULT 1,
  `unit_price` DECIMAL(12,2) NOT NULL,
  `subtotal` DECIMAL(12,2) NOT NULL,
  FOREIGN KEY (`transaction_id`) REFERENCES `transaction`(`id`) ON DELETE CASCADE,
  FOREIGN KEY (`item_id`) REFERENCES `item`(`id`) ON DELETE RESTRICT,
  INDEX idx_txn (transaction_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- Bảng đánh giá
CREATE TABLE `review` (
  `id` BIGINT PRIMARY KEY AUTO_INCREMENT,
  `account_id` BIGINT NOT NULL,
  `item_id` BIGINT NOT NULL,
  `transaction_id` BIGINT NOT NULL,
  `rating` TINYINT CHECK (rating BETWEEN 1 AND 5),
  `content` TEXT,
  `is_verified_purchase` BOOLEAN DEFAULT FALSE,
  `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (`account_id`) REFERENCES `account`(`id`) ON DELETE CASCADE,
  FOREIGN KEY (`item_id`) REFERENCES `item`(`id`) ON DELETE CASCADE,
  FOREIGN KEY (`transaction_id`) REFERENCES `transaction`(`id`) ON DELETE CASCADE,
  UNIQUE KEY `uk_account_item` (`account_id`, `item_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Các thực thể JPA tương ứng được thiết kế với chú giải chuẩn, hỗ trợ lazy loading và tránh N+1 query thông qua chiến lược fetch phù hợp:

import jakarta.persistence.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Entity
@Table(name = "account")
public class AccountEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "login_id", unique = true, nullable = false)
    private String loginId;

    @Column(name = "hashed_password", nullable = false)
    private String hashedPassword;

    @Column(name = "full_name")
    private String fullName;

    @Column(name = "email", unique = true)
    private String email;

    @Column(name = "mobile")
    private String mobile;

    @Enumerated(EnumType.STRING)
    @Column(name = "status", nullable = false)
    private AccountStatus status;

    @Column(name = "created_at", nullable = false, updatable = false)
    private LocalDateTime createdAt;

    @Column(name = "updated_at", nullable = false)
    private LocalDateTime updatedAt;

    @OneToMany(mappedBy = "account", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private List<TransactionEntity> transactions = new ArrayList<>();

    // Constructors, getters, setters...
}

@Entity
@Table(name = "item")
public class ItemEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "sku", unique = true, nullable = false)
    private String sku;

    @Column(name = "name", nullable = false)
    private String name;

    @Column(name = "summary")
    private String summary;

    @Column(name = "base_price", nullable = false, precision = 12, scale = 2)
    private BigDecimal basePrice;

    @Column(name = "stock_quantity", nullable = false)
    private Integer stockQuantity;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "category_id", nullable = false)
    private CategoryEntity category;

    @Column(name = "created_at", nullable = false, updatable = false)
    private LocalDateTime createdAt;

    @Column(name = "updated_at", nullable = false)
    private LocalDateTime updatedAt;

    @OneToMany(mappedBy = "item", fetch = FetchType.LAZY)
    private List<ReviewEntity> reviews = new ArrayList<>();

    // Constructors, getters, setters...
}

@Entity
@Table(name = "transaction")
public class TransactionEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "ref_number", unique = true, nullable = false)
    private String referenceNumber;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "account_id", nullable = false)
    private AccountEntity account;

    @Column(name = "total_amount", nullable = false, precision = 12, scale = 2)
    private BigDecimal totalAmount;

    @Column(name = "currency", length = 3, nullable = false)
    private String currency;

    @Enumerated(EnumType.STRING)
    @Column(name = "status", nullable = false)
    private TransactionStatus status;

    @Column(name = "created_at", nullable = false, updatable = false)
    private LocalDateTime createdAt;

    @Column(name = "confirmed_at")
    private LocalDateTime confirmedAt;

    @OneToMany(mappedBy = "transaction", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<TransactionLineEntity> lines = new ArrayList<>();

    // Constructors, getters, setters...
}

Hệ thống áp dụng cơ chế phân quyền RBAC (Role-Based Access Control) với các vai trò như ADMIN, SHOP_MANAGER, CUSTOMER. Quyền truy cập được cấu hình ở cấp endpoint bằng @PreAuthorize, ví dụ:

@RestController
@RequestMapping("/api/v1/items")
public class ItemController {

    @GetMapping
    @PreAuthorize("hasAnyRole('ADMIN', 'SHOP_MANAGER')")
    public ResponseEntity<List<ItemDto>> listAllItems() { ... }

    @PostMapping
    @PreAuthorize("hasRole('SHOP_MANAGER')")
    public ResponseEntity<ItemDto> createItem(@RequestBody ItemCreateRequest request) { ... }
}

Để đảm bảo tính sẵn sàng cao và xử lý tải lớn, hệ thống hỗ trợ phân mảnh ngang (sharding) tại tầng dữ liệu thông qua việc tách bảng transaction theo tháng hoặc theo ID người dùng — được điều khiển bởi custom ShardRoutingDataSource. Đồng thời, toàn bộ quy trình CI/CD được tự động hóa bằng GitHub Actions, từ build, test unit/integration, đến deploy lên môi trường staging bằng Docker Compose hoặc Kubernetes.

Thẻ: SpringBoot jpa vuejs mysql rbac

Đăng vào ngày 23 tháng 10 lúc 11:37