AstroUI Anatomy

Điền form bên trái, prompt tự sinh bên phải. Mục đích không phải viết hộ bạn — mà là không để sót phạm vi và tiêu chí kiểm tra, hai thứ mà thiếu là AI sẽ tự do sửa lung tung.
Gõ vài chữ để chọn từ 74 thành phần đã có tên chuẩn. Chưa biết tên? Mở bài Bản đồ giao diện.
Đây là hàng rào chặn AI "tiện tay dọn dẹp" mất thứ đang chạy tốt.

Bạn đang cần gì?

Chọn một việc bên dưới. Mỗi việc là một lộ trình ngắn — làm theo thứ tự là được.

Ba lộ trình

Không chắc bắt đầu từ đâu? Chọn việc đầu tiên — nó dạy bạn gọi đúng tên mọi thứ trên màn hình, và dùng được ngay trong tin nhắn tiếp theo bạn gửi cho AI.

Astrocat Creative AstroUI Anatomy — công cụ học cho người vibe code · phiên bản 0.18
  1. Bấm vào bất kỳ phần nào của webapp mẫu bên dưới
  2. Panel bên phải hiện tên chuẩn và câu feedback mẫu
  3. Bấm Copy rồi dán thẳng vào tin nhắn gửi AI
Thêm

Dùng bàn phím: bấm Tab để đi qua từng thành phần, Enter để chọn.

Hoặc chọn nhanh từ danh sách:

Projects / Vinamilk TVC / Offline

Vinamilk — Tết 2027

Offline cut v4 · Delivery 12.09.2026

Tất cả VFX Color Audio
Shots hoàn tất 86▲ 12
VFX pending14▼ 3
Ngày còn lại38
Storage4.2 TB

Shot list

Shot ▾ StageAssigneeTrạng thái
SH_012 Comp
NLTP
Approved
SH_013Roto
HV
In review
SH_014Cleanup
MQ
Retake
SH_015—
?
Chưa gán
1 23› 1–4 của 128

Ghi chú delivery

Dùng naming convention của studio.
Phải bắt đầu từ 01:00:00:00.

Bản render gần đây

Chưa có bản render nào Đẩy timeline sang Media Encoder để bắt đầu.
Đã lưu v4. Hoàn tác

Công thức câu feedback chính xác

Vấn đề lớn nhất khi feedback UI là Claude không biết bạn đang nói tới chỗ nào. Dùng công thức 5 phần này thì gần như không bao giờ sửa nhầm.

VỊ TRÍ→TÊN THÀNH PHẦN→TRẠNG THÁI→VẤN ĐỀ→MONG MUỐN
MƠ HỒ"Cái nút màu xấu quá, sửa lại đi."
CHÍNH XÁC"Ở page header góc phải, primary button 'Gửi duyệt', trạng thái hover bị tối hơn trạng thái default → làm nó sáng hơn 10% thay vì tối đi."
MƠ HỒ"Chữ bên trái nhìn chật."
CHÍNH XÁC"Trong sidebar, các nav item có vertical padding quá nhỏ → tăng lên 10px và tăng gap giữa các item lên 4px."

3 chiều để định vị

ChiềuCách nói
Khu vựcsidebar / top bar / content area / right panel / footer / modal
Thành phầnbutton, badge, chip, card, table row, input, tab, toast…
Trạng tháidefault, hover, active, focus, selected, disabled, loading, empty, error

Nói đủ 3 chiều = Claude sửa đúng dòng code ngay lần đầu. Ví dụ: "table row ở trạng thái hover trong card 'Shot list'".

Từ vựng chỉnh sửa — nói cái này thay vì "nhìn kỳ kỳ"

Muốn nóiThuật ngữ
paddingkhoảng trống bên trong viền của một thành phần
marginkhoảng trống bên ngoài, giữa thành phần này với thành phần khác
gap / spacingkhoảng cách đều giữa các item trong một nhóm
border-radiusđộ bo góc
contrastđộ tương phản chữ/nền — "chữ xám quá đọc không ra"
hierarchythứ tự ưu tiên thị giác — "cái quan trọng nhất phải nổi nhất"
alignmentcăn lề — "3 cột này không thẳng hàng nhau"
densityđộ dày đặc thông tin — "làm compact hơn / thoáng hơn"
affordancenhìn là biết bấm được — "cái này không giống nút bấm"
z-index / layerlớp chồng lên nhau — "modal bị chìm dưới header"
above the foldphần thấy được mà không cần cuộn
viewportvùng màn hình đang nhìn thấy
breakpointmốc kích thước màn hình để layout đổi (mobile/tablet/desktop)
truncate / ellipsischữ dài bị cắt thành "…"

Mẫu câu copy dùng ngay

ĐỔI STYLETrong [khu vực], [thành phần] đang [mô tả hiện tại] → đổi thành [mong muốn]. Giữ nguyên mọi thứ khác.
ĐỔI LAYOUT[Thành phần A] đang nằm [vị trí cũ] → chuyển sang [vị trí mới], phía [trên/dưới/trái/phải] của [thành phần B].
SỬA TRẠNG THÁI[Thành phần] ở trạng thái [hover/active/disabled] chưa có phản hồi thị giác → thêm [đổi màu nền / viền / độ mờ].
CHỈ SỬA 1 CHỖChỉ sửa [X]. Không đụng tới [Y], [Z] — chúng đang đúng rồi.

Câu cuối cùng quan trọng nhất: luôn khoá phạm vi để tránh Claude "sửa luôn cả nhà".

Terminal là nơi app của bạn thật sự chạy. Lỗi backend hiện ở đây, thư viện cài từ đây, deploy bắt đầu từ đây. Nó trông đáng sợ vì không có nút bấm, nhưng thực tế bạn chỉ cần khoảng 20 lệnh — và đã dùng vài cái mỗi ngày rồi mà không để ý.

1. Đọc dấu nhắc lệnh

khoa@macbook  ~/Projects/review-app  (main)  $
  ↑ máy của bạn      ↑ ĐANG Ở THƯ MỤC NÀY   ↑ nhánh git   ↑ gõ lệnh sau dấu này

90% rắc rối của người mới là gõ lệnh sai thư mục. Chạy npm run dev ở ngoài thư mục dự án thì báo lỗi khó hiểu. Không chắc thì gõ pwd xem đang ở đâu và ls xem có file package.json không — có nghĩa là đang đứng đúng chỗ.

2. Bộ lệnh sống còn

3. Ba phím tiết kiệm 80% thời gian gõ

Mũi tên lên ↑
LẶP LẠI LỆNH CŨ

Gọi lại lệnh vừa gõ. Bấm nhiều lần để đi ngược lịch sử. Không ai gõ lại npm run dev bằng tay cả.

Phím Tab
TỰ HOÀN THÀNH

Gõ vài chữ đầu của tên thư mục rồi bấm Tab, nó tự điền nốt. Vừa nhanh vừa không gõ sai chính tả.

Ctrl + C
DỪNG LẠI

Dừng thứ đang chạy. Quan trọng nhất trong ba phím. Dùng khi muốn tắt app, hoặc khi lệnh bị treo.

4. Đọc những gì terminal in ra

Terminal in ra bốn loại thứ. Phân biệt được là hết hoảng:

Bạn thấyNghĩa làLàm gì
Chữ trắng/xám chạy đềuNhật ký bình thường, app đang làm việcKệ nó
warning — chữ vàngCảnh báo, app vẫn chạyGhi nhận, không cần xử lý ngay. Đừng để tích tụ hàng trăm cái
error — chữ đỏLỗi thật, thường app dừng luônCopy nguyên văn. Đọc dòng đầu tiên và dòng có tên file của bạn
"ready · Local: http://localhost:3000" rồi đứng imApp đang chạy đúngĐây KHÔNG phải treo. Mở trình duyệt vào địa chỉ đó. Đừng đóng cửa sổ terminal
Hiểu nhầm kinh điển: terminal "đứng im không làm gì" sau khi chạy npm run dev nghĩa là app đang chạy tốt và đang chờ bạn mở trình duyệt. Cửa sổ này phải để nguyên. Muốn gõ lệnh khác thì mở một cửa sổ terminal thứ hai.

5. Dự án của bạn có sẵn lệnh gì

Mở file package.json ở gốc dự án, tìm mục scripts. Đó là danh sách lệnh riêng của dự án, chạy bằng npm run [tên]:

"scripts": {
  "dev":   "next dev",         ← chạy bản phát triển ở máy, tự cập nhật khi sửa code
  "build": "next build",       ← dựng bản thật, đây là bước hay báo lỗi khi deploy
  "start": "next start",       ← chạy bản đã dựng
  "lint":  "next lint"         ← soi lỗi cú pháp và code cẩu thả
}
Mẹo tiết kiệm rất nhiều thời gian: chạy npm run build ở máy trước khi deploy. Bản dựng nghiêm ngặt hơn bản chạy thử, nên lỗi sẽ hiện ra ở máy bạn thay vì hiện ra khi đã đẩy lên hosting.

6. An toàn khi dùng terminal

Ba thứ có thể phá máy hoặc mất dữ liệu

1
Đừng dán lệnh lạ từ internetNhất là lệnh có dạng tải về rồi chạy thẳng, hoặc lệnh dài loằng ngoằng khó đọc. Đây là cách phổ biến để máy bị chiếm. Không hiểu lệnh thì hỏi AI giải thích trước khi chạy.
2
rm -rf xoá vĩnh viễn, không có thùng rácGõ sai một dấu cách là xoá nhầm cả thư mục. Trước khi gõ, chạy pwd xác nhận đang đứng đúng chỗ.
3
sudo là chạy với quyền cao nhấtNó bỏ qua mọi lớp bảo vệ của hệ điều hành. Với dự án web bạn gần như không bao giờ cần tới. Thấy hướng dẫn nào bảo dùng sudo cho npm thì nên nghi ngờ.
Deploy là phát hành. Mọi thứ bạn đã quen ở post đều có bản tương ứng: bản dựng ở máy, bản gửi duyệt, bản phát sóng — và một quy trình kiểm tra tự động chặn không cho bản lỗi lên sóng.

1. Ba môi trường — đừng lẫn lộn

Môi trườngTương đương ở postAi thấyDatabase
LocalBàn dựng của bạnChỉ mình bạnDatabase riêng, dữ liệu giả, xoá thoải mái
Preview / StagingBản gửi duyệtBạn + người bạn gửi linkDatabase staging, dữ liệu giống thật nhưng không phải thật
ProductionBản phát sóngToàn bộ người dùngDữ liệu thật — mất là mất luôn
Luật số một: không bao giờ thử nghiệm trên production. Nghe hiển nhiên, nhưng vibe-coder dính suốt vì lúc đầu chỉ có một môi trường. Tách ra ngay khi có người dùng thật đầu tiên.

2. Chuỗi deploy hiện đại

bạn sửa code ở máy
      │
      ├─ git push                        đẩy lên GitHub
      │        │
      │        ├─ hosting tự phát hiện có thay đổi
      │        │
      │        ├─ BUILD   dựng bản thật     ← lỗi cú pháp, lỗi kiểu dữ liệu hiện ở đây
      │        ├─ TEST    chạy kiểm thử     ← fail thì DỪNG, không cho lên
      │        │
      │        ├─ đẩy lên nhánh phụ  →  URL PREVIEW riêng   gửi khách xem trước
      │        └─ đẩy lên nhánh main →  PRODUCTION          người dùng thật thấy ngay
      │
      └─ hỏng? rollback về bản trước trong khoảng 30 giây

Điểm hay nhất với người làm dịch vụ như bạn: mỗi nhánh được một URL riêng. Muốn cho khách xem thử một hướng giao diện mới thì tạo nhánh, đẩy lên, gửi link — bản chính không hề bị đụng tới. Đúng bằng workflow gửi cut cho khách duyệt.

3. Biến môi trường theo từng môi trường

Đây là nguyên nhân số một của "máy tôi chạy được mà lên mạng thì hỏng":

Môi trườngKhoá nằm ở đâuSai lầm thường gặp
LocalFile .env.local trên máy bạnKhông có gì — nhưng file này không bao giờ được commit
PreviewNhập tay trong bảng điều khiển hostingQuên nhập, hoặc trỏ nhầm vào database production
ProductionNhập tay trong bảng điều khiển hostingQuên nhập → app chạy nhưng mọi thứ liên quan API đều undefined
Nhớ: file .env không tự đi theo khi deploy — đó chính là mục đích của nó. Mỗi lần thêm một biến mới ở máy, phải nhớ nhập tay vào hosting cho cả preview và production. Đổi biến xong phải deploy lại thì mới có hiệu lực.

4. CI/CD — cái máy gác cổng

CI/CD là quy trình tự động chạy mỗi lần bạn đẩy code lên. Với vibe-coder giá trị lớn nhất của nó không phải tự động hoá — mà là chặn bạn deploy một bản hỏng, giống gate QC không cho file sai spec đi qua.

BướcNó kiểm gìCó bắt buộc không
BuildCode có dựng được thành bản chạy thật khôngBắt buộc — hosting tự làm sẵn
Type checkKiểu dữ liệu có khớp khôngRất nên — bắt được nhiều lỗi trước khi người dùng gặp
LintCode có lỗi cú pháp hay cẩu thả khôngNên có
TestCác luồng chính còn chạy đúng khôngNên có khi đã có người dùng thật
Kiểm tra thư viện lỗ hổngCó thư viện nào đang dính lỗ hổng đã công bố khôngNên chạy hàng tháng

5. Sáu mươi giây đầu khi production hỏng

Thứ tự này quan trọng. Người mới hay làm ngược lại và kéo dài thời gian app chết:

Rollback TRƯỚC, điều tra SAU

Đưa app về bản chạy được ngay lập tức. Hosting có nút hoàn tác về bản deploy trước, mất khoảng 30 giây. Đừng ngồi sửa code trong khi người dùng đang gặp lỗi.

Xác nhận đã hết lỗi

Tự mở app kiểm tra như người dùng thật, không tin vào bảng điều khiển.

Giờ mới đi tìm nguyên nhân

Xem log của hosting quanh thời điểm hỏng, và xem bản deploy vừa rồi đổi những gì. Không còn áp lực nên tìm chính xác hơn.

Sửa trên nhánh riêng, thử ở preview

Sửa xong đẩy lên nhánh phụ, mở URL preview kiểm tra kỹ, rồi mới gộp vào bản chính.

Ghi lại một dòng

Hỏng gì, vì sao, sửa thế nào. Ba tháng sau bạn sẽ cảm ơn chính mình.

6. Ba khái niệm về tên miền

Domain
TÊN MIỀN

Địa chỉ người ta gõ vào. Mua theo năm ở nhà đăng ký tên miền. Nhớ bật tự động gia hạn — hết hạn là mất trang.

DNS
DANH BẠ

Bảng chỉ đường từ tên miền tới server. Đổi xong có thể mất vài giờ mới lan khắp nơi — đừng hoảng khi chưa thấy ngay.

SSL / HTTPS
KHOÁ Ổ KHOÁ

Mã hoá đường truyền. Vercel/Netlify tự cấp miễn phí. Không có ổ khoá là trình duyệt cảnh báo và người dùng bỏ đi.

7. Biết app hỏng trước khi khách nhắn tin

LoạiNó trả lời câu hỏiKhông có thì
Uptime monitorApp còn sống không?App chết cả đêm mà sáng hôm sau mới biết
Error tracking (Sentry)Có ai đang gặp lỗi không, lỗi gì, ở màn hình nàoChỉ biết khi có người chịu khó phàn nàn — phần lớn họ im lặng rời đi
Log hostingChuyện gì đã xảy ra lúc đóKhông có bằng chứng để tìm nguyên nhân
Cảnh báo chi phíCó gì đang đốt tiền bất thường khôngBiết khi nhận hoá đơn

8. Checklist ngày deploy đầu tiên

Ba thứ trong tab này có điểm chung: đo được bằng con số, không phải cảm giác. Bạn quen làm việc với waveform và scope rồi — đây là scope cho web. Đừng đoán "hình như hơi chậm", hãy đo.

1. Lighthouse — chạy một nút ra bốn điểm số

Mở DevTools → tab Lighthouse → Analyze. Chạy ở chế độ ẩn danh để tiện ích trình duyệt không làm sai kết quả. Điểm dưới 50 là đỏ, 50–89 là vàng, từ 90 là xanh.

Performance
MỤC TIÊU ≥ 90

Tốc độ tải và phản hồi. Với app nhiều media thì đây thường là điểm thấp nhất, và cũng là điểm đáng sửa nhất.

Accessibility
MỤC TIÊU ≥ 95

Dễ sửa nhất trong bốn mục — phần lớn là thêm nhãn và sửa tương phản. Đạt 95 thường chỉ mất một buổi.

Best Practices
MỤC TIÊU ≥ 95

Bắt các lỗi cơ bản: dùng HTTPS chưa, ảnh sai tỉ lệ, thư viện có lỗ hổng, lỗi trong console.

SEO
MỤC TIÊU ≥ 90

Google có hiểu trang không. Quan trọng nếu bạn muốn người ta tìm thấy; không quan trọng với app nội bộ.

2. Ba chỉ số tốc độ thật sự quan trọng

Chỉ sốNghĩa dễ hiểuTốtKém
LCPBao lâu thì thấy được nội dung chính. Như thời gian từ lúc bấm play tới lúc có hình.≤ 2.5s> 4s
INPBấm xong bao lâu thì có phản hồi. Đây là cảm giác "app này mượt hay ì".≤ 200ms> 500ms
CLSNội dung có nhảy lung tung khi đang tải không. Như jump cut không mong muốn — người dùng bấm nhầm vì nút vừa nhảy chỗ.≤ 0.1> 0.25
CLS là thứ vibe-coder hay bỏ qua nhất nhưng người dùng ghét nhất: ảnh chưa khai kích thước nên khi tải xong đẩy toàn bộ nội dung xuống. Sửa đơn giản — luôn khai chiều rộng và chiều cao cho ảnh, và cho skeleton đúng chiều cao nội dung thật.

3. Tám nguyên nhân chậm — xếp theo mức độ hay gặp

