Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

TranKhanhPC

Website bán máy tính và linh kiện PC tích hợp công cụ kiểm tra tương thích cấu hình và chatbot AI tư vấn build PC.

Khóa luận tốt nghiệp — Trần Đức Khánh (A45039) — GVHD: ThS. Trần Văn Nam — Trường Đại học Thăng Long.

Công nghệ

Thành phần Công nghệ
Frontend React 18, Vite, React Router, Axios — phục vụ bằng nginx
Backend Node.js 20, Express 5, mysql2, JWT (jsonwebtoken), bcryptjs, zod
Cơ sở dữ liệu MySQL 8.0 (utf8mb4)
Hạ tầng Docker, Docker Compose
Kiểm thử Jest (unit test), Postman/Newman (API test)

Chạy dự án bằng một lệnh

Yêu cầu: Docker Desktop (Docker Compose v2).

docker compose up -d --build
Dịch vụ Địa chỉ
Website (frontend) http://localhost:3000
REST API http://localhost:5000/api
MySQL localhost:3307 (user tkpc / tkpc_secret, database trankhanhpc)

Lần chạy đầu tiên MySQL tự nạp schema và dữ liệu trong database/init/. Các script này chỉ chạy khi volume còn trống; sau khi sửa schema hoặc seed, nạp lại từ đầu:

docker compose down -v      # xóa cả volume dữ liệu MySQL
docker compose up -d --build

Có thể ghi đè cấu hình (cổng, mật khẩu, JWT secret...) bằng cách sao chép .env.example thành .env. Không có .env thì dùng giá trị mặc định cho môi trường dev.

Tài khoản demo

Vai trò Email Mật khẩu
Quản trị viên admin@trankhanhpc.vn Admin@123
Nhân viên staff@trankhanhpc.vn Staff@123
Khách hàng customer@trankhanhpc.vn Customer@123

Chạy không dùng Docker (dev)

docker compose up -d mysql                 # chỉ chạy MySQL
cd backend && cp .env.example .env && npm install && npm run dev
cd frontend && npm install && npm run dev  # http://localhost:5173, proxy /api → :5000

Kiến trúc

Trình duyệt ──► nginx (frontend:80)
                 ├── /        → React SPA (static)
                 └── /api/*   → backend:5000 (Express) ──► MySQL 8

Backend tổ chức theo module, mỗi module tách lớp routes → controller → service → repository:

backend/src
├── app.js, server.js, routes.js
├── config/         env, MySQL pool, transaction helper
├── middlewares/    authenticate / authorize (RBAC), validate (zod), errorHandler
├── constants/      roles
├── utils/          ApiError, pagination, response, slugify
└── modules/
    ├── auth/       đăng ký, đăng nhập, refresh token, đăng xuất, đổi mật khẩu
    ├── users/      quản lý tài khoản & phân quyền (Admin)
    ├── catalog/    danh mục 2 cấp, thương hiệu, specRegistry, metadata bộ lọc động
    ├── products/   tìm kiếm/lọc/phân trang, chi tiết, quản lý sản phẩm & máy tính bộ
    ├── wishlist/   sản phẩm yêu thích
    └── compatibility/  Rule Engine kiểm tra tương thích (đọc luật từ CSDL)

Frontend (React + Vite) dùng chung một hệ thống giao diện (font Be Vietnam Pro, token màu trong styles/base.css):

Trang Đường dẫn Ghi chú
Trang chủ / Hero, Flash Sale (sản phẩm đang giảm giá, đếm ngược tới 24h), PC bán chạy theo tầm giá, Build PC theo tựa game, dải giới thiệu danh mục
Danh mục / tìm kiếm /danh-muc/:slug, /tim-kiem?q= Bộ lọc động theo thông số, đồng bộ trên URL
Chi tiết sản phẩm /san-pham/:slug Đối chiếu tương thích với cấu hình Build PC đang soạn; máy bộ thì kiểm tra chính cấu hình của máy
Build PC /build-pc (?chon=cpu mở sẵn cửa sổ chọn) 8 vị trí linh kiện, mẫu cấu hình từ máy bộ đang bán, kết quả Rule Engine, công suất, xuất CSV / in / sao chép
Giỏ hàng → Thông tin đặt hàng /gio-hang, /thanh-toan Giỏ lưu trên trình duyệt; thanh toán khi nhận hàng (COD). Tạo đơn hàng sẽ nối API đơn hàng ở giai đoạn sau
Yêu thích /yeu-thich Cần đăng nhập
Trợ lý AI /tro-ly-ai (?q= hỏi luôn) Giao diện toàn màn hình. Chưa kết nối Gemini: hiện gợi ý theo ngân sách/nhu cầu từ kho hàng thật (utils/assistant.js)
Quản trị / Nhân viên /admin, /staff Theo vai trò

Ảnh sản phẩm để trống (image_url NULL) và hiển thị khung "Chưa có hình ảnh" theo loại linh kiện cho tới khi được thêm qua trang quản trị.

Xác thực & phân quyền

  • Access token (JWT, mặc định 15 phút) gửi qua header Authorization: Bearer <token>.
  • Refresh token (JWT, mặc định 7 ngày) lưu dạng SHA-256 trong bảng refresh_tokens, xoay vòng mỗi lần refresh. Dùng lại token đã thu hồi → thu hồi toàn bộ phiên của người dùng.
  • Mỗi request xác thực đều nạp lại user từ CSDL nên khóa tài khoản / đổi vai trò có hiệu lực ngay.
  • Vai trò lưu ở bảng roles (customer, staff, admin), mỗi người dùng có đúng một vai trò (users.role_id). Middleware authorize(...roles) kiểm soát từng endpoint.

Cơ sở dữ liệu

Schema đầy đủ có chú thích trong database/init/01_schema.sql. Các nhóm bảng:

Nhóm Bảng
Người dùng roles, users, refresh_tokens
Danh mục & sản phẩm categories (2 cấp), brands, products, product_components (linh kiện cấu thành máy tính bộ)
Thông số linh kiện cpu_specs, mainboard_specs, ram_specs, gpu_specs, psu_specs, storage_specs, cooler_specs, case_specs
Kho hàng inventory, inventory_transactions, inventory_transaction_items
Yêu thích wishlist_items
PC Builder pc_builds, pc_build_items
Kiểm tra tương thích compatibility_rules, compatibility_rule_conditions, compatibility_checks, compatibility_check_results
Giỏ hàng & đơn hàng cart_items, orders, order_items, order_status_history
Chatbot AI chat_sessions, chat_messages, ai_build_requests, ai_build_recommendations

Thông số kỹ thuật: mỗi loại linh kiện một bảng

Thông số được lưu trong bảng riêng theo loại linh kiện với cột có kiểu dữ liệu rõ ràng (cpu_specs.socket VARCHAR, gpu_specs.length_mm SMALLINT...). Nhờ vậy Rule Engine đối chiếu trực tiếp các cột, ví dụ CPU.socket = MAINBOARD.socket, GPU.length_mm <= CASE.gpu_max_length_mm.

Các cột đó được mô tả trong backend/src/modules/catalog/specRegistry.js (nhãn, kiểu, đơn vị, có lọc được, bắt buộc hay không). Bộ lọc động, API tạo/sửa sản phẩm và bảng thông số trên giao diện đều đọc từ sổ đăng ký này, nên thêm một thông số mới chỉ cần thêm cột vào bảng *_specs và một dòng vào registry.

Cột nhiều giá trị (socket tản nhiệt hỗ trợ, chuẩn mainboard case hỗ trợ...) lưu dạng danh sách phân cách dấu phẩy không có khoảng trắng (LGA1700,AM4,AM5) và lọc bằng FIND_IN_SET.

Máy tính bộ

Máy tính bộ là products thuộc nhóm danh mục Máy tính bộ (PC Gaming, PC AMD Gaming, PC Workstation, PC Mini, PC Văn phòng, PC AI); linh kiện cấu thành lưu ở product_components. Vì linh kiện lẫn máy bộ đều là products nên giỏ hàng, đơn hàng và yêu thích dùng chung một cách tham chiếu.

Luật tương thích

Bảng compatibility_rules + compatibility_rule_conditions chứa 18 luật khởi tạo (socket CPU–mainboard–tản nhiệt, loại/bus/dung lượng/số thanh RAM, kích thước mainboard/GPU/tản nhiệt/radiator/nguồn so với case, công suất và đầu cấp nguồn PSU, giao tiếp ổ cứng, tồn kho). Điều kiện có dạng <linh kiện>.<cột> <toán tử> <linh kiện>.<cột>; Rule Engine (backend/src/modules/compatibility/ruleEngine.js) đọc bảng này nên Admin cấu hình được luật mà không sửa code; mỗi luật trả về PASS / FAIL / WARNING / INFO / SKIPPED.

Dữ liệu

File Nội dung
database/init/01_schema.sql Schema
database/init/02_reference_data.sql Vai trò, 2 + 14 danh mục, 14 thương hiệu, 18 luật tương thích
database/init/03_seed_data.sql Sinh tự động — 160 linh kiện (8 nhóm × 20), 7 máy tính bộ, tồn kho, 3 tài khoản demo, yêu thích mẫu

Muốn thêm/sửa sản phẩm: sửa database/seed/source_data.py rồi chạy python database/seed/build_seed.py để sinh lại 03_seed_data.sql.

REST API

Phản hồi thống nhất:

// Thành công
{ "success": true, "data": ..., "meta": { "page": 1, "limit": 12, "totalItems": 167, "totalPages": 14, "hasNextPage": true, "hasPrevPage": false } }
// Lỗi
{ "success": false, "message": "Dữ liệu không hợp lệ", "details": [{ "field": "email", "message": "Email không hợp lệ" }] }
Method Endpoint Quyền Mô tả
GET /api/health Công khai Kiểm tra API và CSDL
POST /api/auth/register Công khai Đăng ký (vai trò Khách hàng)
POST /api/auth/login Công khai Đăng nhập, trả access + refresh token
POST /api/auth/refresh Công khai Cấp lại token (xoay vòng refresh token)
POST /api/auth/logout Công khai Thu hồi refresh token
GET /api/auth/me Đã đăng nhập Thông tin người dùng hiện tại
PUT /api/auth/change-password Đã đăng nhập Đổi mật khẩu (đăng xuất mọi thiết bị)
GET /api/users Admin Danh sách người dùng (role, isActive, q, page, limit)
POST /api/users Admin Tạo tài khoản với vai trò bất kỳ
GET /api/users/:id Admin Chi tiết người dùng
PATCH /api/users/:id/role Admin Đổi vai trò
PATCH /api/users/:id/status Admin Khóa / mở khóa
GET /api/categories Công khai Cây danh mục 2 cấp kèm số sản phẩm
GET /api/categories/:slug Công khai Chi tiết danh mục, danh mục con, định nghĩa thông số
GET /api/categories/:slug/filters Công khai Metadata bộ lọc động (hãng, khoảng giá, giá trị thông số + số lượng)
GET /api/brands?category= Công khai Thương hiệu (theo danh mục)
GET /api/products Công khai Tìm kiếm, lọc, sắp xếp, phân trang
GET /api/products/:idOrSlug Công khai Chi tiết sản phẩm: bảng thông số, hoặc linh kiện cấu thành nếu là máy bộ
POST /api/products Nhân viên, Admin Tạo linh kiện (specs) hoặc máy tính bộ (components)
PATCH /api/products/:id Nhân viên, Admin Cập nhật một phần; specs/components thay toàn bộ
DELETE /api/products/:id Admin Ẩn sản phẩm (xóa mềm)
GET /api/wishlist Đã đăng nhập Danh sách yêu thích (items, productIds)
POST /api/wishlist/:productId Đã đăng nhập Thêm vào yêu thích (idempotent)
DELETE /api/wishlist/:productId Đã đăng nhập Bỏ yêu thích
POST /api/compatibility/check Công khai Kiểm tra cấu hình { items: [{ productId, quantity }] }: tóm tắt, kết quả từng luật, công suất ước tính
POST /api/compatibility/candidates Công khai Chấm điểm danh sách sản phẩm cho một vị trí (componentType, productIds) so với cấu hình hiện tại

Tham số GET /api/products

Tham số Ví dụ Ý nghĩa
q q=ryzen 7600 Mỗi từ khóa phải có trong tên, SKU hoặc thương hiệu
category category=cpu / category=pc Slug danh mục; danh mục cha lấy cả danh mục con. Bắt buộc khi dùng specs
brand brand=intel,amd Slug thương hiệu, nhiều giá trị cách nhau dấu phẩy
minPrice, maxPrice minPrice=2000000 Khoảng giá bán thực tế (đã tính khuyến mãi)
inStock inStock=true Chỉ còn hàng / hết hàng (theo inventory)
onSale onSale=true Chỉ sản phẩm đang có giá khuyến mãi
ids ids=1003,2001 Lấy theo danh sách id (tối đa 50) – dùng cho giỏ hàng, Build PC
sort price_asc newest (mặc định), price_asc, price_desc, name_asc, name_desc
page, limit page=2&limit=12 Phân trang (limit tối đa 100)
status status=all Chỉ Nhân viên/Admin: active (mặc định), inactive, discontinued, all
specs[...] xem bên dưới Lọc theo thông số kỹ thuật

Lọc thông số kỹ thuật — key là tên cột trong bảng *_specs, danh sách hợp lệ lấy từ GET /api/categories/:slug/filters:

specs[socket]=AM5,LGA1700                     # text: khớp một trong các giá trị
specs[vram_gb]=8,12                           # number: khớp một trong các giá trị
specs[cores][min]=6&specs[cores][max]=12      # number: khoảng (có thể chỉ min hoặc max)
specs[wifi]=true                              # boolean
specs[supported_sockets]=AM5                  # cột đa giá trị: danh sách có chứa giá trị

Trong một thông số các giá trị kết hợp bằng OR, giữa các thông số kết hợp bằng AND. Key không thuộc danh mục trả về 400 kèm danh sách allowedKeys.

Ví dụ: tản nước AIO hỗ trợ AM5, giá ≤ 3 triệu

GET /api/products?category=cooler&specs[cooler_type]=AIO&specs[supported_sockets]=AM5&maxPrice=3000000

Kiểm thử

# Unit test (bộ dựng truy vấn lọc, chuẩn hóa thông số, specRegistry, slugify)
cd backend && npm test

# API test: chạy toàn bộ Postman collection (cần hệ thống đang chạy)
npx newman run postman/TranKhanhPC.postman_collection.json -e postman/TranKhanhPC.local.postman_environment.json

Hoặc import 2 file trong postman/ vào Postman và chạy bằng Collection Runner theo thứ tự — các request đăng nhập tự lưu token vào collection variables. Collection được sinh từ postman/generate.js (node postman/generate.js).

Endpoint đăng nhập/đăng ký giới hạn 50 request / 15 phút / IP. Nếu chạy collection nhiều lần liên tiếp bị 429, chạy docker compose restart backend.

Quy ước commit

Theo Conventional Commits: feat, fix, test, docs, chore, refactor + phạm vi (auth, products, database, frontend...).

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages