Skip to content

Checklist SEO, marketing và website ​

Hai repo (16.10.2026)

Từ 16.10.2026 www, check-seo.mjs và check-seoquake.mjs nằm ở repo conan-web; lệnh trong trang này chạy ở repo đó. Xem Hai repo.

Playbook, tin, thông báo đã sang CMS (17.10.2026)

Các mục dưới đây nói "sửa ở nguồn (pack JSON + migration)" hay meta-rewrite-*.json là đường CŨ, đã đóng: title, description, thân bài của playbook (cùng tin và thông báo Conan School) giờ sửa ở cms.conan.school, không còn migration nào ở repo này ghi chúng. Gác --check vẫn chạy cho pack mới ở conan-content; trùng target_keyword với bài không có pack thì tra meta.target_keyword ở api-cms. Xem nội dung biên tập đã sang CMS.

Mười mảng, mỗi mảng hai mươi việc, cho www.conan.school. Lập ngày 08.10.2026 từ ba nguồn đo thật: Google Search Console, scripts/check-seoquake.mjs (kiểu SEOquake, chạy trên URL lấy từ sitemap) và curl lên production. Trạng thái ghi theo cái đã kiểm, không theo cái đã viết mã.

Ký hiệuNghĩa
✅Đã có và đã kiểm trên production
🔧Làm trong đợt 08.10.2026 (PR có tên trong mục)
👤Việc của người vận hành: giao diện Search Console, GA4, GTM, DNS, tài khoản bên ngoài
⏳Còn mở, chưa ai nhận

Chạy lại kiểm tra trước khi đổi một ô từ 🔧 sang ✅:

bash
node scripts/check-seoquake.mjs --per 6
node scripts/check-seo.mjs
npm run check:analytics

Một lưu ý trước khi đọc "bounce rate" ​

GA4 không còn đo bounce theo nghĩa cũ. Bounce rate = 1 trừ engagement rate, và một phiên được tính là "engaged" khi kéo dài trên 10 giây, hoặc có từ hai lượt xem trang, hoặc có một key event. Có hai cách làm số này đẹp lên: làm trang tốt hơn, hoặc bắn sự kiện giả (ping mỗi 5 giây, đánh dấu cuộn trang là key event). Cách thứ hai làm hỏng chính con số mình dùng để biết trang có tốt không, nên checklist này chỉ có cách thứ nhất. Mục 8 ghi rõ điều cấm.

1. Đo lường: GA4, GTM, Search Console ​

  1. ✅ Một container GTM duy nhất GTM-MZ6DXZZ3, khai một chỗ mỗi cụm (app/env.public.ts).
  2. ✅ www nạp gtm.js trong <head> và có <noscript> iframe (app/root.tsx).
  3. ✅ tokyo nạp GTM và tự đẩy page_view mỗi lần đổi route (SPA).
  4. ✅ GA4 cấu hình bên trong container: tag Google G-0TSE5G23HV, năm tag sự kiện GA4 (đọc từ gtm.js 08.10.2026).
  5. ✅ dataLayer không mang PII, chỉ user_id (gác check:analytics).
  6. ✅ GTM không chạy trên inside6.com và không chạy ở dev.
  7. 👤 Đánh dấu key event trong GA4: đăng ký thành viên, bấm "Học thử", gửi form liên hệ. Key event là thứ GA4 dùng để tính phiên "engaged", phải là hành động có giá trị thật.
  8. 👤 Bật Enhanced Measurement trong luồng dữ liệu GA4 (scroll, outbound click, site search, file download). Không cần sửa mã.
  9. 👤 Liên kết GA4 với Search Console (Admin > Product links) để thấy truy vấn cạnh số liệu hành vi.
  10. 👤 Bỏ sitemap cũ conan.school/sitemap_index.xml khỏi Search Console, giữ https://www.conan.school/sitemap.xml.
  11. 👤 Thêm thuộc tính miền conan.school (Domain property) nếu chưa có, để thấy cả subdomain.
  12. 👤 Đặt cảnh báo GA4 khi phiên/ngày giảm quá 40%: dấu hiệu GTM bị gỡ hoặc site sập.
  13. ✅ docs, admin, mam, play, video không đo: công cụ nội bộ, quyết định có chủ ý (analytics).
  14. 🔧 Sự kiện content_read (page_path, read_seconds) khi người đọc kéo tới chân trang của một trang dài: đo chứ không phải để làm đẹp bounce, nên không đánh dấu nó là key event. 👤 Tạo tag GA4 Event trong GTM nghe content_read.
  15. 👤 Bật Consent Mode v2 trong GTM nếu chạy quảng cáo cho người dùng EU.
  16. 👤 Kiểm "DebugView" GA4 sau mỗi lần đổi container, vì đổi trong GTM không có gì trong git để rà.
  17. ✅ Không có mã GA4 (gtag/js) rời trong HTML, mọi thứ đi qua GTM (kiểm 08.10.2026).
  18. 👤 Ghi lại trong GTM "Versions" lý do mỗi lần publish container.
  19. 👤 Bảng Looker Studio (phiên, engagement rate, landing page, truy vấn GSC): dựng trong giao diện Looker Studio, cần quyền GA4 và GSC của người vận hành.
  20. 👤 Xem báo cáo "Pages and screens" theo engagement rate mỗi tháng, sửa trang thấp nhất trước.

