<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mạnh Digital</title>
    <description>The latest articles on DEV Community by Mạnh Digital (@manhdigital68).</description>
    <link>https://dev.to/manhdigital68</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4194714%2F69f7eb2b-151d-4c15-a2bc-4aaaa51d6318.png</url>
      <title>DEV Community: Mạnh Digital</title>
      <link>https://dev.to/manhdigital68</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/manhdigital68"/>
    <language>en</language>
    <item>
      <title>Viết lại tờ brief SEO: 9 ô cần điền trước khi gõ chữ đầu tiên</title>
      <dc:creator>Mạnh Digital</dc:creator>
      <pubDate>Wed, 21 Oct 2026 08:59:05 +0000</pubDate>
      <link>https://dev.to/manhdigital68/viet-lai-to-brief-seo-9-o-can-dien-truoc-khi-go-chu-dau-tien-3deg</link>
      <guid>https://dev.to/manhdigital68/viet-lai-to-brief-seo-9-o-can-dien-truoc-khi-go-chu-dau-tien-3deg</guid>
      <description>&lt;p&gt;Một kịch bản mình hay gặp (ví dụ minh họa, không phải một khách hàng cụ thể): chủ website nhắn cho writer "viết giúp anh bài 1.500 từ, keyword là X". Hai ngày sau bài về, câu chữ mượt, đúng chính tả. Đăng lên, ba tháng sau vẫn không ai tìm thấy.&lt;/p&gt;

&lt;p&gt;Người viết không làm sai. Họ chỉ nhận một tờ brief gồm hai thứ: keyword và số từ. Còn lại họ phải tự đoán.&lt;/p&gt;

&lt;p&gt;Dưới đây là cách mình viết lại tờ brief, theo kiểu nhật ký: mỗi lần bài hỏng, mình thêm một ô vào form.&lt;/p&gt;

&lt;h2&gt;
  
  
  9 ô cần điền trước khi viết
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Ô cần điền&lt;/th&gt;
&lt;th&gt;Câu hỏi nó trả lời&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Keyword chính&lt;/td&gt;
&lt;td&gt;Cụm từ người dùng thực sự gõ là gì?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Keyword phụ&lt;/td&gt;
&lt;td&gt;Những biến thể nào cùng intent với nó?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Intent&lt;/td&gt;
&lt;td&gt;Họ muốn học, so sánh hay mua?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Nhiệm vụ của người đọc&lt;/td&gt;
&lt;td&gt;Đọc xong họ làm được việc gì?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Vai trò URL&lt;/td&gt;
&lt;td&gt;Đây là pillar, guide hay template?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Câu trả lời bắt buộc&lt;/td&gt;
&lt;td&gt;Câu hỏi nào bài phải trả lời ngay phần đầu?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Bằng chứng&lt;/td&gt;
&lt;td&gt;Số liệu, ví dụ, nguồn nào chứng minh?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Internal link&lt;/td&gt;
&lt;td&gt;Bài này nối với trang nào, và từ trang nào trỏ tới?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;KPI sau đăng&lt;/td&gt;
&lt;td&gt;Đo bằng gì: index, hiển thị, click, vị trí?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Ô số 5 là ô bị bỏ sót nhiều nhất. Hai bài cùng tranh một intent thì tự cạnh tranh với chính mình. Mỗi URL cần một nhiệm vụ riêng.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist kỹ thuật trước khi bấm đăng
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Trang trả về HTTP 200.&lt;/li&gt;
&lt;li&gt;Có self-canonical, không bị noindex.&lt;/li&gt;
&lt;li&gt;Nội dung chính nằm trong HTML ban đầu, không phụ thuộc hoàn toàn vào JavaScript chạy sau.&lt;/li&gt;
&lt;li&gt;Schema (nếu có) khớp với nội dung hiển thị.&lt;/li&gt;
&lt;li&gt;Title, H1, meta description khác nhau giữa các URL.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Một lưu ý quan trọng
&lt;/h2&gt;

&lt;p&gt;Template chỉ là lan can chống bỏ sót, không phải công thức xếp hạng. Điền đủ 9 ô không đảm bảo lên top. Nó chỉ đảm bảo người viết không phải đoán, và bạn có chỗ để quay lại xem bài hỏng ở khâu nào.&lt;/p&gt;

&lt;p&gt;Bản đầy đủ có ví dụ điền sẵn: &lt;a href="https://manhdigital.com/blog/mau-bai-viet-chuan-seo" rel="noopener noreferrer"&gt;mẫu bài viết chuẩn SEO trên ManhDigital&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>contentmarketing</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Biến template bài viết chuẩn SEO thành YAML + script Python kiểm tra tự động</title>
      <dc:creator>Mạnh Digital</dc:creator>
      <pubDate>Tue, 20 Oct 2026 17:13:51 +0000</pubDate>
      <link>https://dev.to/manhdigital68/bien-template-bai-viet-chuan-seo-thanh-yaml-script-python-kiem-tra-tu-dong-858</link>
      <guid>https://dev.to/manhdigital68/bien-template-bai-viet-chuan-seo-thanh-yaml-script-python-kiem-tra-tu-dong-858</guid>
      <description>&lt;p&gt;Viết content SEO theo template thì dễ quên ô này, bỏ sót ô kia. Dân kỹ thuật có một cách quen thuộc để xử lý chuyện đó: biến template thành &lt;strong&gt;dữ liệu có cấu trúc&lt;/strong&gt;, rồi viết một script nhỏ để kiểm tra. Bài này hướng dẫn từng bước làm việc đó với YAML và Python, khoảng 60 dòng code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lưu ý: script chỉ kiểm tra "đủ ô" và vài lỗi hình thức. Nó không chấm được nội dung có hữu ích hay không. Phần đó vẫn cần người biên tập.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Bước 1: Định nghĩa brief bằng YAML
&lt;/h2&gt;

&lt;p&gt;Tạo file &lt;code&gt;brief.yaml&lt;/code&gt; cho mỗi bài:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;keyword&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mẫu&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bài&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;viết&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;chuẩn&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;seo"&lt;/span&gt;
&lt;span class="na"&gt;secondary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;template&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bài&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;viết&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;seo"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;intent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;informational&lt;/span&gt;        &lt;span class="c1"&gt;# informational | commercial | transactional | navigational&lt;/span&gt;
&lt;span class="na"&gt;reader&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;người&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;viết&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;mới,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;đã&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;biết&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;SEO&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;cơ&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bản"&lt;/span&gt;
&lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tự&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;lập&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;brief&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;và&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;dàn&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bài&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;mà&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;không&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bỏ&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;sót&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;onpage"&lt;/span&gt;
&lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cluster&lt;/span&gt;                &lt;span class="c1"&gt;# pillar | cluster | landing | tool&lt;/span&gt;
&lt;span class="na"&gt;must_answer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Mẫu&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;gồm&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;những&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;phần&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;nào?"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Điền&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;brief&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;thế&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;nào?"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Kiểm&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tra&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;gì&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;trước&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;khi&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;đăng?"&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Mẫu&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bài&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;viết&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;chuẩn&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;SEO:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;template&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;có&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ví&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;dụ"&lt;/span&gt;
&lt;span class="na"&gt;meta&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Brief,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;dàn&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ý&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;heading&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;và&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;checklist&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Onpage&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;điền&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;sẵn,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;kèm&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ví&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;dụ&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;thật."&lt;/span&gt;
&lt;span class="na"&gt;internal_links&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/blog/search-intent-la-gi"&lt;/span&gt;
&lt;span class="na"&gt;sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Google&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Search&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Central&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;helpful&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;content"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Điểm quan trọng: &lt;code&gt;task&lt;/code&gt; và &lt;code&gt;must_answer&lt;/code&gt; là bắt buộc. Một brief chỉ có keyword và số từ là brief chưa xong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bước 2: Viết bản nháp bằng Markdown
&lt;/h2&gt;

&lt;p&gt;Bản nháp &lt;code&gt;draft.md&lt;/code&gt; dùng &lt;code&gt;#&lt;/code&gt; cho H1, &lt;code&gt;##&lt;/code&gt; cho H2. Mỗi H2 nên ứng với một câu hỏi trong &lt;code&gt;must_answer&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bước 3: Viết script kiểm tra
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# check_brief.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;yaml&lt;/span&gt;

