8 phút

Mẫu cấu hình môi trường cho dev, staging, prod

Mô tả các mẫu cấu hình môi trường giúp giữ URL, khóa và feature flag ngoài mã nguồn cho web, backend và mobile trong dev, staging và prod.

Mẫu cấu hình môi trường cho dev, staging, prod

Tại sao cấu hình ghi cứng trong mã liên tục gây ra vấn đề

Cấu hình được ghi cứng trong mã có vẻ ổn ban đầu. Rồi bạn cần một môi trường staging, một API phụ, hoặc một công tắc tính năng nhanh, và thay đổi “đơn giản” đó biến thành rủi ro khi phát hành. Cách khắc phục rõ ràng: giữ các giá trị môi trường ra khỏi file nguồn và đặt chúng trong một cách tổ chức có thể dự đoán được.

Những thủ phạm thường gặp dễ nhận ra:

  • URL cơ sở API được nướng vào app (gọi prod khi đang test, hoặc gọi dev sau khi phát hành)
  • Khóa API bị commit vào repo (rò rỉ, hoá đơn bất ngờ, phải xoay khoá khẩn cấp)
  • Toggle tính năng viết dưới dạng hằng số (phải ship code để tắt tính năng)
  • ID analytics và báo lỗi bị mã hoá cứng (dữ liệu đổ vào nơi sai)

“Chỉ thay cho prod” tạo thói quen sửa phút chót. Những chỉnh sửa đó thường bỏ qua review, test và tính lặp lại. Một người đổi URL, người kia đổi khoá, và giờ bạn không thể trả lời câu hỏi cơ bản: chính xác cấu hình nào đã đi kèm bản build này?

Một kịch bản phổ biến: bạn build phiên bản mobile mới với staging, rồi ai đó đổi URL về prod ngay trước khi phát hành. Backend thay đổi ngày hôm sau và bạn phải rollback. Nếu URL được ghi cứng, rollback đồng nghĩa với cập nhật app lần nữa. Người dùng phải chờ, và vé hỗ trợ tăng dồn.

Mục tiêu ở đây là một sơ đồ đơn giản hoạt động cho web app, backend Go, và app Flutter:

  • quy tắc rõ ràng về cái gì nên nằm trong mã và cái gì là config
  • mặc định an toàn cho dev, staging và prod
  • công tắc tính năng có thể thay đổi mà không cần build lại
  • bí mật được xử lý ngoài codebase, dễ xoay khoá

Thực sự khác nhau gì giữa dev, staging và prod

Dev, staging và prod nên giống như cùng một ứng dụng chạy ở ba nơi khác nhau. Ý tưởng là thay đổi giá trị, chứ không phải hành vi.

Những gì nên thay đổi là bất kỳ thứ gì gắn với nơi app chạy hoặc ai đang dùng nó: base URL và hostname, thông tin xác thực, tích hợp sandbox vs thật, và các biện pháp an toàn như mức log hoặc cấu hình bảo mật nghiêm ngặt hơn ở prod.

Những gì nên giữ nguyên là logic và hợp đồng giữa các phần. Route API, hình dạng request/response, tên tính năng, và quy tắc nghiệp vụ cốt lõi không nên khác nhau theo môi trường. Nếu staging hành xử khác, nó sẽ không còn là nơi diễn tập đáng tin cậy cho production.

Một quy tắc thực tế cho “môi trường mới” so với “giá trị config mới”: chỉ tạo môi trường mới khi bạn cần một hệ thống cô lập (dữ liệu riêng, quyền truy cập riêng, và rủi ro riêng). Nếu bạn chỉ cần endpoint khác hoặc số liệu khác, hãy thêm một giá trị config.

Ví dụ: bạn muốn thử một nhà cung cấp tìm kiếm mới. Nếu an toàn để bật cho một nhóm nhỏ, giữ một môi trường staging và thêm feature flag. Nếu cần database riêng và kiểm soát truy cập chặt chẽ, đó là lúc nên tạo môi trường mới.