2. Thu thập và lập chỉ mục ​

  1. ✅ robots.txt cho phép tất cả, chặn /auth/, /logout, /onboarding, /style-guide, trỏ tới sitemap.
  2. ✅ Sitemap index với bảy sitemap con (8 <loc> kể cả index), khai hai chỗ (app/routes.ts và CHILDREN).
  3. ✅ Không khai URL trả chuyển hướng trong sitemap (gác check-seo).
  4. ✅ http://conan.school và https://conan.school chuyển về https://www.conan.school (301/308).
  5. ✅ HSTS có preload, X-Frame-Options: DENY, nosniff, đặt ở entry.server.tsx.
  6. ✅ Không route nào khai headers() (gác check-seo).
  7. ✅ /_next/* trả 410 Gone (PR #353).
  8. ✅ /playbooks/tags/* chuyển 301 về /playbooks (PR #353).
  9. ✅ Hai bảng courses có một slug chuẩn mỗi id, slug kia 301 về.
  10. ✅ Trang 404 trả mã 404 thật và gợi ý trang tiếp theo.
  11. ✅ CTA đăng nhập sang tokyo có rel="nofollow" (PR #353).
  12. 👤 Cho subdomain Vercel chết (personal-branding., jtbd., books.conan.school, trả 402) chuyển 301 về trang tương ứng trên www, ở DNS/Cloudflare.
  13. 👤 "Validate fix" các nhóm lỗi trong Search Console sau mỗi đợt sửa.
  14. 👤 Gộp chuỗi http://conan.school → https://conan.school → www thành một bước: một Redirect Rule ở Cloudflare (tên miền gốc không đi qua worker cầu nên không sửa được bằng mã).
  15. ✅ hreflang vi, en, x-default trên mọi trang (kiểm trang chủ và trang con).
  16. 🔧 Sách (242) và chương (1.175) đã khai bản /en trong sitemap; ⏳ các họ khác khi cột *_en đủ.
  17. ✅ Canonical tự trỏ về chính trang, có tính tiền tố /en.
  18. 🔧 llms.txt ở gốc site, chỉ đường cho công cụ AI tới năm họ nội dung chính.
  19. 👤 Gửi lại sitemap trong Search Console sau đợt thêm bốn playbook mới.
  20. 👤 Theo dõi số URL "Đã phát hiện, chưa lập chỉ mục" mỗi tuần trong Search Console.

3. On-page: title, description, heading ​

  1. 🔧 Hàm dùng chung fitTitle / fitDescription (app/lib/seo.ts): title 30 đến 60 ký tự, description 70 đến 158, cắt ở ranh giới từ.
  2. 🔧 Áp cho khoá học, unit, sách, chương, playbook, mentor, workshop, sự kiện, JTBD (13/32 URL mẫu sai title, 12/32 sai description trước khi sửa).
  3. 🔧 Description trang chủ từ 196 xuống 136 ký tự, cả hai bản ngôn ngữ.
  4. 🔧 Title trang Thông báo từ 24 lên 38 ký tự.
  5. 🔧 Playbook: H1 trong thân bài hạ xuống H2, mỗi trang một H1.
  6. ✅ Mỗi trang chi tiết có meta description (gác check-seo).
  7. ✅ OG title, description, image, twitter:card trên mọi trang mẫu.
  8. ✅ Ảnh OG cho khoá học là JPEG riêng từng khoá.
  9. ✅ Ảnh trang trí dùng alt="" có chủ ý; ảnh nội dung có alt (checker chấp nhận alt="").
  10. ✅ Trang chương ở /en có title, description tiếng Anh (PR #354) và dữ liệu đủ cho 1.175 chương (PR #357).
  11. 🔧 Viết lại title cho 24 playbook dài hơn 60 ký tự, ở nguồn (pack JSON + migration). Nay title dài nhất 60 ký tự.
  12. 🔧 Viết lại description 120 đến 158 ký tự cho 49 playbook thiếu từ khoá trong 120 ký tự đầu (content/playbook-plan/meta-rewrite-20261008.json).
  13. ✅ Từ khoá chính có trong thân bài playbook (playbook_pack_to_sql.py --check).
  14. ✅ Không trùng target_keyword giữa các playbook (cùng gác).
  15. 🔧 Trang mentor có thêm khoá học và workshop của mentor; 👤 tiểu sử dài hơn cần người soạn viết (dữ liệu về người thật, agent không bịa).
  16. 🔧 Trang sự kiện có thêm "Sự kiện sắp tới"; 👤 tóm tắt sau sự kiện cần người tổ chức viết (chuyện đã xảy ra thật).
  17. ✅ URL tiếng Việt không dấu, gạch nối, không tham số.
  18. ✅ Không dấu gạch dài trong nội dung (gác check:emdash).
  19. 🔧 Ngày cập nhật hiển thị trên playbook khi bản nội dung mới hơn ngày đăng (ngày theo ngôn ngữ trang).
  20. ✅ Thân bài 75 playbook không có ảnh nào (rà HTML production 08.10.2026), không có alt để sửa.

4. Structured data ​

  1. ✅ EducationalOrganization + WebSite trên mọi trang.
  2. ✅ Book + BreadcrumbList + Person trên trang sách.
  3. ✅ Chapter + BreadcrumbList trên trang chương, khai isAccessibleForFree.
  4. 🔧 Article + BreadcrumbList trên trang playbook (trước đây chỉ có khối dùng chung).
  5. 🔧 Breadcrumb và inLanguage của trang chương theo bản ngôn ngữ (PR #354).
  6. ✅ Nội dung trả phí khai isAccessibleForFree: false + hasPart CSS selector.
  7. 🔧 Course có hasCourseInstance (courseMode Online) và offers loại Subscription; tên và inLanguage theo bản. courseWorkload để trống có chủ ý vì dữ liệu chưa có thời lượng, không bịa.
  8. 🔧 Event trên trang sự kiện (ngày, địa điểm, eventStatus, hình thức tham dự).
  9. ✅ Quyết định: không dùng FAQPage (Google đã thu hẹp rich result FAQ).
  10. 🔧 ItemList trên /playbooks; ⏳ khoá học và sách (danh sách 200+ mục, cân nhắc cỡ HTML).
  11. 👤 Chạy Rich Results Test cho năm loại trang sau mỗi lần đổi schema.
  12. 👤 Xem báo cáo "Enhancements" trong Search Console (Breadcrumbs, Articles).
  13. 🔧 ProfilePage + Person trên trang mentor; ⏳ sameAs khi có hồ sơ công khai trong dữ liệu.
  14. ✅ JSON-LD đi qua meta của route, không chèn chuỗi thô vào DOM.
  15. ✅ publisher trỏ @id của tổ chức, không lặp khối tổ chức.
  16. ✅ logo của tổ chức trỏ icons/icon-512.png.
  17. 🔧 sameAs của tổ chức: conan1.com + trang Facebook chính thức (facebook.com/conanschool2711, URL đã dùng khắp site). ⏳ YouTube, LinkedIn khi có URL chính thức.
  18. 🔧 SearchAction trong WebSite, trỏ /playbooks?q=.
  19. ✅ Không khai schema cho nội dung không hiển thị trên trang.
  20. 🔧 Gác trong check-seo: mỗi họ trang chi tiết phải có JSON-LD; mốc nợ còn 7 họ (album, section sách, challenge, deep book, việc làm, thành viên, ảnh). Đợt này thêm Article cho tin, thông báo, câu chuyện người học; Event cho workshop.

5. Tốc độ và Core Web Vitals ​

  1. 🔧 Stale-while-revalidate ở worker cầu: bản quá hạn trả ngay, dựng lại chạy nền. Trước đó lượt MISS chờ 1,5 s (trang chủ) đến 4,9 s (/books).
  2. ✅ Bản lưu ở edge có TTL do worker tự thi hành bằng dấu thời gian, không tin s-maxage.
  3. ✅ Trình duyệt luôn nhận no-store cho HTML, cache chỉ nằm ở edge.
  4. ✅ Lượt lỗi khi dựng lại không đè lên bản tốt (đợt này).
  5. ✅ Nén Brotli/gzip: /courses 517 KB thô còn 49 KB trên dây, /books 34 KB.
  6. ✅ Loader chỉ trả trường JSX đọc (trang chủ 1,99 MB còn 37,7 KB, 09.09.2026).
  7. ✅ Ảnh danh sách có loading="lazy" (212/213 ở /courses).
  8. ✅ preconnect tới image.conan.school.
  9. 🔧 fetchpriority="high" cho ảnh bìa trang khoá học (phần tử LCP, đo 3,1 s); trang chủ, sách, playbook có LCP là chữ, không cần.
  10. 🔧 width/height + lazy cho ảnh card sách (236 bìa trước đây tải cùng lúc), khoá học, playbook, bài liên quan, avatar review.
  11. 🔧 preconnect tới tokyo.conan.school, nơi phục vụ ảnh bìa khoá học; ⏳ chuyển sang image.conan.school.
  12. 👤 Xem báo cáo Core Web Vitals trong Search Console, nhóm "Poor" trước.
  13. 🔧 Đo Lighthouse di động (08.10.2026, máy đo ở Việt Nam): điểm 49 đến 59, CLS 0, TBT 90 đến 330 ms; FCP/LCP 4 đến 12 s nhưng phần lớn là đường mạng của máy đo (cùng URL đi qua SIN, CDG, HKG; lượt HIT từ máy này mất 1,2 đến 2,9 s). Số lab không đáng tin; 👤 dùng báo cáo Core Web Vitals (dữ liệu người dùng thật) trong Search Console. Hai phát hiện thật: cache edge theo từng điểm Cloudflare (👤 bật Tiered Cache), và GTM nạp HAI đích GA4 (G-0TSE5G23HV, G-CNHTF2PQ56) mỗi đích ~190 KB (👤 gỡ đích thừa trong GTM).
  14. ✅ Asset có hash, Pages giữ asset của bản cũ nên HTML cũ không gãy.
  15. ✅ Không nạp font web nào (kiểm 08.10.2026), chữ Arial hệ thống.
  16. ✅ Bundle của site nhỏ (entry 67 KB, chunk lớn nhất 44 KB); phần JS thừa lớn nhất là của GTM (mục 5.13).
  17. ✅ Không chặn render bằng script bên thứ ba ngoài GTM (async).
  18. 🔧 public/sw.js (bản Next cũ, cache-first mọi asset) thay bằng worker tự gỡ: xoá cache, unregister, tải lại trang.
  19. 👤 Cảnh báo TTFB: dùng Cloudflare Health Check hoặc dịch vụ uptime bên ngoài; không đặt cron trong GitHub Actions (giới hạn phút CI).
  20. ✅ HTTP/2, TLS 1.3 do Cloudflare.

6. Nội dung và độ phủ chủ đề ​

  1. ✅ 54 playbook ≥ 900 từ, 3 câu quiz, meta 70 đến 160 ký tự (gác PlaybookPack).
  2. ✅ Bốn playbook từ truy vấn có hiển thị không có lượt bấm trong GSC (PR #353).
  3. ✅ 1.175 chương sách có essential question và big idea song ngữ (PR #357).
  4. ✅ 4.180 section có guiding question song ngữ.
  5. ✅ Trang sách có khung "viết cho ai, bạn đang gặp gì, đọc xong làm được gì" (PR #353).
  6. ✅ Quyết định: 28 thân bài thuộc ba sách AI chưa xuất bản (is_published = 0), không trang nào hiện chúng; dịch khi sách được xuất bản.
  7. 👤 Mỗi tháng lấy 10 truy vấn có hiển thị cao, CTR thấp trong GSC, quyết viết bài mới hay sửa title.
  8. 🔧 Keyword plan có trường da_viet (slug bài đã viết): 9/272 từ khoá đã có bài.
  9. 🔧 Cụm chủ đề theo pillar: bài liên quan ưu tiên cùng pillar, cuối bài trỏ về khoá học của pillar.
  10. ✅ Không trang mỏng trong sitemap: chỉ khai họ URL đã đo có ruột.
  11. 🔧 Lưu trữ 5 bài trùng chủ đề (social jobs, emotional jobs, network effects, 4 lực, switch interview), 301 về bài giữ lại ở worker cầu.
  12. ⏳ Bản tiếng Anh cho playbook (75 bài × ~1.000 từ): đợt dịch riêng, chưa làm.
  13. ✅ Nội dung trả phí khoá bằng trang xem trước, không 302 sang đăng nhập.
  14. 🔧 Bỏ "(2025)", "Hướng dẫn 2025" khỏi title; 👤 rà số liệu trong thân bài cũ cần người soạn kiểm nguồn.
  15. 👤 Trích dẫn nguồn cho số liệu: người soạn kiểm và gắn nguồn thật, agent không bịa nguồn.
  16. ✅ Thương hiệu thật không bịa (luật story-world).
  17. 🔧 Ảnh minh hoạ vẽ bằng thuật toán cho 75 playbook (scripts/playbook_art_svg.py, phong cách theo pillar, không chữ), dùng làm ảnh thẻ khi chưa có ảnh riêng.
  18. 👤 Câu chuyện người học cần ngày, ngành, kết quả đo được từ chính người học.
  19. ✅ Không nội dung máy dịch thô: bản Anh dịch theo nghĩa, có gác số liệu cho thân bài.
  20. 👤 Người soạn đọc lại 1.200 câu hỏi section vừa dịch (đợt 08.10.2026).

7. Liên kết nội bộ và điều hướng ​

  1. 🔧 Chân trang dựng từ FOOTER_NAV_SECTIONS (trước đây năm liên kết viết cứng; HTML SSR không có liên kết nào tới /playbooks, /books, /jtbd dù gác báo xanh). Gác check-seo nay chỉ đếm chân trang.
  2. 🔧 /news vào chân trang.
  3. 🔧 /playbooks vào chân trang.
  4. ✅ Gác check-seo: mọi route gốc phải có trong navigation.ts (mốc nợ còn 4: /activities, /album, /style-guide, /workshop-setup-guide).
  5. ✅ Unit có liên kết unit trước, unit sau.
  6. 🔧 Playbook có khối bài liên quan: sửa ô ✅ cũ, API chi tiết không bao giờ trả related nên khối chưa từng hiện; loader nay tự tính (cùng pillar trước).
  7. ✅ Trang 404 có liên kết tới các họ nội dung chính.
  8. ✅ Trang gom /communities + 18 hub, mỗi trang cách trang chủ hai cú bấm.
  9. ✅ Mọi <Link> nội bộ qua localizePath.
  10. ✅ Trang sách liệt kê chương kèm câu hỏi của chương.
  11. 🔧 Trang chương: thẻ "Đọc tiếp chương N" là <Link> thật ở cuối trang (nút phía trên dùng navigate(), máy không theo được).
  12. 🔧 Trang mentor liệt kê khoá học (course_mentors) và workshop (workshop_mentors) của mentor; API trả thêm hai trường. Person có sameAs từ Facebook/website của mentor.
  13. 🔧 Trang sự kiện: "Sự kiện sắp tới" (tối đa 4) + liên kết tới workshop.
  14. 🔧 Playbook trỏ tới một khoá học theo pillar (bảng PILLAR_COURSE, quyết định biên tập).
  15. 🔧 Ba liên kết "Xem tất cả →" ở trang chủ đổi thành chữ mô tả đích (ảnh cộng đồng, mentor).
  16. ✅ Breadcrumb hiển thị trên sách, chương, unit.
  17. ✅ Playbook có liên kết "Trở lại Playbooks" ở đầu bài và BreadcrumbList trong JSON-LD.
  18. ✅ Không liên kết nội bộ trỏ tới URL chuyển hướng (slug chuẩn).
  19. ✅ /activities, /album đã chuyển hướng 301 và không có trong sitemap: không cần liên kết.
  20. 👤 Báo cáo "Links" trong Search Console mỗi quý.

8. Trải nghiệm và bounce rate ​

  1. 🔧 Stale-while-revalidate (mục 5.1): chờ trang là nguyên nhân bỏ đi lớn nhất có thể đo.
  2. ✅ Không popup chặn nội dung khi vào trang.
  3. ✅ Bố cục ba khổ cố định (max-w-[1600px], max-w-3xl cho trang đọc dài).
  4. ✅ Chữ tối thiểu 14px, Arial (design system).
  5. ✅ Trang chương ở /en hiện tiếng Anh, không còn người đọc tiếng Anh rơi vào trang tiếng Việt.
  6. ✅ Trang 404 gợi ý trang tiếp theo thay vì ngõ cụt.
  7. 🔧 "Đọc tiếp" ở cuối chương sách (chương sau); ⏳ sách cùng danh mục ở chương cuối.
  8. 🔧 Mục lục "Trong bài này" cho playbook có từ ba H2 trở lên; H2 được gắn id ở server, sau bước lọc HTML.
  9. ✅ Thời gian đọc ước tính ở đầu playbook (có từ trước).
  10. 🔧 CTA cuối playbook là khoá học cùng chủ đề, không CTA chung (cùng mục 7.14).
  11. 🔧 Ô tìm cho /books và /playbooks, bỏ dấu khi so, từ khoá trên URL ?q= nên SSR trả sẵn kết quả lọc.
  12. 🔧 Trạng thái tìm nằm trên URL (?q=), chia sẻ được, quay lại không mất.
  13. ✅ Trạng thái lỗi không giả làm "đang cập nhật" (luật catch).
  14. 🚫 Cấm: bắn sự kiện định kỳ, đánh dấu scroll là key event, hay mọi cách khác làm phiên "engaged" mà người đọc không làm gì. Làm đẹp số là mất công cụ đo.
  15. 🚫 Cấm: chặn nút quay lại, mở liên kết nội bộ ở tab mới để giữ phiên.
  16. ✅ Bảy mẫu trang ở 360px không cuộn ngang (kiểm trên production 08.10.2026).
  17. 🔧 Nút lên đầu trang (Motion), hiện sau hai màn hình, góc trái dưới để không đè ô chat.
  18. ✅ Song ngữ: công tắc ngôn ngữ là liên kết thật.
  19. 👤 Xem "Engagement rate" theo landing page trong GA4, sửa 5 trang thấp nhất mỗi tháng.
  20. 🔧 "Bài này có giúp bạn không?" cuối playbook, đẩy article_feedback vào dataLayer (không phải key event). 👤 Tạo tag GA4 cho sự kiện này.

9. Song ngữ và thị trường ​

  1. ✅ Hai bản là hai URL (/, /en), không cookie.
  2. ✅ hreflang vi, en, x-default.
  3. ✅ Chữ thiếu bản dịch rơi về tiếng Việt, không để trống.
  4. ✅ Cột *_en có cho cả hai họ bảng.
  5. ✅ Meta trang chương theo ngôn ngữ (PR #354).
  6. ✅ Dữ liệu tiếng Anh cho câu hỏi chương, big idea, câu hỏi section (PR #357).
  7. 🔧 Sitemap /en cho sách và chương.
  8. ✅ og:locale theo bản (root.tsx); 🔧 og:locale:alternate.
  9. ✅ 242/242 sách đã xuất bản có description_en.
  10. 🔧 description_en cho 227 khoá (cả hai họ bảng); API khoá học trước đây không trả name_en/description_en nên /en hiện tiếng Việt, đã sửa.
  11. ✅ /privacy, /terms cố ý chỉ tiếng Việt (văn bản pháp lý).
  12. 🔧 inLanguage của Course và Book theo bản.
  13. 👤 GSC: lọc hiệu suất theo quốc gia để quyết ưu tiên dịch.
  14. ⏳ Playbook tiếng Anh: cùng đợt dịch với mục 6.12.
  15. ✅ ui() trả tên khoá khi thiếu dịch: mở trang thử sau mỗi lần thêm khoá.
  16. 🔧 Gác check-seo: mọi <Link to> nội bộ phải qua localizePath/L(); bắt và sửa 10 chỗ.
  17. 🔧 Ngày dạng chữ (tin, thông báo, playbook) theo ngôn ngữ; ngày dạng số dd.mm.yyyy dùng chung cho hai bản.
  18. ✅ Bản Anh giữ "đồng" (VND), không quy đổi; gác trong book_section_body_en_to_sql.py.
  19. ✅ GTM không chạy trên inside6.com (thương hiệu khác).
  20. ✅ /en/communities và 18 hub có bản tiếng Anh (kiểm 08.10.2026).

10. Marketing, off-page và SEOquake ​

  1. 🔧 scripts/check-seoquake.mjs: kiểm kiểu SEOquake trên URL thật từ sitemap (title, description, H1, alt, canonical, hreflang, OG, JSON-LD, cỡ HTML, số từ, thời gian).
  2. 🔧 Web manifest được trỏ tới từ <head> (file có từ lâu mà không trang nào nạp), màu theo token thương hiệu.
  3. ✅ Favicon, icon SVG, apple-touch-icon.
  4. ✅ Ảnh chia sẻ OG mặc định 1200×630.
  5. 👤 Google Business Profile cho Conan School, trỏ về www.
  6. 👤 Trang Facebook, YouTube, LinkedIn trỏ về www, cùng tên thương hiệu.
  7. 👤 Xử lý hub.conan.school (Substack) và team.conan.school: ngoài repo, trỏ canonical về www hoặc giữ thương hiệu riêng có chủ ý.
  8. 👤 Tìm backlink từ đối tác, báo chí, cộng đồng ngành; ghi vào bảng theo dõi.
  9. 👤 Trang báo chí: cần mô tả chính thức, đầu mối liên hệ và bộ logo được duyệt.
  10. 🔧 UTM (utm_source=email, utm_campaign=<loại thư>) gắn ở cổng sendEmail() cho liên kết trang công khai; không chạm liên kết có mã, /auth/, /api/.
  11. 👤 Theo dõi thương hiệu trên Google Alerts.
  12. 👤 Bản tin email hằng tuần: quyết định sản phẩm (ai nhận, tần suất, đồng ý nhận); khi có quyết định thì thêm một loại vào EMAIL_CATALOG.
  13. ✅ Tỉ lệ chữ/HTML thấp là hệ quả của Tailwind, không phải yếu tố xếp hạng; checker chỉ cảnh báo dưới 3%.
  14. ✅ Không trang nào chặn bởi noindex nhầm (trang chủ, danh sách, chi tiết đã kiểm).
  15. ✅ Không có liên kết ra ngoài trả tiền (rà 08.10.2026: chỉ Facebook, Messenger, Google Meet của chính Conan School).
  16. 👤 SEOquake trên trình duyệt: chạy "Page SEO audit" cho năm mẫu trang mỗi quý, so với checker.
  17. 👤 Trang so sánh đối thủ: cần dữ liệu đối thủ có thật và quyết định thương hiệu; agent không viết so sánh từ suy đoán.
  18. 👤 Landing page cho chiến dịch: tạo khi có chiến dịch cụ thể.
  19. 👤 Thiết lập Microsoft Clarity hoặc tương đương qua GTM để xem bản ghi phiên (kiểm PII trước).
  20. ✅ Bốn cửa của một trang (200, SSR, tự mô tả, sitemap + liên kết) có gác check-seo.

Đã làm trong đợt 08.10.2026 ​

PR #353 (Search Console, 10 việc), #354 (meta chương /en), #357 (dữ liệu tiếng Anh cho 1.080 chương và 1.200 section), và PR của checklist này: SWR ở edge, fitTitle/fitDescription cho 12 route, Article + Breadcrumb cho playbook, H1 đơn, /books /news /playbooks vào điều hướng, manifest, llms.txt, checker kiểu SEOquake.

Đợt Search Console 10.10.2026 ​

  • 🔧 Trang chỉ có tiếng Việt (playbook; tin và thông báo chưa dịch) ở /en canonical về bản tiếng Việt, không khai hreflang en, và /en/playbooks rời sitemap. Search Console đang lập chỉ mục /en/playbooks/... (nội dung tiếng Việt) như trang riêng. Cơ chế: handle: { viOnly: true } hoặc viOnly trong dữ liệu loader, đọc ở root.tsx.
  • 🔧 Title chương sách và unit giữ tên sách/tên khoá khi phải cắt (fitTitle(..., keepSuffix)): "trope là gì" (58 lượt hiển thị, vị trí 9) vào chương 1 của sách Tropes mà title đã cắt mất chữ Tropes.
  • 👤 hub.conan.school (Substack): bài "Ứng dụng AI vào content marketing" có 1.293 lượt hiển thị, CTR 0,3%, và Search Console báo lượt hiển thị vừa giảm 100%. Ngoài repo; sửa title/mô tả trên Substack hoặc trỏ canonical về playbook content marketing của www.
  • 👤 Xoá sitemap cũ conan.school/sitemap_index.xml (0 URL, đọc lần cuối 03.2025) và gỡ token xác minh không dùng (Search Console báo 1 token thừa).
  • Hiện trạng: 1.512 trang đã lập chỉ mục, 3.420 "Đã phát hiện, chưa lập chỉ mục" (chủ yếu chương sách và thông báo: vấn đề ngân sách thu thập, đòn bẩy là liên kết nội bộ đã thêm ở các đợt trước). Core Web Vitals: chưa đủ dữ liệu người dùng thật.

Tài liệu nội bộ nền tảng Conan School.