&lt;span class="n"&gt;REQUIRED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;keyword&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;intent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reader&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;task&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;must_answer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;meta&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;brief_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;draft_path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;yaml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safe_load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;brief_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;md&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;draft_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;issues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="c1"&gt;# 1. Brief đủ ô
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;REQUIRED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;issues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;brief thiếu: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 2. Độ dài title/meta theo quy ước biên tập (không phải quy định của Google)
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;issues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title &amp;gt; 60 ký tự&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;meta&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;160&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;issues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;meta &amp;gt; 160 ký tự&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 3. Đúng một H1
&lt;/span&gt;    &lt;span class="n"&gt;h1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;^# (.+)$&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;issues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cần đúng 1 H1, đang có &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 4. Keyword bị nhồi vào heading?
&lt;/span&gt;    &lt;span class="n"&gt;h2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;^## (.+)$&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;kw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;keyword&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;stuffed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;h2&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;kw&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;h2&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stuffed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;issues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hơn nửa số H2 lặp keyword chính&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 5. Mỗi câu hỏi bắt buộc có H2 tương ứng (so khớp thô theo từ)
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;must_answer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]):&lt;/span&gt;
        &lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\w+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\w+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;issues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chưa thấy H2 trả lời: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 6. Số liệu không có nguồn (heuristic: có % mà không có link)
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splitlines&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;issues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;số liệu chưa dẫn nguồn: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;issues&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;problems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;problems&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OK: không phát hiện lỗi hình thức&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;problems&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Chạy thử:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;pyyaml
python check_brief.py brief.yaml draft.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bước 4: Đưa vào quy trình
&lt;/h2&gt;

&lt;p&gt;Vài cách dùng thực tế:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pre-commit hook&lt;/strong&gt;: nếu nội dung nằm trong repo (Hugo, Astro, Next.js), chặn commit khi script trả mã lỗi.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI&lt;/strong&gt;: chạy trong GitHub Actions cho mỗi pull request chứa file &lt;code&gt;.md&lt;/code&gt; mới, để reviewer thấy danh sách lỗi trước khi đọc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Biên tập thủ công&lt;/strong&gt;: ngay cả khi không có repo, chạy script trên bản export Markdown từ Google Docs hoặc Notion cũng đủ bắt được lỗi quên ô.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Bước 5: Biết giới hạn của script
&lt;/h2&gt;

&lt;p&gt;Script này không biết:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bài có thật sự trả lời đúng ý định tìm kiếm không.&lt;/li&gt;
&lt;li&gt;Ví dụ và số liệu có chính xác không (nó chỉ phát hiện thiếu link nguồn).&lt;/li&gt;
&lt;li&gt;Mở bài có đi thẳng vào vấn đề không.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hướng dẫn về nội dung hữu ích của Google Search Central cũng không đặt ra số từ hay mật độ từ khóa cố định. Vì vậy hãy coi script như lan can chống bỏ sót, không phải công thức xếp hạng.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lấy phần template ở đâu?
&lt;/h2&gt;

&lt;p&gt;Các ô trong &lt;code&gt;brief.yaml&lt;/code&gt; ở trên được rút gọn từ &lt;a href="https://manhdigital.com/blog/mau-bai-viet-chuan-seo" rel="noopener noreferrer"&gt;bộ template bài viết chuẩn SEO của Mạnh Digital&lt;/a&gt;, trong đó có bảng giải thích từng ô brief, khung heading và checklist Onpage đầy đủ. Bạn có thể map thêm các mục checklist thành rule mới cho script, ví dụ kiểm tra alt ảnh hoặc canonical.&lt;/p&gt;

