CodeGym /Các khóa học /ChatGPT Apps /Môi trường: local dev, staging, production + Dev Mode

Môi trường: local dev, staging, production + Dev Mode

ChatGPT Apps
Mức độ , Bài học
Có sẵn

1. Tại sao cần nghĩ về môi trường ngay từ đầu

Trong phát triển web thông thường, sớm hay muộn cũng xuất hiện bộ ba: phát triển cục bộ, máy chủ kiểm thử và môi trường production. Ở thế giới ChatGPT Apps cũng tương tự, nhưng có thêm một điểm khác: client (ChatGPT) luôn ở trên đám mây, ngay cả khi bạn đang phát triển “trên máy local”.

Nếu mọi thứ chỉ chạy trên laptop của bạn dưới một địa chỉ đường hầm ngẫu nhiên, sẽ phát sinh vài hiệu ứng khó chịu. Thứ nhất, URL thay đổi liên tục và bạn không nhớ chính xác Dev Mode hiện đang trỏ vào endpoint nào. Thứ hai, hiệu năng và mạng không giống điều kiện thực chiến. Thứ ba, môi trường local thường dùng key khác, dịch vụ khác và nói chung “sống” trong một thực tại song song.

Mặt khác, “sống mãi ở prod” cũng tệ. Bất kỳ chỉnh sửa nào cũng có thể bất ngờ phá vỡ kịch bản của người dùng thật, đặc biệt nếu bạn đã có tích hợp kiểu Stripe, OAuth hoặc thanh toán qua ACP. Về mặt pháp lý và chính sách cũng rắc rối: thử nghiệm trên người dùng thật không phải con đường tốt để lên Store.

Vì vậy mục tiêu của bài giảng — hình thành trong đầu một sơ đồ đơn giản nhưng chặt chẽ: có local dev, có staging, có production, và có Dev Mode như một cách để điều hướng ChatGPT vào đúng môi trường. Chứ không phải một “laptop của tôi với tunnel, đôi khi bất ngờ biến thành prod”.

2. Đặc thù của ChatGPT Apps: client luôn ở trên đám mây

Trong ứng dụng kiểu SPA cổ điển, bạn thường chạy cả client lẫn server trên máy của mình: trình duyệt tại localhost, backend tại localhost, và mọi thứ nói chuyện hạnh phúc trong một máy.

Trong ChatGPT Apps điều đó không xảy ra. Client (ChatGPT + widget của bạn) luôn sống trong hạ tầng OpenAI. Ngay cả khi code ứng dụng của bạn chạy trên laptop, request đi như sau:

sequenceDiagram
    participant User as Người dùng
    participant ChatGPT as ChatGPT (đám mây)
    participant Tunnel as Đường hầm HTTPS
    participant App as Next.js + MCP của bạn

    User->>ChatGPT: Tin nhắn / click vào widget
    ChatGPT->>Tunnel: Yêu cầu HTTPS tới URL của App
    Tunnel->>App: Proxy về localhost
    App-->>Tunnel: Phản hồi (UI/JSON)
    Tunnel-->>ChatGPT: Phản hồi
    ChatGPT-->>User: Chat được cập nhật + widget

Ngay cả khi bạn “chỉ test local”, bạn đã sống trong một hệ thống phân tán: có client trên đám mây, có mạng, có đường hầm, có server local của bạn.

Điều này quan trọng vì:

  1. Môi trường local không phải “mọi thứ đều local”. Nó là “đám mây → đường hầm → server local”.
  2. Khi sau này bạn thêm staging và production, sơ đồ chỉ khác nhau ở chỗ ChatGPT gửi request tới đâu: vào đường hầm, domain staging hay domain production.

3. Local dev: sơ đồ hiện tại của bạn trông thế nào

