Skip to main content

⚛️ Kiến trúc Frontend React 19 + Vite & Zustand

Tài liệu kỹ thuật hướng dẫn chuẩn phát triển giao diện người dùng Single Page Application (SPA) trên nền tảng React 19, Vite 8, Zustand 5Tailwind CSS v4.


1. Cấu trúc Thư mục Frontend (frontend/src/)

Frontend được tổ chức theo kiến trúc Domain-Driven Design (DDD) với các alias đường dẫn @/app, @/modules, @/shared:

frontend/src/
├── app/
│ ├── layouts/ # AdminLayout.jsx (nhân sự), UserLayout.jsx (Portal)
│ ├── router/ # AppRouter.jsx với lazy loading & code splitting
│ └── store/ # authStore.js, themeStore.js (Zustand Global State)
├── modules/ # Feature Modules độc lập
│ ├── academic/ # pages/, api/, hooks/, components/
│ ├── crm/
│ ├── finance/
│ ├── hrm/
│ └── examination/
├── shared/
│ ├── components/ # Reusable UI: Button, Input, Select, Modal, Badge, Table...
│ ├── hooks/ # useAuth, useDebounce, usePagination...
│ ├── services/ # apiClient.js (Axios instance với Interceptors)
│ └── utils/ # cn.js, format.js, currency.js
├── App.jsx, main.jsx, index.css

2. Quy tắc Lập trình Bắt buộc trên Frontend

R1: Không gọi trực tiếp apiClient trong React Component

Mọi thao tác gọi API BẮT BUỘC phải đi qua tầng Service (modules/< name>/api/< service>.js) và được bọc bởi Custom Hook (modules/< name>/hooks/use< Feature>.js).

// ✅ modules/academic/api/classService.js
import apiClient from '@/shared/services/apiClient';

export const classService = {
getClasses: (params) => apiClient.get('/api/v1/academic/classes', { params }),
createClass: (data) => apiClient.post('/api/v1/academic/classes', data),
};

R2: Quản lý Auth State & X-Center-ID Header

  • Token xác thực Sanctum Bearer và activeCenterId được lưu trong authStore.js (persisted as lms-auth-storage trong localStorage).
  • Axios Interceptor trong apiClient.js tự động gắn Authorization: Bearer < token>X-Center-ID: < activeCenterId> vào mọi request.
  • Khi nhận response 401 Unauthorized → Tự động xóa state và chuyển hướng về /admin/login.
  • Khi nhận response 403 INVALID_CENTER → Chuyển hướng người dùng về màn hình chọn chi nhánh (/select-center).

R3: Sử dụng Shared Components & Lucide Icons

  • Tuyệt đối không dùng thẻ HTML thô < input>, < select>; sử dụng component chuẩn từ @/shared/components/ (Input, Select, Button, Modal, DataTable).
  • Sử dụng thư viện icon lucide-react. Tuyệt đối không chèn ký tự emoji vào mã nguồn code.

🔗 Xem thêm