prompts.chatprompts.chatprompts.chat
BotPromptKỹ năngQuy trìnhDanh mụcThẻCao thủ PromptPhong cách
SáchCho trẻ emNhà phát triển
Đăng nhập
CC0 2026 prompts.chat
DeepWikiHướng dẫn...Tài liệuAPIQuyền riêng tưĐiều khoảnHỗ trợGiới thiệuGitHub

Hướng dẫn Chung cho các Dự án React / Next.js

Bộ hướng dẫn này phù hợp cho cả các dự án mới và các dự án hiện có.

R
@ramazan747
about 4 hours agolúc 15:31 30 tháng 10, 2026
Web Development

Nội dung

Biến
1# Hướng dẫn Chung cho các Dự án React / Next.js
2
3> Mục đích: Các quy tắc chung để phát triển nhiều loại dự án khác nhau với React + TypeScript, Next.js + TypeScript và Tailwind CSS.
4> Cách sử dụng: Đặt tệp này vào thư mục gốc của một dự án mới dưới tên `AGENTS.md`, `CLAUDE.md` hoặc `PROJECT_RULES.md`, hoặc sử dụng nó làm tập hướng dẫn cơ sở cho một tác tử AI (AI agent).
5> Quan trọng: Các hướng dẫn này không chứa quy tắc đặc thù của từng sản phẩm. Hãy lưu giữ mọi thứ liên quan đến một dự án riêng lẻ trong một tệp `PROJECT_RULES.md` tách biệt.
6
7---
8
9# 1. Nguyên tắc Cốt lõi
10
11Xây dựng một ứng dụng sẵn sàng cho môi trường thực tế (production-ready), chứ không phải một tập hợp các thành phần (components) rời rạc.
12
13Luôn tuân theo trình tự sau:
14
151. Xem xét cấu trúc dự án hiện tại, `package.json`, cơ chế định tuyến (routing), các nguyên hàm giao diện (UI primitives), các kho lưu trữ trạng thái (stores), hooks, lược đồ (schemas) và quy tắc dự án.
162. Tìm kiếm các hành động (actions), hàm bổ trợ (helpers), lược đồ và các thành phần hiện có có thể tái sử dụng được.
173. Xác định thay đổi nhỏ nhất cần thiết cho tác vụ.
184. Bảo toàn hành vi hiện có.
195. Triển khai từng tính năng mới trọn vẹn từ đầu đến cuối (end to end): mô hình dữ liệu, xác thực, giao diện, lưu trữ/nhập/xuất, các trường hợp biên và bước xác minh.
206. Chạy các bước kiểm tra có liên quan và báo cáo kết quả một cách trung thực.
21
22Không thêm các thư viện phụ thuộc (dependencies), lớp trừu tượng, store toàn cục hoặc tầng kiến trúc trừ khi chúng thực sự cần thiết.
23Sử dụng `shadcn/ui` theo mặc định cho công việc giao diện. Không thêm một bộ UI kit khác chồng lên trên nó nếu không có lý do rõ ràng.
24
25---
26
27# 2. Lựa chọn giữa React và Next.js
28
29Sử dụng Next.js khi dự án cần:
30
31- định tuyến (routing);
32- tối ưu hóa công cụ tìm kiếm (SEO);
33- SSR / Server Components;
34- Server Actions;
35- Route Handlers / các tuyến API (API routes);
36- xác thực người dùng (authentication);
37- truy cập cơ sở dữ liệu;
38- các biến môi trường riêng tư;
39- xuất bản nội dung.
40
41Sử dụng React + Vite khi:
42
43- ứng dụng chạy hoàn toàn ở phía trình khách (client-side);
44- không yêu cầu SEO;
45- đó là một công cụ cục bộ, bảng điều khiển (dashboard), trình soạn thảo, trang quản trị (admin panel) hoặc giao diện giống ứng dụng máy tính để bàn;
46- máy chủ đã tồn tại như một dịch vụ riêng biệt.
47
48Đừng chọn Next.js chỉ vì nó phổ biến. Không thêm Redux, Zustand, React Query, thư viện biểu mẫu hoặc một bộ UI kit khác nếu không có lý do cụ thể.
49
50---
51
52# 3. Bộ công nghệ Mặc định và Các bước Kiểm tra
53
54Sử dụng các công nghệ sau theo mặc định:
55
56- React;
57- TypeScript ở chế độ nghiêm ngặt (strict mode);
58- Tailwind CSS;
59- `shadcn/ui` làm phương pháp tiếp cận giao diện bắt buộc để có thiết kế gọn gàng và phát triển giao diện nhanh chóng;
60- Lucide React hoặc thư viện biểu tượng được sử dụng bởi cấu hình shadcn hiện tại;
61- ESLint;
62- hàm bổ trợ `cn()` dùng chung;
63- xác thực thời gian chạy (runtime validation) đối với dữ liệu bên ngoài;
64- các phần tử HTML hỗ trợ khả năng tiếp cận (accessible HTML elements).
65
66Sử dụng `shadcn/ui` làm nguồn chính cung cấp các nguyên hàm giao diện: nút bấm, ô nhập liệu, ô chọn (selects), hộp thoại (dialogs), bảng trượt (sheets), menu thả xuống (dropdowns), chú giải công cụ (tooltips), các tab, băng chuyền (carousels), thẻ (cards), huy hiệu (badges), khung xương tải trang (skeletons), vùng cuộn (scroll areas) và các thành phần cần thiết khác. Chỉ tạo các nguyên hàm tùy chỉnh khi shadcn không cung cấp thành phần phù hợp hoặc khi dự án đã có sẵn một nguyên hàm cục bộ ổn định.
67
68Đối với một bản MVP, hãy bắt đầu với dữ liệu giả lập (mock)/JSON/localStorage và xác thực các luồng người dùng cục bộ trước tiên. Thêm phần backend, cơ sở dữ liệu, thanh toán, xác thực và các tích hợp bên ngoài vào sau cùng, một khi giao diện, các mô hình dữ liệu và các luồng thao tác đã rõ ràng.
69
70Ở mức tối thiểu, hãy chạy các lệnh này sau khi thay đổi mã nguồn:
71
72```bash
73npm run typecheck
74npm run lint
75npm run build
76```
77
78Đừng tuyên bố rằng dự án hoạt động tốt nếu các lệnh này chưa được chạy hoặc chạy xong nhưng có lỗi.
79
80---
81
82# 4. Kiến trúc
83
84Đối với các dự án Next.js dự kiến sẽ phát triển lớn hơn, hãy giữ mã nguồn bên trong `src/` theo mặc định: `src/app`, `src/components`, `src/lib`, `src/data`, `src/hooks` và `src/features`. Giữ các thư mục và tệp hỗ trợ cấp gốc (`public`, các tệp cấu hình, tệp khóa phiên bản lockfiles và README) ở thư mục gốc của dự án.
85
86Đối với các dự án nhỏ, cấu trúc sau đây có thể chấp nhận được:
87
88```text
89src/
90 app/ or pages/
91 components/
92 features/
93 lib/
94 shared/
95```
96
97Đối với các dự án vừa và lớn, hãy sử dụng phương pháp tiếp cận tương tự FSD (Feature-Sliced Design):
98
99```text
100src/
101 app/ # bootstrap, providers, layouts, routes
102 views/ # page-level composition
103 widgets/ # large UI blocks
104 features/ # user workflows
105 entities/ # domain model
106 shared/ # generic helpers, config, thin wrappers around shadcn/ui
107```
108
109Chiều hướng import:
110
111```text
112app/views -> widgets -> features -> entities -> shared
113```
114
115Tuyệt đối không:
116
117- import `widgets` vào trong `features`;
118- đặt logic nghiệp vụ vào trong `shared`;
119- biến `shared/lib` thành nơi chứa tạp nham các hàm không liên quan với nhau;
120- sao chép trùng lặp logic thay đổi dữ liệu (mutation logic) trên nhiều thành phần giao diện;
121- sử dụng cách import sâu vào cấu trúc nội bộ của một mô-đun khác khi mô-đun đó đã cung cấp một API công khai (public API).
122
123---
124
125# 5. API Công khai (Public API)
126
127Mỗi thư mục tính năng (feature), thực thể (entity) hoặc giao diện dùng chung nên cung cấp một API công khai rõ ràng thông qua tệp `index.ts` khi mô-đun đó được sử dụng từ bên ngoài. Đối với các nguyên hàm shadcn, API công khai thường đã nằm sẵn trong `components/ui/*` hoặc tầng giao diện cục bộ của dự án.
128
129Tốt:
130
131```ts
132import { createTask } from "@/features/create-task";
133```
134
135Kém:
136
137```ts
138import { createTask } from "@/features/create-task/model/createTask";
139```
140
141Ngoại lệ: mã nguồn nội bộ bên trong cùng một tính năng hoặc thực thể.
142
143---
144
145# 6. TypeScript
146
147Bắt buộc:
148
149- bật `strict: true`;
150- không sử dụng `any` ngoại trừ trong phần mã tương tác hệ thống (interoperability code) đã được cô lập;
151- không che giấu lỗi kiểu dữ liệu bằng phép ép kiểu `as`;
152- sử dụng kiểu hợp phân biệt (discriminated unions) cho trạng thái phức tạp;
153- xác thực dữ liệu JSON lúc chạy (runtime) bằng một lược đồ (schema);
154- không tạo nhiều kiểu dữ liệu giống hệt nhau nếu không có lý do có ý nghĩa.
155
156Ví dụ về kiểu trạng thái:
157
158```ts
159type LoadState<T> =
160 | { status: "idle" }
161 | { status: "loading" }
162 | { status: "success"; data: T }
163 | { status: "error"; message: string };
164```
165
166---
167
168# 7. Trạng thái (State) và Hiệu ứng (Effects) trong React
169
170Lưu trữ trạng thái ở nơi nó thực sự thuộc về:
171
172| Loại trạng thái | Nơi lưu trữ |
173| ----------------------------- | ----------------------------------------------------------------------- |
174| Giao diện cục bộ (Local UI) | `useState`, `useReducer` |
175| Trạng thái URL | các tham số route/search |
176| Trạng thái máy chủ | kết xuất phía máy chủ (server rendering) hoặc tầng cache/query |
177| Trạng thái biểu mẫu | hook/thư viện quản lý biểu mẫu |
178| Giao diện toàn cục | một store nhỏ khi cần thiết |
179| Trạng thái miền (Domain state)| thực thể/store khi trạng thái được chia sẻ qua nhiều luồng thao tác |
180
181Không đặt những thứ sau đây vào store toàn cục:
182
183- trạng thái di chuột (hover state);
184- trạng thái đóng/mở của một menu thả xuống đơn lẻ;
185- giá trị nháp của một ô nhập liệu đơn lẻ;
186- trạng thái của một hộp thoại (modal) đơn lẻ;
187- tab đang chọn tạm thời của một thành phần.
188
189Sử dụng `useEffect` để đồng bộ hóa với các hệ thống bên ngoài:
190
191- các API của trình duyệt;
192- bộ hẹn giờ (timers);
193- các đăng ký lắng nghe sự kiện (subscriptions);
194- các store bên ngoài;
195- các tích hợp DOM.
196
197Không sử dụng `useEffect` cho các giá trị dẫn xuất (derived values).
198
199Kém:
200
201```tsx
202const [fullName, setFullName] = useState("");
203
204useEffect(() => {
205 setFullName(` `);
206}, [firstName, lastName]);
207```
208
209Tốt:
210
211```tsx
212const fullName = ` `;
213```
214
215---
216
217# 8. Ranh giới trong Next.js
218
219Trong App Router, các thành phần là Server Components theo mặc định.
220
221Chỉ thêm `"use client"` ở những nơi bạn cần:
222
223- các trình xử lý sự kiện (event handlers);
224- trạng thái cục bộ;
225- các hiệu ứng (effects);
226- `window`, `document` hoặc `localStorage`;
227- kéo và thả (drag and drop);
228- `contenteditable`;
229- các thư viện chỉ chạy ở phía trình khách (client-only libraries).
230
231Đừng biến toàn bộ một bố cục (layout) thành Client Component nếu không có nhu cầu rõ ràng.
232
233Mã nguồn chỉ chạy trên máy chủ (Server-only code) bao gồm:
234
235- truy cập cơ sở dữ liệu;
236- xác thực người dùng;
237- các trình khách API riêng tư;
238- các biến môi trường bí mật;
239- webhooks;
240- kiểm tra quyền truy cập.
241
242Không bao giờ import một mô-đun chỉ dành cho máy chủ vào trong một Client Component.
243
244---
245
246# 9. Xác thực Thời gian chạy và Di chuyển dữ liệu (Migrations)
247
248Xác thực toàn bộ dữ liệu bên ngoài ngay tại ranh giới tiếp nhận:
249
250- phần thân yêu cầu (request bodies);
251- dữ liệu biểu mẫu;
252- các tham số URL/search;
253- các tệp được tải lên;
254- dữ liệu JSON được nhập vào;
255- dữ liệu trong localStorage/IndexedDB;
256- các phản hồi từ API bên ngoài.
257
258Khi thêm một trường mới vào mô hình dữ liệu, hãy cập nhật toàn bộ vòng đời của nó:
259
2601. Kiểu dữ liệu TypeScript.
2612. Lược đồ kiểm tra thời gian chạy (Runtime schema).
2623. Các giá trị khởi tạo (factory)/mặc định.
2634. Trình phân tích cú pháp/chuyển đổi cho dữ liệu cũ (legacy data).
2645. Các hàm bổ trợ chuẩn hóa dữ liệu (Normalization helpers).
2656. Tính năng nhập/xuất (Import/export).
2667. Đánh chỉ mục tìm kiếm/lọc, nếu trường đó cần có khả năng tìm kiếm được.
2678. Bản chụp hoàn tác/làm lại (Undo/redo snapshots), nếu người dùng có thể chỉnh sửa trường đó.
2689. Giao diện để tạo, chỉnh sửa và xóa giá trị trường đó.
26910. Các trường hợp biên và bước kiểm tra.
270
271Ví dụ:
272
273```ts
274return {
275 ...item,
276 status: item.status ?? "active",
277 tags: normalizeTags(item.tags),
278 dueDate: normalizeDate(item.dueDate),
279};
280```
281
282Đừng chỉ thêm một trường mô hình dữ liệu ở mỗi tầng giao diện.
283
284---
285
286# 10. Biểu mẫu (Forms)
287
288Mọi biểu mẫu phải bao gồm:
289
290- một lược đồ xác thực (validation schema);
291- hiển thị lỗi của từng trường;
292- trạng thái đang gửi/đang tải (submitting/loading);
293- nút gửi bị vô hiệu hóa trong khi đang gửi;
294- cơ chế bảo vệ chống gửi trùng lặp nhiều lần;
295- trạng thái báo lỗi;
296- hành vi khi gửi thành công;
297- hành vi đặt lại (reset)/lưu nháp, khi áp dụng.
298
299Một biểu mẫu chưa được coi là hoàn chỉnh nếu nó chỉ hoạt động khi yêu cầu gửi đi thành công mỹ mãn.
300
301---
302
303# 11. shadcn/ui và Giao diện Dùng chung
304
305Sử dụng `shadcn/ui` theo mặc định để xây dựng các giao diện sạch sẽ, nhất quán một cách nhanh chóng.
306
307Quy tắc:
308
309- trước tiên hãy kiểm tra xem thành phần cần thiết có tồn tại trong kho đăng ký (registry) của shadcn hay không;
310- thêm các thành phần shadcn thông qua CLI hoặc phương thức cục bộ đã được thiết lập của dự án;
311- không tự tạo mới Button, Input, Modal, Dropdown, Tooltip, Tabs hoặc Card tùy chỉnh nếu shadcn đã đáp ứng được trường hợp sử dụng đó;
312- điều chỉnh các thành phần shadcn thông qua `className`, các biến thể (variants) và sự kết hợp (composition) thay vì sao chép ra các thành phần tương tự;
313- giữ các thành phần nghiệp vụ tách biệt khỏi các nguyên hàm giao diện: `components/marketplace`, `features/*/ui`, `widgets/*` hoặc `entities/*/ui`;
314- chỉ giữ các nguyên hàm shadcn và các lớp bọc mỏng có thể tái sử dụng trong `components/ui` hoặc `shared/ui`;
315- không đặt các thành phần nghiệp vụ đặc thù của sản phẩm vào đó;
316- nếu shadcn không cung cấp một thành phần nào đó, hãy tạo một lớp bọc cục bộ tối giản nhất quán với cấu hình shadcn hiện tại.
317
318Tập hợp cơ sở các thành phần shadcn dành cho giao diện hiệu suất công việc (productivity interfaces):
319
320```text
321button
322input
323select
324textarea
325checkbox
326switch
327dialog
328sheet
329dropdown-menu
330popover
331tooltip
332tabs
333card
334badge
335avatar
336separator
337scroll-area
338skeleton
339carousel
340accordion
341collapsible
342hover-card
343```
344
345Đối với các luồng chợ thương mại (marketplace), trò chuyện (chat) và hỗ trợ khách hàng, hãy lên kế hoạch sử dụng thêm các thành phần shadcn mới hơn sau đây:
346
347```text
348message
349message-scroller
350attachment
351marker
352```
353
354Luôn sử dụng hàm `cn()`:
355
356```ts
357export function cn(...values: Array<string | false | null | undefined>) {
358 return values.filter(Boolean).join(" ");
359}
360```
361
362---
363
364# 12. Chọn Bề mặt Giao diện Phù hợp
365
366Trước khi thêm một công cụ mới, hãy chọn bề mặt hiển thị phù hợp:
367
368| Quy mô tính năng | Vị trí đặt | Ví dụ |
369| -------------------------------------------- | ---------------------------------------- | -------------------------------------------- |
370| 1-5 cài đặt nhanh | menu ngữ cảnh / dropdown / popover | trạng thái, ngày đến hạn, thẻ gắn (tags) |
371| 5-12 cài đặt được phân nhóm | popover chia mục, có thể cuộn | thuộc tính thực thể, bộ lọc thu gọn |
372| tập dữ liệu lớn hoặc thao tác hàng loạt | thanh bên (sidebar) / ngăn kéo (drawer) | bộ lọc, bảng công cụ |
373| biểu mẫu phức tạp hoặc hành động nguy hiểm | hộp thoại (modal) | nhập/xuất dữ liệu, xác nhận xóa |
374| không gian làm việc cố định | trang/khung nhìn/widget chuyên dụng | bảng điều khiển, lịch, trình soạn thảo |
375
376Quy tắc:
377
378> Nếu một điều khiển chỉ được sử dụng thỉnh thoảng, hãy giữ nó trong một menu.
379> Nếu một điều khiển được sử dụng liên tục, hãy giữ nó hiển thị trên bề mặt chính.
380> Nếu một điều khiển phức tạp và dài dòng, hãy chuyển nó sang thanh bên hoặc hộp thoại modal.
381
382Đừng biến một nhóm nhỏ các điều khiển thành một thẻ (card) lớn chiếm diện tích trên trang. Trong các giao diện làm việc tập trung vào năng suất, điều này làm lãng phí không gian quý giá.
383
384---
385
386# 13. Giao diện Thu gọn cho Trình soạn thảo, Bảng điều khiển và Không gian làm việc
387
388Trong các ứng dụng hiệu suất công việc, nội dung chính phải luôn là tâm điểm chú ý.
389
390Bắt buộc:
391
392- tiêu đề, phần thân, bảng công việc hoặc trình soạn thảo không được bị đẩy tụt xuống dưới bởi các điều khiển phụ;
393- các thuộc tính của thực thể nhìn chung nên được mở từ một nút biểu tượng nằm cạnh tiêu đề;
394- các nút cài đặt phải có thuộc tính `aria-label`;
395- một trạng thái quan trọng có thể được hiển thị dưới dạng một huy hiệu (badge) nhỏ;
396- các hành động tạo/thêm mới phải xuất hiện trong một ngữ cảnh rõ ràng;
397- các luồng phụ thuộc nhiều vào thanh bên phải bao gồm một menu hoặc bộ chuyển đổi thân thiện với thiết bị di động;
398- đừng làm cho một công cụ làm việc trông giống như một trang đích quảng cáo (landing page).
399
400Kém:
401
402```tsx
403
404 <Select>Status</Select>
405 <Select>Task</Select>
406 <Input>Date</Input>
407 <Input>Tags</Input>
408</LargePropertiesCard>
409```
410
411Tốt:
412
413```tsx
414
415 <TitleInput />
416 <PropertiesMenu />
417</TitleRow>
418```
419
420---
421
422# 14. Lớp phủ (Overlays), Menu thả xuống (Dropdowns), Popovers và Menu Ngữ cảnh
423
424Mọi menu phải hoạt động như một lớp phủ (overlay) thực thụ.
425
426Quy tắc:
427
428- nếu một menu có thể vượt ra ngoài khung chứa của nó, hãy kết xuất nó thông qua `createPortal(..., document.body)`;
429- sử dụng `position: fixed` hoặc một công cụ định vị đáng tin cậy;
430- đặt giá trị `z-index` tường minh;
431- sử dụng `backgroundColor` đặc (không trong suốt);
432- không chỉ dựa vào nền bán trong suốt `bg-black/50` hoặc hiệu ứng làm mờ (blur);
433- thêm đường viền (border), vòng viền (ring) hoặc bóng đổ (shadow);
434- đặt `max-height` và `overflow-y-auto`;
435- đóng lại khi nhấn phím `Escape`;
436- đóng lại khi nhấp chuột/chạm ra bên ngoài;
437- ngăn văn bản trên trang hiển thị xuyên qua hoặc đè lên trên menu;
438- trạng thái di chuột (hover) và kích hoạt (active) không được làm thay đổi kích thước của mục chọn.
439
440Kiểu dáng lớp phủ tối thiểu:
441
442```tsx
443<div
444 role="menu"
445 className="rounded-2xl border p-2 shadow-2xl"
446 style="#151a21",
447 boxShadow: "0 24px 70px rgb(0 0 0 / 78%)",
448 isolation: "isolate",
449 zIndex: 1000,
450>
451 ...
452</div>
453```
454
455Nếu nền menu không hiển thị đúng hoặc nội dung bên dưới xuất hiện đè lên trên nó, hãy kiểm tra:
456
457- portal;
458- `position`;
459- `z-index`;
460- ngữ cảnh xếp chồng (stacking contexts) của phần tử cha;
461- `isolation`;
462- độ mờ đục (opacity)/màu nền;
463- thuộc tính tràn (overflow)/cắt xén (clipping) của phần tử cha.
464
465---
466
467# 15. Danh sách Tùy chọn trong Menu
468
469Danh sách các tác vụ, dự án, người dùng, thẻ gắn hoặc các tùy chọn khác trong một menu không được trông giống như một bức tường văn bản dày đặc.
470
471Đối với một mục hiển thị hai dòng:
472
473- sử dụng `min-height` từ 40-44px;
474- bao gồm khoảng cách `gap` giữa biểu tượng, văn bản và dấu tích chọn;
475- sử dụng khoảng đệm dọc chẳng hạn như `py-1.5`;
476- cung cấp chiều cao dòng (line heights) khác nhau cho tiêu đề và siêu dữ liệu (metadata);
477- thêm `mt-0.5` giữa tiêu đề và siêu dữ liệu;
478- áp dụng `min-w-0` cho phần tử cha chứa văn bản;
479- áp dụng `truncate` cho tiêu đề và siêu dữ liệu;
480- áp dụng `shrink-0` cho dấu tích chọn và các biểu tượng.
481
482Ví dụ:
483
484```tsx
485<button className="flex min-h-11 items-center gap-2.5 rounded-lg px-2.5 py-1.5">
486 <span className="min-w-0 flex-1">
487 <span className="block truncate font-medium leading-5"></span>
488 <span className="mt-0.5 block truncate text-xs leading-4 text-muted">
489 {meta}
490 </span>
491 </span>
492 {isActive ? <Check className="shrink-0" /> : null}
493</button>
494```
495
496---
497
498# 16. Văn bản Dài và Hiện tượng Tràn khung (Overflow)
499
500Bất kỳ văn bản nào do người dùng cung cấp cũng có thể chứa một từ rất dài không có khoảng trắng.
501
502Đối với các trình soạn thảo, phần tử `contenteditable`, Markdown, tiêu đề thẻ (card titles) và bình luận:
503
504- sử dụng `min-w-0` trên các phần tử con của flex/grid;
505- sử dụng các lớp tiện ích (utilities) hiện hành của Tailwind để ngắt dòng các từ dài;
506- trong các phiên bản Tailwind mới hơn, `break-words` có thể được viết là `wrap-break-word`;
507- kiểm tra tài liệu của phiên bản Tailwind hiện tại trong dự án trước khi sử dụng các lớp ngắt dòng, tràn khung, text-wrap, grid, khoảng cách hoặc giá trị tùy ý (arbitrary-value);
508- nếu một phần tử nằm bên trong khung chứa flex và văn bản dài làm vỡ chiều rộng của nó, hãy kiểm tra xem `wrap-anywhere` có phù hợp hay không;
509- sử dụng `truncate` cho các dòng ngắn trong thẻ;
510- ngắt dòng văn bản phần thân thay vì để xảy ra hiện tượng tràn ngang;
511- văn bản không được hiển thị đè lên trên menu, popover hoặc hộp thoại modal;
512- kiểm thử bằng một chuỗi ký tự dài không chứa khoảng trắng.
513
514Đối với một khối có thể chỉnh sửa:
515
516```tsx
517className = "min-w-0 wrap-break-word whitespace-pre-wrap";
518```
519
520Nếu dự án sử dụng phiên bản Tailwind cũ hơn chưa có `wrap-break-word`, hãy kiểm tra phiên bản Tailwind đã cài đặt cùng tài liệu chính thức hoặc ghi chú phiên bản, sau đó sử dụng cách tương đương được hỗ trợ: `break-words`, một giá trị tùy ý hoặc thuộc tính CSS thuần.
521
522Đối với một huy hiệu (badge):
523
524```tsx
525className = "inline-flex whitespace-nowrap";
526```
527
528Một huy hiệu không được ép nén văn bản theo chiều dọc. Nếu không đủ chỗ, hãy chuyển nó xuống dòng mới hoặc sử dụng `truncate` với chiều rộng tường minh, dễ hiểu.
529
530---
531
532# 17. Tailwind CSS: Xác minh Tên Lớp (Class Names) Hiện hành
533
534Tác tử AI phải kiểm tra phiên bản Tailwind được cài đặt trong dự án trước khi sử dụng các lớp mới hoặc có khả năng phụ thuộc vào phiên bản.
535
536Quy trình:
537
5381. Kiểm tra `package.json` và tệp lockfile.
5392. Xác định phiên bản chính (major version) của Tailwind.
5403. Nếu một lớp có thể khác nhau giữa các phiên bản, hãy kiểm tra tài liệu chính thức cho đúng phiên bản đó.
5414. Không thay thế các lớp một cách máy móc mà không xác minh.
5425. Khi sử dụng một giá trị tùy ý, hãy xác nhận rằng nó được đưa vào kết quả bản dựng (build output).
543
544Đặc biệt chú ý đến:
545
546- `break-words` / `wrap-break-word` / `wrap-anywhere`;
547- `text-wrap`, `text-balance` và `text-pretty`;
548- `overflow-*`;
549- `size-*`;
550- các màu sắc tùy ý chẳng hạn như `bg-[#151a21]`;
551- bóng đổ tùy ý;
552- các mẫu lưới (grid templates) tùy ý;
553- tên lớp được tạo động.
554
555Không tạo các lớp Tailwind động theo cách này:
556
557```tsx
558const color = "red";
559return <div className={`bg--500`} />;
560```
561
562Tailwind có thể không phát hiện ra lớp đó trong quá trình dựng (build). Hãy sử dụng một bảng ánh xạ (map):
563
564```tsx
565const colorClassName = {
566 danger: "bg-red-500",
567 success: "bg-emerald-500",
568};
569```
570
571Nếu một màu nền lớp phủ quan trọng không được phép phụ thuộc vào đầu ra bản dựng của Tailwind, việc sử dụng thuộc tính nội tuyến `style.backgroundColor` là có thể chấp nhận được.
572
573---
574
575# 18. Bố cục và Thu gọn Thanh bên (Sidebar Collapse)
576
577Việc thu gọn thanh bên hoặc ngăn kéo không được làm thay đổi chiều cao trang hoặc để lại một khối trống.
578
579Quy tắc:
580
581- khung vỏ ứng dụng (app shell): `h-dvh min-h-dvh overflow-hidden`;
582- các vùng bên trong: `flex min-h-0 flex-1 overflow-hidden`;
583- chỉ bật cuộn trên vùng phù hợp bằng `overflow-y-auto`;
584- khi thu gọn, hãy thay đổi chiều rộng/flex-basis thay vì chiều cao;
585- thanh bên đã thu gọn phải có chiều rộng ổn định;
586- cung cấp một nút điều khiển rõ ràng để khôi phục lại thanh bên;
587- các hành động mang tính phá hủy hoặc tạo mới không được nằm trơ trọi như những nút bấm cô lập không có ngữ cảnh;
588- các tùy chọn giao diện của người dùng có thể được lưu giữ trong localStorage.
589
590Ví dụ:
591
592```tsx
593<main className="flex h-dvh min-h-dvh flex-col overflow-hidden">
594 <div className="flex min-h-0 flex-1 overflow-hidden">
595 <Sidebar className="h-full min-h-0 shrink-0" />
596 <section className="min-h-0 flex-1 overflow-y-auto" />
597 </div>
598</main>
599```
600
601---
602
603# 19. Các API Trình duyệt và localStorage
604
605Trong Next.js, các API trình duyệt chỉ khả dụng bên trong Client Components.
606
607Quy tắc:
608
609- một tệp sử dụng `localStorage`, `window`, `document`, kéo và thả hoặc `contenteditable` bắt buộc phải có khai báo `"use client"`;
610- không đọc `localStorage` trong một Server Component;
611- không gây ra lỗi đồng bộ hóa (hydration errors) do các giá trị khởi tạo khác nhau giữa máy chủ và trình duyệt;
612- bọc các thao tác lưu trữ trong khối `try/catch`;
613- lỗi lưu trữ không được làm hỏng giao diện;
614- xác minh các tùy chọn giao diện đã lưu sau khi tải lại trang;
615- quá trình dựng (build) không được thất bại với lỗi `window is not defined`.
616
617Ví dụ:
618
619```tsx
620const toggle = useCallback(() => {
621 setIsCollapsed((current) => {
622 const next = !current;
623
624 try {
625 window.localStorage.setItem(KEY, next ? "true" : "false");
626 } catch {
627 // UI still works without browser storage.
628 }
629
630 return next;
631 });
632}, []);
633```
634
635Xác minh rằng:
636
637- trạng thái mặc định hoạt động tốt khi bộ nhớ trống;
638- việc tải lại trang vẫn giữ nguyên trạng thái;
639- chế độ ẩn danh (private mode) hoặc lỗi bộ nhớ không làm hỏng màn hình;
640- quá trình dựng không bị lỗi `window is not defined`.
641
642---
643
644# 20. Mối quan hệ Giữa các Công cụ
645
646Nếu một thực thể được liên kết với một thực thể khác, mối quan hệ đó phải là thật:
647
648- lưu trữ nó trong mô hình dữ liệu;
649- hiển thị nó trên giao diện;
650- nhấp vào nó sẽ mở ra thực thể được liên kết;
651- khi tạo thực thể có liên quan, hãy lưu mối quan hệ đó ngay lập tức;
652- bảo toàn mối quan hệ trong quá trình nhập/xuất dữ liệu;
653- đưa mối quan hệ vào hành vi tìm kiếm/lọc khi hữu ích;
654- nếu thực thể được liên kết bị xóa, hãy hiển thị trạng thái dự phòng (fallback) trên giao diện.
655
656Đừng tạo một nút "Liên kết" chỉ mang tính trang trí nếu mối quan hệ đó không được lưu trữ bền vững.
657
658---
659
660# 21. Thống nhất các Thao tác Miền (Domain Operations)
661
662Mỗi thao tác của người dùng phải có một nguồn chân lý duy nhất (single source of truth).
663
664Tuyệt đối không:
665
666- tạo một thực thể theo một kiểu từ menu lệnh gạch chéo (slash menu);
667- tạo nó theo một kiểu khác từ thanh công cụ;
668- bỏ qua bước xác thực khi gọi từ bảng lệnh (command palette);
669- sao chép trùng lặp logic thay đổi dữ liệu trong menu ngữ cảnh.
670
671Thay vào đó:
672
673- giữ thao tác miền ở một nơi duy nhất;
674- để các thành phần giao diện gọi tới thao tác đó;
675- sử dụng cùng một quy trình xác thực và các ràng buộc cho mọi điểm truy cập.
676
677---
678
679# 23. Khả năng Tiếp cận (Accessibility)
680
681Bắt buộc:
682
683- sử dụng `<button>` cho các hành động;
684- sử dụng `<a>` cho việc điều hướng;
685- thêm `aria-label` cho các nút chỉ có biểu tượng;
686- cung cấp nhãn (labels) cho các ô nhập liệu;
687- hiển thị trạng thái tiêu điểm (focus state) rõ ràng;
688- hỗ trợ điều hướng bằng bàn phím;
689- đóng hộp thoại modal và popover khi nhấn `Escape`;
690- đóng popover khi nhấp chuột ra bên ngoài;
691- sử dụng bẫy tiêu điểm (focus trap) trong các hộp thoại modal;
692- không sử dụng màu sắc làm cách duy nhất để truyền đạt ý nghĩa;
693- không thay thế `<button>` bằng ``.
694
695---
696
697# 24. Trạng thái Đang tải, Trống và Lỗi
698
699Các màn hình hiển thị theo dữ liệu phải tính đến:
700
701- trạng thái đang tải (loading);
702- trạng thái thành công (success);
703- trạng thái trống (empty state);
704- từ chối quyền truy cập (permission denied);
705- lỗi mạng (network error);
706- lỗi máy chủ (server error);
707- thao tác thử lại (retry).
708
709Một màn hình trắng trơn không có lời giải thích nào là một lỗi (bug).
710
711---
712
713# 25. Bảo mật
714
715Bắt buộc:
716
717- chỉ giữ các thông tin bí mật (secrets) ở phía máy chủ;
718- sử dụng xác thực thời gian chạy (runtime validation);
719- thực thi kiểm soát quyền truy cập ở phía máy chủ;
720- xác thực kiểu MIME và kích thước của tệp tải lên;
721- làm sạch (sanitize) mã HTML do người dùng cung cấp;
722- không sử dụng `dangerouslySetInnerHTML` mà không có bộ làm sạch mã (sanitizer);
723- không ghi nhật ký (log) các mã thông báo (tokens) hoặc dữ liệu cá nhân;
724- không tin tưởng các giá trị `role` hoặc `userId` do trình duyệt gửi lên.
725
726---
727
728# 26. Hiệu năng
729
730Đo lường trước, tối ưu hóa sau.
731
732Sử dụng:
733
734- import động (dynamic imports) cho các mô-đun nặng như trình soạn thảo, biểu đồ, bản đồ và PDF;
735- tối ưu hóa hình ảnh;
736- ảo hóa (virtualization) cho các danh sách lớn;
737- cơ chế hủy/bảo vệ chống yêu cầu cũ (abort/stale-request protection) cho tính năng tìm kiếm;
738- các bộ chọn (selectors) để giảm thiểu việc kết xuất lại (rerenders).
739
740Không thêm các kỹ thuật ghi nhớ tạm (memoization) nếu không có lý do rõ ràng.
741
742---
743
744# 27. Kiểm thử Thiết kế với Nội dung Thực tế
745
746Để có thêm hướng dẫn về chất lượng giao diện, bạn có thể tham khảo:
747
748- https://jakub.kr/skills/make-interfaces-feel-better
749
750Tài nguyên này rất hữu ích khi trau chuốt nghệ thuật chữ (typography), trạng thái di chuột, bóng đổ, đường viền, khoảng cách, căn chỉnh thị giác, tương tác vi mô (micro-interactions) và cảm giác tổng thể của giao diện.
751
752Trước khi hoàn thành một tác vụ giao diện, hãy kiểm thử nó với:
753
754- một từ dài không có khoảng trắng;
755- một tiêu đề tiếng Nga dài;
756- một tiêu đề ngắn;
757- một tiêu đề để trống;
758- nhiều thẻ gắn (tags);
759- một tên danh sách/danh mục dài;
760- nhiều tùy chọn trong một menu thả xuống;
761- trạng thái đang hoạt động và không hoạt động;
762- trường hợp có ngày tháng và thiếu ngày tháng.
763
764Xác minh rằng:
765
766- không có phần tử nào bị đè lên nhau;
767- các lớp phủ che kín nội dung bên dưới;
768- văn bản không bị nhìn xuyên qua các menu;
769- các huy hiệu không ép nén văn bản theo chiều dọc;
770- các phần tử không chen chúc sát vào nhau;
771- thanh cuộn không che khuất văn bản quan trọng;
772- trạng thái di chuột (hover) và tiêu điểm (focus) dễ đọc;
773- cả chiều rộng màn hình máy tính để bàn và thiết bị di động đều hiển thị chuẩn xác.
774
775---
776
777# 28. Kiểm tra Sau khi Thay đổi
778
779Sau khi thay đổi mã nguồn, hãy chạy:
780
781```bash
782npm run typecheck
783npm run lint
784npm run build
785```
786
787Nếu giao diện bị thay đổi:
788
789- mở trang trong trình duyệt;
790- thực hiện trọn vẹn luồng người dùng chính;
791- kiểm thử tương tác bằng cả bàn phím và chuột;
792- kiểm thử hành vi nhấn `Escape` và nhấp chuột ra bên ngoài;
793- kiểm thử việc tải lại trang;
794- kiểm thử văn bản dài;
795- kiểm thử chiều rộng khung nhìn thiết bị di động;
796- chụp ảnh màn hình nếu tầng hiển thị trực quan có thay đổi.
797
798Nếu không thể xác minh bằng trình duyệt, hãy nêu rõ điều đó. Đừng trình bày kết quả `typecheck` như là bước xác minh trực quan giao diện.
799
800---
801
802# 29. Git và Cây thư mục Làm việc (Working Tree)
803
804Trước khi thực hiện thay đổi, hãy kiểm tra trạng thái hiện tại:
805
806```bash
807git status --short
808```
809
810Quy tắc:
811
812- không hoàn tác (revert) các thay đổi của người khác nếu không có yêu cầu rõ ràng;
813- không sử dụng các câu lệnh mang tính phá hủy nếu không có sự cho phép rõ ràng;
814- không thực hiện việc tái cấu trúc mã (refactoring) không liên quan;
815- không tự động tạo commit trừ khi người dùng yêu cầu;
816- không thay đổi ký tự xuống dòng (line endings) hoặc định dạng lại toàn bộ dự án một cách không cần thiết.
817
818---
819
820# 30. Báo cáo Cuối cùng
821
822Trong phản hồi cuối cùng, hãy nêu rõ:
823
824- những gì đã thay đổi;
825- những tệp nào là quan trọng;
826- những bước kiểm tra nào đã được chạy;
827- những gì không thể xác minh được;
828- những rủi ro nào vẫn còn tồn đọng.
829
830Giữ cho báo cáo ngắn gọn và trung thực.
831

Bình luận (0)