Một mô hình cấu hình thực tế có thể dùng lại ở mọi nơi

Một thiết lập tốt làm tốt một việc: khiến việc vô tình ship URL dev, khoá test, hoặc tính năng chưa hoàn thành trở nên khó xảy ra.

Dùng cùng ba tầng cho mọi app (web, backend, mobile):

  1. Defaults: giá trị an toàn hoạt động ở hầu hết nơi.
  2. Environment overrides: thứ thay đổi cho dev, staging, prod.
  3. Secrets: giá trị nhạy cảm không bao giờ nằm trong repo.

Để tránh nhầm lẫn, chọn một nguồn chân lý duy nhất cho mỗi app và tuân thủ. Ví dụ: backend đọc từ biến môi trường khi khởi động, web app đọc từ biến build-time hoặc một file runtime config nhỏ, và mobile đọc từ một file môi trường được chọn lúc build. Sự nhất quán bên trong mỗi app quan trọng hơn việc ép mọi nơi dùng cùng một cơ chế.

Một sơ đồ đơn giản, có thể tái sử dụng trông như sau:

  • Defaults nằm trong mã dưới dạng hằng không nhạy cảm (timeouts, kích thước trang, số lần thử lại).
  • Overrides nằm trong file riêng theo env hoặc biến môi trường (API base URL, analytics bật/tắt).
  • Secrets nằm trong kho bí mật và được inject trong quá trình deploy/build (JWT secret, mật khẩu database, khóa API bên thứ ba).

Đặt tên để mọi người hiểu

Đặt tên mỗi mục cấu hình rõ ràng trả lời ba câu hỏi: nó là gì, áp dụng ở đâu, và kiểu dữ liệu là gì.

Một quy ước thực tế:

  • Tiền tố theo app: WEB_, API_, MOBILE_
  • DÙNG CHỮ IN HOA và dấu gạch dưới
  • Gom theo mục đích: API_BASE_URL, AUTH_JWT_SECRET, FEATURES_NEW_CHECKOUT
  • Giữ boolean rõ ràng: FEATURES_SEARCH_ENABLED=true

Như vậy, không ai phải đoán “BASE_URL” là cho React app, dịch vụ Go hay app Flutter.

Bước từng bước: cấu hình web app (React) không ghi cứng

Code React chạy trong trình duyệt người dùng, nên bất cứ thứ gì bạn ship đều có thể đọc được. Mục tiêu đơn giản: giữ bí mật trên server, và cho trình duyệt chỉ đọc các thiết lập "an toàn" như API base URL, tên app, hoặc toggle tính năng không nhạy.

1) Quyết định cái gì là build-time vs runtime

Build-time config được inject khi bạn build bundle. Phù hợp với các giá trị ít thay đổi và an toàn để công khai.

Runtime config được tải khi app khởi động (ví dụ từ một file JSON nhỏ được serve cùng app, hoặc một global inject). Thích hợp cho các giá trị bạn có thể muốn thay đổi sau deploy, như chuyển API base URL giữa các môi trường.

Một quy tắc đơn giản: nếu thay đổi nó không nên yêu cầu build lại UI, hãy để nó là runtime.

2) Lưu base URL API mà không commit nó

Giữ file local cho developer (không commit) và đặt giá trị thực trong pipeline deploy.

  • Local dev: dùng .env.local (bị gitignore) với ví dụ VITE_API_BASE_URL=http://localhost:8080
  • CI/CD: đặt VITE_API_BASE_URL như biến môi trường trong job build, hoặc cho vào file runtime config được tạo trong lúc deploy

Ví dụ runtime (serve cùng app):

{ "apiBaseUrl": "https://api.staging.example.com", "features": { "newCheckout": false } }

Rồi load nó một lần lúc startup và giữ ở một nơi duy nhất:

export async function loadConfig() {
  const res = await fetch('/config.json', { cache: 'no-store' });
  return res.json();
}

3) Chỉ phơi bày giá trị an toàn cho trình duyệt

