82 lines
3.1 KiB
Markdown
82 lines
3.1 KiB
Markdown
# APLP Frontend — Conventions
|
|||
|
|
|
||
|
|
| | |
|
||
|
|
| --- | --- |
|
||
|
|
| **Status** | Phase 0 hoàn tất |
|
||
|
|
|
||
|
|
## 1. Language & Tooling
|
||
|
|
|
||
|
|
- **TypeScript** cho toàn bộ code. Không dùng `any` tùy tiện; ưu tiên explicit types.
|
||
|
|
- Lint: **oxlint** (đã confirm Phase 0); format: **Prettier**.
|
||
|
|
- Convention: file `.tsx` cho React components; kiểu dùng interface cho props.
|
||
|
|
|
||
|
|
## 2. Naming
|
||
|
|
|
||
|
|
| Loại | Quy ước |
|
||
|
|
| --- | --- |
|
||
|
|
| Component | PascalCase (`CourseCard.tsx`) |
|
||
|
|
| Hook | camelCase, prefix `use` (`useLearningProgress.ts`) |
|
||
|
|
| Page/route | PascalCase trong `pages/` |
|
||
|
|
| API function | camelCase (`fetchCourseDetail`) |
|
||
|
|
| Types/interface | PascalCase (`CourseDetailDto`, `ApiError`) |
|
||
|
|
|
||
|
|
## 3. Component Rules
|
||
|
|
|
||
|
|
- Component nhỏ, single responsibility.
|
||
|
|
- Props dùng interface; optional props explicit.
|
||
|
|
- Logic phức tạp nên tách vào hooks.
|
||
|
|
- Components dùng chung đặt `src/shared/components`; feature-specific vào `features/<feature>/components`.
|
||
|
|
- Không đặt business logic vào JSX.
|
||
|
|
|
||
|
|
## 4. State Management
|
||
|
|
|
||
|
|
- **Server state** → TanStack Query (query keys chuẩn: `['course', id]`).
|
||
|
|
- **UI/local state** → `useState`; nếu cần chia sẻ toàn app → Zustand store.
|
||
|
|
- Không đặt server data vào Zustand khi đã có React Query (tránh trùng source of truth).
|
||
|
|
- Tên store: domain concept (`useLearnerStore`).
|
||
|
|
|
||
|
|
## 5. API Layer
|
||
|
|
|
||
|
|
- Gọi backend qua `src/api` wrapper. Không gọi `fetch`/axios trực tiếp tại component.
|
||
|
|
- Response mapping/error handling nằm trong api layer.
|
||
|
|
- Có hằng số endpoint riêng, không đặt URL rải rác.
|
||
|
|
|
||
|
|
## 6. Error & Loading States
|
||
|
|
|
||
|
|
- Mọi view fetch/save cần xử lý: loading, empty, error, success.
|
||
|
|
- Dùng shared components (Spinner, EmptyState, ErrorState / ErrorBoundary).
|
||
|
|
- Hiển thị lỗi user-friendly từ `ApiError` của backend; không hiện stack trace.
|
||
|
|
|
||
|
|
## 7. Styling
|
||
|
|
|
||
|
|
- Dùng design tokens/theme (xác nhận stack Phase 0).
|
||
|
|
- Không hard-code color/margin lộn xộn; ưu tiên class utility/component thống nhất.
|
||
|
|
- Responsive theo grid/breakpoints chuẩn.
|
||
|
|
|
||
|
|
## 8. Testing
|
||
|
|
|
||
|
|
- Unit test components/hooks: Vitest.
|
||
|
|
- Render test với testing-library.
|
||
|
|
- E2E (Playwright) — optional, đánh giá sau.
|
||
|
|
- Test file đặt cạnh source (`Component.test.tsx`) hoặc `__tests__/` — chọn 1 để thống nhất.
|
||
|
|
|
||
|
|
## 9. Git & Collaboration
|
||
|
|
|
||
|
|
- Commit nhỏ, message rõ (theo style repo khi setup lại).
|
||
|
|
- Dùng feature branch + review.
|
||
|
|
- Lint + typecheck + test chạy qua (lệnh chuẩn `npm run lint`, `npm run typecheck`, `npm test`) trước khi merge.
|
||
|
|
|
||
|
|
## 10. Security
|
||
|
|
|
||
|
|
- **Không** lưu secret/token vào code hay log.
|
||
|
|
- Không put credentials vào env file committed (`.env` → `.env.example`).
|
||
|
|
- Không render user content bằng `dangerouslySetInnerHTML` trừ khi đã sanatize.
|
||
|
|
|
||
|
|
## 11. Open Questions
|
||
|
|
|
||
|
|
| ID | Question | Status |
|
||
|
|
| --- | --- | --- |
|
||
|
|
| CON-001 | ESLint config (airbnb/custom)? | **Resolved: oxlint (default config)** |
|
||
|
|
| CON-002 | Path alias (`@/`)? | **Resolved: có (`@` → `src`)** |
|
||
|
|
| CON-003 | Test file location convention? | **Resolved: đặt cạnh source (`Component.test.tsx`)** |
|
||
|
|
| CON-004 | Storybook có cần? | Open |
|