Nguyên nhânCách sửa
Ảnh không nén, kích thước gốc — thủ phạm số một, đặc biệt với người làm media vì quen dùng file gốcXuất đúng kích thước hiển thị, dùng định dạng WebP hoặc AVIF, dùng component ảnh có sẵn của framework để nó tự tối ưu
Tải hết mọi ảnh ngay từ đầuLazy loading — ảnh ngoài màn hình chỉ tải khi cuộn tới
Font nặng, tải nhiều biến thểChỉ tải độ dày thật sự dùng, dùng font-display: swap để chữ hiện ngay bằng font tạm
Thư viện thừaXem thư viện nào nặng nhất, bỏ cái chỉ dùng một hàm nhỏ. Đây là lý do phải hỏi mỗi khi AI thêm thư viện
Gọi API tuần tự thay vì song songNếu ba lời gọi không phụ thuộc nhau thì cho chạy cùng lúc, thời gian bằng cái lâu nhất thay vì tổng ba cái
Truy vấn database không có indexThêm index cho cột hay lọc. Trăm dòng thì không thấy gì, trăm nghìn dòng là treo
Lấy về nhiều dữ liệu hơn cầnChỉ lấy cột cần dùng, phân trang thay vì tải hết một lượt
Video tự phát ở đầu trangĐặt poster tĩnh, chỉ tải video khi người dùng bấm play

4. Accessibility — tám điểm bạn tự kiểm được

Không cần chuyên gia. Ba cách kiểm nhanh: bấm Tab đi hết trang, chạy Lighthouse, phóng to trình duyệt lên 200%. Ngoài lý do đúng đắn, làm tốt phần này còn giúp SEO và là yêu cầu pháp lý ở nhiều thị trường.

5. Chi phí — biết mình đang trả tiền cho cái gì

Dịch vụTính tiền theoThứ dễ tăng vọt
HostingLượng dữ liệu truyền đi, thời gian máy chạy, số phút buildDeploy liên tục cả ngày đốt phút build. Ảnh và video nặng đốt băng thông
DatabaseDung lượng lưu, số kết nối đồng thời, lượng dữ liệu đọc raTruy vấn không index chạy trong vòng lặp
Lưu trữ fileSố GB lưu và số GB tải xuốngPhí tải xuống là bẫy lớn nhất với app video — lưu thì rẻ, cho người ta xem mới đắt
API của mô hình AILượng chữ gửi đi và nhận vềGửi cả file dài trong mỗi lần gọi. Vòng lặp lỗi gọi liên tục
Email, SMSSố lượng gửiGửi lặp do lỗi logic
Ba việc làm ngay hôm nay, mất 10 phút: bật cảnh báo chi phí ở mọi dịch vụ · đặt trần chi tiêu ở dịch vụ nào cho phép · thêm rate limit cho các route gọi tới dịch vụ tính tiền. Câu chuyện hoá đơn nghìn đô sau một đêm gần như luôn thiếu đúng ba thứ này.
Tab "Cách feedback" dạy bạn sửa một chỗ cho đúng. Tab này là bước tiếp theo: sửa cả hệ thống cho nhất quán. Đây đúng là ranh giới giữa app nghiệp dư và app chuyên nghiệp — không phải đẹp hơn, mà là đều hơn.

1. Design token — LUT cho giao diện

Mỗi lần bạn bảo AI "chỗ này màu xám nhạt hơn tí", nó đặt một mã màu mới ngay tại chỗ đó. Làm 30 lần thì app có 30 sắc xám khác nhau, không cái nào giống cái nào — và muốn đổi tông toàn app thì phải sửa 30 chỗ.

Token là biến dùng chung. Định nghĩa một lần ở đầu, mọi nơi gọi tên biến. Đổi một dòng là đổi cả app — đúng nguyên lý bạn dùng LUT thay vì grade tay từng shot.

KHÔNG TOKENMỗi component tự đặt màu và khoảng cách riêng. Muốn đổi tông: sửa 30 file, sót 5 chỗ, app lệch màu.
CÓ TOKENMọi component gọi var(--accent). Muốn đổi tông: sửa 1 dòng, cả app đổi theo, không sót chỗ nào.

Năm nhóm token cần có. Chỉ dùng giá trị trong thang, không chế số lẻ:

Spacing — thang 4px

4 · 8 · 12 · 16 · 24 · 32 · 48 · 64
Mọi padding, margin, gap phải là một trong các số này. Thấy 13px, 17px, 22px là dấu hiệu chắp vá.

Typography — 6 cỡ là đủ

12 · 14 · 16 · 20 · 24 · 32
Nhiều hơn 6 cỡ chữ là mất thứ bậc. Mỗi cỡ kèm một độ dày cố định.

Màu — đặt tên theo VAI TRÒ

--accent · --success · --warning · --danger · --text-muted
Đừng đặt --blue-500. Sau này đổi sang tông xanh lá thì tên biến thành nói dối.

Bo góc — 3 mức

--r-sm 6px · --r-md 10px · --r-full 99px
Trong một app chỉ nên có 2–3 độ bo. Mỗi component một kiểu là nhìn ra ngay.

Độ nổi — 3 tầng

--sh-1 card · --sh-2 dropdown · --sh-3 modal
Bóng đổ thể hiện thứ gì nổi trên thứ gì, không phải để trang trí.

Chuyển động — 2 tốc độ

--fast 120ms · --slow 240ms
Nhanh cho hover, chậm cho panel trượt. Trên 300ms là người dùng thấy ì.

Khai báo một lần ở đầu file CSS gốc:

:root {
  /* màu — theo vai trò, không theo tên màu */
  --bg: #0d0f13;          --surface: #14171d;
  --text: #e6e9ef;        --text-muted: #9aa4b4;
  --accent: #5b8cff;      --danger: #ff5d5d;
  --success: #3ecf8e;     --warning: #f5b642;

  /* khoảng cách — thang 4px, cấm số ngoài thang */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px;  --sp-4: 16px;
  --sp-5: 24px; --sp-6: 32px; --sp-7: 48px;

  /* chữ */
  --fs-xs: 12px; --fs-sm: 14px; --fs-md: 16px;
  --fs-lg: 20px; --fs-xl: 24px; --fs-2xl: 32px;

  /* bo góc và độ nổi */
  --r-sm: 6px; --r-md: 10px; --r-full: 99px;
  --sh-1: 0 1px 2px rgba(0,0,0,.4);
  --sh-2: 0 4px 10px rgba(0,0,0,.5);
}
Feedback sau khi có token mạnh hơn hẳn: thay vì "sidebar nhìn chật" bạn nói "nav item đang dùng --sp-2, đổi sang --sp-3". AI sửa đúng một dòng, và mọi chỗ khác dùng cùng token cũng đồng bộ theo.

2. Ma trận 8 trạng thái — dấu hiệu rõ nhất của app pro

App vibe-code hầu như luôn chỉ có một trạng thái: bình thường, dữ liệu đầy đủ, mọi thứ suôn sẻ. Người dùng thật thì bấm khi đang tải, bấm khi không có quyền, mở màn hình chưa có dữ liệu, gõ sai định dạng. Bảng dưới là thứ bạn đưa cho AI để nó không quên. Bấm vào ô để đánh dấu đã làm:

Ô gạch chéo = không áp dụng cho loại component đó.

Trạng tháiKhi nào xuất hiệnHay bị quên vì
DefaultBình thường, không tương tác—
HoverRê chuột lênKhông có thì người dùng không biết bấm được
FocusChọn bằng phím TabBị xoá vì "viền xấu" — đây là lỗi accessibility nghiêm trọng
ActiveĐang nhấn xuốngKhông có thì cảm giác bấm bị "đơ"
DisabledChưa đủ điều kiện dùngLàm mờ nhưng không nói LÝ DO bị khoá
LoadingĐang chờ serverKhông có thì người dùng bấm 5 lần liên tiếp
EmptyChưa có dữ liệu nàoLúc dev luôn có dữ liệu mẫu nên không ai thấy
ErrorThao tác thất bạiChỉ test đường đi thuận lợi

3. Ngưỡng tối thiểu không được phá

Vùng bấm ≥ 44×44px
MOBILE

Icon nhìn 20px cũng được, nhưng vùng bấm phải đủ 44px. Đây là lý do nút của bạn "khó bấm trên điện thoại".

Tương phản chữ ≥ 4.5:1
ĐỌC ĐƯỢC

Chữ xám nhạt trên nền tối trông sang nhưng nhiều người không đọc nổi. DevTools có sẵn công cụ đo — hover vào màu trong panel Styles.

Không xoá focus ring
ACCESSIBILITY

Người không dùng chuột phải Tab để đi. Xoá viền focus là chặn họ hoàn toàn. Muốn đẹp thì thiết kế lại, đừng xoá.

Màu không phải tín hiệu duy nhất
MÙ MÀU

Khoảng 8% nam giới không phân biệt đỏ-xanh lá. Trạng thái phải có thêm chữ hoặc icon, không chỉ đổi màu.

Chữ nhỏ nhất 12px
ĐỌC ĐƯỢC

Dưới 12px là không đọc được trên điện thoại. Trên input, dưới 16px làm iPhone tự phóng to trang khi gõ.

Nút phá huỷ phải xác nhận
AN TOÀN

Xoá, huỷ, ghi đè — phải hỏi lại hoặc cho hoàn tác. Và đừng đặt cạnh nút thường dùng.

4. Sáu thứ phải giống nhau toàn app

Đây là danh sách để bạn tự soi app mình. Không đều một trong sáu thứ này là nhìn ra ngay dù không biết vì sao:

ThứKiểm bằng cách
Độ bo gócChụp màn hình 5 chỗ khác nhau, so bo góc có giống nhau không
Thang khoảng cáchDùng DevTools soi padding vài component — có phải đều thuộc thang 4px không
Cỡ chữĐếm số cỡ chữ khác nhau trong app. Trên 6 là quá nhiều
Kích thước iconMọi icon cùng cấp phải cùng cỡ. Lệch 2px là mắt thấy
Chiều cao nút và inputNút và ô nhập đứng cạnh nhau phải cùng chiều cao
Tốc độ chuyển độngMọi hover cùng tốc độ. Chỗ nhanh chỗ chậm là cảm giác rời rạc
Bạn không cần viết được code. Nhưng bạn phải duyệt được code AI viết — giống bạn không cầm máy nhưng vẫn duyệt từng shot. Không duyệt thì sau ba tháng bạn sở hữu một dự án mà không ai, kể cả bạn, hiểu nó đang chạy thế nào.

1. Đọc diff — kỹ năng nền

Diff là bảng so sánh trước và sau. Dòng có dấu trừ là bị bỏ đi, dấu cộng là được thêm vào. Xem bằng git diff, hoặc trong Cursor/VS Code, hoặc trên GitHub.

--- a/components/ProjectCard.tsx
+++ b/components/ProjectCard.tsx
@@ -20,7 +20,12 @@                          ← đang xem quanh dòng 20
   export function ProjectCard({ project }) {
-   return <h3>{project.name}</h3>              ← DÒNG BỊ BỎ ĐI
+   if (!project) return null                   ← DÒNG ĐƯỢC THÊM
+   return (
+     <h3>{project.name ?? 'Chưa đặt tên'}</h3>
+   )
   }
   (dòng không dấu = không đổi, chỉ để bạn biết ngữ cảnh)

Ba câu hỏi bắt buộc khi nhìn một diff, theo đúng thứ tự:

Nó có đụng thứ tôi không nhờ không?

Nhìn danh sách file ở đầu diff. Tôi nhờ sửa sidebar mà thấy 6 file lạ bị đổi là dấu hiệu cần hỏi lại ngay. Đây là câu hỏi bắt được nhiều tai nạn nhất.

Nó xoá cái gì không?

Dòng đỏ là thứ biến mất. Nếu có dòng đỏ mà bạn không hiểu tại sao phải xoá — hỏi. AI hay "dọn dẹp" mất thứ đang chạy tốt.

Nó thêm thư viện mới không?

Xem file package.json có trong diff không. Mỗi thư viện thêm vào là thêm rủi ro bảo mật, thêm dung lượng, thêm thứ phải cập nhật. Hỏi: có cách nào không cần thư viện này không?

2. Checklist 10 điểm — chạy mỗi lần AI sửa xong

3. Dấu hiệu code đang xuống cấp

Bạn không cần hiểu code vẫn nhận ra được những dấu hiệu này. Thấy là bảo AI dọn ngay, để lâu thì càng khó gỡ:

Dấu hiệuVì sao đáng lo
Một hàm dài trên 100 dòngLàm quá nhiều việc cùng lúc. Sửa một chỗ dễ vỡ chỗ khác. Bảo AI tách nhỏ theo từng việc.
Lồng nhau 4–5 tầng, thụt lề sâu như bậc thangLogic quá rối, gần như chắc chắn có trường hợp chưa xử lý. Nhờ viết lại phẳng hơn.
Tên biến data, data2, temp, x, handleClick2Dấu hiệu code viết vội, không ai đọc lại được — kể cả AI ở phiên sau.
Cùng một đoạn xuất hiện 3 lần trở lênSửa một chỗ quên hai chỗ kia là nguồn bug kinh điển. Gộp thành một chỗ dùng chung.
Số lạ nằm rải rác trong code (86400, 1024, 0.85)Không ai biết số đó nghĩa gì kể cả bạn ba tuần sau. Phải đặt tên cho nó.
Bắt lỗi rồi bỏ trống, không làm gìLỗi bị nuốt im lặng — app hỏng mà không ai biết vì sao. Nguy hiểm nhất trong bảng này.
any rải khắp nơi (TypeScript)Tắt hết kiểm tra an toàn để cho qua build. Đang giấu lỗi chứ không sửa.
Comment dài giải thích một đoạn khó hiểuThường là dấu hiệu nên viết lại cho dễ hiểu, thay vì chú thích cho khó hiểu.
Còn sót console.log, TODO, code bị chú thích để đóRác từ các lần thử. Dọn trước khi deploy.
File dài trên 500 dòngĐến lúc tách. Vừa khó tìm, vừa làm AI tốn ngữ cảnh vô ích ở mỗi phiên.

4. Nợ kỹ thuật — khi nào được nợ, khi nào phải trả

Nợ kỹ thuật là làm nhanh cho xong, biết là chưa chuẩn, tính sửa sau. Không phải lúc nào cũng xấu — vấn đề là nợ có ý thức hay nợ mà không biết mình đang nợ. Cứ ghi vào một file NO-KY-THUAT.md mỗi lần bạn cố tình chọn đường tắt.

ĐƯỢC PHÉP NỢĐang thử ý tưởng chưa chắc giữ · bản demo cho khách xem · tính năng chưa biết có ai dùng không · giao diện phần quản trị chỉ mình bạn vào
PHẢI TRẢ NGAYMọi thứ liên quan bảo mật · chỗ có thể làm mất dữ liệu người dùng · phần bạn biết sẽ sửa hàng tuần · cấu trúc database khi đã có người dùng thật
Quy tắc thực dụng: nợ ở phần dễ vứt đi thì rẻ. Nợ ở phần mọi thứ khác dựa lên — database, đăng nhập, cấu trúc dữ liệu — thì lãi chồng lãi rất nhanh. Đó là lý do tab Dữ liệu nên đọc trước khi code, không phải sau.
Sửa giao diện: năm phút. Sửa cấu trúc dữ liệu khi đã có người dùng thật: đau đớn và có thể mất dữ liệu. Đây là phần phải nghĩ trước khi code — giống đặt cấu trúc thư mục và naming convention cho project: sai từ đầu thì cả pipeline chịu khổ tới lúc kết thúc.

1. Bốn khái niệm là đủ dùng

Bảng (table)
MỘT LOẠI THỨ

Mỗi loại đối tượng một bảng. Đặt tên danh từ số nhiều: users, projects, comments.

Cột (column)
MỘT THUỘC TÍNH

Mỗi thuộc tính một cột, có kiểu cố định: chữ, số, ngày, đúng/sai.

Hàng (row)
MỘT BẢN GHI

Một người dùng cụ thể, một project cụ thể. Bảng có bao nhiêu hàng là có bấy nhiêu bản ghi.

Khoá (key)
CÁCH NỐI CÁC BẢNG

id là mã riêng của mỗi hàng. project_id nằm trong bảng khác là sợi dây trỏ ngược về bảng projects.

2. Ba loại quan hệ — nhận biết bằng tiếng Việt

Không cần lý thuyết. Đặt hai câu hỏi bằng tiếng Việt thường là ra ngay loại quan hệ và cách làm:

Hai câu hỏiLoạiCách làm
Một project có nhiều comment? Có
Một comment thuộc nhiều project? Không
Một–nhiềuĐặt cột project_id trong bảng comments. Phổ biến nhất, chiếm khoảng 80% trường hợp.
Một user tham gia nhiều project? Có
Một project có nhiều user? Có
Nhiều–nhiềuCần bảng trung gian project_members chứa user_id + project_id + vai trò. Đây là chỗ vibe-code hay làm sai nhất.
Một user có một profile? Có
Một profile thuộc một user? Có
Một–mộtHiếm khi cần tách. Thường gộp luôn vào một bảng cho đơn giản.

3. Schema mẫu — app review cut cho khách

Đọc thử để thấy một schema đủ dùng trông ra sao. Chú ý mọi bảng đều có id, created_at, và bảng trung gian ở cuối:

users
  id            uuid       khoá chính
  email         text       duy nhất
  full_name     text
  created_at    timestamp

projects
  id            uuid
  name          text
  owner_id      uuid   → users.id      một user có nhiều project
  status        text       'offline' | 'online' | 'delivered'
  deadline      date
  created_at    timestamp
  deleted_at    timestamp  null = chưa xoá (xoá mềm)

videos
  id            uuid
  project_id    uuid   → projects.id   một project có nhiều bản cut
  version       int        v1, v2, v3…
  storage_path  text       ĐƯỜNG DẪN file, không phải file
  duration_ms   int
  created_at    timestamp

comments
  id            uuid
  video_id      uuid   → videos.id
  author_id     uuid   → users.id
  timecode_ms   int        comment gắn vào giây thứ mấy
  body          text
  resolved      boolean
  created_at    timestamp

project_members   ← BẢNG TRUNG GIAN cho quan hệ nhiều–nhiều
  project_id    uuid   → projects.id
  user_id       uuid   → users.id
  role          text       'owner' | 'editor' | 'viewer'
  khoá chính = (project_id, user_id) — một người chỉ vào một lần

4. Mười quy tắc không cần suy nghĩ, cứ theo

