CRUD — xương sống của mọi ứng dụng
CRUD = Create, Read, Update, Delete. 90% công việc app là 4 thao tác này trên dữ liệu. Bài này dạy cách yêu cầu AI viết CRUD an toàn — vì đây là nơi lỗ hổng bảo mật hay xuất hiện nhất.
Hai cách viết logic server (Next.js)
| Server Actions | API Routes | |
|---|---|---|
| Dạng | Hàm chạy trên server, gọi trực tiếp từ component | Endpoint HTTP (/api/...) |
| Hợp với | Form, mutation trong cùng app Next.js | Khi cần endpoint cho client ngoài, webhook |
| Ưu điểm | Gọn, không cần tự định nghĩa endpoint | Linh hoạt, chuẩn REST |
Với app Next.js thuần, Server Actions thường gọn và an toàn hơn cho CRUD nội bộ.
Mẫu Server Action an toàn
'use server';
import { createClient } from '@/lib/supabase/server';
export async function createPost(formData: FormData) {
const supabase = await createClient();
// 1. Xác thực người dùng (đừng tin client)
const { data: { user } } = await supabase.auth.getUser();
if (!user) throw new Error('Chưa đăng nhập');
// 2. Validate đầu vào
const title = String(formData.get('title') ?? '').trim();
if (!title || title.length > 200) throw new Error('Tiêu đề không hợp lệ');
// 3. Ghi DB — RLS vẫn là lớp bảo vệ cuối
const { error } = await supabase
.from('posts')
.insert({ title, user_id: user.id });
if (error) throw error;
}
3 lớp an toàn cho mọi thao tác ghi
- Xác thực: luôn
getUser()ở server, không tinuser_iddo client gửi lên. - Validate đầu vào: kiểm tra kiểu, độ dài, giá trị hợp lệ trước khi ghi. Đừng tin dữ liệu từ form.
- RLS là tấm lưới cuối: kể cả code sai, policy ở DB (bài Module 1) vẫn chặn ghi trái phép.
Prompt mẫu cho AI
"Viết các Server Action CRUD cho bảng
taskstrong Next.js + Supabase: createTask, getTasks (chỉ task của user hiện tại), updateTask, deleteTask. Mỗi action phải: xác thực user qua getUser, validate đầu vào, và dựa vào RLS. Trả lỗi rõ ràng bằng tiếng Việt."
Anti-pattern phải tránh
- ❌ Nhận
user_idtừ client rồi tin luôn → kẻ xấu giả mạo ID người khác - ❌ Không validate → lưu dữ liệu rác/độc hại
- ❌ Dùng service role key ở client để "cho tiện" → bỏ qua mọi RLS, thảm hoạ bảo mật
- ❌ Trả lỗi DB thô ra UI → lộ cấu trúc database
Tổng kết khoá học
Bạn đã đi trọn vòng dữ liệu: thiết kế schema bằng lời nói → dựng bảng/khoá ngoại/index trên Supabase → bảo mật bằng RLS & triggers → nối frontend bằng state management + real-time → CRUD an toàn bằng Server Actions. Đây là nền tảng để xây bất kỳ app có dữ liệu nào.
Bước tiếp theo: đưa sản phẩm lên Internet trong khoá Deployment & Production Operations. Và đừng quên chia sẻ schema/pattern hay của bạn lên cộng đồng!
Hẹn gặp bạn ở những khoá tiếp theo của Cộng Đồng Vibe Code! 🚀