Xem mọi biến env trong React là public. Đừng đặt mật khẩu, khoá API riêng tư, hoặc URL database trong web app.

Ví dụ an toàn: API base URL, Sentry DSN (public), phiên bản build, và các feature flag đơn giản.

Bước từng bước: cấu hình backend (Go) bạn có thể validate

Cấu hình backend an toàn hơn khi có kiểu rõ ràng, được load từ biến môi trường, và được validate trước khi server bắt đầu nhận traffic.

Bắt đầu bằng việc quyết định backend cần gì để chạy, và làm rõ các giá trị đó. Những giá trị "bắt buộc" điển hình:

  • APP_ENV (dev, staging, prod)
  • HTTP_ADDR (ví dụ :8080)
  • DATABASE_URL (DSN Postgres)
  • PUBLIC_BASE_URL (dùng cho callback và link)
  • API_KEY (cho dịch vụ bên thứ ba)

Sau đó load vào một struct và fail fast nếu thiếu hoặc sai định dạng. Như vậy bạn phát hiện lỗi trong vài giây, không phải sau một deploy không hoàn chỉnh.

package config

import (
	"errors"
	"net/url"
	"os"
	"strings"
)

type Config struct {
	Env           string
	HTTPAddr      string
	DatabaseURL   string
	PublicBaseURL string
	APIKey        string
}

func Load() (Config, error) {
	c := Config{
		Env:           mustGet("APP_ENV"),
		HTTPAddr:      getDefault("HTTP_ADDR", ":8080"),
		DatabaseURL:   mustGet("DATABASE_URL"),
		PublicBaseURL: mustGet("PUBLIC_BASE_URL"),
		APIKey:        mustGet("API_KEY"),
	}
	return c, c.Validate()
}

func (c Config) Validate() error {
	if c.Env != "dev" && c.Env != "staging" && c.Env != "prod" {
		return errors.New("APP_ENV must be dev, staging, or prod")
	}
	if _, err := url.ParseRequestURI(c.PublicBaseURL); err != nil {
		return errors.New("PUBLIC_BASE_URL must be a valid URL")
	}
	if !strings.HasPrefix(c.DatabaseURL, "postgres://") {
		return errors.New("DATABASE_URL must start with postgres://")
	}
	return nil
}

func mustGet(k string) string {
	v, ok := os.LookupEnv(k)
	if !ok || strings.TrimSpace(v) == "" {
		panic("missing env var: " + k)
	}
	return v
}

func getDefault(k, def string) string {
	if v, ok := os.LookupEnv(k); ok && strings.TrimSpace(v) != "" {
		return v
	}
	return def
}

Cách này giữ DSN database, API keys và callback URL ra khỏi code và git. Trong môi trường hosted, bạn inject những env vars này theo mỗi môi trường để dev, staging và prod khác nhau mà không cần thay dòng mã nào.

Bước từng bước: cấu hình mobile (Flutter) giữ độ linh hoạt

Avoid emergency mobile rebuilds
Sinh app Flutter với flavors và remote config URL để endpoints linh hoạt.

App Flutter thường cần hai lớp cấu hình: flavor lúc build (định danh app) và setting runtime (cái app có thể thay đổi mà không cần phát hành lại). Tách hai thứ này ngăn tình trạng “chỉ sửa nhanh URL” biến thành build khẩn cấp.

1) Dùng flavors cho định danh, không phải endpoints

Tạo ba flavor: dev, staging, prod. Flavors nên điều khiển những thứ phải cố định lúc build, như tên app, bundle id, signing, dự án analytics, và có bật công cụ debug không.

Rồi chỉ truyền default không nhạy cảm bằng --dart-define (hoặc CI) để không hardcode chúng trong mã:

  • ENV=staging
  • DEFAULT_API_BASE=https://api-staging.example.com
  • CONFIG_URL=https://config.example.com/mobile.json

Trong Dart, đọc bằng String.fromEnvironment và xây một AppConfig đơn giản khi startup.

2) Đưa URL và công tắc vào config lấy về

Nếu muốn tránh rebuild cho thay đổi nhỏ, đừng coi API base URL là hằng số. Lấy một file config nhỏ khi app khởi chạy (và cache nó). Flavor chỉ định nơi lấy config.

Phân tách thực tế:

  • Flavor (build-time): định danh app, URL config mặc định, dự án báo lỗi
  • Remote config (runtime): API base URL, feature flags, tỉ lệ rollout, maintenance mode
  • Secrets: không bao giờ ship trong app (mobile binaries có thể bị inspect)

Nếu bạn di chuyển backend, cập nhật remote config để trỏ sang base URL mới. Người dùng hiện tại sẽ nhận thay đổi ở lần mở app tiếp theo, với fallback an toàn về giá trị cached cuối cùng.

Feature flags và cách để chúng không thành hỗn loạn

Feature flags hữu ích cho rollout dần, A/B test, kill switch nhanh, và thử thay đổi rủi ro trong staging trước khi bật ở prod. Chúng không thay thế kiểm soát bảo mật. Nếu một flag bảo vệ thứ gì đó cần bảo mật, thì đó không phải flag — đó là quy tắc xác thực.

Đối xử với mỗi flag như một API: tên rõ ràng, có người chịu trách nhiệm, và ngày kết thúc.

Đặt tên sao cho ý định rõ

Dùng tên cho biết điều gì xảy ra khi flag BẬT, và phần sản phẩm nào bị ảnh hưởng. Một vài ví dụ:

  • feature.checkout_new_ui_enabled (tính năng cho khách)
  • ops.payments_kill_switch (công tắc tắt khẩn cấp)
  • exp.search_rerank_v2 (thử nghiệm)
  • release.api_v3_rollout_pct (rollout dần)
  • debug.show_network_logs (chẩn đoán)

Ưu tiên boolean mang nghĩa tích cực (..._enabled) thay vì phủ định. Giữ prefix ổn định để dễ tìm kiếm và audit.

Default, guardrail và dọn dẹp

Bắt đầu với mặc định an toàn: nếu dịch vụ flag sập, app nên hành xử như phiên bản ổn định.

Một mẫu thực tế: deploy endpoint mới ở backend, giữ endpoint cũ chạy, và dùng release.api_v3_rollout_pct để chuyển traffic dần. Nếu lỗi tăng, bật lại mà không cần hotfix.

Để tránh flag chất đống:

  • Mỗi flag có owner và ngày “remove by”
  • Xóa flag trong 1-2 release sau khi rollout xong
  • Log giá trị flag trong các luồng chính để debug
  • Review flag hàng tháng như bạn review dependency

Bí mật: nơi lưu, truy cập và nguyên tắc xoay khoá

Ship with safer defaults
Deploy bằng biến môi trường và giữ giá trị production ngoài môi trường dev local.

"Bí mật" là bất cứ thứ gì gây hại khi bị lộ. Nghĩ tới token API, mật khẩu DB, OAuth client secret, signing key (JWT), webhook secret, và chứng chỉ riêng. Không phải bí mật: API base URL, số build, feature flag hay ID analytics công khai.

Tách bí mật khỏi các cài đặt khác. Developer nên dễ dàng thay đổi config an toàn, trong khi bí mật chỉ được inject lúc runtime và chỉ ở nơi cần.

Bí mật nên nằm ở đâu (theo môi trường)

Trong dev, giữ bí mật local và dễ bỏ. Dùng .env hoặc keychain OS và dễ reset. Không bao giờ commit.

Trong staging và prod, bí mật nên nằm trong kho bí mật chuyên dụng, không trong repo, không trong chat logs, và không nướng vào mobile app.

  • Web (React): đừng đặt bí mật trong trình duyệt. Nếu client cần token, dùng token ngắn hạn do backend cấp.
  • Backend (Go): load bí mật từ env vars hoặc secrets manager lúc startup, giữ trong memory thôi.
  • Mobile (Flutter): coi app là public. Bất kỳ "bí mật" nào trong app có thể bị tách ra, nên dùng token do backend cấp và secure storage trên thiết bị chỉ cho session người dùng.