Quy tắcLý do
Tên bảng số nhiều, chữ thường, nối bằng gạch dướiproject_members chứ không phải ProjectMember. Nhất quán để không bao giờ phải đoán.
Mọi bảng có id, created_at, updated_atBa cột này về sau luôn cần tới. Thêm sau khi đã có dữ liệu thì phiền.
Không lưu thứ tính đượcĐừng lưu cột total_comments nếu đếm được. Lưu rồi là có ngày số lưu và số thật lệch nhau.
Tiền lưu bằng số nguyên, đơn vị nhỏ nhấtLưu 150000 (đồng), không lưu 150.0. Số thực làm tròn sai và kế toán sẽ tìm bạn.
Thời gian lưu theo UTC, đổi múi giờ lúc hiển thịKhông thì app có khách ở nước ngoài là lệch ngày ngay.
Không lưu file trong databaseLưu file lên dịch vụ lưu trữ, database chỉ giữ đường dẫn. Cực kỳ quan trọng với app media.
Trạng thái dùng chuỗi có nghĩa, không dùng số'approved' đọc là hiểu. status = 3 thì phải đi tra bảng.
Xoá mềm bằng deleted_atNgười dùng bấm nhầm là chuyện thường. Khôi phục được thì bạn đỡ một đêm mất ngủ.
Cột dùng để tìm kiếm thì thêm indexKhông có index, 100 dòng vẫn nhanh, 100 nghìn dòng là treo. Thêm cho các cột hay lọc theo.
Tạo bảng mới là bật RLS ngay trong cùng một lượtĐể sau là quên. Bảng không có RLS là bảng công khai cho cả internet.

5. Bốn cạm bẫy vibe-code hay dính

Nhận ra sớm thì sửa dễ

1
Để AI tự sinh bảng mỗi lần thêm tính năngSau 10 tính năng bạn có 25 bảng chồng chéo, ba bảng cùng lưu thông tin người dùng. Luôn hỏi "có bảng nào đang có dùng được không" trước khi cho tạo bảng mới.
2
Cùng một thông tin nằm ở hai nơiTên người dùng vừa nằm ở bảng users vừa chép sang bảng comments. Đổi tên một chỗ, chỗ kia vẫn tên cũ. Mỗi dữ liệu chỉ có một nơi là nguồn thật.
3
Nhét mọi thứ vào một cột dạng khối dữ liệu tự doTiện lúc đầu, nhưng sau này không tìm kiếm được, không lọc được, không kiểm tra được tính hợp lệ. Cái gì cần tìm kiếm thì phải là cột riêng.
4
Đổi cấu trúc bảng khi đã có người dùng mà không có kế hoạchĐổi tên cột là mọi chỗ gọi tên cũ hỏng hết. Backup trước, chạy trên staging trước, và đọc kỹ migration trước khi bấm.
DevTools là bộ scope của dev. Bạn không grade bằng mắt thường mà nhìn waveform — ở đây cũng vậy: thay vì đoán "hình như nó bị lỗi", bạn mở ra và nhìn thấy đúng thành phần nào, request nào, lỗi nào. Đây là công cụ biến feedback của bạn từ mô tả cảm tính thành bằng chứng.
Mở bằng: F12 hoặc Ctrl+Shift+I (Windows) · Cmd+Option+I (Mac). Chuột phải vào bất kỳ chỗ nào trên trang → Inspect để mở thẳng vào đúng thành phần đó.

5 tab cần biết — ánh xạ sang pipeline post

Elements
≈ INSPECT LAYER / SOI NODE

Xem cấu trúc HTML thật và CSS đang thực sự áp lên từng thành phần.

  • Sửa thử trực tiếp, không lưu
  • Xem box model padding/margin
  • Biết class nào đang thắng
Console
≈ ERROR LOG

Nơi mọi lỗi JavaScript hiện ra. Đỏ là lỗi, vàng là cảnh báo.

  • Copy nguyên văn lỗi đưa cho AI
  • Xem log do code in ra
Network
≈ KIỂM TRA MEDIA OFFLINE

Mọi lời gọi ra server: gọi cái gì, gửi gì, nhận về gì, mất bao lâu.

  • Chẩn đoán "dữ liệu không lên"
  • Phát hiện khoá bị lộ
Application
≈ PROJECT SETTINGS

Cookie, token đăng nhập, dữ liệu lưu trong trình duyệt.

  • Xoá storage khi lỗi đăng nhập
  • Kiểm tra token có tồn tại không
Lighthouse
≈ QC TRƯỚC DELIVERY

Chấm điểm tốc độ, accessibility, SEO. Bấm một nút ra báo cáo.

  • Chạy trước khi deploy
  • Ưu tiên mục điểm thấp nhất
Device toolbar
≈ CHECK ASPECT / SAFE AREA

Xem giao diện trên kích thước điện thoại, tablet.

  • Ctrl/Cmd+Shift+M
  • Test breakpoint thật

Siêu năng lực: thử trước, rồi mới nhờ AI sửa

Đây là kỹ thuật giá trị nhất trong cả tab này. Thay vì mô tả mơ hồ rồi chờ AI đoán, bạn tự chỉnh trong DevTools cho tới khi ưng mắt, rồi đưa con số chính xác cho AI. Một vòng là xong thay vì năm vòng.

Bấm biểu tượng mũi tên chọn phần tử

Ctrl/Cmd+Shift+C rồi click vào đúng chỗ muốn sửa trên trang. Panel Elements nhảy tới đúng dòng HTML đó.

Nhìn panel Styles bên phải

Đó là CSS thật đang áp. Thuộc tính bị gạch ngang nghĩa là đã bị luật khác đè lên. Cuộn xuống dưới cùng thấy sơ đồ box model: màu cam là margin, tím là padding.

Sửa thẳng trong DevTools

Click vào giá trị và gõ số mới, hoặc bấm phím mũi tên lên/xuống để tăng giảm từng đơn vị. Trang đổi ngay lập tức. Không có gì được lưu — reload là mất hết, cứ thử thoải mái.

Chốt con số rồi đưa cho AI

Khi ưng mắt, ghi lại giá trị đã thử. Giờ prompt của bạn có bằng chứng: không còn "nhìn chật quá" mà là "padding 8px chưa đủ, tôi thử 14px thì đẹp".

KHÔNG DÙNG DEVTOOLS"Sidebar nhìn chật, làm thoáng hơn tí đi" → AI đoán, sửa 3 chỗ, vẫn không đúng ý, lặp 4 lần.
CÓ DÙNG DEVTOOLS"Trong sidebar, nav item đang có padding 8px 9px — tôi thử trong DevTools thấy 11px 12px là vừa, và gap giữa các item từ 2px lên 4px. Chỉ sửa đúng hai giá trị này." → một lần là xong.

Network — chẩn đoán "dữ liệu không lên"

Mở tab Network, lọc Fetch/XHR, rồi thao tác lại trên trang. Hỏi ba câu theo đúng thứ tự:

Có gọi đi không?

Không thấy dòng nào xuất hiện = lỗi ở frontend, nút chưa gọi hàm. Sửa ở phía giao diện, không phải server.

Gọi đúng địa chỉ không?

Nhìn cột Name và Status. Nếu 404 thì URL sai hoặc route backend chưa tồn tại.

Trả về cái gì?

Click vào dòng đó → tab Payload xem bạn gửi gì đi, tab Response xem server trả gì về. Đây là nơi lỗi thật hiện nguyên hình.

Kiểm tra bảo mật ngay tại đây: click một request bất kỳ → tab Headers. Nếu bạn thấy khoá API hay token dài dằng dặc được gửi từ trình duyệt tới một dịch vụ bên thứ ba, nghĩa là khoá đó đang lộ cho mọi người dùng. Chuyển ngay lời gọi đó về backend.

Câu hỏi nào thì mở tab nào

Bạn đang gặpMở tabTìm gì
Màn hình trắng trơnConsoleDòng đỏ đầu tiên — thường là lỗi làm sập cả trang
Bấm nút không phản ứngConsole + NetworkCó lỗi đỏ không, có request nào bắn đi không
Dữ liệu không hiện / hiện saiNetworkResponse trả về gì, có đúng dữ liệu mong đợi không
Màu / khoảng cách saiElementsPanel Styles — luật nào đang thắng, có bị gạch ngang không
Đăng nhập rồi vẫn bị đá raApplicationCookie và localStorage — token còn không, hết hạn chưa
Trang tải chậmNetwork + LighthouseFile nào nặng nhất, request nào lâu nhất
Trên điện thoại bị vỡ layoutDevice toolbarĐổi kích thước tới khi vỡ, ghi lại con số đó
Chạy local ổn, lên mạng lỗiConsole + NetworkThường là biến môi trường chưa set trên hosting, hoặc CORS
Cảnh báo an toàn: nếu có ai bảo bạn dán một đoạn code vào Console để "sửa lỗi" hay "mở khoá tính năng" — đừng làm. Đó là cách phổ biến để chiếm tài khoản. Console chỉ dùng để đọc, trừ khi bạn hiểu rõ đoạn code đó làm gì.
Kỹ năng số một tách dev khỏi vibe coder: đọc được lỗi. Không đọc được thì mọi sự cố đều phải hỏi AI, và bạn không kiểm chứng được câu trả lời. Tin tốt: 90% lỗi chỉ nằm trong khoảng hai chục dạng, và luôn có một dòng duy nhất đáng đọc.

1. Lỗi đang nằm ở đâu

App có ba nơi sinh lỗi khác nhau. Mở nhầm chỗ là tìm cả buổi không thấy gì:

Console trình duyệt
LỖI PHÍA NGƯỜI DÙNG

Giao diện, nút bấm, hiển thị. Mở bằng F12.

  • Màn hình trắng
  • Bấm không ăn
  • Giao diện vỡ
Terminal đang chạy app
LỖI PHÍA SERVER

Cửa sổ bạn gõ lệnh chạy app. Lỗi backend và lỗi build hiện ở đây.

  • App không khởi động
  • Lỗi 500
  • Lỗi database
Log của hosting
LỖI KHI ĐÃ LÊN MẠNG

Trong bảng điều khiển Vercel/Railway. Chạy local ổn mà live hỏng thì xem ở đây.

  • Build failed
  • Thiếu biến môi trường
Quy tắc: luôn kiểm cả hai chỗ — Console và terminal. Nhiều người chỉ nhìn một chỗ rồi báo cho AI thông tin nửa vời, và AI đoán sai theo.

2. Giải phẫu một thông báo lỗi

Lỗi trông dài và đáng sợ, nhưng chỉ có hai dòng quan trọng:

TypeError: Cannot read properties of undefined (reading 'name')   ← DÒNG 1: LỖI GÌ
    at ProjectCard (components/ProjectCard.tsx:24:31)              ← DÒNG 2: Ở ĐÂU (file của BẠN)
    at renderWithHooks (node_modules/react-dom/cjs/react-dom.js:16305)   ← nhiễu, bỏ qua
    at mountIndeterminateComponent (node_modules/react-dom/...:20074)    ← nhiễu, bỏ qua
    at beginWork (node_modules/react-dom/cjs/react-dom.js:21587)         ← nhiễu, bỏ qua
LUẬT ĐỌCĐọc dòng đầu tiên (lỗi gì) + dòng đầu tiên có đường dẫn KHÔNG chứa node_modules (ở đâu). Mọi dòng chứa node_modules đều là ruột thư viện — bỏ qua hết.
DỊCH RA TIẾNG NGƯỜI"Cannot read properties of undefined (reading 'name') tại ProjectCard dòng 24" = tại dòng 24, code đang cố lấy .name của một thứ không tồn tại. Thường là dữ liệu chưa tải xong, hoặc gọi sai tên trường.

3. Đọc mã HTTP — lỗi của ai

Thấy trong tab Network. Con số đầu tiên cho biết ngay nên đi sửa phía nào:

MãNghĩaLỗi ở đâuLàm gì
200 / 201Thành công—Nếu vẫn sai thì lỗi nằm ở cách hiển thị dữ liệu, không phải ở gọi API
400Dữ liệu gửi lên saiFrontendXem tab Payload — thiếu trường hay sai định dạng
401Chưa đăng nhậpXác thựcToken thiếu hoặc hết hạn — kiểm tra Application tab
403Đăng nhập rồi nhưng không có quyềnPhân quyền / RLSPolicy database đang chặn. Đây là dấu hiệu RLS đang hoạt động
404Không tìm thấyURL hoặc routeSai đường dẫn, hoặc route backend chưa được tạo
409Xung đột dữ liệuDatabaseThường do trùng giá trị phải là duy nhất, ví dụ email đã tồn tại
422Đúng định dạng nhưng không hợp lệFrontendVí dụ email sai cú pháp, ngày trong quá khứ
429Gọi quá nhiềuRate limitBị chặn vì gọi liên tục — hoặc code đang lặp vô hạn
500Server sập khi xử lýBackendXem terminal hoặc log hosting — lỗi thật nằm ở đó, không ở trình duyệt
502 / 503Server không phản hồiHostingServer chưa khởi động xong, hết tài nguyên, hoặc deploy đang chạy

4. Bảng tra 22 lỗi hay gặp nhất

Thông báoNghĩa thật + hướng sửa

5. Quy trình chẩn đoán 5 bước

Làm theo thứ tự này thay vì dán lỗi rồi cầu nguyện. Hầu hết lỗi được tìm ra ở bước 2:

Tái hiện được không?

Làm lại đúng các bước xem có lỗi lần nữa không. Lỗi ổn định thì dễ sửa. Lỗi lúc có lúc không thường liên quan tới thời điểm dữ liệu về, hoặc trạng thái còn sót lại trong trình duyệt.

Trước đó có chạy không?

Câu hỏi quyền lực nhất. Nếu sáng nay còn chạy thì nguyên nhân nằm trong đúng những thay đổi từ lúc đó tới giờ. Dùng git log xem đã commit gì, hoặc quay về commit trước để xác nhận.

Thu hẹp phạm vi

Bỏ bớt cho tới khi hết lỗi. Tắt tính năng vừa thêm, xoá bớt dữ liệu, thử với tài khoản khác. Chỗ mà bỏ đi thì hết lỗi chính là chỗ chứa nguyên nhân.

Đọc lỗi thật, không đọc triệu chứng

"Màn hình trắng" là triệu chứng. Dòng đỏ trong Console mới là lỗi. Luôn lấy nguyên văn, không diễn giải lại bằng lời của mình.

Sửa nguyên nhân, không vá triệu chứng

Thêm một câu điều kiện để tránh lỗi hiện ra thì lỗi vẫn còn, chỉ là bị giấu đi. Hỏi tiếp: tại sao chỗ đó lại không có dữ liệu?

6. "Máy tôi chạy được mà"

Chạy local ổn nhưng deploy lên là hỏng — bốn nguyên nhân chiếm gần hết:

Nguyên nhânDấu hiệu
Chưa khai biến môi trường trên hostingLỗi kiểu "undefined" ở chỗ gọi API, hoặc không kết nối được database. File .env của bạn không được đẩy lên — phải nhập tay vào bảng điều khiển hosting.
Phân biệt hoa thường trong tên fileMáy Mac/Windows không phân biệt, server Linux thì có. Button.tsx và button.tsx là hai file khác nhau trên server.
Phiên bản Node khác nhauBuild fail với lỗi cú pháp lạ. Khai rõ phiên bản Node trong cấu hình dự án.
CORS hoặc URL còn trỏ về localhostCòn địa chỉ localhost:3000 nằm trong code — phải dùng biến môi trường theo từng môi trường.
Git là hệ thống version cho code. Với bạn nó dễ hiểu hơn người khác nhiều: commit = lưu một version của timeline có tên, branch = duplicate timeline ra thử ý tưởng mới, merge = gộp cái hay trở lại, remote = bản trên server. Không có Git thì mỗi lần nhờ AI sửa là một canh bạc không có bản backup.

Vòng lặp hàng ngày — 4 lệnh là đủ 90%

Quy tắc vàng cho vibe-coder: commit TRƯỚC khi nhờ AI làm việc lớn. Chỉ mất 5 giây, và nó biến mọi thảm hoạ sau đó thành một lệnh hoàn tác. Đây là thói quen quan trọng nhất trong cả trang này.

16 tình huống hoảng loạn — tra là có lệnh

Lệnh nguy hiểm — đọc kỹ trước khi gõ

LệnhNó làm gìHoàn tác được?
git reset --hardXoá sạch mọi thay đổi chưa commit, quay về commit chỉ địnhViệc chưa commit thì mất vĩnh viễn. Commit đã tạo thì cứu được bằng reflog
git clean -fdXoá mọi file chưa từng được Git theo dõiKhông. Git chưa từng biết file đó nên không có bản lưu
git push --forceGhi đè lịch sử trên server bằng bản của máy bạnNguy hiểm khi làm nhóm — xoá mất commit của người khác
git branch -DXoá nhánh kể cả khi chưa gộpCứu được bằng reflog trong khoảng 30 ngày
git checkout .Vứt bỏ mọi sửa đổi chưa commit trong thư mụcKhông
Trước khi gõ bất kỳ lệnh nào có --hard, --force, hoặc -D: chạy git status xem đang có gì chưa lưu, và tự hỏi "nếu cái này biến mất thì tôi mất bao nhiêu giờ làm việc". Không chắc thì commit trước đã — commit thừa không hại ai.

Quy tắc commit cho người mới

Commit khi nào

Mỗi lần app chạy được, dù chưa hoàn hảo. Đừng đợi đẹp mới lưu.

Đặt tên thế nào

Động từ + cái gì: "thêm màn hình comment", "sửa lỗi upload file lớn". Đừng viết "update", "fix", "abc".

Commit bao lớn

Một commit = một ý. Sửa 5 thứ khác nhau thì chia 5 commit — sau này quay lại từng cái được.

Không bao giờ commit

.env, node_modules, file build, file media nặng, và bất cứ thứ gì chứa khoá.

File .gitignore tối thiểu — đặt ở gốc dự án, tạo trước commit đầu tiên:

# bí mật — quan trọng nhất
.env
.env.local
.env.*.local
*.pem

# thư viện và file sinh ra tự động
node_modules/
.next/
dist/
build/

# rác hệ thống
.DS_Store
Thumbs.db
*.log

# media nặng — dùng dịch vụ lưu trữ riêng
*.mp4
*.mov
*.prproj
*.drp

Nhánh — cách thử ý tưởng mà không phá bản đang chạy

main       ──●──●──●─────────────────●──▶   luôn chạy được, đây là bản deploy
                    ╲               ╱
thu-nghiem           ●──●──●──●────╯        thử tính năng mới ở đây
                     ↑           ↑
                tạo nhánh      gộp lại khi ổn
                                             nếu tệ: xoá nhánh, main không hề hấn gì

Với vibe-code, nhánh có giá trị nhất khi bạn muốn bảo AI thử một hướng lớn: tạo nhánh, cho nó làm thoải mái, hỏng thì xoá cả nhánh — main vẫn nguyên vẹn. Giống duplicate timeline trước khi thử một cấu trúc dựng khác.

Vibe-code hỏng không phải vì AI code dở, mà vì đưa việc sai cách. Bạn đã quen brief cho ekip rồi — brief cho AI cũng vậy: spec rõ, chia lát nhỏ, duyệt từng bước, có bản lưu để quay lại. Tab này là quy trình đó.

