Bản đồ công trìnhTờ này lắp: Giao diện app, API, Database
Bài nàyĐã họcChưa tớiĐã thay thế
Bạn sẽ học được gì
Tiêu chí nghiệm thu
Ba tầng qua hình ảnh một tiệm bánh
Ở bài Phần mềm thực chất là gì01-01, bạn đã biết mọi phần mềm có ba thành phần: dữ liệu, logic, giao diện. Trong một ứng dụng web, ba thành phần đó được “đặt” vào ba nơi vật lý khác nhau, gọi là ba tầng (tier/layer).
- Gian hàng, quầy order
- Bếp và quầy thu ngân
- Kho và sổ cái
- lịch sự
- an toàn
- chắc chắn
Hãy đi một vòng quanh tiệm Bánh Mộc chi nhánh Thảo Điền:
- Gian hàng phía trước có tủ kính, bảng giá, quầy order. Khách nhìn thấy, chạm vào, chỉ trỏ. Đây là frontend.
- Bếp và quầy thu ngân phía sau: nơi nhận phiếu order, kiểm tra còn nguyên liệu không, tính tiền, quyết định làm hay không. Khách không được vào. Đây là backend.
- Kho và tủ hồ sơ: nơi cất nguyên liệu và sổ cái ghi mọi đơn hàng. Chỉ bếp được ra vào. Đây là database.
Điểm mấu chốt trong ẩn dụ này: khách có thể làm bất cứ điều gì ở gian hàng phía trước. Họ có thể tự viết phiếu order, tự ghi giá, thậm chí mang phiếu giả từ nhà tới. Bếp phía sau phải luôn kiểm tra lại. Giữ hình ảnh này trong đầu, bạn sẽ hiểu được phần lớn các lỗ hổng bảo mật phổ biến.
Frontend: phần chạy trên máy người dùng
Frontend là mọi thứ người dùng nhìn thấy và tương tác: màn hình, nút bấm, form, hiệu ứng. Nó được xây bằng ba công nghệ nền của web:
- HTML: khung và nội dung (tiêu đề, ô nhập, nút).
- CSS: trang trí (màu, cỡ chữ, bố cục). Trong stack Bánh Mộc, chúng ta dùng Tailwind CSS để viết CSS nhanh hơn.
- JavaScript: hành vi (bấm nút thì làm gì, kiểm tra ô nhập, cập nhật danh sách không cần tải lại trang). Thư viện React giúp tổ chức JavaScript thành các khối giao diện tái sử dụng.
Điều quan trọng nhất về frontend: code frontend được tải về và chạy trên thiết bị của người dùng. Điện thoại của Hà, laptop của khách, máy của bất kỳ ai mở trang web. Hệ quả:
- Ai cũng xem được code frontend. Chỉ cần bấm F12 trên trình duyệt. Mọi thứ nằm trong code frontend, kể cả một “khóa bí mật” vô tình để ở đó, đều công khai.
- Ai cũng sửa được hành vi frontend. Người dùng có kỹ thuật có thể bỏ qua giao diện và gửi thẳng request tới server với bất kỳ dữ liệu nào họ muốn.
- Bạn không kiểm soát được môi trường chạy. Trình duyệt cũ, mạng chập chờn, màn hình nhỏ, tất cả đều ảnh hưởng tới trải nghiệm.
Backend: phần chạy trên server bạn kiểm soát
Backend là phần chạy trên server, nơi người dùng không nhìn thấy và không chạm tới được. Nhiệm vụ của backend:
- Xác thực và phân quyền: người này là ai, có được làm việc này không.
- Thực thi quy tắc nghiệp vụ: tính tổng tiền, sinh mã đơn
BM-YYMMDD-XXX, kiểm tra chuyển trạng thái hợp lệ. - Kiểm tra dữ liệu (validate): số lượng phải là số nguyên dương, giờ nhận phải ở tương lai.
- Nói chuyện với database và các dịch vụ bên ngoài (gửi Zalo, tạo mã VietQR).
- Giữ bí mật: khóa API, mật khẩu kết nối database chỉ nằm ở backend.
Backend có thể viết bằng nhiều ngôn ngữ (TypeScript, Python, Go, PHP…). Trong stack Bánh Mộc, backend viết bằng TypeScript và chạy trong Next.js.
Database: kho và sổ cái
Database (cơ sở dữ liệu) là nơi lưu trữ dữ liệu bền vững, có tổ chức, tìm kiếm nhanh. Database của Mộc OMS là PostgreSQL (thường gọi tắt là Postgres), được Supabase vận hành hộ. Dữ liệu tổ chức thành các bảng như orders, order_items, customers, products.
Database không chỉ là “chỗ chứa”. Một database tốt còn là tuyến phòng thủ cuối cùng cho tính đúng đắn của dữ liệu: nó có thể từ chối một khách hàng thứ hai có cùng số điện thoại (ràng buộc UNIQUE), từ chối một dòng đơn hàng trỏ tới sản phẩm không tồn tại, từ chối số lượng âm. Bạn sẽ học về các ràng buộc này trong bài Cơ sở dữ liệu04-03.
Ba tầng trong một thao tác thật: Hà tạo đơn bánh kem
Hãy xem ba tầng phối hợp khi Hà tạo đơn bánh kem dâu 20cm cho chị Hương, giao lúc 15 giờ:
Vuốt ngang để xem hết sơ đồ
Vuốt ngang để xem hết sơ đồ
Đọc sơ đồ dạng chữ
- Thiết bị của Hà (trình duyệt)
- Server Mộc OMS (Next.js trên Vercel)
- Supabase
- FRONTEND Form tạo đơn kiểm tra sơ bộ, hiển thị tạm tính → BACKEND xác thực, phân quyền validate, lấy giá thật tính tổng, sinh mã đơn (1. gửi: khách, món, số lượng, giờ nhận)
- BACKEND xác thực, phân quyền validate, lấy giá thật tính tổng, sinh mã đơn → Auth quản lý đăng nhập (2. Hà là ai?)
- BACKEND xác thực, phân quyền validate, lấy giá thật tính tổng, sinh mã đơn → DATABASE orders, order_items customers, products (3. đọc giá, ghi đơn)
- DATABASE orders, order_items customers, products → BACKEND xác thực, phân quyền validate, lấy giá thật tính tổng, sinh mã đơn (4. đơn đã lưu)
- BACKEND xác thực, phân quyền validate, lấy giá thật tính tổng, sinh mã đơn → FRONTEND Form tạo đơn kiểm tra sơ bộ, hiển thị tạm tính (5. mã BM-261012-007, tổng 450.000đ)
| Tầng | Chạy ở đâu | Ai xem được code | Việc trong thao tác tạo đơn | Ẩn dụ |
|---|---|---|---|---|
| Frontend | Trình duyệt của Hà | Bất kỳ ai mở trang | Hiển thị form, báo lỗi ngay khi bỏ trống ô, hiển thị tạm tính cho tiện | Gian hàng, quầy order |
| Backend | Server (Vercel) | Chỉ đội làm phần mềm | Kiểm tra Hà đã đăng nhập, lấy giá thật từ database, tính tổng, sinh mã, ghi đơn | Bếp và quầy thu ngân |
| Database | Supabase | Không ai “xem code”, chỉ truy cập dữ liệu khi được phép | Lưu đơn bền vững, chặn dữ liệu vi phạm ràng buộc | Kho và sổ cái |
Chú ý rằng tạm tính xuất hiện ở cả frontend lẫn backend. Frontend tính để Hà thấy ngay con số khi chọn món, cho trải nghiệm mượt. Backend tính lại từ đầu để quyết định con số thật được lưu. Đây không phải lặp thừa; đây là thiết kế đúng.
Quy tắc vàng: không tin dữ liệu từ trình duyệt
Nếu chỉ nhớ một điều từ bài này, hãy nhớ: mọi thứ đến từ trình duyệt đều có thể bị giả mạo.
Ẩn dụ tiệm bánh: khách đưa phiếu order tự ghi “Bánh kem dâu 20cm, giá 50.000đ”. Thu ngân tốt sẽ không nhìn con số khách ghi; thu ngân tra bảng giá của tiệm và tính lại. Thu ngân tồi sẽ thu 50.000đ.
Trong phần mềm, “phiếu tự ghi” chính là request gửi từ trình duyệt. Chỉ cần mở công cụ dành cho lập trình viên (F12) hoặc dùng một công cụ gửi request, bất kỳ ai cũng có thể gửi lên server bất cứ thứ gì: giá 1 đồng, số lượng âm, mã chi nhánh khác, trạng thái hoan_tat cho đơn chưa làm.
Trước và sau: code AI hay viết sai
Đây là kiểu code AI hay viết khi không được dặn kỹ. Hãy đọc chú thích, bạn chưa cần hiểu từng chữ (bài Đọc hiểu code cơ bản01-04 sẽ giúp bạn đọc tốt hơn):
// ❌ SAI: backend tin con số tổng tiền do trình duyệt gửi lên
"use server";
export async function taoDon(input: {
customerPhone: string;
items: { productId: number; quantity: number }[];
total: number; // tổng tiền do frontend tự tính rồi gửi lên
}) {
// Lưu thẳng con số input.total vào database, không kiểm tra gì cả
await luuDonVaoDatabase({ ...input, total: input.total });
}
Phiên bản đúng: backend kiểm tra người gọi, kiểm tra hình dạng dữ liệu, lấy giá thật từ database và tự tính tổng.
// ✅ ĐÚNG: backend tự kiểm tra và tự tính, không tin frontend
"use server";
import { z } from "zod";
// Mô tả hình dạng dữ liệu hợp lệ. Lưu ý: KHÔNG nhận giá hay tổng tiền từ frontend.
const TaoDonSchema = z.object({
customerPhone: z.string().regex(/^0\d{9}$/, "Số điện thoại phải có 10 chữ số, bắt đầu bằng 0"),
items: z
.array(
z.object({
productId: z.number().int().positive(),
quantity: z.number().int().min(1).max(50),
})
)
.min(1, "Đơn phải có ít nhất 1 món"),
});
export async function taoDon(raw: unknown) {
// 1. Ai đang gọi? Chưa đăng nhập thì từ chối.
const nhanVien = await layNhanVienDangNhap();
if (!nhanVien) throw new Error("Bạn cần đăng nhập");
// 2. Dữ liệu có đúng hình dạng không? Sai là dừng ngay.
const input = TaoDonSchema.parse(raw);
// 3. Lấy giá THẬT từ database, tự tính tạm tính (tiền là số nguyên VNĐ).
let subtotal = 0;
for (const item of input.items) {
const sp = await laySanPham(item.productId);
if (!sp || !sp.isActive) throw new Error("Sản phẩm không tồn tại hoặc đã ngừng bán");
subtotal += sp.price * item.quantity;
}
// 4. Chi nhánh lấy từ hồ sơ nhân viên, không lấy từ dữ liệu frontend gửi.
await luuDonVaoDatabase({ ...input, subtotal, branchId: nhanVien.branchId });
}
Hai đoạn code trông đều “chạy được”. Trên giao diện, chúng cho kết quả giống hệt nhau với người dùng bình thường. Khác biệt chỉ lộ ra khi có người cố tình gian lận, hoặc khi frontend có lỗi tính sai. Đây chính là loại lỗi mà “trông có vẻ xong” không bao giờ phát hiện ra.
Kiểm tra ở đâu cho đúng
Vậy có nên bỏ kiểm tra ở frontend không? Không. Mỗi tầng kiểm tra vì một lý do khác nhau:
| Tầng kiểm tra | Mục đích | Ví dụ | Có thể bị vượt qua? |
|---|---|---|---|
| Frontend | Trải nghiệm: báo lỗi ngay, không bắt người dùng chờ | “Vui lòng nhập số điện thoại” hiện ngay dưới ô | Có, rất dễ |
| Backend | An toàn và đúng nghiệp vụ: quyết định cuối cùng | Từ chối đơn có giờ nhận trong quá khứ, tính lại tổng | Không, nếu viết đúng |
| Database | Lưới an toàn cuối cùng cho tính toàn vẹn dữ liệu | Không cho hai khách trùng số điện thoại | Không |
Một cách nhớ: frontend kiểm tra để lịch sự, backend kiểm tra để an toàn, database kiểm tra để chắc chắn.
Form tạo đơn giả có ô total sửa được như F12: gửi 50.000đ cho bánh 450.000đ → so phiên bản SAI (lưu thẳng) với ĐÚNG (backend tra giá, tự tính, chi nhánh lấy từ phiên đăng nhập)
Bàn thử cần bật JavaScript.
Kết quả chỉ để tham khảo, không thay cho việc bạn tự duyệt.
Next.js: khi một dự án chứa cả gian hàng lẫn bếp
Ngày trước, frontend và backend thường là hai dự án riêng, đôi khi do hai đội riêng làm. Ngày nay, các framework fullstack như Next.js (trong stack Bánh Mộc) cho phép viết cả hai trong cùng một dự án, cùng một ngôn ngữ. Đây là lý do lớn giúp một người cùng AI có thể làm cả ứng dụng.
Trong Next.js với App Router (tại thời điểm viết, 2026), có vài cách code được đánh dấu để biết nó chạy ở đâu:
- Server Component: mặc định, các component trong thư mục
app/chạy trên server. Chúng có thể đọc database trực tiếp, và code của chúng không bị gửi xuống trình duyệt. - Client Component: file bắt đầu bằng dòng
"use client"chạy được trên trình duyệt, dùng cho phần tương tác (bấm nút, gõ chữ, mở hộp thoại). - Server Action: hàm được đánh dấu
"use server"(như ví dụtaoDonở trên). Frontend gọi nó như gọi một hàm bình thường, nhưng thực chất đó là một request gửi lên server. - Route Handler: file
route.tstrong thư mụcapp/, tạo ra một địa chỉ API như/api/orderscho phần mềm khác gọi tới.
Điền ô trống rồi sao chép
src/app/don-hang/
├── page.tsx # Server Component: đọc danh sách đơn từ database (chạy trên server)
├── form-tao-don.tsx # "use client": form có tương tác (chạy trên trình duyệt)
└── actions.ts # "use server": hàm taoDon, xử lý và ghi đơn (chạy trên server)
Sự tiện lợi này đi kèm một rủi ro: ranh giới giữa gian hàng và bếp trở nên mờ. Hai file nằm cạnh nhau trong cùng thư mục, nhưng một file ai cũng xem được, file kia thì không. AI đôi khi đặt nhầm logic quan trọng vào Client Component, hoặc tin tưởng dữ liệu từ form vì “cùng một dự án mà”.
Backend-as-a-Service: thuê sẵn bếp và kho
Xây backend và vận hành database từ đầu tốn công: phải lo đăng nhập, mã hóa mật khẩu, sao lưu, bảo mật server, mở rộng khi đông khách. Backend-as-a-Service (BaaS) là dịch vụ cung cấp sẵn những phần này, giống thuê một bếp trung tâm đã có sẵn kho, sổ sách và bảo vệ.
Hai cái tên phổ biến:
- Supabase (trong stack Bánh Mộc): cung cấp database PostgreSQL, hệ thống đăng nhập (Auth), lưu trữ file (Storage), và tự sinh API để đọc/ghi dữ liệu.
- Firebase (của Google): cung cấp database dạng tài liệu (Firestore), đăng nhập, lưu trữ file, hàm chạy trên server.
Điểm đặc biệt của BaaS: frontend có thể nói chuyện trực tiếp với database thông qua API mà dịch vụ cung cấp, không cần đi qua backend riêng. Nghe rất tiện, nhưng hãy nhớ lại quy tắc vàng: frontend thì ai cũng xem và sửa được. Vậy cái gì ngăn một người lạ đọc toàn bộ bảng customers?
Câu trả lời là luật truy cập đặt ngay tại database:
- Với Supabase, đó là Row Level Security (RLS, bảo mật theo từng dòng): các luật kiểu “nhân viên chỉ đọc được đơn có
branch_idbằng chi nhánh của mình”. - Với Firebase, đó là Security Rules.
| Tiêu chí | Tự xây backend + database | Dùng BaaS (Supabase, Firebase) |
|---|---|---|
| Tốc độ khởi đầu | Chậm hơn | Nhanh, có sẵn đăng nhập, lưu file |
| Vận hành (sao lưu, cập nhật bảo mật server) | Tự lo | Nhà cung cấp lo phần lớn |
| Kiểm soát | Toàn quyền | Theo khả năng của dịch vụ |
| Rủi ro chính | Tự cấu hình sai server | Cấu hình sai luật truy cập (RLS/Rules) |
| Chi phí | Tùy hạ tầng | Thường có gói miễn phí để bắt đầu; tăng theo quy mô (kiểm tra bảng giá chính thức) |
Mộc OMS chọn cách nào?
Chị Lan cùng agent chọn một cách kết hợp, phổ biến và an toàn cho người mới:
- Dùng Supabase làm database Postgres và hệ thống đăng nhập (không phải tự vận hành).
- Mọi thao tác ghi quan trọng (tạo đơn, đổi trạng thái, ghi nhận thanh toán) đi qua backend Next.js (Server Action), nơi kiểm tra quyền, validate và tính tiền.
- Vẫn bật RLS cho mọi bảng như lớp phòng thủ thứ hai, phòng khi có chỗ nào đó frontend truy cập trực tiếp.
Đây là nguyên tắc “phòng thủ nhiều lớp”: không đặt toàn bộ niềm tin vào một chỗ duy nhất.
Áp dụng vào dự án Bánh Mộc
Nhật ký công trình · Bánh Mộc
BM-261013-009
13.10.2026
- Chị LanChủ chuỗi

