Hệ thống quản lý trung tâm IELTS (ICMS) gồm hai phần chính: Frontend (React + Vite) và Backend (Node.js + Express + Supabase PostgreSQL).
Mỗi khi bạn clone dự án hoặc vừa git pull nhánh mới nhất về, hãy luôn thực hiện các bước sau để đảm bảo môi trường đồng bộ:
Vì đây là 2 dự án độc lập, bạn cần chạy cài đặt cho cả Backend và Frontend:
# Cài đặt cho Backend
cd backend
npm install
# Cài đặt cho Frontend
cd ../frontend
npm install- Backend: Tạo file
.envở thư mụcbackend/dựa theo mẫu.env.example. - Cấu hình các thông số cốt lõi:
PORT(Thường là 5000),SUPABASE_URL, vàSUPABASE_KEY(Sử dụng API credentials từ Supabase Dashboard).
Mở 2 cửa sổ Terminal (hoặc tab) riêng biệt:
Terminal 1 - Chạy Backend:
cd backend
npm run devBackend sẽ khởi chạy tại http://localhost:5000. Bạn có thể truy cập API Docs qua Swagger tại http://localhost:5000/api-docs.
Terminal 2 - Chạy Frontend:
cd frontend
npm run devFrontend sẽ được Host tại http://localhost:5173.
Sử dụng React 19, Vite, Tailwind CSS và Shadcn/UI:
src/components/: Reusable UI components (Nút bấm, Input, Modal,...).src/pages/: Layout của các trang chính (Login, Home, Admin Dashboard,...).src/services/: Logic gọi API (thông qua Axios/Fetch).src/hooks/: Custom React Hooks.src/layouts/: Các khung Layout tái sử dụng (MainLayout, AuthLayout,...).src/store/hoặcsrc/context/: Quản lý State toàn cục.
Sử dụng Node.js, Express, TypeScript và Jest:
src/configs/: Khởi tạo kết nối DB Supabase, cấu hình hệ thống và Swagger.src/middlewares/: Filter trung gian (Xác thực Auth Token, phân quyền Role, xử lý Lỗi,...).src/modules/: [QUAN TRỌNG] Chứa logic nghiệp vụ được đóng gói theo từng domain (Ví dụ: Auth, Account, Courses,...).src/utils/: Hàm tiện ích dùng chung (Regex Validator, Gửi Email OTP,...).
Khi phát triển một API / Tính năng mới, hãy tuân thủ kiến trúc Module Pattern để giữ code Clean và dễ mở rộng.
Giả sử tạo tính năng Payment. Tạo thư mục backend/src/modules/payment và tạo các file sau:
payment.model.ts:- Nhiệm vụ: Định nghĩa các Interface, Type, DTO (Data Transfer Object) hoặc Schema (ví dụ dùng Zod) dùng chung cho toàn bộ module. Giúp đảm bảo tính toàn vẹn dữ liệu (Type-Safety) xuyên suốt từ Request cho đến Database.
payment.controller.ts:- Nhiệm vụ: Tiếp nhận Request (
req.body,req.query) và chuyển tiếp xuống Service. Tuyệt đối KHÔNG thực hiện Validate dữ liệu tại Controller. - Nhận kết quả từ Service và trả về Response (ví dụ:
200 OKhoặc catch lỗi để trả về400/500).
- Nhiệm vụ: Tiếp nhận Request (
payment.service.ts:- Nhiệm vụ: Thực hiện Validate rất nghiêm ngặt dữ liệu đầu vào dựa trên Model/DTO và chứa toàn bộ Business Logic cốt lõi (Kiểm tra điều kiện, tính toán,...).
- Xử lý lỗi (Error Handling): Khi xử lý logic hoặc validate mà phát hiện lỗi, tiến hành
throwluôn tại đây (VD:throw new Error('Invalid data')). Không đẩy luồng dữ liệu lỗi xuống Repository mới throw nếu có thể bắt được từ sớm. - Gọi tới Repository/Supabase để lấy hoặc lưu dữ liệu khi các điều kiện đã hợp lệ.
payment.repository.ts(Tùy chọn):- Nhiệm vụ: Nơi chứa 100% các câu Query tương tác trực tiếp tới DB / Supabase Client.
payment.route.ts:- Nhiệm vụ: Khai báo URL Endpoint, gắn Middleware (VD:
verifyToken,requireRole(['ADMIN'])) và liên kết tới Controller.
- Nhiệm vụ: Khai báo URL Endpoint, gắn Middleware (VD:
Trong file payment.route.ts, hãy sử dụng JSDoc phía trên từng định nghĩa Route để tạo tài liệu tự động:
/**
* @swagger
* /api/payment/checkout:
* post:
* summary: Xử lý thanh toán
* tags: [Payment]
* security:
* - bearerAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* amount:
* type: number
* responses:
* 200:
* description: Thanh toán thành công
*/
router.post('/checkout', verifyToken, PaymentController.checkout);Trong thư mục module vừa tạo, thêm một thư mục con là __tests__ (backend/src/modules/payment/__tests__). Mọi việc kiểm thử sẽ gom gọn vào đây!
Tạo file payment.http:
- File này dùng Extension "REST Client" trong VS Code.
- Cấu hình một cái
@baseUrlvà viết các request mẫu để Frontend hoặc Backend có thể clickSend Requestvà Test API nhanh chóng ngay trong Editor mà không cần Postman.
@baseUrl = http://localhost:5000/api
@accessToken = YOUR_BEARER_TOKEN
### Tạo thanh toán mới
POST {{baseUrl}}/payment/checkout
Authorization: Bearer {{accessToken}}
Content-Type: application/json
{
"amount": 500000
}Tạo file payment.controller.test.ts:
- Sử dụng
supertestkết hợpjest. - Tập trung bao phủ toàn bộ các Edge Cases (Trường hợp dị thường):
- Gửi thiếu trường
amount-> Expect trả về lỗi 400. - Gửi
amountlà chữ -> Expect trả về lỗi 400. - Mockup Service báo lỗi "Số dư không đủ" -> Expect trả về 400 và câu thông báo.
- Gửi thiếu trường
- Chạy lệnh test:
npm run testĐảm bảo kết quả test luôn đạt màu xanh 100% trước khi đẩy code lên!