1. Trước khi tạo dự án — chốt 6 thứ này

Bảo AI "làm cho tôi cái app quản lý project" là brief một câu cho một phim 3 phút. Chốt 6 thứ dưới đây trước, mọi thứ sau đó nhanh gấp ba:

1 · Một câu

App này giúp AI làm được VIỆC GÌ. Một câu, không hai.

"Cho khách xem cut và comment theo timecode"
2 · Danh sách màn hình

Liệt kê 3–7 màn. Nhiều hơn 7 là v1 quá to.

Đăng nhập · Danh sách project · Xem cut · Comment
3 · Dữ liệu lưu gì

Mỗi nhóm dữ liệu sẽ thành một bảng trong database.

User · Project · Video · Comment
4 · Ai được vào

Công khai hay phải đăng nhập? Có mấy loại người dùng?

Admin · Editor · Khách xem
5 · Cắt phạm vi v1

Quan trọng nhất. Ghi rõ cái gì ĐỂ SAU. Không ghi thì AI sẽ làm hết.

V2: thông báo, export, phân tích
6 · Stack

Chọn một bộ rồi khoá lại, ghi vào file quy ước.

Next.js + Supabase + Vercel
Mẹo mạnh nhất cho người không rành: đừng tự viết spec — bắt AI phỏng vấn bạn. Bạn giỏi trả lời câu hỏi về sản phẩm hơn là giỏi viết tài liệu kỹ thuật.

2. Vòng lặp chuẩn của một phiên làm việc

BƯỚC 1

Bắt AI lên kế hoạch, chưa code

BƯỚC 2

Bạn đọc, sửa, duyệt kế hoạch

BƯỚC 3

Cho làm một lát nhỏ duy nhất

BƯỚC 4

Bạn mở app, bấm thử thật

BƯỚC 5

Chạy được thì commit ngay

BƯỚC 6

Lặp lại lát tiếp theo

Bước 5 là bước bị bỏ nhiều nhất và cũng là bước cứu bạn. Commit = lưu version. Có commit thì mọi sai lầm sau đó chỉ tốn 30 giây để quay lại. Không commit thì một lần AI "dọn dẹp giúp" có thể xoá mất hai ngày làm việc.

Một phiên = một tính năng. Xong một tính năng thì commit và mở phiên mới. Phiên càng dài, AI càng quên đoạn đầu và bắt đầu sửa lung tung — y như render một timeline đã nát: nên conform lại từ đầu thay vì vá tiếp.

3. Dùng công cụ nào cho việc gì

Claude Code
VAI: THỢ CHÍNH

Chạy trong terminal, tự đọc và sửa nhiều file, chạy lệnh, cài thư viện, đọc lỗi. Nó nhìn thấy cả dự án chứ không chỉ đoạn bạn dán vào.

✓ Xây tính năng, sửa bug xuyên nhiều file, refactor, deploy
✕ Không hợp để bàn ý tưởng lan man
Codex / Copilot agent
VAI: THỢ THAY THẾ

Cùng nhóm agent chạy trên codebase, khác nhà cung cấp. Chọn một cái làm chủ dự án là đủ.

✓ Thay thế vai trò thợ chính nếu bạn quen hơn
✕ Đừng chạy song song hai agent trên cùng repo
ChatGPT / Claude (chat)
VAI: CỐ VẤN

Không thấy dự án của bạn, chỉ thấy cái bạn dán vào. Bù lại rất tốt để hỏi khái niệm và lấy ý kiến thứ hai.

✓ Giải thích khái niệm, review một file, chọn hướng, hỏi "cách này ổn không"
✕ Đừng dùng để xây tính năng đa file
Cursor / Windsurf
VAI: BÀN DỰNG

Trình soạn code có AI, thấy từng dòng thay đổi trước khi nhận.

✓ Khi bạn muốn kiểm soát và nhìn diff từng dòng
✕ Chậm hơn nếu chỉ muốn ra kết quả nhanh
MẸO: LẤY Ý KIẾN THỨ HAIKhi thợ chính loay hoay hoặc đề xuất một hướng bạn thấy nghi: copy đoạn code + mô tả vấn đề, dán sang một model khác và hỏi "cách làm này có vấn đề gì không, có cách đơn giản hơn không". Hai model hiếm khi sai giống nhau — giống như đưa cut cho một editor khác xem.
ĐỪNGCho hai agent cùng sửa một repo cùng lúc. Chúng ghi đè lên nhau và bạn sẽ không biết dòng nào của ai.

4. Trí nhớ của AI — thứ bạn phải quản lý

AI không nhớ gì giữa hai phiên, và trong một phiên dài nó cũng quên dần phần đầu. Cách xử lý: đưa trí nhớ ra file.

Tạo file quy ước ở gốc dự án — Claude Code đọc CLAUDE.md, Codex đọc AGENTS.md, Cursor đọc .cursorrules. Nội dung gần như nhau, tạo cả ba cũng được:

# DỰ ÁN
App review cut cho khách hàng. Khách xem video và comment theo timecode.

# STACK — KHÔNG ĐỔI
Next.js App Router · TypeScript · Supabase (DB + Auth) · Tailwind · Vercel

# NGUYÊN TẮC BẢO MẬT — BẮT BUỘC
- Mọi bảng phải bật RLS. Không tạo bảng mới mà không kèm policy.
- Không bao giờ đặt khoá bí mật ở frontend. Chỉ dùng NEXT_PUBLIC cho thứ vô hại.
- Mọi route backend phải kiểm tra người gọi là ai và có quyền không.
- Validate lại toàn bộ input ở phía server.

# CÁCH LÀM VIỆC VỚI TÔI
- Luôn trình bày kế hoạch trước, chờ tôi duyệt rồi mới code.
- Mỗi lần chỉ làm một việc. Không tự ý sửa file ngoài phạm vi tôi nêu.
- Tôi không rành backend: giải thích bằng tiếng Việt, không dùng từ chuyên môn mà không giải thích.
- Chọn cách đơn giản nhất chạy được. Không thêm thư viện nếu chưa hỏi tôi.
- Sau mỗi thay đổi, tóm tắt đã sửa file nào và tại sao.

# ĐANG LÀM DỞ
(cập nhật cuối phiên: đang làm màn hình comment, chưa xong phần timecode)
DẤU HIỆU PHIÊN ĐÃ QUÁ DÀIAI sửa lại thứ vừa sửa xong · quên quy ước đã thống nhất · nói "đã sửa" nhưng không đổi gì · đề xuất thư viện đã bỏ · trả lời chung chung dần.
XỬ LÝBảo nó cập nhật mục "ĐANG LÀM DỞ" trong CLAUDE.md → commit → đóng phiên → mở phiên mới. Phiên mới đọc file là biết đang ở đâu.

5. Mười luật viết prompt code

1
Bắt lên kế hoạch trước, cấm code

Luật quan trọng nhất. Sửa một đoạn kế hoạch mất 30 giây; sửa 800 dòng code đã sinh ra mất cả buổi.

SAI"Làm cho tôi tính năng upload video"
ĐÚNG"Tôi muốn thêm upload video. Trình bày kế hoạch: sẽ tạo/sửa file nào, thêm bảng gì, luồng chạy ra sao. Chưa viết code, chờ tôi duyệt."
2
Một yêu cầu một việc

Gộp ba việc vào một prompt thì lỗi ở việc nào bạn cũng không biết. Chia lát như dựng: một sequence một lần.

SAI"Sửa layout, thêm dark mode, và tối ưu tốc độ luôn"
ĐÚNG"Chỉ sửa layout sidebar. Xong tôi kiểm rồi mới sang việc khác."
3
Khoá phạm vi rõ ràng

Không khoá thì AI hay "tiện tay dọn luôn" và làm hỏng thứ đang chạy tốt.

SAI"Cải thiện phần này đi"
ĐÚNG"Chỉ sửa file Sidebar. Không đụng tới bất kỳ file nào khác. Nếu thấy chỗ khác cần sửa thì liệt kê ra, đừng tự sửa."
4
Dán lỗi nguyên văn, đừng kể lại

Thông báo lỗi là bằng chứng gốc — như đưa file log thay vì nói "nó bị giật giật".

SAI"Nó báo lỗi gì đó không chạy được"
ĐÚNG"Tôi bấm nút Lưu thì màn hình trắng. Đây là toàn bộ lỗi trong console: [dán nguyên văn]. Đây là lỗi ở terminal: [dán nguyên văn]."
5
Mô tả kết quả mong muốn, không chỉ đạo cách làm

Bạn là đạo diễn, không phải người cầm máy. Nói cái muốn thấy; nếu bạn không rành kỹ thuật thì đừng áp cách làm.

SAI"Dùng useEffect với setTimeout để làm cái này"
ĐÚNG"Tôi muốn thông báo tự biến mất sau 5 giây, nhưng nếu rê chuột vào thì giữ lại. Chọn cách đơn giản nhất."
6
Bắt nó nêu giả định trước khi làm

Phần lớn kết quả sai là do AI tự đoán thứ bạn chưa nói. Bắt nó nói ra thì bạn chặn được ngay.

SAI"Làm phần đăng nhập"
ĐÚNG"Trước khi làm, liệt kê mọi giả định bạn đang đặt ra và mọi câu hỏi bạn cần tôi trả lời."
7
Chặn phức tạp hoá

AI có xu hướng dựng kiến trúc cho công ty nghìn người trong khi bạn chỉ cần một trang. Code càng nhiều thì càng nhiều chỗ hỏng.

SAI"Làm sao cho chuyên nghiệp, chuẩn production"
ĐÚNG"Làm cách đơn giản nhất chạy được. Không thêm thư viện, không tạo lớp trừu tượng, không chuẩn bị cho tính năng tương lai."
8
Yêu cầu tóm tắt thay đổi sau mỗi lần

Bạn không đọc được hết code, nhưng bạn đọc được tóm tắt. Đây là cách duy nhất để biết nó vừa đụng vào đâu.

SAI(không hỏi gì, tin luôn)
ĐÚNG"Tóm tắt: đã sửa file nào, mỗi file đổi gì, tại sao. Có chỗ nào có thể làm hỏng tính năng đang chạy không?"
9
Bắt nó tự chạy và tự kiểm

"Xong rồi" của AI thường có nghĩa là "tôi đã viết xong", không phải "tôi đã chạy thử và nó chạy".

SAITin câu "đã sửa xong"
ĐÚNG"Chạy thật đi và dán kết quả cho tôi xem. Nếu không chạy được thì nói rõ chưa kiểm chứng được chỗ nào."
10
Không hiểu thì hỏi lại ngay, đừng bấm tiếp

Mỗi thứ bạn không hiểu mà vẫn nhận là một chỗ sau này không tự sửa nổi. Hỏi lại rẻ hơn nhiều.

SAIThấy chữ lạ, kệ, bấm chấp nhận
ĐÚNG"Giải thích đoạn này như giải thích cho người chưa từng code. Nếu tôi xoá nó thì hỏng cái gì?"

6. Khi AI sửa mãi không xong — quy tắc 3 lần

Ai cũng gặp: bảo sửa, nó sửa, vẫn lỗi, sửa tiếp, hỏng thêm chỗ khác. Vòng xoáy này đốt tiền và làm nát code. Quy tắc: thử 3 lần không xong thì dừng, đổi cách — đừng thử lần 4.

LẦN 1–3

Sửa bình thường. Mỗi lần dán nguyên văn lỗi mới.

DỪNG

Không bảo "thử lại" nữa. Đổi chiến thuật.

ĐỔI CÁCH

Bắt nó chẩn đoán thay vì vá.

VẪN KẸT

Rollback về commit sạch, làm lại hướng khác.

Vì sao rollback lại tốt hơn vá tiếp: sau 5 lần vá, code đã đầy đoạn thừa từ các lần thử thất bại — cả bạn lẫn AI đều không còn hiểu nó đang chạy thế nào. Quay về bản sạch và làm lại với hướng khác thường nhanh hơn, giống như relink lại từ project gốc thay vì cứu một timeline đã hỏng.

7. Kiểm chứng AI không bịa

Kiểu bịa hay gặpCách phát hiện
Thư viện không tồn tạiCài không được, hoặc tên na ná tên thật. Bắt nó đưa link trang chủ.
Hàm/tính năng không có thậtChạy là lỗi ngay. Hỏi "chỗ nào trong tài liệu chính thức nói vậy?"
"Đã sửa xong" mà chưa chạyBắt chạy thật và dán kết quả ra. Đừng nhận báo cáo suông.
Số liệu, giá, giới hạn gói dịch vụNhững thứ này đổi liên tục — bắt nó tra web trước khi trả lời.
Sửa test cho pass thay vì sửa codeXem nó có vừa đổi file test không. Nếu có, hỏi thẳng.
Đồng ý với bạn dù bạn saiNếu bạn phản đối mà nó lập tức quay xe hoàn toàn, hỏi lại: "trước đó bạn sai chỗ nào, giải thích cụ thể".

8. Kiểm thử tối thiểu — đừng bỏ hẳn

Không cần phủ 100%. Vibe-coder chỉ cần đủ để biết thứ đang chạy có bị hỏng khi sửa cái khác không — giống check gate trước khi gửi master, không phải xem lại từng frame.

Mức tối thiểu
Luồng chính

Đăng nhập → tạo → xem → xoá. Chạy được là ổn.

Nên thêm
3 ca lỗi

Nhập rỗng, nhập sai định dạng, không có quyền.

Khi có người dùng thật
Test tự động

Chạy mỗi lần deploy, chặn không cho lên nếu hỏng.

9. Thư viện prompt — copy dùng ngay

Giao diện là phần ai cũng thấy. Nhưng thứ làm sập một webapp lại nằm ở phần không ai thấy: database, khoá bí mật, phân quyền. Vibe-code khiến app chạy được rất nhanh — nhưng "chạy được" và "cho người lạ dùng được" là hai mức khác nhau, y hệt rough cut vs. master delivery. Tab này là checklist để qua được ranh giới đó.

App của bạn gồm những mảnh nào

Đối chiếu sang pipeline post cho dễ hình dung:

Frontend

Giao diện chạy trên máy người dùng. Ai cũng xem được toàn bộ code này.

≈ Bản master đã phát — không giấu được gì
Backend / API

Code chạy trên server của bạn. Người dùng không nhìn thấy.

≈ Phòng máy, chỉ ekip vào
Database

Nơi lưu dữ liệu người dùng vĩnh viễn.

≈ NAS lưu toàn bộ project
Auth

Xác định bạn là ai và được xem cái gì.

≈ Phân quyền truy cập folder
Env / Secrets

Khoá API, mật khẩu DB. Chỉ được nằm ở backend.

≈ Password NAS — không dán lên tường
Hosting

Nơi app thực sự chạy 24/7 cho người ngoài truy cập.

≈ Nền tảng phát hành

5 lỗi làm sập dự án vibe-code — đọc trước tiên

1
API key nằm trong code frontendBất kỳ ai bấm F12 đều đọc được. Bot quét GitHub tìm key trong vài phút. Nguyên tắc: mọi khoá bí mật phải nằm ở backend, frontend chỉ gọi API của chính bạn.
2
Database không bật phân quyền (RLS)Mặc định Supabase/Firebase để mở. Không bật Row Level Security = ai biết URL là đọc được dữ liệu của toàn bộ người dùng, kể cả bạn đã làm màn hình đăng nhập.
3
Chỉ kiểm tra dữ liệu ở frontendKiểm tra ở giao diện chỉ để người dùng đỡ nhầm. Kẻ tấn công gọi thẳng API, bỏ qua giao diện. Mọi validate và phân quyền phải lặp lại ở backend.
4
Không có backup và không có stagingMột lệnh migration sai xoá sạch bảng, không hoàn tác được. Cần bản sao tự động hàng ngày + môi trường thử riêng (staging) trước khi đụng vào production.
5
Không giới hạn chi phí và tần suấtKhông đặt rate limit + spend cap: một bot spam hoặc một vòng lặp lỗi có thể sinh hoá đơn hàng chục triệu qua đêm. Bật cảnh báo chi phí ngay hôm đầu tiên.

Stack mặc định an toàn cho vibe-coder

Không phải lựa chọn duy nhất, nhưng là bộ ít gây tai nạn nhất khi bạn không rành backend:

Framework
Next.js

Frontend + backend trong một dự án, đỡ phải nối hai thứ.

Database + Auth
Supabase

Postgres + đăng nhập sẵn + RLS. Nhớ BẬT RLS.

Hosting
Vercel

Deploy bằng git push, tự có preview cho mỗi thay đổi.

Thanh toán
Stripe / Polar

Không bao giờ tự lưu số thẻ. Không bao giờ.

Báo lỗi
Sentry

Biết app lỗi trước khi người dùng phàn nàn.

Email
Resend

Đừng tự dựng mail server.

Ba thứ tuyệt đối không tự viết: đăng nhập / mật khẩu (auth), thanh toán, và mã hoá. Đây là ba mảng mà lỗi nhỏ nhất cũng thành thảm hoạ — luôn dùng dịch vụ có sẵn. Nếu Claude bắt đầu tự viết hàm hash mật khẩu hay lưu thẻ tín dụng, hãy dừng lại và bảo nó dùng thư viện chuẩn.

Đèn đỏ — thấy những dòng này thì dừng lại hỏi

Claude viết ra thứ nàyNghĩa là
Khoá dài dán thẳng trong file .js/.tsxSecret bị lộ ra frontend → chuyển sang biến môi trường ở server
NEXT_PUBLIC_… chứa khoá bí mậtTiền tố PUBLIC nghĩa là cả thế giới đọc được → sai chỗ
service_role / admin key ở phía clientKhoá toàn quyền bị phơi ra → nguy hiểm nhất trong tất cả
Câu SQL nối chuỗi bằng dấu +Rủi ro SQL injection → phải dùng tham số hoá
dangerouslySetInnerHTML / innerHTML với dữ liệu người dùngRủi ro XSS → phải làm sạch dữ liệu trước
cors: origin "*"Mọi website đều gọi được API của bạn → giới hạn domain
DROP TABLE / TRUNCATE trong migrationXoá sạch dữ liệu → backup trước, chạy trên staging trước
Mật khẩu lưu dạng chữ thường đọc đượcKhông bao giờ được phép → phải hash

Từ điển backend — hiểu Claude đang nói gì

4 prompt bắt Claude tự kiểm tra

Phần pháp lý ở trên chỉ là thông tin tham khảo, không phải tư vấn pháp lý. Nếu app xử lý dữ liệu cá nhân ở quy mô thật, nên hỏi luật sư về Nghị định 13/2023/NĐ-CP.