⚛️ 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 5 và Tailwind 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 trongauthStore.js(persisted aslms-auth-storagetronglocalStorage). - Axios Interceptor trong
apiClient.jstự động gắnAuthorization: Bearer < token>và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.