&lt;p&gt;Nếu bạn đã tự động hóa phần kiểm tra content theo cách khác, chia sẻ ở phần bình luận nhé.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>python</category>
      <category>writing</category>
      <category>automation</category>
    </item>
    <item>
      <title>Checklist kỹ thuật để website vừa lên Google vừa được AI trích dẫn</title>
      <dc:creator>Mạnh Digital</dc:creator>
      <pubDate>Tue, 20 Oct 2026 08:15:33 +0000</pubDate>
      <link>https://dev.to/manhdigital68/checklist-ky-thuat-de-website-vua-len-google-vua-duoc-ai-trich-dan-3nlp</link>
      <guid>https://dev.to/manhdigital68/checklist-ky-thuat-de-website-vua-len-google-vua-duoc-ai-trich-dan-3nlp</guid>
      <description>&lt;p&gt;Bài này dành cho dev và người tự quản website. Mình tổng hợp lại cách &lt;a href="https://manhdigital.com" rel="noopener noreferrer"&gt;Mạnh Digital&lt;/a&gt; phân biệt hai lớp tối ưu: SEO website truyền thống và SEO AI (GEO/AEO). Không có trick, chỉ là những tín hiệu mà Google và các công cụ AI dùng để hiểu một trang.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hai hệ thống, một nền móng
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tiêu chí&lt;/th&gt;
&lt;th&gt;SEO website&lt;/th&gt;
&lt;th&gt;SEO AI&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mục tiêu&lt;/td&gt;
&lt;td&gt;Lên top khi khách tìm trên Google&lt;/td&gt;
&lt;td&gt;Được nhắc tên, trích dẫn trong câu trả lời của AI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nơi hiển thị&lt;/td&gt;
&lt;td&gt;Google Search, Google Maps&lt;/td&gt;
&lt;td&gt;ChatGPT, Gemini, Perplexity, Copilot, Google AI Overviews&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tín hiệu chính&lt;/td&gt;
&lt;td&gt;Kỹ thuật, độ liên quan, backlink, trải nghiệm trang&lt;/td&gt;
&lt;td&gt;Thông tin thương hiệu nhất quán, câu trả lời rõ ràng, nguồn bên ngoài nhắc tới&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Chung một nền: trang được Google index tốt, và nội dung trả lời đúng câu hỏi người dùng. Nếu lớp dưới hỏng thì lớp trên cũng không đứng được.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lớp 1: indexing và kỹ thuật
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Trang quan trọng nằm trong sitemap, không bị &lt;code&gt;noindex&lt;/code&gt; nhầm.&lt;/li&gt;
&lt;li&gt;[ ] URL cũ đã 301 thì gỡ khỏi sitemap, sửa link nội bộ trỏ thẳng về URL mới.&lt;/li&gt;
&lt;li&gt;[ ] Mỗi trang có một title riêng, không bị hard-code trong template khiến CMS không đổi được.&lt;/li&gt;
&lt;li&gt;[ ] Tốc độ tải ổn trên mobile. Gói Growth của Mạnh Digital có hạng mục riêng cho tốc độ.&lt;/li&gt;
&lt;li&gt;[ ] Kiểm tra trạng thái index định kỳ trong Search Console.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Lớp 2: nội dung trả lời thẳng
&lt;/h2&gt;

&lt;p&gt;AI thích đoạn văn trả lời ngay câu hỏi trong 1–3 câu đầu, sau đó mới giải thích. Gợi ý cấu trúc:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;H2: &amp;lt;câu hỏi thật của khách&amp;gt;
Đoạn 1: câu trả lời ngắn, có số liệu nếu có
Đoạn 2+: giải thích, ví dụ, ngoại lệ
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Trang chủ manhdigital.com làm điều này ở phần FAQ: "Có cam kết chắc chắn được AI nhắc tên không?" và câu đầu là "Không." Rõ ràng, dễ trích.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lớp 3: thực thể thương hiệu
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Tên, địa chỉ, số điện thoại giống hệt nhau trên website, Google Business Profile và mạng xã hội.&lt;/li&gt;
&lt;li&gt;[ ] Có trang hồ sơ người phụ trách (author/founder) với kinh nghiệm thật.&lt;/li&gt;
&lt;li&gt;[ ] Có nguồn bên ngoài nhắc tới thương hiệu: báo, diễn đàn, hồ sơ doanh nghiệp.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ví dụ thông tin nhất quán: Mạnh Digital, Tòa AZ Sky, Định Công, Hoàng Mai, điện thoại 0396 200 150.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lớp 4: đo lường
&lt;/h2&gt;

&lt;p&gt;Không đo thì không biết có tác dụng không. Search Console cho số lượt nhấp, hiển thị, vị trí; GA4 cho hành vi và chuyển đổi. Case Kho Tài Khoản trên trang chủ dùng đúng nguồn này: khoảng 193 nghìn lượt nhấp và 1,4 triệu lượt hiển thị trong 12 tháng theo ảnh GSC chụp 05/10/2026.&lt;/p&gt;