Chị Lan mở lại app “vibe” ngày trước, giờ với con mắt mới. Chị nhờ một coding agent đọc code và trả lời ba câu: logic tính tiền nằm ở đâu, dữ liệu lưu ở đâu, khóa bí mật nằm ở đâu. Kết quả:
- Logic tính tiền: nằm hoàn toàn trong một Client Component. Tổng tiền được tính trên trình duyệt rồi gửi thẳng vào database.
- Dữ liệu: frontend gọi trực tiếp Supabase, nhưng bảng
ordersvàcustomerschưa bật RLS. Agent giải thích: ai có địa chỉ trang web đều có thể đọc danh sách số điện thoại khách hàng. - Khóa bí mật: một khóa API của dịch vụ AI được đặt trong biến
NEXT_PUBLIC_AI_KEY. Bài 01-08 sẽ kể chuyện gì đã xảy ra với chiếc khóa này.
Chị Lan không tự sửa được. Nhưng lần này chị biết mình cần yêu cầu gì. Chị ghi vào sổ tay ba quy tắc cho dự án Mộc OMS mới, sau này sẽ đưa vào file hướng dẫn agent (AGENTS.md):
## Quy tắc ranh giới frontend/backend
- Mọi thao tác ghi dữ liệu (tạo/sửa/hủy đơn, thanh toán) đi qua Server Action ở backend.
- Backend không bao giờ nhận giá, tổng tiền, vai trò, chi nhánh từ dữ liệu frontend gửi lên;
luôn tự lấy từ database hoặc từ phiên đăng nhập.
- Mọi bảng trong Supabase phải bật RLS. Không dùng service role key ở code chạy trên trình duyệt.
Bài học chị rút ra: app cũ trông giống hệt một app tốt. Khác biệt nằm ở chỗ đặt logic và chỗ đặt niềm tin, những thứ không nhìn thấy trên màn hình.
Prompt mẫu
Điền ô trống rồi sao chép
Đọc code của tính năng [tạo đơn hàng] và trả lời dưới dạng bảng:
1. Những file nào chạy trên trình duyệt (frontend), những file nào chạy trên server (backend)?
2. Logic tính tiền, kiểm tra quyền, sinh mã đơn nằm ở tầng nào, file nào?
3. Liệt kê mọi trường dữ liệu backend nhận từ frontend. Với mỗi trường, backend có
tự kiểm tra lại hoặc tự xác định lại không? Đánh dấu trường nào đang bị tin tưởng mù quáng.
Chưa sửa gì cả, chỉ báo cáo.
Điền ô trống rồi sao chép
Viết Server Action đổi trạng thái đơn hàng. Yêu cầu:
- Chỉ nhận từ frontend: mã đơn và trạng thái mới.
- Backend tự lấy nhân viên đang đăng nhập; staff chỉ đổi được đơn thuộc chi nhánh của mình.
- Chỉ cho phép chuyển trạng thái theo thứ tự: moi -> da_xac_nhan -> dang_lam -> dang_giao -> hoan_tat,
hoặc chuyển sang da_huy khi đơn còn ở moi, da_xac_nhan hoặc dang_lam (trước dang_giao).
- Ghi một dòng vào order_status_history cho mỗi lần đổi.
- Validate đầu vào bằng Zod. Báo lỗi tiếng Việt.
Sau khi viết, giải thích ngắn đoạn nào chạy ở đâu và chạy test liên quan.
Điền ô trống rồi sao chép
Liệt kê tất cả bảng trong database Supabase của dự án. Với mỗi bảng: RLS đã bật chưa,
có những policy nào, policy đó cho phép ai đọc/ghi gì (giải thích bằng tiếng Việt dễ hiểu).
Chỉ ra bảng nào có rủi ro bị người lạ đọc dữ liệu. Không thay đổi gì, chỉ báo cáo.
Sai lầm thường gặp
-
Sự cố 01
Đặt logic nghiệp vụ quan trọng ở frontend.
Triệu chứngTính tiền, kiểm tra quyền, đổi trạng thái chỉ trên trình duyệt. Chạy đúng với người dùng ngoan, sai với người gian lận.
Cách tránhQuy định rõ trong file hướng dẫn agent: logic nghiệp vụ và mọi thao tác ghi nằm ở backend.
-
Sự cố 02
Bỏ kiểm tra ở frontend vì “đằng nào backend cũng kiểm tra”.
Triệu chứngNgười dùng phải bấm gửi, chờ, rồi mới thấy lỗi. Trải nghiệm tệ.
Cách tránhKiểm tra ở cả hai nơi; frontend để lịch sự, backend để an toàn. Có thể dùng chung một schema Zod cho cả hai.
-
Sự cố 03
Để khóa bí mật trong code frontend.
Triệu chứngMọi thứ trong frontend đều công khai, kể cả khi nằm trong file “ẩn” hay đã được nén.
Cách tránhKhóa bí mật chỉ nằm ở backend, đọc từ biến môi trường không có tiền tố
NEXT_PUBLIC_. -
Sự cố 04
Dùng BaaS mà không bật luật truy cập.
Triệu chứngSupabase không bật RLS, Firebase để luật “cho phép tất cả” trong lúc thử nghiệm rồi quên.
Cách tránhBật RLS cho mọi bảng ngay khi tạo; đưa vào checklist trước khi ra mắt; yêu cầu agent báo cáo trạng thái RLS định kỳ.
-
Sự cố 05
Không biết đoạn code nào chạy ở đâu.
Triệu chứngTrong Next.js, file cạnh nhau có thể chạy ở hai nơi khác nhau.
Cách tránhMỗi khi review, hỏi agent “file này chạy trên server hay trình duyệt?” cho đến khi bạn tự nhận ra được qua dấu hiệu
"use client","use server".
Checklist
Bài tập thực hành
-
Bài 1
Cơ bản
Phân loại tầng
Với mỗi việc sau trong Mộc OMS, ghi rõ nên làm ở frontend, backend, database, hay nhiều tầng: (a) đổi màu nút khi rê chuột; (b) tính tổng tiền đơn; (c) không cho hai khách cùng số điện thoại; (d) báo “chưa nhập số điện thoại”; (e) kiểm tra nhân viên có thuộc chi nhánh của đơn không; (f) gửi tin nhắn Zalo xác nhận đơn.
Kết quả mong đợi
(a) frontend; (b) backend quyết định, frontend chỉ hiển thị tạm; (c) database (và backend báo lỗi thân thiện); (d) frontend và backend; (e) backend và RLS ở database; (f) backend.
-
Bài 2
Cơ bản
Nhìn code frontend của một trang web
Mở một trang web bất kỳ, bấm F12, vào tab Sources (hoặc Debugger). Duyệt qua các file JavaScript. Mục tiêu không phải hiểu code, mà là tự thấy rằng code frontend công khai.
Kết quả mong đợi
Bạn thấy hàng loạt file JavaScript, có file đọc được, có file bị nén thành một dòng dài. Tất cả đều tải về được.
-
Bài 3
Nâng cao
Tìm lỗi “tin trình duyệt”
Nếu bạn có một dự án (kể cả dự án vibe cũ), dùng Prompt mẫu 1 để agent liệt kê các trường dữ liệu backend nhận từ frontend. Đánh dấu những trường đang bị tin tưởng mù quáng.
Kết quả mong đợi
Một danh sách cụ thể các trường cần sửa, ưu tiên những trường liên quan đến tiền, quyền và dữ liệu khách hàng.
Thuật ngữ trong bài
- Frontend
- Phần giao diện chạy trên thiết bị người dùng
- Backend
- Phần xử lý chạy trên server, người dùng không chạm tới
- Database
- Nơi lưu dữ liệu bền vững, có tổ chức
- HTML / CSS / JavaScript
- Khung nội dung / trang trí / hành vi của trang web
- React
- Thư viện xây giao diện thành các khối tái sử dụng
- Fullstack framework
- Framework cho phép viết cả frontend và backend trong một dự án (như Next.js)
- Server Component
- Component Next.js chạy trên server
- Client Component
- Component Next.js chạy trên trình duyệt, đánh dấu
"use client" - Server Action
- Hàm chạy trên server, frontend gọi tới, đánh dấu
"use server" - Validate
- Kiểm tra dữ liệu có hợp lệ không
- Zod
- Thư viện TypeScript để mô tả và kiểm tra hình dạng dữ liệu
- BaaS (Backend-as-a-Service)
- Dịch vụ cung cấp sẵn database, đăng nhập, lưu trữ
- RLS (Row Level Security)
- Luật truy cập theo từng dòng dữ liệu trong PostgreSQL/Supabase
- Phòng thủ nhiều lớp
- Kiểm tra ở nhiều tầng, không dựa vào một chỗ duy nhất
Đọc thêm
- Next.js Documentation: tìm “Server and Client Components”, “Server Actions”.
- Supabase Docs: tìm “Row Level Security”.
- MDN Web Docs: tài liệu về HTML, CSS, JavaScript.
- Bảo mật xác thực và phân quyền dữ liệu: session, RLS, nguyên tắc đặc quyền tối thiểu09-04
- Chọn tech stack: công nghệ ‘nhàm chán’ và thân thiện với AI04-06
Nghiệm thu tờ 01-03
Đọc xong và tự kiểm theo phiếu nghiệm thu, rồi đánh dấu tờ này.