Nguyên tắc xoay khoá (không làm trật production)

Xoay khoá thất bại khi bạn đổi khoá và quên client cũ vẫn dùng nó. Lên kế hoạch có cửa sổ overlap.

  • Hỗ trợ hai bí mật hợp lệ cùng lúc (active + previous) trong một khoảng ngắn.
  • Roll out bí mật mới trước, rồi đổi con trỏ "active".
  • Giám sát lỗi auth, sau đó remove bí mật cũ sau khi cửa sổ kết thúc.
  • Log phiên bản bí mật (không phải giá trị) để debug an toàn.

Cách overlap này phù hợp cho API keys, webhook secrets và signing keys. Nó tránh outage bất ngờ.

Ví dụ rollout: đổi URL API mà không làm hỏng người dùng

Bạn có API staging và API prod mới. Mục tiêu là chuyển traffic theo giai đoạn, với cách quay lại nhanh nếu có vấn đề. Việc này dễ hơn khi app đọc API base URL từ config, không từ mã.

Xem URL API là giá trị deploy-time ở mọi nơi. Trong web (React) thường là build-time value hoặc runtime config file. Trong mobile (Flutter) thường là flavor cộng remote config. Trong backend (Go) là env var runtime. Quan trọng là nhất quán: code dùng một tên biến (ví dụ API_BASE_URL) và không nhúng URL vào component, service hay screen.

Một rollout an toàn theo giai đoạn có thể như sau:

  • Deploy prod API và giữ nó "dark" (chỉ traffic nội bộ) khi staging vẫn là mặc định.
  • Thay dependencies backend trước (nếu backend gọi dịch vụ khác), dùng env vars và restart nhanh.
  • Chuyển traffic web sang một lát nhỏ (hoặc chỉ tài khoản nội bộ).
  • Phát hành mobile app với thiết lập mới, nhưng giữ một feature flag do server điều khiển để trì hoãn chuyển khi chưa sẵn sàng.
  • Tăng traffic dần và luôn sẵn phương án rollback.

Xác minh chủ yếu là phát hiện mismatch sớm. Trước khi người dùng thực sự gặp thay đổi, kiểm tra các health endpoint, luồng auth, và một tài khoản test có thể hoàn thành một hành trình chính end-to-end.

Checklist nhanh trước khi ship

Hầu hết lỗi config production đều tẻ nhạt: giá trị staging còn sót, default flag bật, hoặc thiếu API key ở vùng. Một lần rà nhanh bắt được hầu hết.

Trước khi deploy, xác nhận ba thứ khớp môi trường mục tiêu: endpoints, secrets và defaults.

  • Base URLs trỏ đúng nơi (API, auth, CDN, payments). Kiểm tra web, backend và mobile riêng.
  • Không có test key trong production, và không có production key trong dev hoặc staging. Đồng thời xác nhận tên key khớp mong đợi.
  • Feature flags có default an toàn. Mọi thứ rủi ro nên mặc định tắt và bật có chủ ý.
  • Cài đặt build và release khớp (bundle ID/package name, custom domain, CORS origins, OAuth redirect URLs).
  • Observability được cấu hình (logs, báo lỗi, tracing) và gắn nhãn môi trường đúng.

Rồi làm smoke test nhanh. Chọn một flow người dùng thật và chạy end to end, dùng cài đặt mới hoặc profile trình duyệt sạch để không dựa vào token cached.

  • Mở app và xác nhận nó load không có lỗi console.
  • Đăng nhập và gọi một API cần auth (profile, settings, hoặc list dữ liệu đơn giản).
  • Gây một lỗi có kiểm soát (input sai hoặc offline) và xác nhận bạn thấy thông báo thân thiện, không phải màn hình trắng.
  • Kiểm tra logs và báo lỗi: một lỗi test nên hiện lên dưới môi trường đúng trong vài phút.

Thói quen thực tế: coi staging giống production nhưng với giá trị khác. Nghĩa là cùng schema config, cùng quy tắc validate, và cùng hình thức deploy. Chỉ khác giá trị, không khác cấu trúc.

Những sai lầm phổ biến dẫn đến outage

Keep browser config safe
Tạo app React sử dụng runtime config an toàn cho URL API và feature switches.

Phần lớn outage do cấu hình không phải chuyện lạ. Là những lỗi đơn giản lọt qua vì config rải rác khắp file, build step và dashboard, và không ai trả lời được: "Bản build này đang dùng giá trị nào ngay bây giờ?" Một setup tốt khiến câu hỏi đó dễ trả lời.

Trộn build-time và runtime settings

Cạm bẫy phổ biến là đặt giá trị runtime vào chỗ build-time. Nướng API base URL vào build React nghĩa là bạn phải build lại cho mỗi môi trường. Rồi ai đó deploy artifact sai và production trỏ sang staging.

Quy tắc an toàn: chỉ nướng vào build những giá trị thực sự không đổi sau release (như version app). Giữ chi tiết môi trường (API URLs, feature switches, analytics endpoints) ở runtime khi có thể, và làm nguồn chân lý rõ ràng.

Ship endpoint dev hoặc key test

Hay xảy ra khi default "giúp ích" nhưng không an toàn. Mobile app có thể default về API dev nếu không đọc được config, hoặc backend fallback về DB local nếu thiếu env var. Điều đó biến một lỗi config nhỏ thành outage toàn bộ.

Hai thói quen hữu ích:

  • Fail closed: nếu một giá trị bắt buộc thiếu, crash sớm với lỗi rõ ràng.
  • Làm cho production khó cấu hình sai nhất: không có dev defaults, không chấp nhận test keys, không bật debug endpoints.

Ví dụ thực tế: release tối thứ sáu, và build production vô tình chứa key thanh toán staging. Mọi thứ “hoạt động” cho đến khi giao dịch thất bại. Cách khắc phục không phải thư viện thanh toán mới, mà là validate từ chối key không phải production khi deploy.

Để staging trôi dạt khỏi production

Staging khác production khiến tin tưởng sai. Cấu hình DB khác, job background thiếu, hoặc flag thừa làm lỗi chỉ xuất hiện sau launch.

Giữ staging gần production bằng cách mirror cùng schema config, cùng quy tắc validate và cùng hình thức deploy. Chỉ khác giá trị.

Bước tiếp theo: làm cho cấu hình trở nên nhàm chán, có thể lặp lại và an toàn

Mục tiêu không phải tooling xịn. Là sự nhất quán nhàm chán: cùng tên, cùng kiểu, cùng quy tắc trên dev, staging và prod. Khi config có thể dự đoán, việc phát hành không còn cảm giác rủi ro.

Bắt đầu bằng cách viết ra một hợp đồng cấu hình rõ ràng ở một chỗ. Giữ ngắn nhưng cụ thể: mỗi tên key, kiểu (string, number, boolean), nơi được phép đến từ (env var, remote config, build-time), và default. Ghi chú cho những giá trị không bao giờ được đặt trong client app (như private API keys). Đối xử hợp đồng này như một API: mọi thay đổi cần review.

Rồi làm cho lỗi fail sớm. Thời điểm tốt nhất để phát hiện thiếu API base URL là trong CI, không phải sau deploy. Thêm validate tự động load config giống cách app load và kiểm tra:

  • các giá trị bắt buộc có mặt (không chuỗi rỗng)
  • kiểu đúng (không lỗi "true" vs true)
  • quy tắc chỉ-prod pass (ví dụ yêu cầu HTTPS)
  • feature flags có tên biết trước (không typo)
  • secrets không bị check-in repo

Cuối cùng, làm cho việc khôi phục khi thay đổi config sai trở nên dễ dàng. Snapshot cái đang chạy, thay một thứ một lần, verify nhanh, và giữ đường rollback sẵn.

