1. Giải phẫu quy trình deploy: có thể hỏng ở đâu
Hữu ích nhất là nhìn cả chuỗi từ đầu đến cuối. Việc triển khai ChatGPT App trong kiến trúc của bạn có thể hình dung thành chuỗi như sau:
flowchart TD A[Máy tính của bạn
git commit] --> B[Kho Git
GitHub/GitLab] B --> C[Vercel Build
npm run build] C --> D[Vercel Deploy
Preview/Prod] D --> E[HTTP endpoint
/mcp, /api/...] E --> F[ChatGPT / Dev Mode
gọi công cụ, widget]
Lỗi có thể xuất hiện ở bất kỳ bước nào trong số này, nhưng triệu chứng trong ChatGPT thường trông giống nhau: "Error talking to app", "Network error" hoặc chỉ im lặng. Nhiệm vụ của bạn — không bắn đoán mò, mà trước hết phải hiểu: nó hỏng ở bước build, lúc runtime, hay ChatGPT đang trỏ nhầm.
Tiện nhất là chia vấn đề thành ba nhóm lớn:
- Lỗi build: Vercel hoàn toàn không build được dự án. Production không cập nhật — điều này “tốt” theo nghĩa không phát hành lỗi, nhưng bạn thấy build đỏ.
- Lỗi runtime: build đã qua, nhưng khi truy vấn thì nhận 500/502, timeout hoặc hành vi kỳ lạ.
- Config drift (trôi cấu hình): local thì ổn, trên Vercel log vẫn ổn, nhưng ChatGPT truy cập URL cũ, làm việc với manifest cũ hoặc với các biến env trống.
Chúng ta sẽ đi qua ba lớp này và song song xây dựng chiến lược gỡ lỗi tổng quát.
2. Lỗi build: khi dự án không được build
Đây là loại vấn đề đầu tiên trong phần mở đầu — lỗi build: dự án hoàn toàn không được build vì Vercel không thể build dự án Next.js của bạn.
Node và Next.js: môi trường khác, yêu cầu khác
Trên máy local bạn có thể (đáng tiếc) vẫn dùng Node lỗi thời, còn Vercel sẽ cố build dự án Next.js 16 của bạn bằng phiên bản Node được hỗ trợ (tối thiểu 18.18.0). Nếu trong package.json bạn chỉ rõ một phiên bản không tương thích, build có thể rơi ở production dù dev‑server vẫn chạy trên máy bạn.
Cách đơn giản để tự bảo vệ — khai báo rõ "engines" trong package.json:
{
"engines": {
"node": ">=18.18.0"
}
}
Như vậy cả local lẫn CI/Vercel sẽ báo trước rằng Node của bạn quá cũ.
“Máy tôi chạy mà!” và các dependency bị bỏ quên
Kinh điển: bạn cài một thư viện qua npm install some-lib, nhưng không commit package-lock.json đã cập nhật hoặc thậm chí một phần dependency của bạn được cài global. Trên Vercel, ứng dụng được build “từ số 0”, nó thực hiện npm install dựa trên manifest, và some-lib yêu thích của bạn không có ở đó — nhận lỗi build.
Ở đây kỷ luật nghiêm giúp rất nhiều:
- mọi dependency mới đều được thêm và commit ngay;
- trước khi push vào main/production, hãy chạy npm run build trên local. Nếu build local rơi, trên Vercel sẽ chỉ tệ hơn.
Hệ thống tệp phân biệt hoa/thường (case‑sensitive)
Nhiều người dùng macOS hoặc Windows, nơi hệ thống tệp mặc định không phân biệt chữ hoa/thường trong tên file. Trên Vercel, build diễn ra trong môi trường Linux, ở đó Widget.tsx và widget.tsx là hai file khác nhau.
Lỗi điển hình:
// Import trong mã
import { AppWidget } from "@/components/Widget";
// Nhưng trong repo lại có file components/widget.tsx
Trên máy bạn mọi thứ chạy ổn, còn trên Vercel — lỗi module “Cannot find module '@/components/Widget'”. Cách khắc phục là sắp xếp lại đặt tên tệp và chú ý đến chữ hoa/thường.
Biến môi trường (env) ở bước build
Một nguồn bất ngờ khác — sử dụng process.env.* trong mã được thực thi ở bước build (ví dụ trong next.config.mjs hoặc trong các module được import lúc build). Nếu bạn gắn .env.local trên local, còn trên Vercel lại quên tạo các biến này cho môi trường build, thì build hoặc sẽ rơi, hoặc — khó chịu hơn — chạy qua với undefined và “nướng” các giá trị không hợp lệ vào bundle.
Với ChatGPT App điều này đặc biệt quan trọng nếu, ví dụ, bạn tạo baseURL cho MCP endpoint hoặc URL API bên ngoài ngay ở bước build.
Thực hành tốt — xác thực rõ ràng các biến env quan trọng ngay trước khi ứng dụng khởi chạy (chúng ta sẽ bàn ở phần riêng), để build rơi một cách ồn ào và có thể dự đoán.
3. Lỗi runtime: khi build xong nhưng vẫn không chạy
Giờ chuyển sang lớp thứ hai trong phần mở đầu — lỗi runtime: build xong nhưng khi thực thi thì hỏng.
Build đã qua, Vercel vui vẻ hiển thị deploy xanh, bạn chuyển ChatGPT App sang URL prod — và trong chat nhận "Error talking to app". Có nghĩa là vấn đề đã chuyển sang mức runtime.
Env rỗng hoặc thiếu
Phần lớn sự cố production trong thế giới ChatGPT App bắt đầu với từ undefined. Trên local bạn có một .env.local gọn gàng với OPENAI_API_KEY, MCP_BASE_URL và các biến khác, còn trên Vercel bạn quên tạo các biến này hoặc đặt nhầm tên.
Ví dụ, bạn đọc:
const apiKey = process.env.OPENAI_API_KEY;
nhưng trên Vercel lại tạo OPENAI_APIKEY hoặc OPENAI_API_KEY_PROD. Kết quả là ngay lần đầu gọi công cụ MCP, route‑handler của bạn rơi lỗi xác thực.
Dễ chịu hơn nhiều khi ứng dụng rơi ngay và rõ ràng. Mẫu hay — một module riêng trong dự án Next.js của bạn, mà xác thực biến env ngay khi import:
// app/lib/env.ts
const required = ["OPENAI_API_KEY", "MCP_BASE_URL"] as const;
type RequiredKey = (typeof required)[number];
function getEnv(key: RequiredKey): string {
const value = process.env[key];
if (!value) {
throw new Error(`Missing required env var: ${key}`);
}
return value;
}
export const env = {
OPENAI_API_KEY: getEnv("OPENAI_API_KEY"),
MCP_BASE_URL: getEnv("MCP_BASE_URL"),
};
Giờ nếu bạn quên cấu hình biến trên Vercel, Next.js sẽ rơi ngay lần đầu import env, và trong log sẽ có thông báo dễ hiểu "Missing required env var: ...".
Lưu ý rằng trên Vercel thay đổi các biến env sẽ không được áp dụng tự động. Sau khi chỉnh giá trị, bạn cần thực hiện một deploy mới (redeploy), nếu không runtime sẽ tiếp tục chạy với các giá trị cũ.
Lỗi trong route‑handler và MCP endpoint
Trong template chính thức của ChatGPT App, MCP server thường được triển khai ở app/mcp/route.ts. Bên trong là mã parse yêu cầu JSON‑RPC, route đến công cụ và trả về phản hồi. Nếu ở đâu đó trong chuỗi có throw mà không được xử lý — người dùng trong ChatGPT sẽ nhận 500.
Nên luôn bọc tầng trên cùng của MCP handler trong try/catch, ghi log lỗi và trả về phản hồi có cấu trúc:
// app/mcp/route.ts
import { NextRequest, NextResponse } from "next/server";
export const dynamic = "force-dynamic";
export const maxDuration = 30; // giây
export async function POST(req: NextRequest) {
try {
const body = await req.json();
// xử lý yêu cầu MCP tại đây
const result = await handleMcpRequest(body);
return NextResponse.json(result);
} catch (error) {
console.error("MCP route error", error);
return NextResponse.json(
{ error: "Internal MCP error" },
{ status: 500 }
);
}
}
Vài điểm:
- dynamic = "force-dynamic" giúp tránh việc sinh tĩnh và cache ngoài ý muốn cho các route MCP trong Next.js 16.
- maxDuration = 30 nói rõ với Vercel rằng route‑handler có thể chạy đến 30 giây, điều quan trọng với các yêu cầu LLM dài.
Timeout và “Network error” trong ChatGPT
Vercel giới hạn thời gian thực thi các serverless function: gói miễn phí thường khoảng 10 giây, gói trả phí có thể lớn hơn (đến vài phút). Nếu công cụ MCP của bạn thực hiện một yêu cầu dài tới cơ sở dữ liệu hoặc API bên ngoài, nó có thể không kịp trả lời, và ChatGPT sẽ nhận "Network error" hoặc luồng bị cắt.
Nếu bạn dùng streaming (SSE) cho kết quả từng phần, đặc biệt quan trọng là gửi những byte đầu tiên của phản hồi trước khi hết timeout. Khi đó bản thân việc truyền có thể diễn ra lâu hơn, nhưng nền tảng sẽ không coi function là “treo”.
Mẹo nhỏ: đo thời gian gọi các công cụ và ghi log cùng với tên công cụ. Khi đó trong log sẽ thấy, ví dụ, search_flights ổn định mất 12 giây và hơi vượt giới hạn.
export async function safeToolCall<TInput, TOutput>(
name: string,
handler: (input: TInput) => Promise<TOutput>,
input: TInput
): Promise<TOutput> {
const started = Date.now();
try {
const result = await handler(input);
console.log("[tool] ok", name, { ms: Date.now() - started });
return result;
} catch (error) {
console.error("[tool] fail", name, {
ms: Date.now() - started,
error,
});
throw error;
}
}
Sau đó thay vì handler(args) bạn gọi safeToolCall("search_flights", handler, args).
Mạng và dịch vụ bên ngoài
Đôi khi vấn đề chỉ là https:// thay vì http:// hoặc baseURL đã cũ. Đặc biệt nếu bạn ban đầu thử nghiệm trên máy local với một URL, còn ở production bạn đã có domain hoặc port khác.
Nên tách các URL cơ bản vào cấu hình (phụ thuộc môi trường) thay vì khâu trực tiếp chúng vào mã công cụ. Khi đó khi chuyển môi trường, bạn chỉ đổi một biến env, thay vì phải nhớ trong năm chỗ trong code bạn đã viết http://localhost:3001.
4. Cấu hình và trôi môi trường
Và cuối cùng, kiểu thứ ba trong sơ đồ — drift cấu hình giữa các môi trường.
Ngay cả khi build qua và runtime theo log thì khoẻ, ChatGPT vẫn có thể hành xử “như thể đang chạy phiên bản khác của ứng dụng”. Đây chính là trường hợp vấn đề không nằm ở code, mà ở cấu hình và sự nhất quán giữa các môi trường.
Dev Mode so với production
Trong Dev Mode, ChatGPT nhìn vào Connector URL mà bạn chỉ định thủ công: thường là URL qua tunnel (https://myapp-dev.ngrok-free.app/mcp hoặc tương tự) hoặc staging URL trên Vercel. Ở production (qua Store hoặc cài đặt tổ chức), App phải trỏ tới endpoint production ổn định, ví dụ https://myapp.vercel.app/mcp.
Sai lầm mà gần như ai cũng mắc: bạn đã deploy lên Vercel, nhưng trong cài đặt ChatGPT App vẫn là URL tunnel cũ. Server local đã tắt, tunnel đã chết, còn ChatGPT vẫn gõ vào đó và nhận 502. Trong giao diện, điều này trông như "Error talking to app", và học viên bắt đầu sửa mã MCP vốn dĩ không hề được thực thi.
Cách chữa là kỷ luật: sau bất kỳ thay đổi môi trường nào (tunnel → staging, staging → prod) bạn kiểm tra chính xác URL nào được ghi trong Dev Mode và trong cấu hình production của App.
Manifest cũ và cache của ChatGPT
ChatGPT sẽ cache thông tin về App của bạn: danh sách công cụ, mô tả, metadata. Vì vậy tình huống “tôi đã đổi schema của công cụ, nhưng model vẫn nghĩ tham số tên như cũ” — là có thật.
Khi thay đổi lớn về công cụ, hữu ích là:
- đảm bảo rằng bạn thực sự đã deploy phiên bản mới (xem commit hash trong log, in nó ra trong startup‑log);
- tạo lại hoặc kết nối lại App trong Dev Mode để buộc nền tảng đọc lại manifest;
- tạm thời gỡ lỗi qua MCP Inspector, nơi bạn chắc chắn thấy danh sách công cụ và schema hiện thời.
Cấu hình env: dev/staging/prod
Chúng ta đã nói về việc các biến env có thể làm rơi build và runtime như thế nào. Ở đây — góc nhìn tổng thể về dev/staging/prod và sự nhất quán của giá trị giữa chúng.
Nỗi đau phổ biến: .env.local của bạn hoàn hảo, còn ở các môi trường trên Vercel thì hỗn loạn. Kết quả:
- trên local bạn có một API key và một URL dịch vụ ngoài;
- trên staging — giá trị hoàn toàn khác;
- trên prod — một nửa biến chưa hề được đặt.
Một tệp văn bản đơn giản docs/env.md trong repo giúp rất nhiều, nơi bạn liệt kê: cần những biến nào, ở môi trường nào là bắt buộc, ví dụ giá trị ra sao. Có thể trông như quan liêu, nhưng lúc sự cố thì danh sách như vậy tiết kiệm hàng giờ.
5. Lỗi trông như thế nào ở phía ChatGPT
Giờ hãy nhìn tình huống dưới góc người dùng ChatGPT. Họ chỉ thấy giao diện và không biết gì về Vercel, Node và MCP. Còn bạn, đáng tiếc, cũng chưa biết chính xác điều gì vừa hỏng.
Triệu chứng điển hình trong ChatGPT:
- thông báo "Error talking to [App Name]" ngay sau khi cố gắng sử dụng;
- spinner quay mãi không dừng mà không có lỗi hiển thị;
- dòng chữ đỏ "I encountered an error while running the tool";
- widget không xuất hiện hoặc xuất hiện nhưng trống.
Mỗi triệu chứng thường tương ứng với một mức độ hỏng cụ thể:
- nếu App hoàn toàn không truy cập được (URL sai, tunnel rơi, lỗi SSL), ChatGPT không thể gõ tới MCP endpoint — hãy kiểm tra khả dụng của domain trong trình duyệt và log Vercel với mã 4xx/5xx;
- nếu MCP trả về JSON‑RPC hợp lệ với trường error, ChatGPT sẽ thông báo rằng công cụ trả lỗi — đây là vấn đề của business logic hoặc validation tham số;
- nếu MCP trả về thành công nhưng HTML widget bị hỏng hoặc lỗi JS, thì trong console của widget (DevTools → iframe của widget) sẽ thấy chính xác cái gì rơi.
Vì vậy thói quen tốt: ngay khi thấy hành vi kỳ lạ trong chat, hãy ghi lại timestamp (tới phút) và vào log Vercel tìm các request tại thời điểm đó.
6. Chiến lược gỡ lỗi: không hoảng loạn, hãy hành động
Giờ chúng ta ghép tất cả lại thành một “playbook” nhỏ — kịch bản hành động khi có vấn đề. Mục tiêu — thay sự chạy vòng quanh bằng một thuật toán bình tĩnh.
Bước 1: xác định loại vấn đề
Nếu build trên Vercel màu đỏ — hãy mừng: lỗi bị bắt trước khi lên production. Mở build log, xem lỗi thực sự đầu tiên (chứ không phải 200 dòng warning) và tái hiện trên local bằng lệnh npm run build.
Nếu build xanh, còn ChatGPT kêu — đó là runtime hoặc cấu hình. Hãy kiểm tra:
- URL production của App của bạn có truy cập được từ trình duyệt không (https://myapp.vercel.app/mcp có trả về được gì không);
- MCP endpoint trả về 200/500 hay thậm chí không resolve được;
- URL trong cài đặt App có trùng với URL bạn vừa kiểm tra hay không.
Bước 2: đọc log, đừng đoán mò
Điểm dừng tiếp theo — log của Vercel: server log cho đúng deploy và đúng môi trường (Preview/Production).
Tìm:
- các lỗi Error: Missing required env var ... — nghĩa là vấn đề ở cấu hình;
- stack trace từ MCP handler — nghĩa là business logic rơi hoặc lỗi parse dữ liệu đầu vào;
- các thông báo về timeout hoặc vượt quá thời lượng function.
Song song, đừng quên MCP Inspector. Nếu kết nối tới cùng MCP endpoint qua inspector và tự tay gọi công cụ, bạn sẽ nhanh chóng hiểu vấn đề nằm ở chính MCP hay ở liên kết ChatGPT ↔ MCP.
Bước 3: rollback nhanh hay hotfix?
Nếu bạn thấy deploy production rõ ràng bị hỏng (ví dụ, MCP route liên tục ném cùng một lỗi cho mọi request), và deploy trước đó thì khoẻ, quyết định đúng là rollback. Vercel cho phép nhanh chóng chuyển về deploy thành công trước đó mà không cần build lại — thực chất là đổi phiên bản đang hoạt động.
Điều này tốt hơn là cố “chữa” production tại chỗ, đặc biệt khi bạn chưa hiểu hết nguyên nhân sự cố.
Khi tình hình đã ổn định, bạn bình tĩnh tìm nguyên nhân, viết test, sửa trong code và sau đó mới phát hành phiên bản tiếp theo.
Bước 4: củng cố bằng tài liệu
Bất kỳ sự cố nghiêm trọng nào cũng là dịp cập nhật README nội bộ:
- thêm biến env bắt buộc, thiếu là rơi ngay;
- ghi lại case cụ thể dẫn đến lỗi (ví dụ, “import với sai chữ hoa/thường trong tên tệp”);
- mô tả thuật toán hành động ngắn gọn đã giúp khắc phục nhanh.
Nghe có vẻ nhàm chán, nhưng vài tháng nữa chính bạn sẽ cảm ơn mình.
7. Một vài thủ thuật thực hành nhỏ trong code
Giờ lấy vài bước trong playbook và củng cố bằng các thủ thuật code nhỏ trong ứng dụng học tập của chúng ta (ChatGPT App).
Module cấu hình thống nhất
Chúng ta đã viết một trình xác thực biến env đơn giản. Có thể bổ sung để phân biệt môi trường:
// app/lib/config.ts
type NodeEnv = "development" | "test" | "production";
const nodeEnv = (process.env.NODE_ENV || "development") as NodeEnv;
const requiredBase = ["OPENAI_API_KEY"] as const;
const requiredProd = ["MCP_BASE_URL"] as const;
function ensure(keys: readonly string[]) {
for (const key of keys) {
if (!process.env[key]) {
throw new Error(`Missing env var ${key} for NODE_ENV=${nodeEnv}`);
}
}
}
ensure(requiredBase);
if (nodeEnv === "production") {
ensure(requiredProd);
}
export const config = {
nodeEnv,
openaiApiKey: process.env.OPENAI_API_KEY!,
mcpBaseUrl: process.env.MCP_BASE_URL ?? "http://localhost:3000/mcp",
};
Module như vậy sẽ báo ngay nếu production khởi chạy mà thiếu biến cần thiết.
Ghi log các yêu cầu MCP đến
Một lớp bọc đơn giản nhưng rất hữu ích cho MCP handler:
// app/lib/mcp-logger.ts
export function logMcpRequest(body: unknown) {
console.log("[mcp] request", {
time: new Date().toISOString(),
// không ghi log dữ liệu nhạy cảm
keys: typeof body === "object" && body !== null
? Object.keys(body as Record<string, unknown>)
: typeof body,
});
}
Và dùng trong app/mcp/route.ts:
import { logMcpRequest } from "@/app/lib/mcp-logger";
export async function POST(req: NextRequest) {
try {
const body = await req.json();
logMcpRequest(body);
const result = await handleMcpRequest(body);
return NextResponse.json(result);
} catch (error) {
console.error("MCP route error", error);
return NextResponse.json({ error: "Internal error" }, { status: 500 });
}
}
Trong log bạn sẽ thấy ChatGPT gửi gì: ít nhất là theo các key ("jsonrpc", "method", "params"), và sẽ dễ hiểu lời gọi nào đang rơi.
Kiểm tra đơn giản tính sẵn sàng của MCP endpoint
Đôi khi hữu ích có một route‑handler kiểu “healthcheck” cho MCP server, mà ChatGPT không gọi trực tiếp, nhưng bạn có thể nhanh chóng mở trong trình duyệt để biết server có sống không và có thấy các biến env của nó không:
// app/api/health/route.ts
import { NextResponse } from "next/server";
import { config } from "@/app/lib/config";
export async function GET() {
return NextResponse.json({
status: "ok",
env: config.nodeEnv,
hasOpenAiKey: !!config.openaiApiKey,
});
}
Nếu https://myapp.vercel.app/api/health trả về status: "ok", thì ít nhất pipeline cơ bản tới mã Node của bạn đang sống.
8. Những sai lầm thường gặp khi deploy và gỡ lỗi
Lỗi số 1: Deploy mà không build thử trên npm run build local.
Khi lập trình viên không bao giờ chạy build trên local, họ chỉ biết về phiên bản Node không tương thích, vấn đề đường dẫn hoặc lỗi TS trên Vercel. Điều này kéo dài chu kỳ “làm hỏng → sửa”, vì mỗi thử nghiệm là một deploy mới. Thói quen chạy npm run build trước khi push vào main tiết kiệm rất nhiều thời gian (xem thêm mục 2 và bước 6.1 về npm run build local).
Lỗi số 2: Secret chỉ tồn tại trong .env.local.
Dự án chạy hoàn hảo trên máy tác giả, nhưng ở production rơi vì process.env.OPENAI_API_KEY === undefined. Lý do rất đơn giản: quên thêm biến env trong bảng điều khiển Vercel (và đôi khi còn đặt tên khác). Đặc biệt hay quên phân tách Development/Preview/Production và ngạc nhiên vì staging và prod hành xử khác nhau (chi tiết — các mục 3.1, 4.3 và 7.1).
Lỗi số 3: Dùng NEXT_PUBLIC_* cho secret.
Trong Next.js mọi biến có tiền tố NEXT_PUBLIC_ sẽ lọt vào bundle phía trình duyệt. Nếu bạn vô ý đặt API key là NEXT_PUBLIC_OPENAI_API_KEY, nó sẽ đi tới trình duyệt người dùng và có thể bị lấy ra từ devtools. Không được làm vậy. Chỉ nên công khai các giá trị an toàn (ví dụ, ID của feature flag, chứ không phải token).
Lỗi số 4: Bỏ qua log của Vercel và cố “sửa qua ChatGPT”.
Đôi khi lập trình viên thấy trong chat "Error talking to app" và dành hàng giờ thay prompt, mô tả công cụ, sửa gì đó trong Dev Mode, nhưng không hề nhìn serverless log. Trong đó có lỗi rất rõ ràng: "Missing env var", "Cannot find module" hoặc stack trace của công cụ cụ thể. Kỹ sư giỏi trước tiên xem log, rồi mới tranh luận với model.
Lỗi số 5: Lẫn lộn Dev Mode và production app.
Sau lần deploy thành công đầu tiên trên Vercel rất dễ quên rằng Dev Mode vẫn có thể trỏ tới tunnel cũ hoặc preview URL. Kết quả là bạn tin rằng đang test phiên bản production, còn thực tế đang nói chuyện với một nhánh local đáng lẽ phải xoá lâu rồi. Hoặc ngược lại: nghĩ là đang test bản nháp, nhưng ChatGPT lại gõ vào endpoint chạy thật. Cần thường xuyên kiểm tra URL nào được chỉ định trong cài đặt App và Dev Mode (xem thêm mục 4.1 về Dev Mode và production).
Lỗi số 6: Kỳ vọng thay đổi biến env trên Vercel có hiệu lực “ngay lập tức”.
Một số học viên đổi giá trị biến trong bảng điều khiển Vercel và ngay lập tức chạy vào ChatGPT kiểm tra kết quả. Nhưng runtime vẫn dùng giá trị cũ vì chưa có redeploy. Bất kỳ thay đổi nào của biến env đều yêu cầu deploy mới, nếu không function sẽ không thấy cập nhật (chi tiết — mục 3.1).
Lỗi số 7: Không có chiến lược rollback đơn giản.
Khi sự cố xảy ra, cám dỗ rất lớn là “đẩy nhanh bản sửa” thẳng vào main. Nhưng điều đó thêm một deploy có khả năng hỏng nữa, còn người dùng thì vẫn chịu đựng. Bình tĩnh hơn nhiều nếu có thói quen: khi lỗi nghiêm trọng, rollback ngay về deploy thành công trước đó, sửa lỗi trong nhánh riêng và chỉ sau đó mới phát hành phiên bản mới. Vercel có giao diện thuận tiện cho việc này, rất đáng dùng.
GO TO FULL VERSION