&lt;p&gt;Lưu ý: không có cách nào đo chính xác "AI nhắc tên bao nhiêu lần" qua API chính thức. Gói Strategy của Mạnh Digital có hạng mục theo dõi AI nhắc tên, nhưng chính họ cũng nói không ai kiểm soát được câu trả lời của AI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Timeline thực tế
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Tuần 1–4: sửa kỹ thuật, trang dịch vụ, thông tin thương hiệu.&lt;/li&gt;
&lt;li&gt;Sau đó: thứ hạng và khả năng được AI nhắc tên thay đổi chậm hơn, tùy ngành và độ cạnh tranh.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Khi nào nên nhờ người ngoài?
&lt;/h2&gt;

&lt;p&gt;Nếu bạn là dev, lớp 1 bạn tự làm được. Lớp 2 và 3 tốn thời gian nghiên cứu từ khóa và viết. Bảng giá tham khảo của &lt;a href="https://manhdigital.com/dich-vu/seo-tong-the" rel="noopener noreferrer"&gt;dịch vụ SEO tổng thể&lt;/a&gt; bên đó: Starter từ 9 triệu/tháng (5–10 từ khóa, 2–4 bài/tháng), Growth từ 15 triệu (15–25 từ khóa, 4–8 bài), Strategy từ 25 triệu (30–50 từ khóa, 8–12 bài). Chưa gồm VAT.&lt;/p&gt;

&lt;p&gt;Happy optimizing. Nếu có checklist hay hơn, comment bên dưới nhé.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>google</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Debug lỗi không index như debug code: đọc log Search Console trước</title>
      <dc:creator>Mạnh Digital</dc:creator>
      <pubDate>Tue, 20 Oct 2026 01:50:47 +0000</pubDate>
      <link>https://dev.to/manhdigital68/debug-loi-khong-index-nhu-debug-code-doc-log-search-console-truoc-e8o</link>
      <guid>https://dev.to/manhdigital68/debug-loi-khong-index-nhu-debug-code-doc-log-search-console-truoc-e8o</guid>
      <description>&lt;p&gt;Khi production báo lỗi, không ai sửa bừa. Mình mở log, tìm stack trace, khoanh vùng module rồi mới viết patch. Thế nhưng với SEO, rất nhiều developer lại làm ngược: trang không lên Google là lập tức bấm "Request Indexing" năm bảy lần, như bấm F5 khi API trả về 500. Bài này là cách mình áp tư duy debug vào bài toán index, dựa trên hướng dẫn &lt;a href="https://manhdigital.com/blog/index-la-gi" rel="noopener noreferrer"&gt;Index là gì trong SEO&lt;/a&gt; của team Mạnh Digital.&lt;/p&gt;

&lt;h2&gt;
  
  
  Định nghĩa vấn đề cho đúng
&lt;/h2&gt;

&lt;p&gt;Trong ngữ cảnh SEO, index nghĩa là Google đã đọc trang, hiểu nội dung và lưu nó vào chỉ mục — cái database mà Google query mỗi khi người dùng tìm kiếm. Không có bản ghi trong database thì không có kết quả trả về, đơn giản vậy thôi. Nhưng có bản ghi cũng không có nghĩa là bạn ở top; đó mới là điều kiện cần.&lt;/p&gt;

&lt;p&gt;Một điểm dev hay giả định sai: Google không có SLA nào về việc index toàn bộ site. Tài liệu chính thức nói thẳng rằng bạn không nên kỳ vọng mọi URL đều được lập chỉ mục. Vậy "bug" ở đây không phải là "có URL chưa được index", mà là "URL quan trọng chưa được index".&lt;/p&gt;

&lt;h2&gt;
  
  
  Hai stage: fetch và store
&lt;/h2&gt;

&lt;p&gt;Hãy hình dung pipeline gồm hai bước. Bước một là crawl: Googlebot gửi request, tải HTML về. Bước hai là index: hệ thống quyết định có ghi trang đó vào chỉ mục hay không. Hai bước chạy nối tiếp nhưng độc lập — một URL có thể được fetch hàng chục lần mà vẫn bị từ chối ghi.&lt;/p&gt;

&lt;p&gt;Vì vậy Search Console có hai trạng thái nghe rất giống nhau:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Đã phát hiện thấy – hiện chưa được lập chỉ mục&lt;/strong&gt;: URL đã nằm trong hàng đợi nhưng chưa được fetch. Lỗi nằm ở stage một.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Đã thu thập dữ liệu – hiện chưa được lập chỉ mục&lt;/strong&gt;: fetch xong rồi, nhưng stage hai trả về "chưa lưu". Lỗi nằm ở stage hai.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nhầm hai cái này giống như debug frontend trong khi bug nằm ở backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Đọc log: công cụ Kiểm tra URL
&lt;/h2&gt;