Nếu bạn build và deploy với nền tảng như Koder.ai (koder.ai), những quy tắc tương tự áp dụng: coi các giá trị môi trường là input cho build và hosting, giữ bí mật ra khỏi source export, và validate config trước khi ship. Sự nhất quán đó làm cho redeploy và rollback trở nên đều đặn.

Khi config được document, validate và có thể đảo ngược, nó ngừng là nguồn outage và trở thành một phần bình thường của quy trình phát hành.

Câu hỏi thường gặp

Nên đặt gì trong config thay vì trong mã?

Giữ các giá trị thay đổi theo môi trường ở ngoài tệp mã nguồn. Đặt các giá trị mặc định không nhạy cảm trong mã, dùng chế độ cài đặt theo từng môi trường cho URL và công tắc, rồi chèn bí mật khi build hoặc triển khai.

Khi nào tôi cần một môi trường mới?

Dùng các môi trường dev, staging và prod riêng khi cần tách biệt dữ liệu, quyền truy cập hoặc rủi ro. Nếu chỉ thay đổi URL, giới hạn hoặc công tắc, hãy thêm một giá trị config.

Tôi có thể lưu bí mật trong ứng dụng React không?

Không. Mọi thứ gửi đến trình duyệt đều hiển thị với người dùng. Hãy giữ khóa riêng tư và mật khẩu ở backend, chỉ công khai các giá trị an toàn như URL API công khai hoặc cờ tính năng đơn giản.

Ứng dụng web của tôi nên dùng config tại thời điểm build hay thời gian chạy?

Dùng các giá trị tại thời điểm build cho những cài đặt hiếm khi thay đổi và an toàn để công khai. Tải config thời gian chạy cho các giá trị có thể cần thay đổi sau khi triển khai, như URL gốc của API hoặc công tắc bảo trì.

Backend Go nên xử lý cấu hình như thế nào?

Tải các biến môi trường bắt buộc vào một struct config có kiểu khi dịch vụ khởi động. Xác thực các môi trường, URL và chuỗi kết nối cơ sở dữ liệu được phép, rồi dừng khởi động với lỗi rõ ràng nếu thiếu giá trị bắt buộc.

Flutter nên xử lý dev, staging và prod như thế nào?

Dùng Flutter flavors cho các chi tiết theo từng bản build như ID ứng dụng, ký và dự án phân tích. Lấy các cài đặt thời gian chạy không nhạy cảm như URL API và cờ tính năng từ nguồn config từ xa.

Làm sao để cờ tính năng không tích tụ?

Đặt tên cờ theo hành vi chúng bật, chẳng hạn feature.checkout_new_ui_enabled. Gán chủ sở hữu và ngày gỡ bỏ cho từng cờ, mặc định tắt các thay đổi rủi ro, rồi xóa cờ ngay sau khi triển khai đầy đủ.

Tôi nên lưu khóa API và mật khẩu cơ sở dữ liệu ở đâu?

Lưu bí mật cho staging và production trong một kho bí mật chuyên dụng, rồi chỉ chèn chúng vào các dịch vụ cần dùng. Giữ bí mật cho phát triển cục bộ trong tệp cục bộ bị bỏ qua hoặc chuỗi khóa của hệ điều hành.

Làm sao để xoay vòng bí mật mà không gây gián đoạn?

Cho thông tin xác thực cũ và mới cùng hoạt động trong một khoảng thời gian chồng lấp ngắn. Triển khai client hoặc dịch vụ với giá trị mới, chuyển lưu lượng đang hoạt động, theo dõi lỗi xác thực, rồi xóa thông tin xác thực cũ.

Tôi nên kiểm tra gì trước khi phát hành production?

Kiểm tra mọi endpoint đều trỏ đến môi trường đích, các bí mật bắt buộc đều có sẵn và các cờ rủi ro mặc định tắt. Sau đó chạy một luồng người dùng hoàn chỉnh trong hồ sơ trình duyệt sạch hoặc bản cài đặt ứng dụng mới, đồng thời xác nhận log dùng nhãn môi trường đúng.

Related posts