Deploy và cấu hình
Luật gốc
- Cloudflare tự build từ GitHub. Mỗi app được nối thẳng vào repo
conan-webbằng ứng dụng GitHub của Cloudflare: Workers Builds cho Worker, Pages Git cho Pages. Push lênmainlà Cloudflare build và deploy, khoá do Cloudflare tự cấp (quyết định 16.10.2026). - GitHub Actions không deploy gì cả, và không có
CLOUDFLARE_API_TOKENtrong GitHub. Lý do: chủ repo không cầm khoá, và không có khoá rộng quyền nào nằm trong GitHub.ci.ymlchỉ KIỂM (gác, build, test). - Không bao giờ deploy từ máy. Không
wrangler deploy, khôngwrangler pages deploy, không áp migration D1 bằng tay. Phiên Claude Code chạy trên cloud cũng là "máy" theo nghĩa này. - Chỉ merge khi CI xanh.
Cấu hình build theo từng app
Bảng này chép nguyên từ CLAUDE.md của repo. Hai bản phải giống hệt nhau; đổi một bên thì đổi bên kia trong cùng PR.
| App | Loại | Thư mục gốc | Lệnh build | Deploy | Watch paths |
|---|---|---|---|---|---|
| api-cms | Workers Builds, Worker api-cms-conan-school | api-cms.conan.school | npm run check && npm test | npx wrangler d1 migrations apply conan-cms --remote && npx wrangler deploy | api-cms.conan.school/*, packages/cms-contract/* |
| cms | Pages Git, cms-conan-school | cms.conan.school | npm test && npm run build | đầu ra dist | cms.conan.school/*, packages/cms-contract/*, packages/design-system/* |
| cms-docs | Pages Git, cms-docs-conan-school | cms-docs.conan.school | npm run build | đầu ra .vitepress/dist | cms-docs.conan.school/* |
| www | Pages Git, conan-www (từ 16.10.2026) | www.conan.school | npm run typecheck && npm run build | đầu ra build/client | www.conan.school/*, packages/design-system/*, packages/observability/*, packages/api-contract/*; loại www.conan.school/edge-hotfix/* |
| cầu nối www | Workers Builds, Worker conan-www-stale-asset-bridge | www.conan.school/edge-hotfix | (không) | npm run deploy (gắn CONAN_RELEASE = SHA) | www.conan.school/edge-hotfix/* |
- Lệnh build chạy test TRƯỚC. Một commit đỏ trên
mainkhông lên production, kể cả khici.ymlchưa chạy xong. CI và bước build của Cloudflare chạy song song, không chờ nhau. - Cấu hình build (lệnh, thư mục gốc, watch paths) nằm ở dashboard Cloudflare, không nằm trong repo. Đổi ở dashboard mà không sửa bảng trên là bảng nói sai mà không ai biết.
- www chưa deploy từ repo này. Tới ngày cắt nó vẫn deploy từ
conanplatform. Xem Kế hoạch chuyển đổi.
Watch paths
cms và api-cms import gói hợp đồng dùng chung packages/cms-contract/ (ngoài thư mục gốc của app), và các site Tailwind đọc packages/design-system/. Watch paths của mỗi project phải gồm cả thư mục app lẫn các gói nó dùng, nếu không một PR chỉ sửa hợp đồng sẽ không dựng lại app nào, và production chạy hai nửa của một hợp đồng đã lệch nhau.
| App | Watch paths cần có |
|---|---|
| api-cms | api-cms.conan.school/*, packages/cms-contract/* |
| cms | cms.conan.school/*, packages/cms-contract/*, packages/design-system/* |
| cms-docs | cms-docs.conan.school/* |
| www | www.conan.school/*, packages/design-system/*, packages/observability/*, packages/api-contract/*; loại www.conan.school/edge-hotfix/* |
| cầu nối www | www.conan.school/edge-hotfix/* |
ci.yml chỉ kiểm
.github/workflows/ci.yml chạy trên mọi PR và mọi push lên main, gồm hai job:
guards:npm run check:guardsở gốc repo. Xem Gác.build: ma trận bốn app, mỗi appnpm ci --legacy-peer-depsrồi chạy đúng lệnh build như ở Cloudflare (api-cms thêmnpm run build, tứcwrangler deploy --dry-run).
npm ci hỏng phải làm CI đỏ, không có đường rơi: CI xanh với phụ thuộc không ghim là một bài học cũ của conanplatform.
Migration D1 của conan-cms
- File migration nằm ở
api-cms.conan.school/migrations/, đặt tên000N_*.sql. database_idthật của D1conan-cmsnằm trongapi-cms.conan.school/wrangler.toml. Id D1 không phải bí mật: không có khoá Cloudflare thì id không làm được gì.- Lệnh deploy của Workers Builds áp migration bằng
wrangler d1 migrations apply conan-cms --remote, rồi mớiwrangler deploy, nối bằng&&. Áp migration hỏng thì dừng, Worker cũ vẫn chạy với lược đồ cũ. Worker mới không bao giờ chạy trước lược đồ của nó. conan-cmslà DB mới, không có lịch sử lệch, nên dùng sổd1_migrationscó sẵn của wrangler. Khác với D1 củaconanplatform, nơi phải áp từng file một và có sổ riêng.- Thêm migration = thêm file mới. Không bao giờ sửa file đã áp.
- Thử ở máy:
npm run migrate:localtrongapi-cms.conan.school/(D1 cục bộ trong.wrangler/).
Bài học từ conanplatform: khi bước migration đỏ, API đứng yên ở bản cũ trong khi frontend vẫn ship, và nhìn từ ngoài không có gì đỏ. Sau mỗi PR có migration, mở lượt build của Worker api-cms-conan-school ở dashboard (Workers, Deployments) và xem bước deploy có xanh không.
Cài Cloudflare Access
Khi chưa làm bước này, mọi route /admin/* trả 503 access_not_configured, và người soạn thấy màn hình "Cloudflare Access chưa được cấu hình". Đó là đúng thiết kế.
Vào Cloudflare Zero Trust, mục Access, Applications. Tạo một ứng dụng Self-hosted.
Domain:
cms.conan.school. Không đặtapi-cms.conan.schoolsau Access: nhánh/public/*phải công khai cho www, còn nhánh/admin/*đã tự kiểm JWT.Thêm policy Allow, chọn danh sách email người soạn (hoặc một nhóm).
Mở ứng dụng vừa tạo, chép Application Audience (AUD) Tag.
Lấy team domain ở Settings của Zero Trust, dạng
<team>.cloudflareaccess.com.Điền hai giá trị vào
[vars]củaapi-cms.conan.school/wrangler.toml:toml[vars] CF_ACCESS_TEAM_DOMAIN = "<team>.cloudflareaccess.com" CF_ACCESS_AUD = "<AUD tag>"Không ghi
https://trước team domain. Nhiều AUD thì cách nhau bằng dấu phẩy. Hai giá trị này không phải bí mật, nên nằm trongwrangler.tomllà được.Mở PR, chờ CI xanh, merge. Workers Builds dựng và deploy lại Worker với biến mới.
Đăng nhập thử ở
cms.conan.school. Gọi/api/admin/mephải trả email của bạn.
Thêm hay bớt người soạn chỉ cần sửa policy ở bước 3, không cần deploy lại.
Tên miền
| Tên miền | Gắn vào | Cách gắn |
|---|---|---|
api-cms.conan.school | Worker api-cms-conan-school | Tự động: routes với custom_domain = true trong wrangler.toml, gắn mỗi lần deploy |
cms.conan.school | Pages cms-conan-school | Tay, một lần, ở dashboard Pages, Custom domains |
cms-docs.conan.school | Pages cms-docs-conan-school | Tay, một lần, như trên |
www.conan.school | Worker cầu nối conan-www-stale-asset-bridge, trỏ tới một Pages project | Đã có. Ngày cắt chỉ đổi project mà Worker trỏ tới, không đổi tên miền |
Sau khi gắn, so trang ở tên miền với trang ở <project>.pages.dev: hai bản phải giống nhau. Lệch là tên miền đang trỏ vào một project khác.
Kiểm sau lượt deploy đầu
- Mỗi project ở dashboard có lượt build xanh cho commit vừa merge, và lượt đó là production (nhánh
main), không phải preview. curl https://api-cms.conan.school/healthtrả{"ok":true}.ci.ymlcài phụ thuộc bằngnpm ci --legacy-peer-deps, còn Cloudflare tự cài bằng lệnh của nó, không có cờ đó. Nếu bước cài ở Cloudflare đỏ vì xung đột peer dependency thì CI xanh không nói lên gì về production: sửa ngay chỗ xung đột, đừng để hai môi trường cài khác nhau.