&lt;p&gt;Công cụ Kiểm tra URL trong Search Console là thứ gần với log nhất. Paste URL vào thanh trên cùng, kết quả "URL nằm trên Google" nghĩa là pass. Nếu là "URL không nằm trên Google", mở phần Lập chỉ mục trang để thấy reason code và thời điểm crawl gần nhất.&lt;/p&gt;

&lt;p&gt;Nút "Kiểm tra URL đang hoạt động" thì giống chạy test trên bản build mới: nó cho biết phiên bản hiện tại có index được không, rất tiện khi bạn vừa deploy bản gỡ thẻ noindex. Lưu ý công cụ này có rate limit theo ngày cho mỗi property, nên đừng viết script dò từng URL.&lt;/p&gt;

&lt;p&gt;Còn lệnh &lt;code&gt;site:&lt;/code&gt; trên Google? Coi nó như &lt;code&gt;console.log&lt;/code&gt; tạm bợ: nhanh, nhưng không đáng tin để kết luận, vì Google xác nhận kết quả không phải lúc nào cũng đầy đủ. Lệnh &lt;code&gt;cache:&lt;/code&gt; thì đã bị gỡ từ 2024, đừng copy từ tutorial cũ nữa.&lt;/p&gt;

&lt;h2&gt;
  
  
  Những "reason code" thường gặp
&lt;/h2&gt;

&lt;p&gt;Phần lớn URL trong nhóm không được lập chỉ mục là hành vi đúng, không phải bug. Một vài mã và cách xử lý:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;URL có đánh dấu noindex&lt;/strong&gt; — chỉ sửa nếu bạn gắn nhầm, ví dụ template staging lọt lên production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bị chặn bởi robots.txt&lt;/strong&gt; — kiểm tra lại rule Disallow. Lưu ý: nếu chặn crawl, Google không đọc được thẻ noindex bên trong trang.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trang thay thế có thẻ chính tắc thích hợp&lt;/strong&gt; — expected behavior, bỏ qua.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google chọn canonical khác với bạn&lt;/strong&gt; — hai trang quá giống nhau; làm rõ trang chính, gộp hoặc tách nội dung.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trang có lệnh chuyển hướng&lt;/strong&gt; — dọn URL cũ khỏi sitemap và link nội bộ.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;404 / soft 404&lt;/strong&gt; — khôi phục, redirect sang trang tương đương, hoặc để 404 nếu trang thật sự đã chết.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Khi không có error để chỉ tay
&lt;/h2&gt;

&lt;p&gt;Case khó nhất là "đã thu thập dữ liệu" vì không có lỗi kỹ thuật. Thường root cause là một trong ba: nội dung trùng ý với trang khác trên chính site, trang gần như không có internal link trỏ tới, hoặc nội dung không khác gì hàng chục bài cùng chủ đề. Fix là refactor nội dung, không phải retry.&lt;/p&gt;

&lt;p&gt;Với "đã phát hiện thấy" trên site nhỏ, nguyên nhân phổ biến là trang chỉ có trong sitemap.xml mà không có link nội bộ nào. Crawl budget hiếm khi là vấn đề — Google nói chủ đề này dành cho site khoảng một triệu trang hoặc khoảng mười nghìn trang thay đổi mỗi ngày.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quy trình fix gợi ý
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Inspect URL, ghi lại reason code.&lt;/li&gt;
&lt;li&gt;Loại trừ blocker kỹ thuật: meta robots, robots.txt, canonical, redirect.&lt;/li&gt;
&lt;li&gt;Thêm internal link từ những trang đã được index.&lt;/li&gt;
&lt;li&gt;Cải thiện hoặc gộp nội dung trùng.&lt;/li&gt;
&lt;li&gt;Kiểm tra sitemap, rồi request indexing đúng một lần.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Mình khuyên thêm bước kiểm tra meta robots và canonical vào checklist CI trước khi deploy. Nếu team bạn không có người chuyên technical SEO, có thể tham khảo &lt;a href="https://manhdigital.com" rel="noopener noreferrer"&gt;dịch vụ SEO tại Hà Nội&lt;/a&gt; của Mạnh Digital — bài gốc của họ có bảng tra đầy đủ từng trạng thái.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>google</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