Hãy xem sơ đồ tổng quát này trông ra sao với bạn lúc này.
Sau các module 2–6, rất có thể bạn có bức tranh như sau:

  • Next.js dev server, chạy bằng lệnh npm run dev (thường là http://localhost:3000).
  • MCP server local (thường là một tiến trình riêng, ví dụ http://localhost:2091).
  • Đường hầm HTTPS (ngrok, Cloudflare Tunnel, v.v.) công bố endpoint Next.js/HTTP của bạn ra ngoài với địa chỉ kiểu https://abc123.ngrok.app.

Qua Dev Mode trong ChatGPT, bạn chỉ định URL công khai này và ChatGPT bắt đầu gọi vào ứng dụng của bạn. Tất cả đó là môi trường local dev.

Thuộc tính chính của local dev:

  • Môi trường local cho vòng phản hồi rất nhanh. Bạn sửa code trong VS Code, Next.js hot reload, widget cập nhật sau vài giây.
  • Ở đây có thể phá mọi thứ, dùng mock data, test keys, config lạ.
  • Không có người dùng thật; ít ai ngoài bạn thậm chí biết URL này.

Thường sơ đồ như sau:

graph LR
    subgraph Dev Laptop
      Next[Next.js dev server]
      MCP[MCP server]
    end

    ChatGPT((ChatGPT Cloud))
    Tunnel[[Đường hầm HTTPS]]

    ChatGPT --> Tunnel --> Next
    Next --> MCP

Để không nhầm lẫn giữa local/staging/production, hữu ích khi chính ứng dụng “biết” nó đang chạy ở đâu. Về phía code, nên cố định rõ ràng bạn đang ở môi trường dev. Bước đơn giản nhất — thêm một module cấu hình môi trường nhỏ.

Ví dụ, tạo file app/config/env.ts:

// app/config/env.ts
export type AppEnv = 'local' | 'staging' | 'production';

export const APP_ENV: AppEnv =
  (process.env.NEXT_PUBLIC_APP_ENV as AppEnv) ?? 'local';

export const isProd = APP_ENV === 'production';

Tại đây chúng ta:

  1. Giới thiệu một kiểu liệt kê môi trường có typing.
  2. Đọc biến NEXT_PUBLIC_APP_ENV (sau này bạn sẽ đặt giá trị khác nhau cho dev/staging/prod).
  3. Mặc định coi là 'local' để phát triển local “chạy ngay”.

Trước mắt chưa deploy gì, nhưng đã có một điểm tựa: code của bạn hiểu nó đang chạy ở môi trường nào.

Tiếp theo, có thể hiển thị môi trường ngay trong widget để khỏi nhầm lẫn.

// app/components/EnvBadge.tsx
import { APP_ENV } from '../config/env';

export function EnvBadge() {
  return <span>ENV: {APP_ENV}</span>;
}

Một huy hiệu nhỏ như vậy giúp tránh nhầm “mình đang ở staging hay prod?”, nhất là khi widget nhìn y như nhau.

4. Staging: tổng duyệt cho môi trường production

Staging là “bản tổng duyệt của production”. Không còn là laptop với dev server, mà là máy chủ từ xa hoặc bản deploy trên Vercel nơi code đã được build.

Từ góc nhìn ChatGPT, staging gần như production: đó là một endpoint HTTPS ổn định với domain như https://staging.giftgenius.app, nơi:

  • code đã được build (npm run build chạy thành công);
  • dùng các biến môi trường giống prod (tên y hệt, cùng định dạng) nhưng với test keys;
  • có các dịch vụ bên ngoài tương tự (Stripe sandbox, tài khoản OAuth thử nghiệm);
  • topology mạng giống prod (ví dụ cùng loại DB và cùng region).

Tại sao cần staging trong bối cảnh ChatGPT Apps:

Thứ nhất, staging rất tiện để chạy kịch bản end‑to‑end. Ví dụ: người dùng trong ChatGPT → ChatGPT khởi chạy ứng dụng của bạn → widget hỏi người dùng → gọi MCP tool truy cập API bên ngoài → trả về gợi ý → widget hiển thị kết quả. Kịch bản như vậy trên local qua một tunnel ngẫu nhiên có thể hành xử theo một cách. Còn trên staging — đã khác: độ trễ, mạng và tài nguyên gần thực tế hơn.

Thứ hai, staging cho phép kiểm thử các tích hợp mà chạy trên local khiến bạn “run tay”. Ví dụ thanh toán: Stripe, ACP/Instant Checkout, v.v. Trên staging bạn cấu hình test keys, webhook thử nghiệm và chạy kịch bản “như người lớn” nhưng không có tiền thật.

Thứ ba, staging là nơi để cả đội cùng kiểm tra. Nếu bạn có nhiều developer, designer, QA, product — họ cần một URL chung không phụ thuộc laptop của ai đang mở và tunnel của ai vừa sập.

Nên hình dung staging như sau:

graph LR
    ChatGPT((ChatGPT Cloud))
    AppStaging["GiftGenius Staging  https://staging.giftgenius.app"]

    ChatGPT --> AppStaging

Bên trong https://staging.giftgenius.app có thể chạy Next.js, MCP server, DB staging và mọi thứ khác.

Trong bài này, chúng ta chưa đi sâu vào deploy lên Vercel — đó là nội dung các chủ đề sau. Giờ chỉ cần chấp nhận một thực tế: staging là môi trường riêng, giống production tối đa về cấu hình và cách ChatGPT truy cập đến nó.

5. Production: máy chủ thật và người dùng thật

Production là nơi có người dùng thật và tiền thật. Ở đây không còn chuyện “sửa nhanh trên main xem sao” — mọi thay đổi phải có chủ ý, đã được kiểm thử và tốt nhất là có khả năng rollback.

Domain production phải ổn định. Không phải URL ngrok ngẫu nhiên, mà là tên đàng hoàng như https://giftgenius.app hoặc tương tự. Chính địa chỉ này bạn cấu hình trong cài đặt App cho Store: khi người dùng tìm thấy ứng dụng của bạn trong ChatGPT Store và chạy nó, ChatGPT sẽ gọi vào endpoint này.

Với production thường có yêu cầu cao hơn:

  • Ổn định. Tỉ lệ lỗi thấp, thời gian phản hồi dự đoán được, hoạt động đúng dưới tải. Ở các module sau, ta sẽ nói về SLO/SLI, nhưng trực giác là “ứng dụng phải ‘gần như luôn luôn’ chạy và ‘gần như luôn luôn’ phản hồi nhanh”.
  • Bảo mật. Chỉ những secret cần thiết, quyền hạn tối thiểu, xử lý cẩn trọng PII và tiền bạc.
  • Giới hạn thử nghiệm. Không có chuyện “lại restart dev server” giữa ngày làm việc; thử nghiệm qua feature flag, A/B hoặc môi trường dev/staging riêng, chứ không chọc thẳng vào server prod.

Trong ngữ cảnh ChatGPT, production không còn là câu chuyện về Dev Mode, mà là App đã xuất bản: nó đến tay người dùng qua Store hoặc cài đặt tổ chức, qua review và đủ tin cậy để không “quê” trước đội kiểm duyệt.

6. Dev Mode vs sử dụng App ở prod: gắn với cái gì

Giờ đến sự nhầm lẫn phổ biến nhất: Dev Mode trong ChatGPT không phải “một môi trường riêng”. Nó giống như công tắc định tuyến: ChatGPT đang nhìn vào URL nào khi bạn test ứng dụng.

Trong Dev Mode bạn có thể:

  • kết nối ứng dụng local qua tunnel;
  • kết nối môi trường staging;
  • thậm chí tạm thời trỏ Dev Mode vào production (thường không nên làm).

Về mặt hình thức, Dev Mode nói với ChatGPT: “Đây là manifest của App của tôi, đây là URL endpoint MCP/Apps SDK của tôi. Hãy dùng nó khi tôi chạy ứng dụng này”. Và bạn có thể thay đổi URL đó.

Sau khi xuất bản lên Store, App có production endpoint chính thức. Endpoint này được dùng cho người dùng thật và bạn không thể tùy tiện đổi: cần phiên bản mới, review, v.v.

Trong thực tế, sơ đồ hợp lý cho ứng dụng học tập của bạn có thể như sau:

graph TD
    subgraph Dev Mode
      DevApp["GiftGenius Dev App
(Dev Mode)"] end subgraph Store ProdApp["GiftGenius
(Store App)"] end UserDev[Bạn / đội ngũ] --> DevApp UserProd[Người dùng thực] --> ProdApp DevApp -->|URL tunnel| LocalEnv[Local dev
https://abc123.ngrok.app] DevApp -->|staging URL| StagingEnv[Staging
https://staging.giftgenius.app] ProdApp -->|prod URL| ProdEnv[Production
https://giftgenius.app]

Bạn cấu hình ứng dụng Dev Mode GiftGenius Dev để nó thường trỏ vào local dev (qua tunnel), và khi cần — trỏ sang staging. Ứng dụng GiftGenius trên Store gắn chặt với production URL.

Đôi khi còn tạo một App riêng cho QA, ví dụ GiftGenius Staging, chỉ trỏ vào staging URL. Điều này hữu ích nếu bạn có đội kiểm thử lớn; trong khuôn khổ khóa học, một App dev là đủ.

Điều quan trọng là tập suy nghĩ như sau: Dev Mode là sandbox cá nhân cho bạn và đội, nơi có thể đổi URL, sửa metadata, restart tunnel. Còn App production trên Store chỉ nhìn vào production và tuân theo các quy tắc nghiêm ngặt hơn.

7. Liên kết nhánh Git, domain và ChatGPT App

Môi trường không chỉ là máy chủ. Nó còn là nhánh codecấu hình App trong ChatGPT. Sớm muộn bạn sẽ muốn chỉ nhìn URL hoặc tên App là hiểu phiên bản code nào đang chạy ở đó.

Cách tiếp cận tối thiểu, đơn giản như sau.

Để phát triển từng tính năng, bạn dùng nhánh feature/*, ví dụ feature/new-recommendation-algo. Code chạy local + tunnel. Dev Mode trong ChatGPT thường trỏ vào cùng một dev endpoint, nơi bạn lần lượt chạy các phiên bản local. Tạo một App riêng cho mỗi nhánh feature — là quá mức cần thiết.

Để tích hợp các tính năng trước khi phát hành, có thể tạo nhánh develop hoặc staging. Mọi thứ trong nhánh này tự động deploy lên staging, ví dụ Vercel preview URL dạng https://giftgenius-staging.vercel.app. Bạn có thể tạo một App Dev Mode riêng cho nó hoặc thỉnh thoảng đổi cấu hình Dev App chung sang URL này.

Nhánh main (hoặc master) — chỉ có code đã kiểm thử. Chính nhánh này deploy lên production URL và gắn với ứng dụng GiftGenius trên Store.

Sơ đồ có thể trông như sau:

Môi trường Nhánh Git URL ChatGPT App
Local dev
feature/*
https://abc123.ngrok.app
GiftGenius Dev (Dev Mode)
Staging
develop / staging
https://staging.gift...
GiftGenius Dev hoặc GiftGenius Staging
Prod
main
https://giftgenius.app
GiftGenius (Store)

Bạn còn nhớ APP_ENV trong app/config/env.ts chứ? Các giá trị 'local'/'staging'/'production' ở đây tương ứng trực tiếp với cột “Môi trường”: ở local dev bạn chạy ứng dụng với APP_ENV=local, staging deploy — với APP_ENV=staging, còn production — với APP_ENV=production.

Bảng như vậy không phải hình thức, mà là cách để không debug theo kiểu “đang chạy version nào trên domain này vậy?”.

Trong code, có thể siết chặt liên kết này thêm chút. Ví dụ, hiển thị không chỉ ENV mà cả commit/nhánh ở chế độ debug của widget:

// app/config/buildInfo.ts
export const BUILD_COMMIT = process.env.NEXT_PUBLIC_BUILD_COMMIT ?? 'dev';
export const BUILD_ENV = process.env.NEXT_PUBLIC_APP_ENV ?? 'local';
// app/components/BuildInfo.tsx
import { BUILD_COMMIT, BUILD_ENV } from '../config/buildInfo';

export function BuildInfo() {
  return <small>Build: {BUILD_ENV}@{BUILD_COMMIT}</small>;
}

Nếu khi deploy bạn gán SHA commit vào NEXT_PUBLIC_BUILD_COMMIT, widget sẽ hiển thị trung thực chính xác code nào đang chạy. Trên staging/prod, điều này đôi khi cứu hàng giờ gỡ lỗi.

8. Mini‑thực hành: vẽ sơ đồ môi trường của riêng bạn

Trước khi đi vào Vercel và log, rất hữu ích là “vẽ trên khăn giấy” sơ đồ môi trường của mình. Có thể là biểu đồ mermaid trong README.md, phác thảo trên bảng hoặc thậm chí bức hình trong sổ tay.

Với GiftGenius của chúng ta, sơ đồ có thể như sau:

graph TD
    subgraph ChatGPT
      DevMode["Dev Mode
(bạn và đội ngũ)"] Store["Store
(người dùng thực)"] end subgraph Servers Local[Local dev
Đường hầm → localhost] Staging[Staging
staging.giftgenius.app] Prod[Production
giftgenius.app] end DevMode --> Local DevMode --> Staging Store --> Prod

Bài tập hữu ích ngay sau bài giảng:

  1. Liệt kê tất cả môi trường bạn đã có: local với tunnel, có thể là một deploy Vercel sớm, hay gì khác.
  2. Bên cạnh ghi rõ nhánh Git nào deploy vào đó.
  3. Và cạnh nữa — những ChatGPT Apps (hoặc connector) nào đang trỏ vào đâu.
  4. Đánh dấu mũi tên xem ChatGPT đi từ đâu tới mỗi server.

Nếu bạn không làm một mình, hãy tạo file architecture/environments.md trong repo. Điều này giảm ngay khả năng “staging sập mà chẳng ai biết URL là gì”.

Để gắn điều này với ứng dụng, ngay bây giờ trong Dev Mode hãy tạo một App GiftGenius Dev và quyết định: mặc định nó trỏ vào tunnel của môi trường local, còn khi muốn test một bản phát hành, tạm thời đổi sang staging URL. Ở các bài sau bạn sẽ học deploy staging/prod lên Vercel và liên kết với biến môi trường.

Tóm lại: hãy coi các môi trường và Dev Mode như hệ trục tọa độ cho App của bạn. Local — cho phát triển nhanh, staging — cho tổng duyệt, production — cho người dùng thật, còn Dev Mode — công tắc của bạn giữa chúng, chứ không phải một môi trường “ma thuật” riêng.

9. Lỗi thường gặp khi làm việc với môi trường và Dev Mode

Lỗi №1: chỉ sống trên localhost + tunnel và coi đó là prod.
Cách làm này có vẻ tiện: “cần gì staging và prod, tunnel của tôi vẫn chạy, ChatGPT vẫn kết nối”. Nhưng tunnel có URL không ổn định, đặc tính mạng khác, và cả sơ đồ phụ thuộc vào một laptop. Khi bạn cần thứ như OAuth callback, Stripe webhooks hay MCP Gateway, việc thiếu staging/prod tử tế sẽ dẫn đến đau đớn.

Lỗi №2: nhầm lẫn Dev Mode với một môi trường riêng.
Nhiều người nghĩ: “Tôi có Dev Mode, nghĩa là tôi có môi trường dev”. Thực tế, Dev Mode chỉ bảo ChatGPT nên gọi vào đâu: tunnel, staging hay thậm chí prod. Dev Mode là cấu hình phía client, không phải server. Các môi trường server (local/staging/prod) do bạn tự tạo: deploy code, cấu hình domain, biến môi trường.

Lỗi №3: trỏ Dev Mode vào production để “test một chút”.
Về mặt kỹ thuật có thể: bạn điền production URL vào Dev Mode và nghịch App như thể local. Vấn đề là bạn bắt đầu test trên người dùng thật, dữ liệu thật và có thể là tiền thật. Bất kỳ lỗi nào của tool hay widget cũng có thể gây gián đoạn cho người dùng prod, và bạn còn không nhanh chóng hiểu nguyên nhân. Tốt hơn là giữ Dev Mode ở dev/staging và dùng App trên Store cho production.

Lỗi №4: không có bản đồ rõ ràng “nhánh ↔ môi trường ↔ URL ↔ App”.
Nếu không ai trong đội có thể trả lời ngay nhánh nào deploy lên staging, URL của nó là gì và ChatGPT App nào đang trỏ vào đó, thì đó là nguồn hỗn loạn đảm bảo. Bắt đầu các câu chuyện “máy tôi chạy, staging thì không, prod thì lại khác”. Một bảng hoặc file markdown đơn giản với bản đồ này hoàn toàn đáng giá.

Lỗi №5: xem nhẹ khác biệt giữa local dev và staging.
Trên local bạn chạy dev server, có một bộ key, một bộ dịch vụ và một mạng. Trên staging, code đã build, chạy trong môi trường khác, với giới hạn, timeout và route khác. Nếu bạn chỉ test trên local và giữ staging “cho có”, bug nghiêm trọng sẽ lộ ra ở prod. Hãy quen chuỗi: phát triển local, kiểm tra trên staging, rồi mới phát hành lên production.

Lỗi №6: cố giải mọi vấn đề qua ChatGPT, bỏ qua sơ đồ môi trường.
Đôi khi gặp sự cố, developer bắt đầu “hỏi ChatGPT có chuyện gì” thay vì nhìn vào bức tranh: App nào trỏ vào URL nào, môi trường nào sập, log ở đâu. Sơ đồ môi trường hôm nay là nền tảng cho bài sau, nơi ta sẽ debug có hệ thống: xem log, dùng MCP inspector rồi mới đổ lỗi cho mô hình.

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION