Gác
Gác là các script ở scripts/ biến luật trong CLAUDE.md thành thứ máy kiểm được. Chạy tất cả bằng một lệnh ở gốc repo:
npm run check:guardsJob guards của ci.yml chạy đúng lệnh này trên mọi PR và mọi push lên main. Chạy nó trước khi push, ở folder tổng ~/ConanCode/conan-school/ (tức có ../conanplatform bên cạnh), để những gác đọc repo anh em kiểm thật.
Nguồn sự thật là package.json
Danh sách gác là script check:guards trong package.json ở gốc repo. Bảng dưới đây mô tả các gác có mặt lúc viết. Thêm hay bớt một gác thì sửa package.json và sửa trang này trong cùng PR.
Các gác trong check:guards
| Lệnh | Kiểm gì | Vì sao có |
|---|---|---|
check:emdash | Không có dấu gạch dài (U+2014) trong tệp văn bản nào của repo | Đó là thói quen của máy viết; một bài đầy dấu này đọc lên thấy ngay là "máy sinh" |
check:colors | Không bậc số bảng màu Tailwind, không hex tự chế trong khai báo màu; mốc theo thư mục ở scripts/color-token-baseline.json, chỉ được hạ | Token dùng chung mà không ai dùng thì đổi --color-primary không lan tới đâu cả |
check:token-sync | Màu chép tay trong cms-docs.conan.school/.vitepress/theme/custom.css khớp theme.css | VitePress không có Tailwind nên phải chép tay, và bản chép tay lệch im lặng |
check:emoji-icons | Không emoji ở vị trí icon; mốc ở scripts/emoji-icon-baseline.json, chỉ được hạ | Emoji ra ba hình khác nhau trên ba hệ điều hành, không nhận màu token, và trình đọc màn hình đọc nó thành chữ |
check:seo | Các luật SEO của www, kiểm tĩnh: không route nào khai headers(), trang chi tiết có meta description, mọi lời gọi /api/public/* có thật ở router của api, sitemap con khai đủ hai chỗ, mỗi họ trang có đường dẫn nội bộ trỏ tới, robots.txt trỏ tới sitemap | Bốn chỗ hỏng ở www (08.09.2026) đều là trang trả 200 mà rỗng ruột, không gì đỏ |
check:forbidden-deps | Không khai framer-motion, @mui/material, antd, @chakra-ui/react | framer-motion vẫn chạy vì motion re-export nó, nên vi phạm không có triệu chứng nào |
check:shared-packages-sync | packages/design-system, packages/observability, packages/api-contract giống từng file với bản ở conanplatform | Ba gói là bản chép; lệch là www và tokyo khác màu, lọc dữ liệu cá nhân khác nhau, hoặc parse theo hợp đồng api đã bỏ |
check:analytics | www có đúng một container GTM, khai ở một chỗ, có chỗ nạp gtm.js, và dataLayer không mang thông tin định danh | Khai trùng ID, đẩy email vào dataLayer, khai ID mà không nạp gì: cả ba đã có thật và không gì đỏ |
check:observability | Mọi cấu hình wrangler có [observability] enabled = true | Thiếu khối này thì dashboard Observability trống, trông như "không có lỗi nào" |
check:sentry | Mọi chỗ khởi tạo Sentry của www đi qua packages/observability (conanSentryOptions), không dữ liệu cá nhân, setUser chỉ {id}, không Replay/Feedback, DSN chỉ ở dsn.ts, release lấy từ CF_PAGES_COMMIT_SHA, file .map bị xoá sau build | Mặc định của Sentry v11 là thu hết header, cookie, thân request; một init viết theo tài liệu mẫu gửi tất cả đi mà không báo gì |
check:hero-banners | Số ảnh banner trang chủ ở www.conan.school/public/, COUNT của scripts/hero_banner_svg.py và HERO_BANNER_COUNT của api khớp nhau | Lệch là trang chủ trỏ tới ảnh không tồn tại, hoặc có ảnh không bao giờ hiện |
check:select-apps | Mẫu tự kiểm của scripts/ci/select-apps.mjs, script chọn app cần build trong ci.yml theo file đổi | Chọn sót một app là PR đổi gói dùng chung mà không build app dùng nó, CI xanh mà chưa kiểm gì |
Gác nào có mốc (màu, emoji icon) thì mốc chỉ được hạ: dọn xong một chỗ thì hạ mốc, không bao giờ nâng để cho qua.
Gác đọc repo anh em, bị bỏ qua ở CI
Ba gác cần đọc thư mục anh em ../conanplatform (đổi đường dẫn bằng biến API_REPO_DIR):
| Gác | Đọc gì ở repo anh em | Ở CI |
|---|---|---|
check:seo | api.conan.school/src/domains/public/index.ts, để đối chiếu mọi lời gọi /api/public/* của www với router thật | Bỏ qua riêng phần đối chiếu đó, kèm cảnh báo; phần còn lại vẫn chạy |
check:shared-packages-sync | packages/ ở cây làm việc, hoặc ở origin/main của repo anh em | Bỏ qua cả gác, kèm cảnh báo. Phần tự kiểm (mẫu phải bắt, mẫu phải tha) vẫn chạy |
check:hero-banners | HERO_BANNER_COUNT trong api.conan.school/src/shared/heroBanners.ts | Bỏ qua riêng phần so với api, kèm cảnh báo; phần so số ảnh với script vẫn chạy |
Vì sao bỏ qua: conanplatform là repo riêng tư, và GITHUB_TOKEN mặc định của CI không đọc được nó. Đây là nợ đã biết: CI xanh không có nghĩa là ba gác này đã kiểm. Các gác in cảnh báo "BỎ QUA" thành tiếng chứ không im lặng xanh, và người push phải chạy npm run check:guards ở folder tổng trước khi push.
Không nằm trong check:guards
Các script này ở scripts/ nhưng không chạy trong CI, vì chúng gọi mạng, cần một server đang chạy, hoặc cần Chrome trên máy:
| Script | Dùng khi |
|---|---|
check-seoquake.mjs | Đo SEO trên trang THẬT của www, lấy mẫu từ sitemap. Chạy tay sau mỗi đợt sửa SEO |
audit-www-pages.mjs | Mở từng trang công khai của một server www đang chạy, bắt trang lỗi và trang rỗng ruột |
audit-www-mobile.mjs | Rà giao diện mobile qua Chrome trên máy: tràn ngang, chữ quá nhỏ, vùng bấm quá bé, ảnh vỡ |
Ngoài gác, mỗi app còn có kiểm riêng trong lệnh build (test, typecheck), chạy cả ở CI lẫn ở Cloudflare. Xem Deploy và cấu hình.