Changelog

Lịch sử cập nhật & PR của blog · gần đây nhất ở trên

  1. fix(links): bỏ placeholder ![alt](url) gây broken internal link [claude/vssid-bhtn-analysis-seo-arvwmx]

    fix
    • content: bài phân tích VssID không hiển thị quá trình BHTN
    • fix(links): bỏ placeholder !alt gây broken internal link
    • content/posting/viet-blog-bang-local-terminal-khi-ai-het-credit.md (modified, +1/-1)
    • content/posting/vssid-thieu-bhtn-bhtnld-bnn-thoi-gian-bao-luu.md (added, +129/-0)
    • QA Gatekeeper (qa-check): 🟡 đang chạy — qa-check đang chạy
    PR #720 −1 dòng xóa · +130 dòng thêm · Net +129 dòng
  2. update SEO QA scores for 2 new blog posts [claude/beautiful-hopper-eyedqd]

    chore
    • feat: publish 2 blog posts on terminal commands and tools
    • chore: update SEO QA scores for 2 new blog posts
    • content/posting/cac-lenh-terminal-kiem-tra-pr-github.md (added, +358/-0)
    • content/posting/top-10-cong-cu-terminal-mac-2026.md (added, +431/-0)
    • data/seo-qa-scores.json (modified, +203/-1)
    PR #715 −1 dòng xóa · +992 dòng thêm · Net +991 dòng
  3. CMS: bỏ Featured cũ khi chọn 'viet-blog-bang-local-terminal-khi-ai-het-credit'

    chore
    −1 dòng xóa · +0 dòng thêm · Net -1 dòng
  4. CMS: bỏ Featured cũ khi chọn 'viet-blog-bang-local-terminal-khi-ai-het-credit'

    chore
    −2 dòng xóa · +0 dòng thêm · Net -2 dòng
  5. CMS: bỏ Featured cũ khi chọn 'viet-blog-bang-local-terminal-khi-ai-het-credit'

    chore
    −1 dòng xóa · +0 dòng thêm · Net -1 dòng
  6. CMS: bỏ Featured cũ khi chọn 'viet-blog-bang-local-terminal-khi-ai-het-credit'

    chore
    −1 dòng xóa · +0 dòng thêm · Net -1 dòng
  7. CMS: bỏ Featured cũ khi chọn 'viet-blog-bang-local-terminal-khi-ai-het-credit'

    chore
    −2 dòng xóa · +0 dòng thêm · Net -2 dòng
  8. CMS: cập nhật bài 'Viết blog bằng local terminal khi AI hết credit'

    chore
    −9 dòng xóa · +4 dòng thêm · Net -5 dòng
  9. chore(tools): restore dashboard Python deps omitted by #705 route restore [claude/nice-planck-9stwce]

    chore
    • scripts/requirements-f-dashboard.txt (added, +1/-0)
    • scripts/requirements-l-dashboard.txt (added, +1/-0)
    • QA Gatekeeper (qa-check): ⏳ chưa chạy — qa-check chưa chạy cho head sha
    • Auto-merge chỉ chạy khi qa-check xanh (gated qua try_auto_merge.py).
    • Squash-merge → 1 commit duy nhất trên main; revert bằng git revert <merge_sha> rồi push qua PR là rollback hoàn toàn.
    PR #709 −0 dòng xóa · +2 dòng thêm · Net +2 dòng
  10. fix(seo): restyle fallback OG card — red CTA, editorial, Vietnamese-safe font [fix/og-fallback-red-editorial-clean]

    fix
    • static/img/og-manifest.json (modified, +1/-1)
    • static/img/og/seomoney-og.og.webp (modified, +0/-0)
    • static/img/og/seomoney-og.svg (modified, +59/-45)
    • QA Gatekeeper (qa-check): 🟡 đang chạy — qa-check đang chạy
    • Auto-merge chỉ chạy khi qa-check xanh (gated qua try_auto_merge.py).
    PR #708 −46 dòng xóa · +60 dòng thêm · Net +14 dòng
  11. fix(tools): restore F/H/L/O dashboard routes removed by #653 + V30 guard [claude/nice-planck-9stwce]

    fix
    • CLAUDE.md (modified, +3/-0)
    • content/tools/_index.md (modified, +19/-0)
    • content/tools/f-dashboard.md (added, +8/-0)
    • content/tools/h-dashboard.md (added, +8/-0)
    • content/tools/l-dashboard.md (added, +8/-0)
    PR #707 −0 dòng xóa · +20280 dòng thêm · Net +20280 dòng
  12. feat(images): add global blog image watermark rule [feat/blog-image-watermark]

    chore
    • Quét static/img/**, ext .jpg .jpeg .png .webp.
    • Bỏ qua: *.og.webp (OG/social twin), thư mục brand/ og/ placeholder/ icons/ flags/, tên favicon/apple-touch/logo/sprite/placeholder/og-default/author-avatar/-mark, và .svg/.gif/.ico.
    • ⇒ nhắm ảnh bài viết static/img/posting/* + cover bài static/img/covers/.webp (không phải .og.webp).
    • data/image-watermark-manifest.json: path → {hash16, watermark_text, source_sha256, watermarked_sha256, processed_at}.
    • Re-run bỏ qua ảnh có watermarked_sha256 khớp (không cần Pillow). Mỗi ảnh mang thêm EXIF/PNG marker seomoney-wm:<hash> đi theo pixel. Ảnh đổi nội dung → watermark lại hash mới. Manifest chỉ ghi khi có
    PR #699 −4 dòng xóa · +741 dòng thêm · Net +737 dòng
  13. feat(blog): add terminal production posts 2-3, fix post-1 webp refs [feat/blog-terminal-production-cluster]

    fix
    • content/posting/cac-lenh-git-dua-blog-len-production.md (added, +253/-0)
    • content/posting/fix-qa-gatekeeper-github-actions-merge-conflict-zola.md (modified, +2/-2)
    • content/posting/viet-blog-bang-local-terminal-khi-ai-het-credit.md (added, +172/-0)
    • QA Gatekeeper (qa-check): 🟡 đang chạy — qa-check đang chạy
    • Auto-merge chỉ chạy khi qa-check xanh (gated qua try_auto_merge.py).
    PR #698 −2 dòng xóa · +427 dòng thêm · Net +425 dòng
  14. fix(qa-404): remove dead internal links blocking the QA gate

    remove
    • base.html: drop dead /admin-author/ + /admin-countdown/ footer links
    • cms.html: drop dead /admin-author/, /admin-countdown/, /admin/paywall/ links
    • insights.html: drop dead /authority-report/, /ad-report/, /ad-report-v2/ links (keep data cards)
    • content.md: drop 7 dead tool-registry entries (o/f/l/h-dashboard, ad-report*, authority-report)
    • 9 posts + series.md: unlink dead O/F-Dashboard + Content Creator CTAs (prose kept)
    PR #693 −108 dòng xóa · +52 dòng thêm · Net -56 dòng
  15. SEO11: thêm meta description + seo_keyword cho 2 trang còn thiếu

    chore
    • content/posting/ai-thay-doi-lap-ke-hoach-du-lich.md: thêm meta description (148 ký tự, chứa keyword chính) + [extra] seo_keyword "AI lập kế hoạch du lịch" (vốn đã xuất hiện ở title/intro/H2) → điểm SE
    • content/topic/_index.md: thêm description cho section hub Topic Pillars.
    PR #681 −0 dòng xóa · +3 dòng thêm · Net +3 dòng
  16. SEO + AdSense Strategy Hotfix: Canonicalization, GSC Persistence, Reader-Supported Model

    chore
    • robots.txt: Expanded disallow rules from 3 to 19 utility paths (editor, admin, cms, dashboards, tools, GSC, etc.)
    • base.html: Query string stripping on canonical URLs; auto-detect noindex for utility routes
    • page.html: Added noindex frontmatter flag support
    • section.html: Noindex logic for thin tags (≤1 post) and utility sections
    • paywall.html: Changed "Bài viết premium — cần thanh toán để mở khóa nội dung" → "Premium bài viết — Ủng hộ tác giả qua reader-supported model"
    PR #679 −215 dòng xóa · +912 dòng thêm · Net +697 dòng
  17. feat(shortcut): add dantri inspired blog writing shortcut

    chore
    • Added dantri to shortcuts table in shortcuts.md with brief description
    • Added full dantri section definition in shortcuts.md with complete workflow and rules
    • Created .claude/commands/dantri.md handler with parse, execution, and output specs
    • User types: dantri
    • Response: Asks for source content/link + excerpt
    PR #677 −0 dòng xóa · +108 dòng thêm · Net +108 dòng
  18. feat(shortcut): add dantri inspired blog writing shortcut [claude/hopeful-rubin-g4t52d]

    chore
    • .claude/commands/dantri.md (added, +40/-0)
    • shortcuts.md (modified, +68/-0)
    • QA Gatekeeper (qa-check): 🟡 đang chạy — qa-check đang chạy
    • Auto-merge chỉ chạy khi qa-check xanh (gated qua try_auto_merge.py).
    • Squash-merge → 1 commit duy nhất trên main; revert bằng git revert <merge_sha> rồi push qua PR là rollback hoàn toàn.
    PR #674 −0 dòng xóa · +108 dòng thêm · Net +108 dòng
  19. publish case study on Auto Fixer self-healing CI/CD pipeline [claude/amazing-goldberg-9hwo4r]

    feat
    • content/posting/auto-fixer-tu-cuu-bai-viet-ve-auto-fixer.md (added, +262/-0)
    • data/seo-qa-scores.json (modified, +100/-1)
    • QA Gatekeeper (qa-check): 🟡 đang chạy — qa-check đang chạy
    • Auto-merge chỉ chạy khi qa-check xanh (gated qua try_auto_merge.py).
    • Squash-merge → 1 commit duy nhất trên main; revert bằng git revert <merge_sha> rồi push qua PR là rollback hoàn toàn.
    PR #673 −1 dòng xóa · +362 dòng thêm · Net +361 dòng
  20. header/menu regression: navbar to right with 2-item max

    fix
    • Move navbar menu from hidden (display: none) to visible with flex layout
    • Position navbar menu on right side using margin-left: auto
    • Limit visible menu items to max 2 using nth-child(n+3) { display: none }
    • Hide navbar menu on mobile/tablet (≤960px) to prevent duplication
    • Add proper styling for navbar items with padding and hover effects
    PR #670 −12 dòng xóa · +39 dòng thêm · Net +27 dòng
  21. vaccine cheat sheet to static for public deployment

    refactor
    PR #669
  22. README.md

    chore
    −176 dòng xóa · +0 dòng thêm · Net -176 dòng
  23. Remove broken link to non-existent f-dashboard page

    fix
    −1 dòng xóa · +1 dòng thêm · Net +0 dòng
  24. Hide duplicate navbar menu since items now in side-nav [claude/adoring-archimedes-6jhi8o]

    fix
    • Di chuyển menu chính sang sidebar bên phải
    • fix: add missing admin-countdown.js for footer countdown preview
    • Fix: Hide duplicate navbar menu since items now in side-nav
    • sass/_side-nav.scss (modified, +5/-0)
    • static/js/admin-countdown.js (added, +196/-0)
    PR #664 −0 dòng xóa · +242 dòng thêm · Net +242 dòng
  25. add missing admin-countdown.js for footer countdown preview [claude/adoring-archimedes-6jhi8o]

    fix
    • Di chuyển menu chính sang sidebar bên phải
    • fix: add missing admin-countdown.js for footer countdown preview
    • static/js/admin-countdown.js (added, +196/-0)
    • templates/base.html (modified, +41/-0)
    • QA Gatekeeper (qa-check): 🟡 đang chạy — qa-check đang chạy
    PR #663 −0 dòng xóa · +237 dòng thêm · Net +237 dòng
  26. chore(seo-qa): update scores for auto-fixer blog post [claude/great-thompson-xhacsj]

    chore
    • feat(blog): Auto Fixer - GitHub Actions self-healing pipeline
    • chore(seo-qa): update scores for auto-fixer blog post
    • content/posting/auto-fixer-github-actions-he-mien-dich-tu-chua-loi-blog.md (added, +273/-0)
    • data/seo-qa-scores.json (modified, +102/-1)
    • QA Gatekeeper (qa-check): 🟡 đang chạy — qa-check đang chạy
    PR #658 −1 dòng xóa · +375 dòng thêm · Net +374 dòng
  27. fix(content-routing): remove duplicate Auto Fixer article from baochi/

    remove
    −181 dòng xóa · +0 dòng thêm · Net -181 dòng
  28. fix(qa-workflow): Conditionally install dashboard requirements if they exist [claude/tender-bardeen-xurrse]

    fix
    • fix(V21-header-regression): Move cache button from navbar to sidebar
    • fix(qa-workflow): Conditionally install dashboard requirements if they exist
    • .github/workflows/qa.yml (modified, +14/-6)
    • sass/_sidebar.scss (modified, +62/-0)
    • templates/base.html (modified, +19/-14)
    PR #657 −20 dòng xóa · +95 dòng thêm · Net +75 dòng
  29. Claude/ecstatic mccarthy s0v1ar

    chore
    PR #660 −3 dòng xóa · +408 dòng thêm · Net +405 dòng
  30. feat(admin-zone): Add protected backend PDF endpoint for Operation Guideline [claude/busy-fermi-7m8mjx]

    chore
    • services/vipzone/admin_guideline_pdf.py (added, +271/-0)
    • services/vipzone/main.py (modified, +30/-0)
    • services/vipzone/test_admin_guideline_endpoint.py (added, +122/-0)
    • services/vipzone/test_admin_guideline_pdf.py (added, +143/-0)
    • static/js/admin-zone/pdf.js (modified, +69/-9)
    PR #652 −9 dòng xóa · +635 dòng thêm · Net +626 dòng
  31. Phase 1 only — remove Phase 2 features (dashboards, admin zone)

    chore
    • 4 workflows: ad-report-v2, authority-booster, build-dashboard, content-creator
    • 4 dashboards: f-dashboard, h-dashboard, l-dashboard, o-dashboard (templates, content, JS, SCSS)
    • 8+ admin pages: admin-author, admin-countdown, paywall admin, shortensea admin
    • 9 SCSS partials for dashboards and admin zones
    • 7 Python scripts: dashboard parsers, insights engines
    PR #653 −32567 dòng xóa · +1 dòng thêm · Net -32566 dòng
  32. docs(operator): Phase 1 shortcut grouping and quickstart guides

    chore
    • Keep Phase 1 only
    • Add/update operator shortcut grouping docs
    • Add bilingual operator quickstart decision flows
    • Add UI layout sketches for future Phase 2
    • No dashboard, manifest, alias infrastructure, shortcut search/filter, Admin Zone PDF wiring
    PR #651 −1 dòng xóa · +536 dòng thêm · Net +535 dòng
  33. content(tech): add Git push rejected and QA workflow guide [claude/tender-einstein-4zz7uf]

    chore
    • refactor: compress CLAUDE.md to 31KB, move vaccine details to archive
    • content(tech): add Git push rejected and QA workflow guide
    • CLAUDE.md (modified, +89/-2832)
    • content/posting/git-push-bi-reject-cach-xu-ly-an-toan-tren-mac.md (added, +273/-0)
    • data/seo-qa-scores.json (modified, +100/-1)
    PR #650 −2833 dòng xóa · +3459 dòng thêm · Net +626 dòng
  34. feat(admin-zone): Add admin-only utility page with Operation Guideline search, PDF export with watermark, and usage stats [claude/busy-fermi-7m8mjx]

    chore
    • content/tools/admin-zone.md (added, +10/-0)
    • sass/_admin-zone.scss (added, +499/-0)
    • sass/site.scss (modified, +1/-0)
    • scripts/test_admin_zone.py (added, +245/-0)
    • static/js/admin-zone/app.js (added, +97/-0)
    PR #648 −0 dòng xóa · +1669 dòng thêm · Net +1669 dòng
  35. fix(seo): shorten VssID BHXH article title

    fix
    −1 dòng xóa · +1 dòng thêm · Net +0 dòng
  36. docs(operator): Phase 1 vaccine shortcut grouping guide

    chore
    • Add Phase 1 operator shortcut grouping documentation
    • Define top-5 operational functions: fix-merge, fix-deploy, fix-seo, fix-ui, fix-gsc-ga
    • Add bilingual EN/VI decision flows and UI layout sketches
    • Keep CLAUDE.md, qa_vaccines.py, and vaccine registry unchanged
    • CLAUDE.md diff: 0 changes
    PR #649 −1 dòng xóa · +536 dòng thêm · Net +535 dòng
  37. compress CLAUDE.md to 31KB, move vaccine details to archive [claude/tender-einstein-4zz7uf]

    refactor
    • CLAUDE.md (modified, +89/-2832)
    • docs/vaccine-archive.md (added, +2997/-0)
    • QA Gatekeeper (qa-check): 🟡 đang chạy — qa-check đang chạy
    • Auto-merge chỉ chạy khi qa-check xanh (gated qua try_auto_merge.py).
    • Squash-merge → 1 commit duy nhất trên main; revert bằng git revert <merge_sha> rồi push qua PR là rollback hoàn toàn.
    PR #647 −2832 dòng xóa · +3086 dòng thêm · Net +254 dòng
  38. docs(guides): operator guide Phase 1 — decision flows and UI layout sketches [claude/optimistic-goldberg-r4pg2j]

    chore
    • chore(docs): operator guide Phase 1 — grouping vaccine shortcuts into 5 top-level functions
    • docs(guides): operator guide Phase 1 — decision flows and UI layout sketches
    • .claude/OPERATOR-QUICKSTART.md (added, +193/-0)
    • .claude/ui-layout.md (added, +303/-0)
    • shortcuts.md (modified, +40/-1)
    PR #646 −1 dòng xóa · +536 dòng thêm · Net +535 dòng
  39. Add vaccine operator cheat sheet (printable A4) [claude/quirky-gauss-lowevj]

    chore
    • vaccine-cheat-sheet.html (added, +755/-0)
    • QA Gatekeeper (qa-check): 🟡 đang chạy — qa-check đang chạy
    • Auto-merge chỉ chạy khi qa-check xanh (gated qua try_auto_merge.py).
    • Squash-merge → 1 commit duy nhất trên main; revert bằng git revert <merge_sha> rồi push qua PR là rollback hoàn toàn.
    • Chưa merge: đóng PR + xoá branch claude/quirky-gauss-lowevj là đủ (không ảnh hưởng main).
    PR #645 −0 dòng xóa · +755 dòng thêm · Net +755 dòng
  40. chore(vaccine): Daily Vaccine Autofixer run

    chore
    PR #643 −13 dòng xóa · +32 dòng thêm · Net +19 dòng
  41. fix(navbar): remove decorative alphabet letters breaking header layout [claude/loving-maxwell-5n25eh]

    remove
    • templates/base.html (modified, +5/-35)
    • QA Gatekeeper (qa-check): 🟡 đang chạy — qa-check đang chạy
    • Auto-merge chỉ chạy khi qa-check xanh (gated qua try_auto_merge.py).
    • Squash-merge → 1 commit duy nhất trên main; revert bằng git revert <merge_sha> rồi push qua PR là rollback hoàn toàn.
    • Chưa merge: đóng PR + xoá branch claude/loving-maxwell-5n25eh là đủ (không ảnh hưởng main).
    PR #644 −35 dòng xóa · +5 dòng thêm · Net -30 dòng
  42. docs(claude): add local-publish vaccine — no build/dependency artifacts [claude/happy-knuth-f6ax2r]

    chore
    • CLAUDE.md (modified, +29/-0)
    • QA Gatekeeper (qa-check): 🟡 đang chạy — qa-check đang chạy
    • Auto-merge chỉ chạy khi qa-check xanh (gated qua try_auto_merge.py).
    • Squash-merge → 1 commit duy nhất trên main; revert bằng git revert <merge_sha> rồi push qua PR là rollback hoàn toàn.
    • Chưa merge: đóng PR + xoá branch claude/happy-knuth-f6ax2r là đủ (không ảnh hưởng main).
    PR #604 −0 dòng xóa · +29 dòng thêm · Net +29 dòng
  43. chore(gitignore): ignore local seomoney config [chore/ignore-local-seomoney-json]

    chore
    • .gitignore (modified, +3/-0)
    • QA Gatekeeper (qa-check): 🟡 đang chạy — qa-check đang chạy
    • Auto-merge chỉ chạy khi qa-check xanh (gated qua try_auto_merge.py).
    • Squash-merge → 1 commit duy nhất trên main; revert bằng git revert <merge_sha> rồi push qua PR là rollback hoàn toàn.
    • Chưa merge: đóng PR + xoá branch chore/ignore-local-seomoney-json là đủ (không ảnh hưởng main).
    PR #640 −0 dòng xóa · +3 dòng thêm · Net +3 dòng
  44. feat(content): add Mac Terminal app cleanup guide + set as featured [claude/blissful-albattani-nb6ob7]

    cleanup
    • content/posting/cach-xoa-sach-ung-dung-khoi-mac-bang-terminal-84key.md (added, +226/-0)
    • content/posting/tinh-luong-huu-2026-huong-dan.md (modified, +1/-1)
    • data/references.json (modified, +23/-0)
    • data/seo-qa-scores.json (modified, +95/-2)
    • QA Gatekeeper (qa-check): 🟡 đang chạy — qa-check đang chạy
    PR #635 −3 dòng xóa · +345 dòng thêm · Net +342 dòng
  45. docs+feat(triage): Failure Priority Policy — required-on-HEAD-first triage engine [claude/failure-priority-rule-n7ls18]

    chore
    • CLAUDE.md (modified, +58/-0)
    • scripts/failure_priority.py (added, +352/-0)
    • scripts/test_failure_priority.py (added, +157/-0)
    • QA Gatekeeper (qa-check): 🟡 đang chạy — qa-check đang chạy
    • Auto-merge chỉ chạy khi qa-check xanh (gated qua try_auto_merge.py).
    PR #629 −0 dòng xóa · +567 dòng thêm · Net +567 dòng
  46. replace Tera unsupported default(value=[]) with conditional assignment

    fix
    −88 dòng xóa · +168 dòng thêm · Net +80 dòng
  47. feat(wip8): merge theodoi8 into wip8 (single WIP + live CI shortcut)

    chore
    • wip8 = shortcut DUY NHẤT (WIP + TheoDoi8). Không còn theodoi8 riêng.
    • Output đúng 2 heading ##: ## WIP8 table + ## TheoDoi8 table, mobile-readable, fallback khi thiếu data.
    • Banner website "THEODOI8 LIVE" (build_theodoi8_report.py, templates/JS) không đổi — chỉ là nguồn data được reuse.
    • python3 -m py_compile scripts/wip8.py scripts/test_wip8.py → OK
    • cd scripts && python3 -m unittest test_wip8 → 9/9 PASS
    PR #631 −104 dòng xóa · +300 dòng thêm · Net +196 dòng
  48. docs(shortcuts): mobile-safe MD output for shortcut report tables [claude/shortcut-md-mobile-safe-d27hmf]

    chore
    • CLAUDE.md (modified, +17/-15)
    • shortcuts.md (modified, +22/-14)
    • QA Gatekeeper (qa-check): 🟡 đang chạy — qa-check đang chạy
    • Auto-merge chỉ chạy khi qa-check xanh (gated qua try_auto_merge.py).
    • Squash-merge → 1 commit duy nhất trên main; revert bằng git revert <merge_sha> rồi push qua PR là rollback hoàn toàn.
    PR #625 −29 dòng xóa · +39 dòng thêm · Net +10 dòng
  49. feat(perf): Auto Performance Fix Engine — real Google PageSpeed + GA4 APIs [claude/serene-dirac-zn0ppa]

    fix
    • Real Google PageSpeed Insights API: Public endpoint, 25k/day free quota, extracts Core Web Vitals (LCP, CLS, FCP, INP)
    • Real Google Analytics 4 Data API: Service account-based organic search metrics (7-day rolling window)
    • Issue Detection: Automatic threshold checking (LCP > 2.5s, CLS > 0.1, SEO < 90, Performance < 90)
    • Safe Fixes: Lazy loading, image dimensions/aspect-ratio, SEO meta tags (all reversible via git revert)
    • Build Verification: QA check + Zola build validation before committing
    PR #621 −0 dòng xóa · +1797 dòng thêm · Net +1797 dòng
  50. feat(ga-dashboard): production-standard analytics refresh system [claude/ecstatic-lamport-fz94p1]

    chore
    • data/ga-stats.json (modified, +5/-0)
    • sass/_ga-stats.scss (modified, +90/-0)
    • scripts/fetch_ga_stats.py (modified, +98/-1)
    • static/js/ga-stats-refresh.js (added, +223/-0)
    • templates/base.html (modified, +47/-5)
    PR #620 −6 dòng xóa · +463 dòng thêm · Net +457 dòng
  51. resolve CLAUDE manifesto conflict [claude/gracious-newton-0uxf2c]

    fix
    • docs(claude): introduce zero barrier manifesto
    • fix: resolve CLAUDE manifesto conflict
    • CLAUDE.md (modified, +65/-39)
    • QA Gatekeeper (qa-check): 🟡 đang chạy — qa-check đang chạy
    • Auto-merge chỉ chạy khi qa-check xanh (gated qua try_auto_merge.py).
    PR #614 −39 dòng xóa · +65 dòng thêm · Net +26 dòng
  52. fix(claude): remove conflict-marker example triggering QA [claude/amazing-brown-rhu2ne]

    remove
    • chore(ci): enable full auto PR flow for working branches
    • fix(claude): remove conflict-marker example triggering QA
    • .github/workflows/ensure-pr-after-push.yml (modified, +6/-0)
    • CLAUDE.md (modified, +1/-1)
    • data/auto-merge-policy.json (modified, +2/-0)
    PR #617 −1 dòng xóa · +9 dòng thêm · Net +8 dòng
  53. fix(assets): restore shared assets causing repeated 404s

    fix
    PR #618 −6 dòng xóa · +21 dòng thêm · Net +15 dòng
  54. chore(git): ignore private AI notes and local QA artifacts

    chore
    PR #615 −0 dòng xóa · +9 dòng thêm · Net +9 dòng
  55. docs(ci): define tiered QA architecture

    chore
    PR #613 −0 dòng xóa · +98 dòng thêm · Net +98 dòng
  56. docs(claude): add knowledge promotion rule [claude/festive-tesla-wgwmcs]

    chore
    • CLAUDE.md (modified, +132/-0)
    • QA Gatekeeper (qa-check): 🟡 đang chạy — qa-check đang chạy
    • Auto-merge chỉ chạy khi qa-check xanh (gated qua try_auto_merge.py).
    • Squash-merge → 1 commit duy nhất trên main; revert bằng git revert <merge_sha> rồi push qua PR là rollback hoàn toàn.
    • Chưa merge: đóng PR + xoá branch claude/festive-tesla-wgwmcs là đủ (không ảnh hưởng main).
    PR #616 −0 dòng xóa · +132 dòng thêm · Net +132 dòng
  57. feat(tools): add PR Sentinel CI radar

    chore
    PR #612 −4 dòng xóa · +509 dòng thêm · Net +505 dòng
  58. fix(qa): V18 gitignore volatile artifacts; BRAND OG+placeholder; DEPLOY-MON footer widget [claude/determined-curie-q1qs2b]

    fix
    • feat(open-pr-monitor): build-time Open PR Monitor section below footer
    • fix(qa): V18 gitignore volatile artifacts; BRAND OG+placeholder; DEPLOY-MON footer widget
    • .github/workflows/deploy.yml (modified, +5/-0)
    • .github/workflows/qa.yml (modified, +1/-1)
    • .gitignore (modified, +10/-0)
    PR #608 −30 dòng xóa · +719 dòng thêm · Net +689 dòng
  59. feat(security): add Turnstile footer and setup guide

    security
    PR #605 −170 dòng xóa · +522 dòng thêm · Net +352 dòng
  60. feat(security): add Turnstile footer and setup guide

    security
    −170 dòng xóa · +522 dòng thêm · Net +352 dòng
  61. CMS: cập nhật bài 'AI lập kế hoạch du lịch: thay đổi cách đi'

    chore
    −8 dòng xóa · +3 dòng thêm · Net -5 dòng
  62. Merge remote-tracking branch 'origin/main' into claude/jolly-darwin-71ylr9 [claude/jolly-darwin-71ylr9]

    chore
    • fix(seo): force seomoney.org canonical + homepage rebrand after domain move
    • feat(qa-vaccine): add V20 SEO Identity/Homepage Migration + registry guard
    • Merge remote-tracking branch 'origin/main' into claude/jolly-darwin-71ylr9
    • CLAUDE.md (modified, +41/-0)
    • content/_index.md (modified, +2/-2)
    PR #597 −12 dòng xóa · +321 dòng thêm · Net +309 dòng
  63. feat(adsense): readiness hotfix — policy pages, noindex internal pages, env ad slot, clean homepage

    cleanup
    • Mới: /advertising/ (Chính sách quảng cáo) + /editorial/ (Chính sách biên tập)
    • Footer thêm 2 link này cạnh About/Contact/Privacy/Terms/Copyright
    • Privacy đã có sẵn AdSense/Analytics/cookies/DART → thêm cross-link tới Advertising
    • static/ads.txt placeholder (mẫu có comment hướng dẫn)
    • base.html: loader theo env — get_env(ADSENSE_CLIENT) → fallback config.extra.adsense_client; rỗng = không phát script (site sạch). Khi có id: thêm <meta google-adsense-account> + adsbygoogle.js
    PR #591 −42 dòng xóa · +406 dòng thêm · Net +364 dòng
  64. feat(premium): paywall visa Hàn 5 năm — Premium category, single sticky, MoMo link

    chore
    • Category premium added while keeping existing categories → ["Tất cả", "Du lịch", "Báo chí", "premium"]. Uses the canonical lowercase premium term from categories.json (an uppercase Premium would slugi
    • Single active sticky via the existing schema extra.sticky = true (read by templates/index.html → .home-sticky). Unset sticky on the previous sticky post content/posting/ung-ho-du-an-ai-ten-mien-ai.md
    • MoMo premium payment link https://me.momo.vn/G5T1CDFRuJFW added as per-post extra.momo_payment_link (consumed by templates/macros/paywall.html).
    • Premium mechanics: premium = true, price, premium_post_id = "premium-visa-han-5nam". Full body moved to private_content/premium-visa-han-5nam.md (backend-only); public body stripped to teaser via payw
    • Regenerated data/references.json.
    PR #595 −150 dòng xóa · +133 dòng thêm · Net -17 dòng
  65. fix(gsc): serve /gsc/* on deployed vipzone backend (was 404 on Render)

    fix
    • services/visitor-counter/gsc_routes.py: configure() gains optional backend_url/blog_url so each host sets its own OAuth redirect origin. Redirect URI becomes https://blog-vipzone-api.onrender.com/gsc/
    • services/vipzone/main.py: wires the router with a SQLite-backed async KV (gsc_kv.SqliteKV) since this service has no Redis; OAuth state uses single-use setex/getdel. Auth reuses the VIPZone CMS sessio
    • services/vipzone/gsc_kv.py: new minimal async KV (get/set/setex/getdel/delete, TTL-aware).
    • Search Console readonly scope (webmasters.readonly), access_type=offline.
    • Safe refresh-token handling: the token is only persisted when Google returns one; falls back to GSC_REFRESH_TOKEN env for redeploy durability (Render /tmp SQLite is wiped on redeploy).
    PR #594 −3 dòng xóa · +303 dòng thêm · Net +300 dòng
  66. redesign(editor): S-DNA visual language for /editor/ CMS (scoped, emoji-free)

    chore
    • templates/editor.html — every emoji action icon (🔐🔍🗑📝💾📌✎⇄👁📥🚀🧠⚠↻⏻✦+) replaced with inline Lucide-style outline SVGs (new / edit / save / publish / delete / back / search / refresh / logout / check / li
    • templates/partials/editor-seo-rail.html — SEO assistant rendered as S-DNA KPI cards (pastel fill · left accent · circle ring · small label · big value) for words / H2 / internal-links + circle-icon se
    • sass/_editor-sdna.scss (new) — scoped under .editor-app; local --ed- tokens derived from semantic var(--c-) (light/dark safe) + color-mix() pastels. Restyles brand bar, login card, KPI header widgets,
    • sass/site.scss — @import "editor-sdna" LAST (after editor + cms) so it overrides.
    • scripts/qa_vaccines.py → new check_editor_sdna_vaccine (EDITOR-SDNA): FAIL if _editor-sdna.scss missing/unimported, if editor templates carry emoji icons in visible UI (Tera/HTML comments stripped; <k
    PR #590 −38 dòng xóa · +998 dòng thêm · Net +960 dòng
  67. docs(claude): add V22 vaccine — editor save→GitHub, edit SHA, SEO hydrate, single sticky [claude/elegant-noether-mzlmrn]

    chore
    • CLAUDE.md (modified, +60/-0)
    • QA Gatekeeper (qa-check): 🟡 đang chạy — qa-check đang chạy
    • Auto-merge chỉ chạy khi qa-check xanh (gated qua try_auto_merge.py).
    • Squash-merge → 1 commit duy nhất trên main; revert bằng git revert <merge_sha> rồi push qua PR là rollback hoàn toàn.
    • Chưa merge: đóng PR + xoá branch claude/elegant-noether-mzlmrn là đủ (không ảnh hưởng main).
    PR #592 −0 dòng xóa · +60 dòng thêm · Net +60 dòng
  68. Merge remote-tracking branch 'origin/main' into claude/wizardly-cerf-dj77vc [claude/wizardly-cerf-dj77vc]

    chore
    • fix(editor): commit saves to GitHub, SEO hydrate old posts, single-active sticky
    • Merge remote-tracking branch 'origin/main' into claude/wizardly-cerf-dj77vc
    • scripts/qa_vaccines.py (modified, +90/-0)
    • scripts/test_editor_frontmatter.py (modified, +47/-0)
    • scripts/test_qa_vaccines.py (modified, +99/-0)
    PR #588 −197 dòng xóa · +502 dòng thêm · Net +305 dòng
  69. Merge remote-tracking branch 'origin/main' into claude/zealous-ride-ky2br1 [claude/zealous-ride-ky2br1]

    chore
    • fix(nav): anchor desktop side-nav in flow, stop scroll drift/jitter
    • feat(qa): add V21 No Floating Bar / Stable Nav vaccine
    • Merge remote-tracking branch 'origin/main' into claude/zealous-ride-ky2br1
    • CLAUDE.md (modified, +38/-0)
    • sass/_side-nav.scss (modified, +6/-0)
    PR #587 −0 dòng xóa · +293 dòng thêm · Net +293 dòng
  70. Merge origin/main into pr562: resolve GSC V19 conflicts [claude/eager-gauss-o4yj2w]

    chore
    • feat(gsc): migrate to sc-domain:seomoney.org domain property
    • fix(gsc): semantic merge qa_vaccines.py — preserve all detectors (V18+V19+BRAND+DEPLOY-MON+KOREAN-BANNER)
    • Merge remote-tracking branch 'origin/main' into pr562
    • Merge origin/main into pr562: resolve GSC V19 conflicts
    • .github/workflows/gsc-stats.yml (modified, +1/-0)
    PR #562 −15 dòng xóa · +204 dòng thêm · Net +189 dòng
  71. feat(og): OG smoke verified + deterministic stale-twin FAIL (content-hash manifest)

    chore
    • Homepage → og:image + twitter:image = https://seomoney.org/img/og/seomoney-og.og.webp ✅ absolute, with og:image:width=1200 / og:image:height=630.
    • Section / taxonomy pages (no thumbnail) → same absolute seomoney-og.og.webp default — 639 pages.
    • Per-post override works: a real cover post → …/img/covers/<slug>.og.webp (twin exists); posts whose frontmatter sets thumbnail = …placeholder.svg → …/placeholder.og.webp. Per-post thumbnails correctly
    • 0 relative og:image / twitter:image across the whole site — all absolute https://seomoney.org/….
    • templates/base.html OG wiring unchanged.
    PR #586 −19 dòng xóa · +150 dòng thêm · Net +131 dòng
  72. fix(nav): anchor desktop side-nav in flow, stop scroll drift/jitter

    fix
    • sass/_side-nav.scss: .side-nav → position: static (removed sticky + top + z-index). CSS-only.
    • Desktop only. Mobile/tablet (≤960px) hides .side-nav and uses the hamburger .nav-drawer — untouched.
    • Markup/logic unchanged. Search / Clear-cache actions remain inside the panel (.side-nav__actions).
    • No scroll-linked transform/animation was present in JS; the drift was purely the sticky rule.
    • python3 qa_check.py → PASS (UI-SIDEBAR PASS, 0 vaccine failures; only pre-existing unrelated DEPLOY-MON freshness warn).
    PR #585 −4 dòng xóa · +7 dòng thêm · Net +3 dòng
  73. feat(og): polish SEOMONEY OG card + legal VN Google Sans-style font + OG vaccine

    chore
    • Refined calm-enterprise visual: slate→blue gradient, soft sheen on the preview card + thumbnail, accent underline, seomoney.org footer credit. Same 1200×630 canvas + safe-zone layout.
    • Legal Vietnamese, Google Sans-style font fallback via a single <style> block:
    • Regenerated through the existing build_og_images.py pipeline (1200×630). Social networks can't render SVG, so the committed .og.webp twin is what they show.
    • FAIL — SVG missing / not well-formed XML; canvas ≠ 1200×630; .og.webp twin missing or not 1200×630.
    • WARN — twin stale (SVG newer than committed webp → re-render + commit); old-domain (github.io) branding in the SVG.
    PR #584 −35 dòng xóa · +287 dòng thêm · Net +252 dòng
  74. chore(momo): update default paid-content link → y5eVvzz2nlXXeEP

    chore
    PR #583 −8 dòng xóa · +90 dòng thêm · Net +82 dòng
  75. fix(gsc): deploy preflight gate enforcing sc-domain:seomoney.org [claude/hopeful-brown-ng6lpw]

    fix
    • sites.list → property is verified and not siteUnverifiedUser (real read permission).
    • sitemaps.list → https://seomoney.org/sitemap.xml is registered.
    • searchanalytics.query → 7-day smoke fetch answers for the property.
    • scripts/gsc_preflight.py (added) — preflight engine (gate + live verify, redacted output).
    • services/visitor-counter/gsc_client.py (modified) — EXPECTED_GSC_PROPERTY, EXPECTED_SITEMAP_URL, normalize_property_for_match, is_expected_property, find_property_permission, list_sitemap_paths, smoke
    PR #582 −2 dòng xóa · +547 dòng thêm · Net +545 dòng
  76. feat(tooling): preflight conflict checker to prevent dirty branches/m…

    chore
    • scripts/preflight_conflict_check.py: fetch origin/main, report behind/ahead, detect files changed in both branch and main, flag high-risk shared files (CLAUDE.md, README, config, workflows, scripts/au
    • scripts/install_precommit_conflict_hook.py: installs a lightweight pre-commit hook that blocks commits only on HIGH risk (fail-open otherwise).
    • .github/workflows/preflight-conflict.yml: runs on pull_request + dispatch, fetches full history, runs unit tests + checker, fails PR on HIGH risk.
    • Makefile: make preflight-conflict (+ -json, install-preflight-hook) shortcut.
    • scripts/test_preflight_conflict_check.py: tests high-risk detection, real conflict detection, and that the dry-run never mutates the working tree.
    PR #581 −0 dòng xóa · +600 dòng thêm · Net +600 dòng
  77. Merge remote-tracking branch 'origin/main' into claude/eloquent-dirac-1nb2xp [claude/eloquent-dirac-1nb2xp]

    chore
    • fix(search): style internal search dialog to match SEOMONEY UI
    • Merge remote-tracking branch 'origin/main' into claude/eloquent-dirac-1nb2xp
    • CLAUDE.md (modified, +70/-0)
    • sass/_site-search.scss (added, +384/-0)
    • sass/_theme-overrides.scss (modified, +3/-3)
    PR #577 −3 dòng xóa · +645 dòng thêm · Net +642 dòng
  78. fix(deploy-monitor): expire stale in_progress so Deploy Watch can't show "deploying forever"

    fix
    • UPTIME_ME (506c595) = deploy.yml run #839 → success @ 10:10:55Z → LIVE ~2h ago
    • Only genuine in-flight deploy = #846 d8a44cc (Daily Vaccine Autofixer) — unrelated to UPTIME_ME
    • Fetch Merge Report = #229 success (the #222 "in_progress" the report saw had already finished)
    • Build Failure Auto-Remediator & QA Rule Checker = all skipped (healthy)
    • scripts/fetch_deploy_monitor.py — expire non-terminal runs past a 45-min TTL, and any commit already deployed by a success run. Ghosts move to expired[] (not pending), set stale=true, and never drive
    PR #576 −36 dòng xóa · +311 dòng thêm · Net +275 dòng
  79. fix(build_references): code-span-safe URL extraction (PR #551 follow-up vaccine)

    fix
    • build_references.py extract_links() now delegates to link_utils.extract_link_pairs(), which masks fenced code blocks and inline backtick spans before running link regexes
    • Adds scripts/test_build_references.py with 12 regression tests
    • Regenerates data/references.json (205 posts, no phantom /posting/slug/ entry)
    PR #574 −134 dòng xóa · +194 dòng thêm · Net +60 dòng
  80. feat(qa-vaccine): DOMAIN-ROOT detector — block /zola scanner prefix regression

    chore
    • scripts/qa_vaccines.py: new DOMAIN-ROOT detector in DETECTORS[]
    • FAIL if config.toml base_url contains a /zola path segment
    • FAIL if any of 5 key scanner scripts hardcodes SITE_PREFIX/SITE_BASE_PATH/BASE_PATH/SITE_BASE = "/zola" on a non-comment line
    • WARN if stale banhang-chogao.github.io/zola refs found in scanner bodies (comment-only excluded)
    • scripts/test_qa_vaccines.py: DomainRootUrlVaccineTest — 6 cases
    PR #575 −0 dòng xóa · +206 dòng thêm · Net +206 dòng
  81. feat(seo): auto-submit sitemap + expand IndexNow to all content

    chore
    • New scripts/sitemap_ping.py: pings Bing sitemap endpoint after every deploy; also submits to Google Search Console via sitemaps().submit() when GSC_* secrets are configured. Always best-effort (exit 0
    • New .github/workflows/sitemap-submit.yml: triggers on workflow_run after the deploy workflow succeeds → runs sitemap_ping.py. Runs on every push to main.
    • indexnow.yml path expansion: changed trigger from content/posting/ + content/baochi/ to content/ + templates/ — so tools pages, static pages, and template changes now also fire the IndexNow ping.
    • indexnow.py URL collection: now collects URLs from tools/ section + pages/ section (reads path = frontmatter for custom URL overrides like /about/). Total: 222 URLs vs ~192 before.
    PR #561 −5 dòng xóa · +273 dòng thêm · Net +268 dòng
  82. redesign: soften Korean Hangul banner to SEOMONEY editorial style

    chore
    • Validates overflow:hidden on .home-tabs (no bleed)
    • Validates pointer-events:none on .hangeul-pattern (no content block)
    • Validates aria-hidden="true" on banner div (accessibility)
    • Validates mobile breakpoint coverage (responsive layout)
    • Warns if animation added without prefers-reduced-motion guard
    PR #563 −42 dòng xóa · +98 dòng thêm · Net +56 dòng
  83. SEOMONEY rebrand + OG image + placeholder system + Deploy Monitor footer

    feat
    • config.toml title "Duy Nguyen" → "SEOMONEY" — cascades to <title>, og:site_name`, RSS/Atom titles, JSON-LD publisher/WebSite/Breadcrumb, header wordmark, nav drawer, footer ©. Description + tagline re
    • Duy Nguyen preserved as AUTHOR only: author="duynguyenlog", author_bio, author.json name, about.md byline, S-DNA "Maintained by Duy Nguyen" all untouched.
    • Rebranded user-facing site-brand strings blog Duy Nguyen → blog SEOMONEY across section/page _index descriptions, robots.txt, and static dir-listing HTML (converter/fonts/img og:site_name + descriptio
    • New static/img/og/seomoney-og.svg (1200×630, crop-safe): top bar SEOMONEY logo + name | tagline, article preview card with thumbnail slot, layered SEOMONEY motif, "Tác giả: Duy Nguyen".
    • base.html default og:image → SEOMONEY twin seomoney-og.og.webp (committed seed so it never 404s; build_og_images.py re-renders it in CI). Per-post og:image still uses the post's first/thumbnail image,
    PR #557 −951 dòng xóa · +813 dòng thêm · Net -138 dòng
  84. fix(vaccine-v18): stop runtime artifact conflicts in concurrent hotfix PRs

    fix
    PR #551 −647 dòng xóa · +365 dòng thêm · Net -282 dòng
  85. feat(tools): UPTIME_ME — uptime dashboard from 3 UptimeRobot keys + v…

    chore
    • scripts/fetch_uptime_me.py: read UPTIMEROBOT_API_KEY_1/2/3 from env, call getMonitors per account, normalize to one report (status, uptime %, response times, last down, incidents, checked_at, breathin
    • .github/workflows/uptime-me.yml: cron */30 + dispatch; keys via secrets only; publish data/uptime-me.json via push_to_main.sh.
    • templates/uptime-me.html + sass/_uptime-me.scss + static/js/uptime-me.js: load_data render — KPI cards, 3 account cards, response-time sparklines, incident timeline, "Website đang thở ổn không?" verdi
    • content/tools/uptime-me.md + _index.md card (subtitle/locked, additive in tools.html + _content-blocks.scss). data/uptime-me.json safe empty seed.
    • uptime_me_vaccine: check_uptime_me (UI-UPTIME) — no key leak, public JSON schema, route exists, Tools card links, stale-data warning + tests.
    PR #546 −1 dòng xóa · +965 dòng thêm · Net +964 dòng
  86. feat(wip8): B-DNA design discipline — health meter, icon table, section kickers for workspace tracker

    chore
    • Adds scripts/wip8.py — read-only workspace DNA tracker (git status/diff/log/stash/branch/PR snapshot)
    • Upgrades shortcuts.md wip8 output format to B-DNA design discipline: brand bar + health meter + icon context table + section kickers (NN — emoji TITLE)
    • Conflict in shortcuts.md resolved: branch's B-DNA format kept (superset of main's simpler 3-table format — all 3 tables preserved in upgraded form under section kickers 01 — TỔNG QUAN, 02 — FILES CHAN
    • shortcuts.md conflicted between main's simpler format and branch's B-DNA upgrade
    • Semantic resolution: kept branch's B-DNA version (it already contains equivalent of all 3 main tables in upgraded section-kicker form)
    PR #542 −24 dòng xóa · +304 dòng thêm · Net +280 dòng
  87. feat(series): add 5-part Vaccine Số series — digital immune system for blog CI/CD

    chore
    • Adds 5 full articles (Vaccine Số series: vaccine-so) covering the blog's CI/CD self-healing immune system
    • Registers vaccine-so series in templates/macros/series-nav.html + templates/page.html elif chain (V8 prevention)
    • Adds data/vaccine-so-series.json manifest + rebuilt data/references.json + data/seo-qa-scores.json
    PR #544 −2 dòng xóa · +1578 dòng thêm · Net +1576 dòng
  88. docs(policy): mandatory PR flow — no loose finished branches (2026-06-20)

    chore
    • Checklist (5 steps): verify PR exists → no conflict markers → rebase on latest main → enable auto-merge → report status table
    • Stale branch detection: check git show origin/main:<file> before creating a PR for redundant content
    • Clarification: distinguishes "create PR + enable auto-merge" (mandatory on task completion) from "babysit CI" (forbidden)
    • sidebar-layout-fix → stale (content already on main via #541)
    • friendly-dijkstra-oo6gwy → PR #544 created, vaccine-so series registration fixed in page.html
    PR #545 −0 dòng xóa · +34 dòng thêm · Net +34 dòng
  89. vaccine(ui): sidebar_layout_vaccine — lock right-column menu in-grid …

    chore
    • scripts/qa_vaccines.py: check_sidebar_layout (code UI-SIDEBAR) + DETECTORS entry
    • scripts/test_qa_vaccines.py: SidebarLayoutTest (real-repo PASS, baseline PASS, side-nav fixed FAIL, sidebar absolute FAIL, single-track grid FAIL, missing min-width WARN).
    PR #541 −0 dòng xóa · +267 dòng thêm · Net +267 dòng
  90. dns-vaccine: apex NS gate + empty-apex-A Cloudflare fix steps (seomoney.org)

    fix
    • static/CNAME = seomoney.org (13 bytes, exact bare apex) ✅
    • config.toml base_url = https://seomoney.org ✅
    • No seomomey.org typo anywhere ✅
    • Old github.io/zola content refs: only 2 stale doc lines in CLAUDE.md (fixed); remaining hits are legitimate test fixtures / rewrite-examples / historical reports
    • L0-ns (new): dig seomoney.org NS must be delegated to Cloudflare (*.ns.cloudflare.com)
    PR #540 −9 dòng xóa · +252 dòng thêm · Net +243 dòng
  91. docs(shortcuts): wip8 output dạng bảng markdown trực quan

    chore
    PR #539 −15 dòng xóa · +26 dòng thêm · Net +11 dòng
  92. Claude/hello j5dp4s

    chore
    PR #538 −0 dòng xóa · +1221 dòng thêm · Net +1221 dòng
  93. feat(vaccine-hotfix): conflict-safe pipeline self-heal rule

    chore
    • never bypasses required checks — re-runs qa_check.py; merge delegated to try_auto_merge.py so a hotfix PR merges ONLY when qa-check is green
    • never force-pushes / pushes main — engine only writes vaccine-hotfix/*
    • never deletes user content/data — content/, private_content/, *-series.json, categories.json protected
    PR #536 −0 dòng xóa · +1325 dòng thêm · Net +1325 dòng
  94. feat(cms): CMS V2 Control Center — unified shell, AI Writer, Link Graph, SEO Alerts

    chore
    • Insights — KPI cards (CTR, Impressions, Avg position, Content decay, Internal-link strength) from live static/data/*.json + baked data; SEO health bars; GSC status (degrades calmly when GSC offline).
    • Bài viết — 188 real posts with SEO score badges, search/sort → hands off to existing /editor/ (no duplicate editor).
    • AI Writer — human-controlled: Pillar → Mode → Prompt → Quality Gate → Approve/Reject. Mock generator, no auto-publish.
    • Link Graph — real internal-link graph from data/references.json (924 edges / 188 nodes): orphan detection, weak-authority, AI suggestions, node size ∝ authority.
    • SEO Alerts — actionable cards (orphans, weak authority, low score, broken links) with severity filter + sidebar count.
    PR #537 −5 dòng xóa · +1991 dòng thêm · Net +1986 dòng
  95. feat(b-dna): Brand Design DNA branding guideline system at /tools/b-dna/

    chore
    • templates/b-dna.html — the page (HTML + scoped CSS + vanilla JS)
    • content/tools/b-dna.md — Zola routing stub (aliases /b-dna/)
    • content/tools/_index.md — register B-DNA in the tools menu
    • zola build: PASS (227 pages, 0 orphan, exit 0)
    • qa-404-checker.py (hardened): PASS (0 internal broken, exit 0)
    PR #535 −0 dòng xóa · +737 dòng thêm · Net +737 dòng
  96. feat(b-dna): Brand Design DNA branding guideline system page

    chore
    • templates/b-dna.html: the single self-contained page (HTML+CSS+JS)
    • content/tools/b-dna.md: Zola routing stub (aliases /b-dna/)
    • content/tools/_index.md: register B-DNA in the tools menu
    • zola build: PASS (227 pages, 0 orphan, exit 0)
    • qa-404-checker.py: PASS (0 internal broken, exit 0)
    PR #534 −0 dòng xóa · +737 dòng thêm · Net +737 dòng
  97. feat(calendar): add Microsoft 365-style calendar tool in S-DNA visual

    chore
    • content/tools/calendar.md — trang (template calendar.html)
    • templates/calendar.html — chrome MS365 (command bar, side agenda, modal)
    • static/js/calendar/app.js — engine: month/week/day, drag-drop, resize, overlap layout, keyboard, CRUD localStorage, current-time line
    • sass/_calendar.scss — scoped S-DNA styles + responsive (import site.scss)
    • content/tools/_index.md — thêm link "📅 Lịch"
    PR #533 −0 dòng xóa · +1505 dòng thêm · Net +1505 dòng
  98. feat(calendar): add Microsoft 365-style calendar tool in S-DNA visual

    chore
    • content/tools/calendar.md — trang (template calendar.html)
    • templates/calendar.html — chrome MS365 (command bar, side agenda, modal)
    • static/js/calendar/app.js — engine: month/week/day, drag-drop, resize, overlap layout, keyboard, CRUD localStorage, current-time line
    • sass/_calendar.scss — scoped S-DNA styles + responsive (import site.scss)
    • content/tools/_index.md — thêm link "📅 Lịch"
    PR #532 −0 dòng xóa · +1505 dòng thêm · Net +1505 dòng
  99. feat(calendar): add Microsoft 365-style calendar tool in S-DNA visual

    chore
    • content/tools/calendar.md — trang (template calendar.html)
    • templates/calendar.html — chrome MS365 (command bar, side agenda, modal)
    • static/js/calendar/app.js — engine: month/week/day, drag-drop, resize, overlap layout, keyboard, CRUD localStorage, current-time line
    • sass/_calendar.scss — scoped S-DNA styles + responsive (import site.scss)
    • content/tools/_index.md — thêm link "📅 Lịch"
    PR #531 −0 dòng xóa · +1505 dòng thêm · Net +1505 dòng
  100. fix(links): harden link parsing/normalization — fix false skips & false 404s (giữ /zola canonical)

    security
    • Boundary-aware strip: chỉ bỏ đúng segment /zola (hoặc /zola/…). Trước đây strip mọi prefix /zola… → /zola-tutorial/ bị mangle thành -tutorial/, /zolab/→b/ (false 404). Nay giữ target thật.
    • Host-aware: https://<host>/zola-blog/ (site khác chung ký tự zola) từng bị nhận nhầm internal /-blog/ → nay đúng là external.
    • Anti-false-skip: link http:// và protocol-relative //<host>/zola/… của chính site nay được phân loại internal và validate (trước bị bỏ qua như external).
    • SITE_HOST / SITE_BASE_PATH suy ra từ BASE_URL → /zola là single source of truth.
    • Parse HTML attribute thật thay vì regex trên raw text → data-href="/x", xlink:href, JSON nội tuyến… không còn bị nhận nhầm là <a href> (false positive → false fail). HTMLParser vốn đã định nghĩa nhưng
    PR #528 −64 dòng xóa · +285 dòng thêm · Net +221 dòng
  101. gỡ VIPZone/subscription · công cụ miễn phí · nav sidebar ph…

    refactor
    • Xoá templates vipzone.html, vipzone-admin.html; JS vipzone.js, vip-admin.js, content-blocks.js; SCSS _vipzone.scss, _vip-admin.scss; content tools/vipzone*.md.
    • Bỏ menu VIPZone, sidebar widget "kích hoạt VIP", config momo subscription (vipzone_admin_url, vipzone_momo_*). page.html bỏ data-vipzone-premium.
    • GIỮ NGUYÊN backend Render + plumbing dùng chung: cms_auth (vipzone-auth-api, editor + OAuth dashboards) và zola-vipzone-api (GSC/SEO Reality).
    • Gate VIP nằm trong vipzone.js (TOOL_PREFIXES) → gỡ file là tool tự mở.
    • content.html bỏ badge khoá 🔒 (data-gate vip/premium); content.md bỏ tool VIPZone.
    PR #526 −6229 dòng xóa · +1335 dòng thêm · Net -4894 dòng
  102. feat(vu-mua): trang ứng dụng theo dõi bán nông sản + insights tại /vu…

    chore
    • Form nhập tay đúng 7 cột: Tên hàng hoá | Số lượng | Loại | Đơn giá | Thành tiền | Người mua | Ngày mua. Thành tiền tự tính (SL × đơn giá), cho phép chỉnh tay.
    • Bảng giao dịch + lọc (tìm/loại/khoảng ngày) + phân trang + xoá từng dòng.
    • Export JSON/CSV, Import JSON; dữ liệu lưu localStorage (client-side, không gửi server). Placeholder upload PDF (OCR — sắp ra mắt).
    • KPI cards: doanh thu, sản lượng, số đơn, sản phẩm, người mua, giá TB.
    • Phân tích mùa vụ (Đông Xuân/Hè Thu/Vụ Mùa) + xu hướng doanh thu theo tháng (Chart.js), nhu cầu sản phẩm, hành vi người mua, hiệu suất giá.
    PR #525 −0 dòng xóa · +2273 dòng thêm · Net +2273 dòng
  103. fix(ui): canh giãn ảnh placeholder đồng đều trên mobile

    fix
    PR #523 −0 dòng xóa · +37 dòng thêm · Net +37 dòng
  104. feat(content): series "Đáp án chính thức THPT Quốc gia 2026" (Giáo dục)

    chore
    • 1 trang index series + 11 bài môn (content/posting/dap-an-chinh-thuc-thpt-*)
    • Manifest data/thpt-2026-dap-an-series.json (12 parts, category "Giáo dục")
    • Đăng ký series ở series-listing.html, page.html, series-nav.html
    • SEO-safe: không đáp án giả, không lời giải, không nguồn ngoài; nội link giữa các môn + hub chuyên mục Giáo dục; FAQ + CTA mỗi bài
    PR #522 −1 dòng xóa · +949 dòng thêm · Net +948 dòng
  105. chore(vaccine): Daily Vaccine Autofixer run

    chore
    PR #518
  106. fix(vipzone): load picker catalog from admin API instead of unpublish…

    fix
    • fetchPickerCatalog(): query the authenticated admin API first via apiFetch (credentials: include); static JSON is now only a fallback; on total failure return an empty catalog instead of throwing → no
    • renderPickerGroups(): distinct fallback message when the catalog failed to load vs an empty search filter.
    PR #520 −7 dòng xóa · +22 dòng thêm · Net +15 dòng
  107. feat(baochi): bài phân quyền role một nguồn sự thật

    chore
    • content/baochi/thiet-ke-phan-quyen-role-single-source-of-truth.md
    • SEO QA 100/100 A+ · 1609 từ · 5+ internal link + 1 external (OWASP)
    • Generalize, không lộ secret/email/biến môi trường nhạy cảm
    PR #519 −1 dòng xóa · +226 dòng thêm · Net +225 dòng
  108. Feat/super admin session clean

    cleanup
    PR #515
  109. feat(ai): AI Learning Engine for Vaccine AutoFixer + Content Direction

    chore
    • Learn fixed CI/build/deploy failures into reusable vaccine candidates (signature, root cause, files changed, fix summary, proof, risk) in memory/vaccines/learned_failures.jsonl; dedup near-duplicates.
    • Match new failures: stdlib TF-IDF cosine by default; opt-in embedding + FAISS inner-product search (VACCINE_LEARNER_EMBED=1) over case vectors, falling back to numpy then TF-IDF. Auto-apply only low-r
    • Analyzes corpus (reuses related_engine + data/related.json/scores.json + seo-qa-scores.json): topics, clusters, internal-link gaps, orphans, SEO weakness, AdSense-safe + helpful-content direction, key
    • Emits static/data/content-direction/report.json; S-DNA dashboard at /tools/content-direction/ (template + scoped SCSS). CI-safe (exit 0).
    PR #514 −2 dòng xóa · +3884 dòng thêm · Net +3882 dòng
  110. feat(vipzone): SUPER_ADMIN shortcut button on VIPZone landing

    chore
    • config.toml — add vipzone_admin_url (empty → fallback {base_url}/tools/vipzone-admin/)
    • templates/vipzone.html — meta[name=vipzone-admin-url] + hero button [data-vz-super-admin]
    • sass/_vipzone.scss — .vipzone__btn--super-admin (red bg #dc2626, white text, hover/focus/active states; responsive via existing __btn rules)
    • static/js/vipzone.js — reveal button only when VIPZone.isSuperuser() (/auth/me) resolves true; hidden otherwise, never blocks normal users
    • node --check static/js/vipzone.js ✓
    PR #511 −114 dòng xóa · +273 dòng thêm · Net +159 dòng
  111. feat(content): Content hub navbar + S-DNA category/tool blocks; CMS write = superuser only

    chore
    • Navbar: gộp "Bài viết" + "Công cụ" → 1 mục Content (Main content + MS).
    • /content: mọi category bài viết + công cụ → khối màu S-DNA, compact responsive. Khối là link thường — gate VIP (vipzone.js) + paywall (premium) fire khi điều hướng (không nhân bản gate). content-block
    • MS = /tools/content-creator → placeholder "Content Creator · Under construction".
    • CMS write auth → superuser only (reuse is_supervip): can_oauth_login + is_super + OAuth callback; editor.js/admin-author.js ẩn write UI cho non-super (VIP cũng không ghi).
    • zola build EXIT=0 (full site) · qa-404-checker.py 0 internal broken — pass · qa_check.py EXIT=0 · QA Vaccine Gate 100/100 PRODUCTION-SAFE · node --check + py_compile OK.
    PR #513 −152 dòng xóa · +359 dòng thêm · Net +207 dòng
  112. feat(auth): persistent super-admin session (GitHub login = highest privilege)

    chore
    • ADMIN_EMAILS mặc định thêm tamsudev.com@gmail.com (login banhang-chogao vốn đã được ADMIN_USERNAMES phủ).
    • /auth/me trả is_super (tính từ username/email so với whitelist admin) + ép role=supervip cho chủ blog kể cả khi VIPZone API lỗi.
    • Sliding session: TTL gia hạn mỗi require_session + /auth/me, mặc định 30 ngày (env SESSION_TTL) → admin đang dùng gần như không bao giờ phải login lại.
    • templates/base.html: bootstrap chạy sớm trong <head> (trước mọi script defer) — mirror zola-cms-session-id sang localStorage và khôi phục sessionStorage mỗi lần load (sống qua đóng tab + xoá cache; ch
    • static/js/vipzone.js: getCmsSid() fallback localStorage.
    PR #512 −11 dòng xóa · +77 dòng thêm · Net +66 dòng
  113. feat(vipzone): SUPER_ADMIN shortcut button on landing

    chore
    • templates/vipzone.html — new .vipzone__admin-shortcut block inside the hero (after KPIs, before pricing). Renders hidden; JS reveals based on auth state.
    • sass/_vipzone.scss — new &__btn--admin variant (red #dc2626 background, white text, hover/focus/active states) + &__admin-shortcut wrapper with mobile (≤540px) full-width fallback. Reuses the existing
    • static/js/vipzone.js — new initAdminShortcut() runs from initLanding():
    • No CMS session → shortcut visible, marked data-vz-admin-state="shortcut" (role detection unreliable, normal users not blocked since the admin page itself has GitHub OAuth gate).
    • Authenticated + super → visible, marked verified, note becomes ✓ Bạn đã đăng nhập super admin — vào dashboard.
    PR #510 −0 dòng xóa · +108 dòng thêm · Net +108 dòng
  114. fix(vipzone): stop overlay-gating premium articles (deployed paywall owns them)

    fix
    • Khách non-VIP vào bài premium → overlay toàn màn hình "Cần VIP" + html.vz-gated .main-content { filter: blur(2px); pointer-events: none } → che mất paywall MoMo đang hoạt động (mất kênh kiếm tiền chín
    • Khách VIP vào bài premium → paywall-box bị ghi đè bằng placeholder TODO backend ("nội dung premium đang đồng bộ") → không đọc được, mà cũng mất luôn form unlock per-post.
    • static/js/vipzone.js
    • pathNeedsGate: bỏ nhánh data-vipzone-premium → VIPZone chỉ gate Công cụ, không phủ bài premium.
    • initGate: gỡ nhánh placeholder VIP-premium (dead TODO backend).
    PR #507 −10 dòng xóa · +6 dòng thêm · Net -4 dòng
  115. VIPZone GitHub auth routing

    fix
    • Route VIPZone/CMS GitHub auth through meta[name="vipzone-auth-api"] only.
    • Point all login/auth fallbacks and docs/config references at https://blog-vipzone-api.onrender.com.
    • Remove old zola-visitor-api, blog-visitor-api, and zola-cms-auth references from runtime/auth paths.
    • rg -n "zola-visitor-api|blog-visitor-api|zola-cms-auth|CMS_AUTH_URL|AUTH_API_URL" -S . -> no matches.
    • Generated output in /tmp/zola-vipzone-build contains meta name="vipzone-auth-api" content="https://blog-vipzone-api.onrender.com" on sampled pages.
    PR #504 −108 dòng xóa · +85 dòng thêm · Net -23 dòng
  116. Chore/vipzone api url

    chore
    PR #506 −71 dòng xóa · +1157 dòng thêm · Net +1086 dòng
  117. docs(shortcuts): add wip8 — read-only workspace tracker

    chore
    PR #505 −0 dòng xóa · +59 dòng thêm · Net +59 dòng
  118. feat(vipzone): Render backend API + picker catalog

    chore
    • FastAPI VIPZone backend (services/vipzone) — payment requests, redeem codes, admin stats/picker/users
    • render.yaml blueprint entry blog-vipzone-api (SQLite disk, CMS auth bridge)
    • Picker catalog build step in QA + deploy pipelines
    • Admin JS wired to live API when vipzone_api_url is set
    • python3 -m unittest services/vipzone/test_main.py -v
    PR #502 −323 dòng xóa · +2299 dòng thêm · Net +1976 dòng
  119. feat(vipzone): landing + admin panel

    chore
    • VIPZone landing (/tools/vipzone/) — MoMo gói tháng 250k / 6 tháng 500k, mã 16 số, session restore
    • Admin (/tools/vipzone-admin/) — payments, codes, VIP users, insights, Content Picker
    • VIP gate cho Công cụ + premium posts; upload dashboards superuser-only
    • Sidebar stat: số người kích hoạt VIP
    • localStorage prototype khi vipzone_api_url trống (TODO Render backend)
    PR #501 −51 dòng xóa · +1453 dòng thêm · Net +1402 dòng
  120. chore(seo): add GSC HTML-file verification google359ea2ec9d73ed9c

    chore
    PR #500 −0 dòng xóa · +1 dòng thêm · Net +1 dòng
  121. docs(shortcuts): thêm phím tắt tieptuc8 — tiếp tục & hoàn tất tất cả …

    chore
    • Thêm tieptuc8 vào bảng help (§2) + section đầy đủ ngay sau runner.
    • Mục đích: 1 lệnh quét sạch backlog việc dở (todo, thay đổi chưa push, commit chưa lên main, PR chưa merge, CI đỏ, macro dở, background task) rồi tiếp tục/hoàn tất từng cái tới khi xong hết.
    • Phân biệt rõ với runner (retry 1 việc gần nhất) và theodoi8 (chỉ theo dõi).
    • Có bảng backlog, hard rules (P0>P1, không restart, không destructive), scope mở rộng (tieptuc8 content|ci|push).
    PR #499 −0 dòng xóa · +74 dòng thêm · Net +74 dòng
  122. feat(home): move Google Rank + SEO Reality to "📊 Khám phá thêm" band …

    refactor
    • base.html: wrap the two widget calls in an overridable nested block {% block sidebar_seo_widgets %}. Default (article/section pages) keeps them in the sidebar exactly as before.
    • index.html: empty-override that block (so the homepage sidebar drops them — no duplication) and re-call the same macros inside a "📊 Khám phá thêm" band. Guarded by load_data so the titled band never r
    • sass/_discover-more.scss (new): scoped container only — widgets keep their own .sidebar-block / google-rank / seo-reality skins (component reuse). Desktop = responsive auto-fit grid/cards; mobile (≤72
    PR #498 −0 dòng xóa · +119 dòng thêm · Net +119 dòng
  123. docs(shortcuts): add fixrule8 conflict scanner shortcut

    chore
    PR #497 −0 dòng xóa · +75 dòng thêm · Net +75 dòng
  124. feat(header): THEODOI8 LIVE banner + carousel 3 slide (slider thủ công)

    chore
    • Báo cáo theodoi8 → JSON: scripts/build_theodoi8_report.py fetch commit × workflow run (GitHub REST API + GITHUB_TOKEN), dual-write data/ (build-time load_data) + static/data/ (runtime fetch). Graceful
    • Header: thêm banner thứ 3 (👀 THEODOI8 LIVE) vào .header-rotator, GIỮ NGUYÊN 2 banner cũ (Welcome + GitHub). Thay static rotation bằng slider/carousel điều khiển tay: mũi tên ‹ ›, dots, vuốt mobile, ph
    • Banner mới: status/summary/timestamp/CTA từ JSON, click mở GitHub Actions, auto-refresh khi JSON đổi (theodoi8-banner.js poll 60s, chỉ khi tab hiện).
    • UI: S-DNA teal primary, playful/colorful, card bo tròn + soft shadow + micro animation (pulse/bounce), màu viền/dot theo trạng thái CI, responsive ≤720px, prefers-reduced-motion.
    PR #496 −25 dòng xóa · +787 dòng thêm · Net +762 dòng
  125. feat(baochi): bài "Điểm thi tuyển sinh lớp 10 TP.HCM 2026" (SEO A+)

    chore
    • Nội dung: hơn 151.000 thí sinh; cách tra cứu điểm; điểm chuẩn chuyên/tích hợp vừa công bố (chuyên Sinh Lê Hồng Phong 39,25, Trần Đại Nghĩa 37,75, tích hợp Nguyễn Thị Minh Khai 34,25); cách tính điểm x
    • Nguồn thật, có dẫn: Tuổi Trẻ, VietnamNet, Dân Trí, chinhphu.vn — không bịa số liệu (hard rule E-E-A-T).
    • SEO QA: 100/100 (A+) · 1339 từ · 5 FAQ ([[extra.faq]]) · ≥5 internal link + external nguồn · disclosure/miễn trừ.
    • categories = ["Tất cả", "Giáo dục", "Báo chí"] (đúng rule bb/baochi); thêm category "Giáo dục" vào categories.json.
    • Regenerate data/references.json (182 posts).
    PR #489 −2 dòng xóa · +248 dòng thêm · Net +246 dòng
  126. Cập nhật rule báo cáo PR sau merge: 3 quy tắc enforceable (no watch l…

    chore
    • CLAUDE.md §"Báo cáo PR sau merge": chuyển prose → 3 bullet BẮT BUỘC (1) KHÔNG canh PR liên tục; (2) luôn output summary cuối sau merge; (3) fail → đọc §4 Vaccine library → đề xuất Vaccine match + fix
    • shortcuts.md §5: đồng bộ 3 quy tắc trong intro.
    • Format success/fail (box-drawing, SHA, GMT+7, deploy note) giữ nguyên — đã khớp spec.
    • Build/deploy rules KHÔNG đổi.
    PR #490 −6 dòng xóa · +7 dòng thêm · Net +1 dòng
  127. feat(bhtn): trang tính trợ cấp thất nghiệp 2026 (/tools/bhtn/)

    chore
    • Mức hưởng/tháng = bình quân lương BHTN 6 tháng cuối × 60%
    • Trần = 5 × lương tối thiểu vùng 2026 (I 5.31tr·II 4.73tr·III 4.14tr·IV 3.7tr)
    • Số tháng hưởng: 12–36 tháng → 3 tháng; sau 36 mỗi 12 tháng đủ +1; tối đa 12; dư bảo lưu
    • Điều kiện: HĐLĐ hợp pháp, không hưởng hưu/mất sức, đủ 12 tháng, nộp trong 3 tháng, chưa có việc làm
    PR #491 −0 dòng xóa · +699 dòng thêm · Net +699 dòng
  128. merged PR summary rule — no watch loop, vaccine on fail

    chore
    PR #488 −14 dòng xóa · +95 dòng thêm · Net +81 dòng
  129. feat(flight-db): time pickers, combinator sync, API enrich

    chore
    • Native time pickers (Add Flight)
    • Search autocomplete + combinator auto-sync (buildCombinator)
    • AviationStack/OpenSky API enrich with 30m cache
    • Local DB remains source of truth
    PR #487 −24 dòng xóa · +447 dòng thêm · Net +423 dòng
  130. content: add 19 topic authority cluster articles

    chore
    −0 dòng xóa · +2244 dòng thêm · Net +2244 dòng
  131. feat(flight-db): add seed data generator script

    chore
    −0 dòng xóa · +108 dòng thêm · Net +108 dòng
  132. feat(flight-db): add client-side app.js

    chore
    −0 dòng xóa · +389 dòng thêm · Net +389 dòng
  133. feat(flight-db): add styles, JS, seed data and generator script

    chore
    −0 dòng xóa · +453 dòng thêm · Net +453 dòng
  134. feat(flight-db): add Flight DB template

    chore
    −0 dòng xóa · +190 dòng thêm · Net +190 dòng
  135. feat(flight-db): S-DNA Flight DB dashboard tool

    chore
    −0 dòng xóa · +8 dòng thêm · Net +8 dòng
  136. ShortenSEA auth flow and add public/VIP/admin pages

    fix
    −820 dòng xóa · +1310 dòng thêm · Net +490 dòng
  137. docs(shortensea): add Render deploy guide

    chore
    −0 dòng xóa · +105 dòng thêm · Net +105 dòng
  138. Merge remote-tracking branch 'origin/feat/h-dashboard-multi-upload-10' into merge-h-dashboard-multi

    chore
    −55 dòng xóa · +222 dòng thêm · Net +167 dòng
  139. feat(shortensea): S-DNA short URL manager — pages, API, redirect

    chore
    −1 dòng xóa · +3478 dòng thêm · Net +3477 dòng
  140. qa: reinforce QA Gatekeeper with QA Vaccine Gate from CLAUDE.md

    chore
    • load_vaccines() đếm mọi block #### V<N> — … trong CLAUDE.md → 15 vaccine loaded.
    • 18 detector tĩnh ánh xạ vaccine + các nhóm check task yêu cầu:
    • Zola build / template hỏng: Tera replace(old=/new=) thay vì from=/to= (V8), lệch block {% if/for/block/macro %}.
    • Series chưa đăng ký (V8), shared-infra footer trùng (V12).
    • Internal asset thiếu, dashboard data/*.json hỏng, premium/paywall thiếu private_content/<id>.md.
    PR #483 −11 dòng xóa · +1085 dòng thêm · Net +1074 dòng
  141. fix(paywall): restore strict premium paywall (MoMo payment gate) + qa-404 scheduled forward-ref vaccine (V13)

    fix
    • config.toml: enable_premium_lock = true → build runs paywall_prepare_build.py --strip; static HTML ships the teaser only, full content stays in private_content/ (served by the backend after payment).
    • templates/page.html / taxonomy_single.html: render the teaser + paywall box for every premium post (extra.premium or category premium); removed the "category hidden" overlay that was shadowing the pay
    • templates/macros/paywall.html: payment-focused wording — "Thanh toán qua MoMo để đọc tiếp", "Bài viết premium — cần thanh toán để mở khóa nội dung" (not donation). The voluntary MoMo card only renders
    • scripts/paywall_prepare_build.py: strip is now non-destructive — it never overwrites an existing full private_content/ body with the teaser when there is no <!-- more --> marker (the current repo stat
    • content/posting/cau-dieu-kien-gia-dinh-tieng-han.md: added the missing premium_post_id = "premium-han30-27", price, and "Tất cả"/"Học tiếng Hàn" categories so the backend can serve its full content an
    PR #484 −37 dòng xóa · +404 dòng thêm · Net +367 dòng
  142. feat(sidebar): add Premium Posts S-DNA widget above Featured

    chore
    • base.html: thêm field premium/price vào posts-data JSON + render section (server render sẵn 10 bài → no-JS fallback + chống CLS); ẨN hẳn section nếu không có bài premium nào.
    • sidebar.js: pickPremium() Fisher-Yates shuffle (random mỗi lần load, không trùng lặp) + renderPremium() + format giá kiểu VN (49.000đ).
    • _premium-posts.scss: card bo tròn, shadow mềm, hover nhấc nhẹ, icon ring 💎, badge gold — S-DNA flavor; token var(--c-*) đúng light/dark; responsive ≤720px; tôn trọng prefers-reduced-motion.
    PR #482 −1 dòng xóa · +255 dòng thêm · Net +254 dòng
  143. Thêm phím tắt theodoi8 + cập nhật policy: bỏ rào PR thủ công

    chore
    • Map commit → workflow run (list_commits + actions_list/actions_get), output bảng + icon trạng thái + tóm tắt.
    • Mở rộng: theodoi8 deploy / theodoi8 <sha> / theodoi8 watch.
    • Tôn trọng rule cancelled ≠ failed (Build Dashboard / Vaccine V5); gợi ý ff khi failure thật trên deploy.yml.
    • Thêm row vào bảng help; slash command /phimtat tự auto-discover từ header.
    • §1 "Vẫn qua PR" → "Không cần qua PR thủ công"; ghi rõ branch protection chặn push thẳng main nên auto-merge là bước máy tự làm.
    PR #476 −31 dòng xóa · +113 dòng thêm · Net +82 dòng
  144. feat(navbar): gom dropdown "Công cụ" thành 3 nhóm accordion (Content/Dashboard/Khác)

    chore
    • config.toml — children của "Công cụ" lồng thêm 1 cấp (mỗi nhóm có children riêng). Các dropdown khác (Bài viết, Giới thiệu) không đổi.
    • templates/base.html — submenu render đệ quy: child có children → <button> accordion (aria-haspopup / aria-expanded / aria-controls) + panel; child thường → link như cũ (tương thích ngược).
    • sass/_navbar.scss — style nhóm theo S-DNA (bo góc, nền mềm, spacing, hover/focus rõ), xổ/đóng mượt bằng grid 0fr↔1fr, chevron xoay 180°. Mobile: max-height + cuộn nội bộ → không bao giờ chiếm trọn màn
    • static/js/navbar-dropdown.js — toggle accordion (click/tap), điều hướng bàn phím (Arrow/Escape), auto-mở + highlight nhóm chứa trang hiện tại (active item).
    • zola build PASS (182 pages)
    PR #481 −32 dòng xóa · +303 dòng thêm · Net +271 dòng
  145. Xoá trang Thống kê (Web Vitals) /stats/ và link footer

    remove
    • base.html: gỡ link "⚡ Web Vitals" ở footer + script speed-vitals.js + CDN unpkg web-vitals (bỏ luôn 1 external request mỗi page)
    • Xoá content/stats/_index.md, templates/stats.html, static/js/stats-page.js, static/js/speed-vitals.js
    • Xoá sass/_stats.scss + _stats-sembcorp.scss và 2 @import trong site.scss
    • Gỡ .site-footer__stats-link khỏi _reset.scss (class không còn)
    • Gỡ tham chiếu /stats/ trong README.md và bài cong-nghe-blog-duy-nguyen.md
    PR #479 −1060 dòng xóa · +12 dòng thêm · Net -1048 dòng
  146. docs(claude): luật mới — code xong + mở PR là hết nhiệm vụ, không canh PR

    chore
    • Code xong → commit → mở PR (kích hoạt auto-merge) = HẾT NHIỆM VỤ.
    • Pipeline ZERO_BARRIER tự lo: qa-check xanh → auto-merge.yml → deploy.yml production.
    • KHÔNG subscribe_pr_activity, KHÔNG canh CI tới merge, KHÔNG send_later self check-in, KHÔNG babysit/poll PR.
    • Ngoại lệ: chỉ subscribe/autofix khi user chủ động yêu cầu ("canh PR", "babysit", "autofix CI"); dừng khi user bảo dừng hoặc PR đã MERGED/CLOSED.
    PR #477 −8 dòng xóa · +12 dòng thêm · Net +4 dòng
  147. feat(gsc): S-DNA connect UI cho Google Search Console sidebar

    chore
    • Input nhập GSC Property ID / Resource ID, validate URL prefix + sc-domain: (báo "Vui lòng nhập GSC Property ID hợp lệ." khi sai). Enter và nút "Kết nối GSC" cùng kích hoạt một flow OAuth.
    • Success state: check xanh animate (scale-in + draw + glow) + "Đã kết nối Google Search Console thành công. Chúc mừng!" — chỉ hiện sau callback OAuth thật (gsc_connected=1) và xác nhận /gsc/metrics, kh
    • Connected state: badge "Đã kết nối" + checkmark, property ID, last sync, nút "Gỡ kết nối GSC".
    • Disconnect khôi phục input + hiện "Đăng nhập lại Google Search Console" (quick reconnect). OAuth error hiển thị trung thực thay vì giả thành công.
    • Styling: card hover-lift, input bo tròn + focus ring, nút pill primary/ ghost, shimmer loading; tôn trọng prefers-reduced-motion. Giữ badge "GSC API". Dùng token var(--c-*) (sáng/tối). Keyframes ở roo
    PR #478 −71 dòng xóa · +560 dòng thêm · Net +489 dòng
  148. feat(content): bài "Lịch sử đóng BHXH bị mất trên VssID" (SEO A+)

    chore
    • Intro + answer box featured-snippet (50–70 từ)
    • Vì sao bị mất (5 nguyên nhân H3 + bảng) → Có mất quyền lợi không (Không) → 5 cách xử lý step-by-step → Bao lâu cập nhật (bảng) → Hồ sơ cần chuẩn bị → Lưu ý quan trọng
    • 6 FAQ ([[extra.faq]] → hiển thị + JSON-LD FAQPage)
    • SEO QA 97/100 — hạng A+ · 3.243 từ
    • qa_check.py: 0 error (1 warning title 73 ký tự — giữ theo tiêu đề yêu cầu, từ khoá đặt đầu)
    PR #475 −2 dòng xóa · +368 dòng thêm · Net +366 dòng
  149. style(home): Ericsson Blue POSTINGS banner with scattered Hangul

    chore
    • Lớp .hangeul-pattern là aria-hidden, pointer-events: none, overflow: hidden (clip vào banner) → chỉ trang trí, không cản đọc/bấm.
    • Nền #003784 hardcode (không dùng token) để giữ nguyên ở cả light/dark — chữ Hangul trắng cần nền tối.
    • Mobile (≤720px): padding gọn lại + Hangul thu nhỏ 1.1rem, layout không vỡ.
    • Chỉ sửa 2 file: templates/index.html + sass/_home-momo.scss. Không đụng selector global/desktop ngoài phạm vi banner.
    • zola build → PASS (182 trang, 0 lỗi)
    PR #474 −8 dòng xóa · +74 dòng thêm · Net +66 dòng
  150. feat(insights): add Ad-Report V2 daily monetization + UI analysis

    chore
    −0 dòng xóa · +3139 dòng thêm · Net +3139 dòng
  151. fix(gsc): pin property to https://seomoney.org/

    fix
    −11 dòng xóa · +99 dòng thêm · Net +88 dòng
  152. feat(seo): connect Google Search Console API to SEO Reality Check

    chore
    −67 dòng xóa · +1910 dòng thêm · Net +1843 dòng
  153. fix(h-dashboard): load Coffee Analytics module before initialization

    fix
    −40 dòng xóa · +138 dòng thêm · Net +98 dòng
  154. unhide premium posts and add momo support CTA

    fix
    −20 dòng xóa · +144 dòng thêm · Net +124 dòng
  155. chore(ui): temporarily hide QA dashboard from public UI

    chore
    −31 dòng xóa · +49 dòng thêm · Net +18 dòng
  156. Merge branch 'hotfix/remove-ad-slots-keep-placeholders'

    remove
    −38 dòng xóa · +104 dòng thêm · Net +66 dòng
  157. feat(s-dna): make page visually demonstrate Sembcorp design DNA

    chore
    PR #473 −457 dòng xóa · +1178 dòng thêm · Net +721 dòng
  158. feat(h-dashboard): Coffee Life Analytics V2 — S-DNA redesign

    chore
    −752 dòng xóa · +1828 dòng thêm · Net +1076 dòng
  159. publish adsense report as ad-report page

    feat
    PR #472 −0 dòng xóa · +704 dòng thêm · Net +704 dòng
  160. publish adsense report as ad-report page

    feat
    −0 dòng xóa · +704 dòng thêm · Net +704 dòng
  161. resolve PR #469 footer conflicts (Tags → footer) + Vaccine V12 semantic merge

    fix
    • main side còn block TAGS trong sidebar; #469 side còn block CATEGORIES (DANH MỤC) trong sidebar.
    • Truth: cả categories (#468) lẫn tags (#469) giờ đều nằm ở footer → sidebar phải không còn cả hai. Giữ một bên nguyên = nhân đôi 1 module.
    • Resolve: gỡ cả 2 block stale khỏi sidebar, chỉ để comment "đã chuyển xuống footer". google_rank + seo_reality (#467) giữ nguyên ngay dưới.
    • Giữ trọn component .footer-categories (#468) + dùng comment header tag-cloud của #469. Mỗi selector định nghĩa đúng 1 lần.
    • zola build ✅ — 173 pages, exit 0, 0 template error
    PR #471 −37 dòng xóa · +282 dòng thêm · Net +245 dòng
  162. feat(tools): add S-DNA documentation page under /tools/s-dna/

    chore
    PR #470 −0 dòng xóa · +558 dòng thêm · Net +558 dòng
  163. feat(footer): move categories to compact footer navigation grid

    refactor
    PR #468 −166 dòng xóa · +131 dòng thêm · Net -35 dòng
  164. add SEO reality check module below google rank

    feat
    • Không giả lập dữ liệu Google. API chưa kết nối → ghi rõ, không bịa.
    • Mọi số liệu đều có nhãn nguồn: INTERNAL / GSC API / ESTIMATED / NOT MEASURED.
    • Trạng thái blog mới được xử lý trung thực (Indexing Phase, confidence thấp).
    • Wiring tương lai: chỉ cần đổ data/gsc-metrics.json (output GSC API) → các thẻ tự chuyển sang "connected" và hiện số thật, không cần sửa template.
    • python3 -m unittest scripts.test_seo_reality → 16/16 PASS
    PR #467 −0 dòng xóa · +941 dòng thêm · Net +941 dòng
  165. feat(stats): Sembcorp investor-slide UI + bugfixes for /stats/

    chore
    −200 dòng xóa · +606 dòng thêm · Net +406 dòng
  166. chore(vaccine): Daily Vaccine Autofixer run

    chore
    PR #463 −58 dòng xóa · +512 dòng thêm · Net +454 dòng
  167. docs(reports): báo cáo vị trí AdSense + tổng hợp tính năng phiên 18–19/06

    chore
    −0 dòng xóa · +330 dòng thêm · Net +330 dòng
  168. feat(vaccine): Daily Vaccine Autofixer + shortcut vacxin11 (V11)

    chore
    • Engine scripts/vaccine_autofixer.py: parse registry từ CLAUDE.md (#### V<N> —), các step fixer AN TOÀN (V1 HF model id · internal-link 404 --fix · references · rule-checker report-only), QA + build ve
    • Tests scripts/test_vaccine_autofixer.py: 8 test (parse registry · next-run · lock · report shape) — pass hết.
    • Workflow .github/workflows/vaccine-autofixer.yml: cron 0 23 * (= 06:00 Asia/Ho_Chi_Minh) + workflow_dispatch; concurrency (không chạy đồng thời); mở PR cho mọi thay đổi (PR flow — không push thẳng m
    • UI templates/insights.html + sass/_vaccine-autofixer.scss: panel "Daily Vaccine Autofixer" — Last run · Next scheduled · chip vaccine khớp · số đã fix · chip QA/Build/Prod · nút Run Daily Vaccine Auto
    • Docs: shortcuts.md (vacxin11), CLAUDE.md (vaccine V11 + file map).
    PR #458 −695 dòng xóa · +1028 dòng thêm · Net +333 dòng
  169. CMS: cập nhật bài 'Ngày 27 — Câu điều kiện & nghĩa vụ tiếng Hàn'

    chore
    −26 dòng xóa · +3 dòng thêm · Net -23 dòng
  170. feat(ui): add visible breadcrumb on posts (Trang chủ › Chuyên mục › Bài)

    chore
    • templates/page.html: thêm <nav class="breadcrumb"> trong post header, trên tiêu đề: Trang chủ › Chuyên mục › Bài hiện tại. Chuyên mục = category chuyên biệt đầu tiên (bỏ qua "Tất cả"), link qua get_ta
    • sass/_breadcrumb.scss (mới) + import vào site.scss: component dùng semantic token var(--c-*) (đúng light/dark), tách block mobile @media (max-width: 540px) rút gọn tiêu đề dài — không sửa selector glo
    • zola build PASS (172 pages, exit 0) trên nhánh đã rebase lên main mới nhất.
    • Output bài Git: Trang chủ › Công nghệ › Git branch… với link /categories/cong-nghe/ đúng.
    • qa_check.py PASS.
    PR #457 −0 dòng xóa · +93 dòng thêm · Net +93 dòng
  171. content: Series V-Plus & V-Advance VietinBank (5 bài)

    chore
    • Manifest: data/nang-tam-trai-nghiem-cung-2-goi-tien-ich-tai-chinh-moi-v-plu-7715eb-series.json
    • Series nav + related posts wiring
    • Fix series-listing replace filter syntax
    • zola build PASS (225 pages)
    PR #454 −1 dòng xóa · +1409 dòng thêm · Net +1408 dòng
  172. 🔬 Daily Vaccine Autofixer — automatic issue detection & repair

    chore
    • ⏰ Daily Schedule: Runs automatically at 06:00 Asia/Ho_Chi_Minh (23:00 UTC)
    • 🔍 Pattern Matching: Scans CI logs & repo files against 7 vaccine patterns (V1–V7)
    • 🛠️ Auto-fix Safe Issues: V1 (HuggingFace model ID prefix) auto-fixes with validation
    • 📋 PR for Risky Fixes: Creates review PRs for manual_only vaccines (V2–V7)
    • ✅ QA Validation: Runs qa_check.py + zola build + internal links check
    PR #455 −0 dòng xóa · +1079 dòng thêm · Net +1079 dòng
  173. CMS: cập nhật author info

    chore
    −1 dòng xóa · +1 dòng thêm · Net +0 dòng
  174. CMS: cập nhật bài 'Fintech 2026: Paywall premium trên blog cá nhân'

    chore
    −2 dòng xóa · +2 dòng thêm · Net +0 dòng
  175. CMS: thêm category 'premium'

    chore
    −2 dòng xóa · +3 dòng thêm · Net +1 dòng
  176. CMS: bỏ Featured cũ khi chọn 'premium-fintech-paywall-demo'

    chore
    −1 dòng xóa · +0 dòng thêm · Net -1 dòng
  177. CMS: cập nhật bài 'Fintech 2026: Paywall premium trên blog cá nhân'

    chore
    −13 dòng xóa · +5 dòng thêm · Net -8 dòng
  178. hotfix(h-dashboard): fix OCR stuck on worker/WASM init

    fix
    • Align core version to 5.1.1; vendor local tesseract.min.js + worker.min.js (local-first, CDN fallback).
    • Add wasm-unsafe-eval to CSP.
    • workerBlobURL: false, 120s timeout, progress logger, eng language fallback.
    • Surface OCR errors via getLastError() in invoice-parser.
    • Regression tests in scripts/test_ocr_loader.py.
    PR #446 −33 dòng xóa · +228 dòng thêm · Net +195 dòng
  179. CMS: cập nhật footer countdown

    chore
    −1 dòng xóa · +1 dòng thêm · Net +0 dòng
  180. feat(insights): paginate timeline PR list (10 rows per page)

    chore
    −3 dòng xóa · +168 dòng thêm · Net +165 dòng
  181. docs(rules): thêm GLOBAL WRITING RULES (human-first, anti-AI, E-E-A-T)

    chore
    PR #437 −0 dòng xóa · +43 dòng thêm · Net +43 dòng
  182. docs(rules): nguồn ảnh + alt text bắt buộc (chỉ ảnh user, không fetch ngoài)

    chore
    • CHỈ dùng ảnh user cung cấp (attachment / URL user đưa). KHÔNG tự fetch ảnh ngoài (picsum/Unsplash/CDN/search).
    • Không có ảnh user → placeholder hệ thống (img/placeholder/*.svg).
    • Alt text bắt buộc cho MỌI ảnh, contextual + SEO-friendly (không nhồi keyword, không alt rỗng/chung chung).
    PR #436 −0 dòng xóa · +16 dòng thêm · Net +16 dòng
  183. fix(ci): vaccine V6/V7 — bot data stash conflict + remediation tự đỏ

    fix
    PR #435 −3 dòng xóa · +59 dòng thêm · Net +56 dòng
  184. fix(footer): tên sự kiện countdown bị trắng tiệp nền trắng

    fix
    • .site-footer strong:not([class*=footer-countdown]){color:#fff}
    • .footer-countdown__title{color:var(--cd-title,#003784)} (không còn bị đè)
    PR #434 −1 dòng xóa · +5 dòng thêm · Net +4 dòng
  185. chore(content): tạm ẩn bài có category "premium"

    chore
    • Thêm draft = true vào front matter → Zola bỏ qua khi build, bài không còn xuất hiện trên site (listing, taxonomy, sitemap). Đây là cách ẩn tạm thời, có thể đảo ngược (chỉ cần xoá draft = true để hiện
    • Chạy build_references.py để bài bị ẩn rời khỏi data/references.json.
    • Đây là ẩn tạm; nội dung và file vẫn còn trong repo.
    • Các data file khác (related.json, scores.json) được CI tự refresh và đã bỏ qua draft.
    • Nếu sau này muốn ẩn theo cơ chế khác (vẫn build nhưng loại khỏi listing), có thể chuyển sang lọc theo category trong template — báo mình nếu cần.
    PR #428 −0 dòng xóa · +1 dòng thêm · Net +1 dòng
  186. feat(seo): cover SVG → twin .og.webp cho og:image (social hiện đúng ảnh bài)

    chore
    PR #432 −8 dòng xóa · +172 dòng thêm · Net +164 dòng
  187. style(mobile): polish homepage feed thành card momo-style (mobile-only)

    chore
    • Hero card: surface bo góc 18px, đổ bóng nhẹ (--c-shadow-md), ảnh full-bleed phía trên, body có padding, category là pill (--c-accent-soft).
    • .home-card: surface bo góc 16px, shadow, ảnh tràn mép, body padded, category pill, :active scale nhẹ (phản hồi chạm), ẩn nhãn "Insights khán giả" thừa, siết line-clamp.
    • ≤380px: giảm padding + cỡ chữ cho máy nhỏ.
    • ✅ Chỉ sửa trong @media (max-width: 720px) / ≤380px — không sửa selector global, .container, html/body.
    • ✅ Không đụng desktop (grid 3 cột, hero 2 cột giữ nguyên).
    PR #429 −10 dòng xóa · +88 dòng thêm · Net +78 dòng
  188. feat(tools): H-Dashboard — invoice (hóa đơn) spending analyzer with OCR

    chore
    • invoice-parser.js — mỗi mặt hàng = 1 giao dịch chi tiêu (expense). Đọc: cửa hàng, mã HĐ (Check#/Số HĐ), ngày/giờ, thu ngân, POS, hình thức TT, items (SL/đơn giá/thành tiền), tổng tiền. Số tiền kiểu VN
    • ocr-loader.js — thử pdf.js text layer trước; nếu PDF là ảnh scan (CamScanner/biên lai chụp) → fallback Tesseract.js (vie+eng) OCR, 100% client-side. looksLikeText() quyết định có cần OCR.
    • CSP (base.html) — thêm tối thiểu (additive): worker-src 'self' blob: https://cdn.jsdelivr.net + connect-src thêm https://cdn.jsdelivr.net https://tessdata.projectnaptha.com để worker/wasm/traineddata
    • Parser unit-test trên đúng hóa đơn Highlands mẫu → item Nước Tinh Khiết Dasani 510ml · 15.000, tổng 15.000, reconcile khớp ✓; + test hóa đơn nhiều mặt hàng (qty × đơn giá) ✓
    • node --check toàn bộ JS ✓ · zola build ✓ · qa_check.py ✓
    PR #424 −1 dòng xóa · +4744 dòng thêm · Net +4743 dòng
  189. Thêm SEO CONTENT SYSTEM RULE (GLOBAL) vào CLAUDE.md

    chore
    • 15 rule nội dung bắt buộc: search intent (thoả trong 150 từ đầu) · cấu trúc H1→Intro→TOC→H2/H3→FAQ→Related→CTA · ≥5 internal link (tin ≥3, gồm link hub chuyên mục) · content depth tiers (tin 800+, chu
    • Bảng trạng thái hạ tầng Zola — đánh dấu cái đã auto vs cần làm:
    • ✅ Auto: TOC, Related Articles, Article + BreadcrumbList + FAQPage schema, References, internal-link validation.
    • ❌ TODO: prev/next nav + block "Đọc tiếp", pagination category/tag, fail-build on broken link.
    • Checklist nhanh khi viết bài + cập nhật dòng internal-link trong "Quy tắc SEO QA" (≥1 → ≥5).
    PR #425 −3 dòng xóa · +84 dòng thêm · Net +81 dòng
  190. Bài báo chí — VPBank bắt tay Circle ra mắt siêu thẻ Free trọn đời cho Gen Z

    feat
    • File: content/baochi/vpbank-circle-sieu-the-free-tron-doi-gen-z.md
    • Cover: static/img/covers/vpbank-circle-sieu-the-free-tron-doi-gen-z.svg (gradient thương hiệu, không picsum)
    • Category: ["Tất cả", "Báo chí", "Ngân hàng"]
    • SEO QA: 100/100 · Hạng A+ · 1584 từ · từ khoá thẻ VPBank Circle
    • ✅ AdSense-friendly: >1000 từ, 6 H2, FAQ 5 câu (FAQPage schema), ảnh có alt
    PR #421 −1 dòng xóa · +256 dòng thêm · Net +255 dòng
  191. feat(pages): thêm trang Tuyên bố bản quyền (chuẩn AdSense + SEO)

    chore
    • content/pages/copyright.md (mới): quyền sở hữu (© 2026, Luật SHTT VN + Công ước Berne), phạm vi bảo hộ, phân biệt mã nguồn mở vs nội dung, điều kiện trích dẫn/ghi nguồn (gồm cấm scraping & huấn luyện
    • config.toml: thêm vào menu con nhóm "Giới thiệu".
    • templates/base.html: thêm link "Bản quyền" ở footer.
    • content/pages/about.md: liên kết tới trang bản quyền.
    • python3 scripts/build_references.py → OK
    PR #420 −3 dòng xóa · +182 dòng thêm · Net +179 dòng
  192. CMS: cập nhật footer countdown

    chore
    −6 dòng xóa · +6 dòng thêm · Net +0 dòng
  193. Add báo chí article — macOS 27 Golden Gate có gì mới

    feat
    • File: content/baochi/macos-27-golden-gate-co-gi-moi.md
    • Category: ["Tất cả", "Báo chí", "Công nghệ"]
    • Độ dài: 1534 từ · SEO QA 100/100 (A+)
    • Có block FAQ + FAQPage schema (4 câu), thumbnail og:image, internal + external links uy tín.
    • python3 scripts/seo_qa_checker.py content/baochi/macos-27-golden-gate-co-gi-moi.md → 100/100 A+
    PR #414 −1 dòng xóa · +237 dòng thêm · Net +236 dòng
  194. thêm workflow auto-merge thật (ZERO_BARRIER) — hết kẹt merge tay

    feat
    • Chỉ merge khi qa-check (job của QA Gatekeeper) success cho đúng head sha.
    • Bỏ qua: draft, base≠main, có blocked_labels, conflict (dirty).
    • Poll mergeable (GitHub tính async) trước khi merge; conflict → comment, không merge bừa.
    • workflow_run → token có quyền ghi nhưng chạy từ workflow trên main (an toàn với fork).
    • python3 -m py_compile scripts/try_auto_merge.py → OK
    PR #413 −1 dòng xóa · +251 dòng thêm · Net +250 dòng
  195. Bài báo — Giá vàng hôm nay 18/6 giảm mạnh

    feat
    • Category: ["Tất cả", "Báo chí", "Ngân hàng"] (đúng rule bb)
    • 1.532 từ · SEO QA 100/100 (A+) · keyword giá vàng hôm nay
    • Bảng giá vàng miếng SJC + 4 loại nhẫn (mua/bán, mức giảm, chênh lệch)
    • Phân tích nguyên nhân: Fed giữ lãi suất 3,5–3,75% nhưng phát tín hiệu "diều hâu" (dot plot 9/19, CME FedWatch 78%), USD mạnh lên ép vàng
    • Giải thích "nợ vàng"/giấy hẹn + góc nhìn nên mua hay chờ
    PR #412 −28 dòng xóa · +154 dòng thêm · Net +126 dòng
  196. content(baochi): xoá bài V-Family trùng, giữ bản điểm cao (#407)

    remove
    • 🗑️ Xoá content/baochi/vietinbank-v-family-giai-phap-tai-chinh-gia-dinh.md
    • 🔗 Sửa internal link trong bài Starbucks–Fansipan → trỏ sang bản giữ lại (vietinbank-v-family-nhom-gia-dinh) để không gãy link.
    • ✅ grep xác nhận không còn tham chiếu nào tới slug đã xoá.
    PR #410 −100 dòng xóa · +8 dòng thêm · Net -92 dòng
  197. bài báo VNeID 2.2.8 — phản ánh lừa đảo, quét QR căn cước

    feat
    • content/baochi/vneid-2-2-8-phan-anh-lua-dao-quet-qr.md
    • static/img/covers/vneid-2-2-8-phan-anh-lua-dao-quet-qr.svg (cover brand gradient + motif QR)
    • SEO QA 100/100 (A+), 1124 từ, kw VNeID 2.2.8, category ["Tất cả","Báo chí","Công nghệ"]
    • 6 H2, FAQ FAQPage schema 5 câu
    • 2 internal link (/baochi/liobank-bao-mat-an-toan-the-nao/, /baochi/huong-dan-xac-thuc-cccd-msb-digital-bank/) + external chính thống (vneid.gov.vn, dichvucong.gov.vn)
    PR #411 −0 dòng xóa · +113 dòng thêm · Net +113 dòng
  198. CMS: cập nhật bài 'Những Quy Định Cấm Từ Shopee Affiliate 2026 Mới Nhất'

    chore
    −7 dòng xóa · +3 dòng thêm · Net -4 dòng
  199. 2 bài baochi — VietinBank V-Family & Mùa quả chín xứ Đông

    feat
    • SEO QA 100/100 (A+), 1444 từ, kw VietinBank V-Family
    • 6 H2, bảng hạng nhóm + ưu đãi + phòng chờ sân bay, FAQ schema 5 câu
    • Ghi chú YMYL + link /terms/ (đã fix prefix), 3 internal link, nguồn chính thức VietinBank
    • SEO QA 100/100 (A+), 1428 từ, kw Mùa quả chín xứ Đông
    • 6 H2, hái vải thiều Thanh Hà + vườn nho VietGAP + di tích xứ Đông, FAQ schema 5 câu
    PR #407 −0 dòng xóa · +252 dòng thêm · Net +252 dòng
  200. ci: dừng vòng lặp deploy của bot dashboard (giãn cron + bỏ workflow_run)

    chore
    • deploy.yml chạy trên mọi push main (không paths-ignore).
    • build-dashboard.yml + github-activity.yml chạy lại trên workflow_run sau mỗi deploy, ghi JSON có timestamp mới → push main → trigger deploy → re-run → lặp vô hạn. build-dashboard còn cron */5 (288 lần
    • Burst nhiều deploy/phút → cạn API rate limit → bước Setup Pages fail.
    • build-dashboard.yml: bỏ workflow_run; cron /5 → 0 /6 (mỗi 6h).
    • github-activity.yml: bỏ workflow_run; giữ cron daily.
    PR #409 −12 dòng xóa · +12 dòng thêm · Net +0 dòng
  201. content(baochi): Starbucks Fansipan — cửa hàng cà phê cao nhất châu Á

    chore
    • content/baochi/starbucks-cua-hang-cao-nhat-chau-a-fansipan.md
    • categories = ["Tất cả", "Báo chí", "Du lịch"]; seo_keyword = "Starbucks Fansipan"; FAQ 3 câu (FAQPage).
    • Internal: bài V-Family + chuyên mục Du lịch. External: Starbucks Vietnam (ghi nguồn Znews).
    • SEO QA: 94/100 (A), 1112 từ.
    PR #408 −1 dòng xóa · +163 dòng thêm · Net +162 dòng
  202. feat(dashboards): bản đồ "Giao dịch theo vùng địa lý" + bài V-Family

    chore
    • geo.js (mới) đọc nội dung giao dịch → tách địa điểm (63 tỉnh/thành + địa điểm cụ thể: Bàu Bàng, Phú Quốc, Sa Pa…). Không có địa điểm → mặc định TP. Hồ Chí Minh.
    • Khớp whole-word đã bỏ dấu (chống "TIEN THUE NHA" dính "Huế"); địa điểm cụ thể thắng tỉnh cha.
    • Bản đồ SVG: silhouette VN teal trên nền sáng + chấm theo giá trị + nhãn + legend + chip vùng. Style chung .dash-geo__*.
    • content/baochi/vietinbank-v-family-giai-phap-tai-chinh-gia-dinh.md — SEO QA 94/100 (A), 1336 từ, FAQ, disclaimer YMYL.
    • node --check geo + app ×3: OK · detectPlace 6/6 · render smoke test OK
    PR #406 −1 dòng xóa · +1387 dòng thêm · Net +1386 dòng
  203. bài báo tên miền .ai — hòn đảo Anguilla hốt bạc nhờ AI

    feat
    • content/baochi/ten-mien-ai-hon-dao-anguilla-hot-bac.md — bài viết mới, giọng cá nhân (1st person), góc nhìn + phân tích riêng (không paraphrase máy móc).
    • static/img/covers/ten-mien-ai-hon-dao-anguilla-hot-bac.svg — cover brand gradient (#38bdf8 → #1d4ed8).
    • data/references.json, data/seo-qa-scores.json — auto-refresh.
    • SEO QA: 100/100 (A+), 1674 từ, từ khoá chính tên miền .ai.
    • Category: ["Tất cả", "Báo chí", "Công nghệ"] (đúng rule bb).
    PR #405 −2 dòng xóa · +255 dòng thêm · Net +253 dòng
  204. fix(dashboards): khôi phục AI Insights (Starbucks) + PDF nền trắng cho F/L/O

    fix
    • node --check 6 file JS (insights + export ×3): OK
    • python3 scripts/test_f_dashboard.py: 7/7 PASS
    • Repro JS ↔ Python ra output giống hệt (giữ contract mirror)
    • Templates nạp JS trực tiếp qua get_url (không bundle) → deploy là có hiệu lực
    PR #404 −114 dòng xóa · +422 dòng thêm · Net +308 dòng
  205. O-Dashboard — Liobank by OCB PDF statement dashboard

    feat
    PR #403 −0 dòng xóa · +4173 dòng thêm · Net +4173 dòng
  206. content+feat: bb tax article + richer rule-based insights engine

    chore
    PR #402 −145 dòng xóa · +570 dòng thêm · Net +425 dòng
  207. fix(dashboards): PDF export includes full dashboard (5 charts + empty fallbacks)

    fix
    • Capture: live Chart.js via toBase64Image('image/jpeg') → white bg (no black/transparent), aspect-ratio preserved, fits content width.
    • Empty-data fallback (per section, from charts payload): clean card "Chưa đủ dữ liệu để phân tích" — never blank/black chart, never NaN/undefined (values via formatVnd).
    • Page-break aware; watermark / Mysign signature / page-numbers auto-applied to new pages via existing finalizePdfPages. KPI/health/tiers/insights/table/Nokia fonts intact.
    • Untouched: parser, upload, JSON/CSV export, storage, auth. Each bank keeps its own schema (F: amount/balance · L: debit/credit/balance) + its own canvas ids.
    PR #401 −4 dòng xóa · +376 dòng thêm · Net +372 dòng
  208. fix(img): resolve 3 missing-image 404s (header/banner/premium thumbnail)

    fix
    PR #400 −6113 dòng xóa · +12 dòng thêm · Net -6101 dòng
  209. content-based domain selector + offline-safe qa-404-checker

    feat
    PR #399 −1066 dòng xóa · +28658 dòng thêm · Net +27592 dòng
  210. PREVIEW: Phase-4 dashboard analytics + Insights pagination refactor

    refactor
    PR #398 −295 dòng xóa · +593 dòng thêm · Net +298 dòng
  211. qa-domain-selector — domain suggestions on Insights (2h cron)

    feat
    PR #397 −0 dòng xóa · +2677 dòng thêm · Net +2677 dòng
  212. fix(seo-badge): score all posts so SEO badge renders on every post

    fix
    PR #396 −48 dòng xóa · +1911 dòng thêm · Net +1863 dòng
  213. fix(references): / double-prefix 404 in post References blocks

    fix
    PR #395 −173 dòng xóa · +292 dòng thêm · Net +119 dòng
  214. feat(dashboards): Sembcorp UI for F+L dashboards + countdown title brand color

    chore
    • White cards · thin teal border #00a69d · large asymmetric radius (18px/6px) · airy spacing · soft brand shadow + hover lift
    • Headings with teal accent bar; each chart/section in its own bordered card; compact legends with dots matching the brand chart palette (#003784/#00a69d/#e30613/#38bdf8/#ff9500)
    • Prominent numbers (≈1.6rem, weight 800, tabular-nums; income teal / expense red)
    • Header no longer covered by sticky navbar (scroll-margin-top); responsive desktop 2-col → mobile 1-col; tables scroll
    • White cards keep fixed dark ink → readable in OS light & dark
    PR #394 −429 dòng xóa · +913 dòng thêm · Net +484 dòng
  215. feat(toc): global auto Table of Contents (native page.toc)

    chore
    • templates/page.html — render <nav class="toc"> từ page.toc, gate toc_total >= 3 and page.extra.toc|default(true).
    • sass/_toc.scss (mới) + sass/site.scss — style scoped .post-single__content .toc, semantic tokens (dark-mode), responsive ≤720px.
    • 14 content/posting/*.md — gỡ block ## Mục lục thủ công.
    • CLAUDE.md — quy chuẩn TOC.
    • Hiện khi ≥ 3 heading (H2/H3). Bài ngắn → ẩn.
    PR #393 −203 dòng xóa · +102 dòng thêm · Net -101 dòng
  216. footer contrast, AdSense privacy link, version badge SHA, L-Dashboard upload crash

    fix
    PR #392 −18 dòng xóa · +138 dòng thêm · Net +120 dòng
  217. hotfix(l-dashboard): LPBank PDF.js CSP + local vendor assets

    security
    • 'self'
    • cdn.jsdelivr.net
    • … (không có cdnjs)
    • python3 scripts/test_l_dashboard.py — 9/9 OK
    • zola build — PASS
    PR #391 −9 dòng xóa · +247 dòng thêm · Net +238 dòng
  218. seo: optimize 15 new series posts (meta + headings)

    chore
    • Rút description về ≤160 ký tự (SERP)
    • Căn seo_keyword vào H2 / intro
    • Sửa false-positive H1 trong code sample (chan-trang)
    • Bổ sung internal + external links cho premium-fintech-paywall-demo
    PR #390 −32 dòng xóa · +41 dòng thêm · Net +9 dòng
  219. content(series): Bài 4–6 — Uranium 5/5 + AdSense/SEO 6/15

    chore
    PR #378 −43 dòng xóa · +3489 dòng thêm · Net +3446 dòng
  220. feat(seo): SEO Rank auto-fix system and sidebar progress

    fix
    • deploy/QA: --scan-only
    • seo-rank-autofix.yml: weekly run opens PR with content fixes (never main)
    • 6/6 unit tests pass
    • zola build OK
    • No paid APIs
    PR #389 −9 dòng xóa · +2262 dòng thêm · Net +2253 dòng
  221. feat(insights): add GitHub Activity heatmap widget

    chore
    • Build script (scripts/build_github_activity.py): aggregates 365-day activity from git log + GitHub REST API (PRs, issues, reviews) into data/github-activity.json
    • Heatmap UI: week columns, month/weekday labels, green intensity levels, Less→More legend
    • Activity overview: Commits / Pull requests / Issues / Code review breakdown (%)
    • Fallback: keeps cached JSON + shows "GitHub activity data may be outdated" when API fails
    • CI: runs on deploy + QA; daily refresh workflow (github-activity.yml)
    PR #388 −1 dòng xóa · +6090 dòng thêm · Net +6089 dòng
  222. feat(sidebar): add Google Rank SEO authority widget

    chore
    PR #387 −1 dòng xóa · +767 dòng thêm · Net +766 dòng
  223. content(series): Bài 2 — AdSense, SEO, Uranium foundation

    chore
    • Title, meta description, slug
    • Mục lục + H2/H3
    • FAQ Schema (3 câu)
    • Internal links (series + pillar)
    • External links (Google / Wikipedia / IAEA)
    PR #376 −9 dòng xóa · +915 dòng thêm · Net +906 dòng
  224. hotfix(l-dashboard): fix GitHub OAuth login blank page

    fix
    • dataset.fdView → dataset.ldView in showView()
    • Regression tests in scripts/test_l_dashboard.py
    • python3 -m unittest scripts.test_l_dashboard -v — 5/5 pass
    • zola build — OK
    • F-Dashboard auth-gate untouched
    PR #384 −4 dòng xóa · +29 dòng thêm · Net +25 dòng
  225. feat(footer): dual countdown format — days | hours + minutes

    chore
    • X = total remaining days
    • Y = total remaining hours
    • Z = minute remainder within current hour
    • Updates every 60 seconds
    • test_footer_countdown — 6/6 pass
    PR #386 −134 dòng xóa · +172 dòng thêm · Net +38 dòng
  226. style(footer): align countdown band with Hilda theme + QA footer

    chore
    • Số đếm: chip nền #eef3fb, chữ Ericsson Blue #003784, font Hilda 700
    • Prefix/suffix/unit: Be Vietnam Pro meta, màu muted #666
    • Tiêu đề sự kiện: Hilda 800, #000
    • Card: border/shadow giống .qa-card
    • Admin preview: HTML markup đồng bộ với footer live
    PR #383 −47 dòng xóa · +95 dòng thêm · Net +48 dòng
  227. feat(ci): free-first AI Diagnose — replace Claude workflow dependency

    chore
    • scripts/ai_diagnose.py — Tier 1 heuristics, optional Ollama/Claude opt-in
    • Integrated into qa-failed.py, scripts/ff.py, build-failure-handler.yml (AI_DIAGNOSE_USE_CLAUDE=0)
    • scripts/test_ai_diagnose.py, docs/AI-DIAGNOSE-MIGRATION.md
    • Unit tests for tier-1 heuristics and opt-in paths
    PR #380 −23 dòng xóa · +873 dòng thêm · Net +850 dòng
  228. fix(links): repair 11 broken external URLs flagged by zola check

    fix
    • zola check — 0 broken links
    PR #382 −11 dòng xóa · +11 dòng thêm · Net +0 dòng
  229. feat(paywall): reactivate premium via category + 100k VND pricing

    chore
    • categories = ["premium"] triggers premium paywall via paywall_prepare_build.py
    • Injects extra.premium = true + price = 100000 into frontmatter at strip time (Tera in operator unreliable for arrays)
    • Enables paywall API: paywall_api_url = "https://blog-paywall-api.onrender.com", paywall_default_price = 100000
    • UI: gold ⭐ Premium badge, updated CTA, teaser fade, localStorage unlock tokens
    • Demo: premium-fintech-paywall-demo.md uses categories = ["premium"]
    PR #379 −178 dòng xóa · +182 dòng thêm · Net +4 dòng
  230. feat(footer): countdown box + admin config page

    chore
    −3 dòng xóa · +915 dòng thêm · Net +912 dòng
  231. feat(insights): build history snapshots every 5 minutes

    chore
    −19 dòng xóa · +424 dòng thêm · Net +405 dòng
  232. SEO11 phase 2 iter 1: h1 on static asset indexes

    chore
    −2 dòng xóa · +2 dòng thêm · Net +0 dòng
  233. fix(ci): auto-trigger deploy after bot push_to_main

    fix
    −1 dòng xóa · +17 dòng thêm · Net +16 dòng
  234. LPBank L-Dashboard statement analyzer

    feat
    • New /tools/l-dashboard/ page (clone F-Dashboard UX for LPBank PDF)
    • lpbank-parser.js + scripts/lpbank_parser.py for multi-page PDF statements
    • Metadata: account, CIF, opening/ending balance, total debit/credit
    • Transaction table: txn date, value date, description, txn.no, debit, credit, balance
    • Filters, reconciliation warning, export JSON/CSV/PDF
    PR #374 −4 dòng xóa · +3744 dòng thêm · Net +3740 dòng
  235. fix(ci): correct gh pr view --jq syntax in changelog workflow

    fix
    −1 dòng xóa · +1 dòng thêm · Net +0 dòng
  236. fix(ci): stash local changes before pull in push_to_main.sh

    fix
    −0 dòng xóa · +12 dòng thêm · Net +12 dòng
  237. refresh Build Dashboard data

    chore
    • Workflow: Fetch Build Dashboard
    • Branch: chore/build-dashboard-data
    • Gắn label no-auto-merge nếu cần giữ PR chờ review tay
    PR #351 −325 dòng xóa · +325 dòng thêm · Net +0 dòng
  238. feat(prompt-support): v2 token-efficient prompt optimizer for AI agents

    chore
    • static/js/prompt-support.js — engine v2
    • templates/prompt-support.html — UI controls
    • sass/_prompt-support.scss — scores, compare, mobile
    PR #346 −120 dòng xóa · +862 dòng thêm · Net +742 dòng
  239. feat(ci): FULLY AUTOMATED OPERATIONS merge policy

    chore
    • data/auto-merge-policy.json — config machine-readable
    • scripts/auto_merge_policy.py — classify PR: auto-eligible vs manual-required
    • scripts/test_auto_merge_policy.py — 11 unit tests
    • Anti-loop protection (data/auto-merge-loop-state.json)
    • Delete branch sau merge
    PR #349 −113 dòng xóa · +640 dòng thêm · Net +527 dòng
  240. feat(f-dashboard): GitHub auth, JSON/PDF export, health legend

    chore
    • 🔐 GitHub OAuth gate — cùng flow CMS /editor/ (cms_auth_url, session zola-cms-session-id)
    • 📥 Xuất JSON — tải auto + xóa IndexedDB ngay sau download
    • 📄 Xuất PDF infographic — báo cáo tổng hợp + watermark chìm {16hex}_{blog_domain}
    • 📊 Health legend — định nghĩa Excellent/Good/Average/Risky/Danger + highlight cấp hiện tại
    • ⚡ Phiên tạm — không lưu tích lũy online; chỉ IndexedDB browser đến khi export
    PR #334 −132 dòng xóa · +3578 dòng thêm · Net +3446 dòng
  241. refresh Google Trends VN hot search

    chore
    PR #332 −106 dòng xóa · +106 dòng thêm · Net +0 dòng
  242. fix(qa): rule-checker scanner 0 false positives

    fix
    • Skip required approvals = 0 vs auto-merge (aligned)
    • Skip classify cancelled khi có «không» trước
    • Reset loop_detected state
    • CLAUDE.md learning cập nhật
    PR #327 −23 dòng xóa · +32 dòng thêm · Net +9 dòng
  243. changelog after PR #314

    chore
    • Workflow: Auto-update changelog.json
    • Branch: chore/changelog-sync
    • Gắn label no-auto-merge nếu cần giữ PR chờ review tay
    PR #318 −0 dòng xóa · +15 dòng thêm · Net +15 dòng
  244. feat(qa): QA Auto Rule Checker — phát hiện rule xung đột mỗi 8h

    chore
    • reports/rule-conflict-report.json
    • reports/rule-conflict-report.md
    • data/qa-rule-checker-state.json (anti-loop)
    • Append ## QA Rule Checker Learning vào CLAUDE.md
    • confidence >= 90% → sửa + PR branch qa/rule-checker-auto-*
    PR #322 −0 dòng xóa · +1217 dòng thêm · Net +1217 dòng
  245. chore: maintenance merge session — dashboard + compliance + data refresh

    chore
    • Merged #313 cancelled deploy dashboard fix
    • Merged #309 compliance internal links 100/100
    • Merged #311 compliance score refresh
    • Merged #312 build dashboard refresh (status_normalized)
    PR #310
  246. chore: refresh Build Dashboard data

    chore
    • data/build-dashboard.json — refresh sau #313, giữ status_normalized
    PR #312 −5 dòng xóa · +5 dòng thêm · Net +0 dòng
  247. qa: Compliance Score audit + auto-fix

    fix
    • data/compliance-score.json — 100/100 A+ sau #309
    PR #311 −1 dòng xóa · +1 dòng thêm · Net +0 dòng
  248. fix: compliance internal links — root cause + diagnostics

    fix
    • compliance-link-report.json, compliance_audit.py, insights broken-link UI
    PR #309 −96 dòng xóa · +315 dòng thêm · Net +219 dòng
  249. fix(dashboard): phân loại cancelled deploy runs — Build #387/#388

    fix
    • fetch_build_dashboard.py status_normalized, cancelled UI styles
    PR #313 −77 dòng xóa · +517 dòng thêm · Net +440 dòng
  250. qa: Compliance Score audit + auto-fix

    fix
    • Workflow: Compliance Score Audit
    • Branch: qa/compliance-auto
    • KHÔNG auto-merge
    PR #303 −2 dòng xóa · +2 dòng thêm · Net +0 dòng
  251. changelog after PR #300

    chore
    • Workflow: Auto-update changelog.json
    • Branch: chore/changelog-sync
    • KHÔNG auto-merge
    PR #305 −0 dòng xóa · +13 dòng thêm · Net +13 dòng
  252. refresh Build Dashboard data

    chore
    • Workflow: Fetch Build Dashboard
    • Branch: chore/build-dashboard-data
    • KHÔNG auto-merge
    PR #299 −259 dòng xóa · +225 dòng thêm · Net -34 dòng
  253. 🤖 Self-healing: 14 mechanical fix(es)

    fix
    • Normalize tags: lowercase + dedupe + sort
    • Dedupe categories
    • Date format: YYYY/MM/DD → YYYY-MM-DD
    • Trim trailing whitespace trong frontmatter
    • Đảm bảo file kết thúc bằng 1 newline
    PR #301 −16 dòng xóa · +14 dòng thêm · Net -2 dòng
  254. refresh Build Dashboard data

    chore
    • Workflow: Fetch Build Dashboard
    • Branch: chore/build-dashboard-data
    • KHÔNG auto-merge
    PR #294 −173 dòng xóa · +224 dòng thêm · Net +51 dòng
  255. qa: Compliance Score audit + auto-fix

    fix
    • Workflow: Compliance Score Audit
    • Branch: qa/compliance-auto
    • KHÔNG auto-merge
    PR #293 −2 dòng xóa · +2 dòng thêm · Net +0 dòng
  256. qa: Compliance Score audit + auto-fix

    fix
    • Workflow: Compliance Score Audit
    • Branch: qa/compliance-auto
    • KHÔNG auto-merge
    PR #289 −2 dòng xóa · +2 dòng thêm · Net +0 dòng
  257. changelog after PR #272

    chore
    • Workflow: Auto-update changelog.json
    • Branch: chore/changelog-sync
    • KHÔNG auto-merge
    PR #287 −0 dòng xóa · +9 dòng thêm · Net +9 dòng
  258. Feat/devops no dependabot batch 10

    chore
    PR #286
  259. feat(sidebar): Today hot search — Google Trends Vietnam (25 keywords)

    chore
    • scripts/fetch_google_trends.py — batchexecute (primary), RSS fallback, cache fallback
    • data/google-trends-vn.json — build-time data
    • templates/macros/hot-search.html + SCSS Google Trends–style rank list
    • deploy.yml — fetch trước zola build
    • google-trends.yml — refresh hourly → PR chore/google-trends-data
    PR #283 −0 dòng xóa · +701 dòng thêm · Net +701 dòng
  260. feat(science): uranium series infra + Bài 01 + hub Iran article

    chore
    • science-uranium-series.json manifest (5 parts)
    • Category Khoa học: categories.json + menu
    • series-hub macro, multi-series nav/related/breadcrumb
    • Bài 01: Uranium là gì (posting/)
    • Iran article: hub_series, category Khoa học, đọc thêm
    PR #281 −36 dòng xóa · +396 dòng thêm · Net +360 dòng
  261. feat(qa): Related Posts QA checker — topic cluster scoring

    chore
    • Quét posting + baochi (39+ bài)
    • Phân tích category, tags, seo_keyword, title, description, body
    • Gom topic cluster: Du lịch, Ẩm thực, Công nghệ, Tài chính, Thế giới, Khuyến mãi
    • Related: ưu tiên cùng cluster, cross-topic chỉ khi thiếu neighbor + penalty 0.35x
    • --fix ghi data/related.json + data/scores.json
    PR #278 −200 dòng xóa · +721 dòng thêm · Net +521 dòng
  262. Feature/seo foundation series

    chore
    PR #277 −1 dòng xóa · +427 dòng thêm · Net +426 dòng
  263. feat(cms): auto-refresh post list from GitHub on login

    chore
    • Sau xác thực thành công (/auth/me), gọi enterDashboard(true) — fetch ngay từ GitHub API
    • Xóa localStorage cache slug list trước khi fetch
    • GitHub API dùng cache: no-store
    • Force refresh chỉ tin slug từ repo hiện tại (không merge slug đã xóa khỏi repo)
    • Hiển thị loading state trong lúc fetch; fallback về bake nếu API lỗi
    PR #275 −12 dòng xóa · +61 dòng thêm · Net +49 dòng
  264. hotfix: fix GitHub Pages 404s from missing / base path

    fix
    • 95 link thiếu / trong 33 file markdown
    • Trước fix: ~30 trang HTML có href="/baochi/..." hoặc href="/posting/..." (404 trên production)
    • Sau fix: 0 link thiếu prefix
    • Canonical: https://seomoney.org/baochi/uu-dai-hoan-tien-the-liobank/ ✓
    • Body links: href="/baochi/..." ✓
    PR #274 −85 dòng xóa · +282 dòng thêm · Net +197 dòng
  265. feature: auto-generate references section at end of posts

    chore
    PR #273 −6 dòng xóa · +1770 dòng thêm · Net +1764 dòng
  266. QA: Daily performance checker (00:00 GMT+7) + Lighthouse audit automa…

    chore
    • Extend perf-audit.yml: cron 0 17 * (00:00 Asia/Ho_Chi_Minh)
    • Add performance_qa_checker.py: PageSpeed audit, regression compare, SAFE fix PR
    • Extend fetch_pagespeed.py with CWV, resource weight, render-blocking metrics
    • Store audit snapshot baseline; upload reports as CI artifacts
    • NEVER push/merge main — branch qa/performance-auto-fix-YYYYMMDD only
    PR #271 −105 dòng xóa · +760 dòng thêm · Net +655 dòng
  267. Feat/devops no dependabot batch 10

    chore
    PR #269 −389 dòng xóa · +1909 dòng thêm · Net +1520 dòng
  268. ci: build-failure handler + SEO11 polish + prompt-support

    chore
    • CI auto-fix: build-failure-handler.yml, rewrite qa-failed.py, scripts/vaccine_rules.py — PR flow, không push main
    • SEO11: Lighthouse meta/title/OG fixes (10 iter) + nâng 4 bài lên A+
    • Compliance: cron 12h audit + auto-fix warn/fail
    • UI: trang /prompt-support/ (template + SCSS + JS)
    • Workflow: pr-approval.yml, cập nhật pr-policy / main-guard
    PR #270 −522 dòng xóa · +3452 dòng thêm · Net +2930 dòng
  269. ci: remove Dependabot; enforce feature branch PR batch-of-10 merge

    remove
    PR #268 −61 dòng xóa · +23 dòng thêm · Net -38 dòng
  270. 🤖 Self-healing: 12 mechanical fix(es)

    fix
    • Normalize tags: lowercase + dedupe + sort
    • Dedupe categories
    • Date format: YYYY/MM/DD → YYYY-MM-DD
    • Trim trailing whitespace trong frontmatter
    • Đảm bảo file kết thúc bằng 1 newline
    PR #266 −10 dòng xóa · +12 dòng thêm · Net +2 dòng
  271. 🤖 Self-healing: 21 mechanical fix(es)

    fix
    • Normalize tags: lowercase + dedupe + sort
    • Dedupe categories
    • Date format: YYYY/MM/DD → YYYY-MM-DD
    • Trim trailing whitespace trong frontmatter
    • Đảm bảo file kết thúc bằng 1 newline
    PR #265 −14 dòng xóa · +23 dòng thêm · Net +9 dòng
  272. feat(navbar): nền teal #00a69d + gỡ hoàn toàn theme selector

    chore
    • Nền navbar đổi từ gradient xanh dương → #00a69d (teal đặc), shadow + mask cuộn mobile cũng chuyển teal.
    • Gỡ hoàn toàn theme selector (nút 🎨 .theme-dropdown) khỏi navbar. Blog mặc định theme Hilda (đã set bởi inline script ở <head>); các script theme đều guard if(!btn) return nên no-op an toàn khi thiếu m
    • Giữ nguyên: bảng chữ cái trắng mờ trải đều (FreightSans Pro) + chữ menu trắng.
    • qa_check.py pass; zola build (qa-check) compile SASS.
    PR #264 −23 dòng xóa · +16 dòng thêm · Net -7 dòng
  273. feat(report): chặn THẬT bằng backend FastAPI OAuth (gỡ report khỏi repo public)

    chore
    • GET /reports — list metadata (auth).
    • GET /reports/{file} — nội dung .md (auth), 404 nếu thiếu.
    • POST /reports — tạo/ghi đè (auth).
    • POST /reports/delete — xoá (auth).
    • Lưu report:doc:* + report:meta trong Redis; validate filename chống path traversal; cap 500KB.
    PR #263 −139 dòng xóa · +392 dòng thêm · Net +253 dòng
  274. feat(navbar): nền gradient xanh + bảng chữ cái trắng mờ (font FreightSans Pro)

    chore
    • Nền: gradient xanh thương hiệu #38bdf8 → #2563eb → #1d4ed8 (đồng bộ placeholder).
    • Chữ cái trang trí: 30 chữ A–Z rải ngẫu nhiên vị trí + chiều xoay + cỡ, màu trắng opacity 0.05–0.13 (mờ, dịu mắt, không chói), font FreightSans Pro (self-host 2 weight 500/700).
    • An toàn: lớp chữ nằm trong <div class="navbar__letters" aria-hidden pointer-events:none> absolute + overflow:hidden riêng → KHÔNG cắt dropdown menu, không chặn click. Menu nằm trên (z-index:1).
    • Chữ menu / dropdown / theme-toggle chuyển trắng cho hợp nền; mask cuộn phải mobile đổi sang xanh đậm. Tôn trọng prefers-reduced-motion.
    • qa_check.py pass (SCSS brace check); zola build (qa-check) sẽ compile SASS.
    PR #262 −0 dòng xóa · +118 dòng thêm · Net +118 dòng
  275. Add MSB credit card article

    feat
    • Slug: the-tin-dung-msb-huong-dan-chi-tiet
    • Từ khóa chính: "thẻ tín dụng MSB"
    • Danh mục: Tất cả, Ngân hàng, Báo chí
    • Độ dài: ~1,400 từ
    • Nội dung:
    PR #261 −0 dòng xóa · +94 dòng thêm · Net +94 dòng
  276. fix(report) + feat(cms): chặn guest tải report + mở rộng editor + brand button CMS

    fix
    • Mở rộng editor: bỏ cột sidebar + nới container max-width: 1400px qua pattern :has(.editor-app) (giống .insights/.du-lich) → form 2 cột + split preview rộng rãi, dễ thao tác. Chỉ ảnh hưởng /editor/, kh
    • Button "Content Management System (CMS)": badge gradient 5 màu chạy động, bo pill, hơi nghiêng nghịch ngợm, hover scale + đổi glow, chip CMS + ngôi sao xoay. Tôn trọng prefers-reduced-motion.
    • qa_check.py pass (gồm SCSS brace check).
    • CSS scoped component, không sửa global .container/.layout-grid trần (chỉ qua :has).
    PR #260 −0 dòng xóa · +86 dòng thêm · Net +86 dòng
  277. chore(ci): throttle build-related cron 5min→1h, xoá auto-throttle.yml (đang fail)

    remove
    • build-related.yml: cron '/5 ' → '0 *' (mỗi giờ — đủ tươi cho related posts, KHÔNG đốt quota Actions: trước đây ~576 min/ngày dễ vượt free tier).
    • Xoá hẳn auto-throttle.yml (đã hết tác dụng + đang fail).
    • qa_check.py pass.
    • build-related.yml YAML hợp lệ, cron mới 0 .
    • Không workflow nào còn phụ thuộc auto-throttle.
    PR #259 −55 dòng xóa · +4 dòng thêm · Net -51 dòng
  278. perf-audit fixer bỏ qua &lt;img&gt; trong comment + fallback ảnh lỗi → placeholder

    fix
    • qa_check.py pass.
    • perf-fixer test: chỉ sửa <img> thật, bỏ qua comment/LCP.
    PR #258 −3 dòng xóa · +51 dòng thêm · Net +48 dòng
  279. 🚀 Perf audit: 1 file(s) optimized

    chore
    • Thêm loading="lazy" vào <img> tags thiếu (skip LCP hero có fetchpriority=high)
    • Thêm decoding="async" vào <img> tags thiếu
    • KHÔNG thay đổi: source images, JS/CSS, content, layout
    PR #257 −3 dòng xóa · +3 dòng thêm · Net +0 dòng
  280. docs(claude): thư viện VACCINE + fixer từ audit toàn bộ lịch sử CI failed

    chore
    • CLAUDE.md: thêm mục "### 4. THƯ VIỆN VACCINE" trong rule Deploy (hiệu lực cao nhất), gồm:
    • Giao thức auto-fix: khớp Dấu hiệu → chạy FIXER ngay (không chẩn đoán lại); không khớp → ff/ff9 rồi append vaccine mới.
    • 3 vaccine V1–V3, mỗi cái có Dấu hiệu / Nguyên nhân / FIXER cụ thể (file + dòng + lệnh).
    • qa_check.py pass.
    • build-related run #37 (commit fix) = success (đã xác nhận hết 401).
    PR #256 −0 dòng xóa · +53 dòng thêm · Net +53 dòng
  281. fix(related): repo-id HuggingFace đầy đủ — hết 401, build-related hết fail

    fix
    • SentenceTransformer tự suy prefix sentence-transformers/ cho tên model trần.
    • snapshot_download thì KHÔNG → tên trần paraphrase-multilingual-MiniLM-L12-v2 bị HF tra như repo top-level không tồn tại → trả 401 Repository Not Found → fail cả build.
    • py_compile OK.
    • Sau merge, push đổi scripts/build_related.py sẽ trigger lại build-related.yml → kiểm tra build xanh thật.
    PR #255 −2 dòng xóa · +7 dòng thêm · Net +5 dòng
  282. fix(img): ảnh placeholder thương hiệu cho bài không có ảnh (thay picsum không liên quan)

    fix
    • scripts/make_placeholder.py — sinh SVG placeholder 3 tỉ lệ vào static/img/placeholder/ (không cần thư viện ngoài, chạy lại idempotent):
    • placeholder.svg (3:2) — thumbnail / list / hero
    • placeholder-wide.svg (16:9) — ảnh trong nội dung bài
    • placeholder-square.svg (1:1) — khối vuông
    • templates/macros/img.html — macro thumb_src(thumb): trả thumbnail hoặc fallback placeholder.
    PR #254 −83 dòng xóa · +277 dòng thêm · Net +194 dòng
  283. nangcap: nâng cấp 25 bài cũ điểm SEO QA < 90 lên đạt chuẩn A (≥90)

    chore
    • 33 bài quét → 25 bài < 90 đã nâng cấp · điểm trung bình 99.7 · 30/33 đạt 100.
    • 0 bài còn < 90.
    • Khai báo [extra] seo_keyword + đưa keyword vào title / đoạn mở đầu / 1 heading H2 (mở khoá 20đ).
    • Thêm internal link (cluster bài liên quan) + external link tới nguồn uy tín có thật: Wikipedia, IAEA, Visit Korea/Busan, Michelin Guide, UNESCO, GitHub/Zola docs, WCAG, Cổng BHXH Việt Nam, Korail…
    • Cắt description về ≤160, rút title dài (zola-vs-hugo), bổ sung thumbnail (hilda-guideline).
    PR #253 −514 dòng xóa · +1060 dòng thêm · Net +546 dòng
  284. SEO9: meta description duy nhất cho 17 trang section + bài thiếu mô tả

    chore
    • Homepage + 11 section _index: posting, baochi, du-lich, dien-anh,
    • pages/about.md + 5 bài baochi: chon-ngach-noi-dung, iran-uranium,
    • Title vài bài posting/baochi > 60 ký tự (chỉ là warning ở qa_check.py,
    • Một số bài chưa khai [extra] seo_keyword / thiếu external link — tối ưu sâu
    • ✅ python3 qa_check.py → All QA checks passed (178 files)
    PR #251 −53 dòng xóa · +298 dòng thêm · Net +245 dòng
  285. feat(adsense): trang pháp lý + E-E-A-T + disclosure + tiêu chí bb/bb9

    chore
    • content/pages/privacy.md — Chính sách bảo mật (cookies, Google AdSense, GA, opt-out)
    • content/pages/contact.md — Liên hệ (email 292648126+Banhang-Chogao@users.noreply.github.com)
    • content/pages/terms.md — Điều khoản & Miễn trừ (bản quyền, YMYL, affiliate)
    • Mở rộng about.md thành tiểu sử tác giả thật + cam kết nội dung
    • Sửa author.json bio (bỏ placeholder tiếng Anh)
    PR #252 −50 dòng xóa · +482 dòng thêm · Net +432 dòng
  286. feat(seo): thêm FAQ + FAQPage schema cho 8 bài banking/how-to

    chore
    • liobank-gioi-thieu-ban-be-nhan-thuong
    • liobank-la-gi-ngan-hang-so-noi-bat
    • mo-the-tin-dung-liobank-online-nhanh
    • uu-dai-hoan-tien-the-liobank
    • liobank-bao-mat-an-toan-the-nao
    PR #250 −9 dòng xóa · +165 dòng thêm · Net +156 dòng
  287. test: kiểm tra Slack notification trên production

    chore
    • File nằm trong data/, không được Zola publish ra site → an toàn.
    • Có thể xoá sau khi test xong.
    • Sau khi merge → push lên main → workflow Slack Commit Notification chạy, conclusion success, và tin nhắn xuất hiện trong kênh Slack.
    PR #249 −55 dòng xóa · +7 dòng thêm · Net -48 dòng
  288. fix(ci): sửa Slack notify fail do Dependabot bump slack-github-action v1→v3

    fix
    • slack-notify.yml: migrate sang API v3 — thêm webhook + webhook-type: incoming-webhook trong with, bỏ env block cũ. Giữ nguyên payload Block Kit.
    • Các action actions/* khác (checkout@v6, setup-node@v6...) tương thích ngược, qa/deploy vẫn pass — KHÔNG đụng.
    • YAML valid.
    • Push branch này tự chạy slack-notify → kiểm tra job notify xanh trước khi merge.
    PR #248 −3 dòng xóa · +5 dòng thêm · Net +2 dòng
  289. gỡ Dependabot khỏi hệ thống

    chore
    • Không có PR Dependabot nào đang mở cần đóng.
    • Không có workflow nào khác tham chiếu Dependabot.
    • .github/dependabot.yml không còn tồn tại → Dependabot ngừng tạo PR.
    PR #247 −55 dòng xóa · +0 dòng thêm · Net -55 dòng
  290. docs(bb9): cú pháp phím tắt thành `bb9 &lt;topic&gt;`

    chore
    • bb9 <topic> tự sáng tác bài mới từ chủ đề (khác bb là dán báo chí có sẵn).
    • Gõ bb9 trống → HỎI lại chủ đề, không tự bịa.
    • Cập nhật shortcuts.md + CLAUDE.md; đã hợp nhất với commit cùng chủ đề vừa có trên main.
    PR #246 −8 dòng xóa · +12 dòng thêm · Net +4 dòng
  291. deps(scripts): bump the pip-all group in /scripts with 15 updates

    chore
    PR #242 −15 dòng xóa · +15 dòng thêm · Net +0 dòng
  292. docs(bb9): bắt buộc cú pháp bb9 &lt;tên chủ đề&gt;

    chore
    • Đọc shortcuts.md mục bb9 → có block "Cú pháp gọi (BẮT BUỘC)".
    PR #245 −0 dòng xóa · +7 dòng thêm · Net +7 dòng
  293. feat(bb9): đăng bài hẹn giờ — viết draft, auto đăng n+3 buổi tối qua QA gate

    chore
    • Draft = draft = true + [extra] publish_at = "<n+3>T20:00:00+07:00". Zola bỏ qua draft → không lên site dù nằm trên main.
    • scripts/scheduled_publish.py: cron buổi tối flip bài tới hạn (draft=false, set date, xoá publish_at). Đã test: bài quá khứ → publish, bài tương lai → giữ draft. ✅
    • .github/workflows/scheduled-publish.yml: cron 0 13 * (20:00 GMT+7) + dispatch. QA gate: chạy qa_check.py + Zola build trước; PASS mới commit+push (→ deploy). FAIL → không đăng, mở issue (xử lý bằng
    • shortcuts.md: phím tắt bb9 (biến thể hẹn giờ của bb).
    • CLAUDE.md: rule "Đăng bài hẹn giờ".
    PR #244 −0 dòng xóa · +261 dòng thêm · Net +261 dòng
  294. Series Liobank 5 phần — ưu điểm & dẫn hướng đăng ký

    feat
    • Tất cả category ["Tất cả", "Báo chí", "Ngân hàng"], SEO QA 100/100 (A+).
    • Phần 3 & 5 dùng ảnh app thật (static/img/covers/liobank-app-quan-ly-chi-tieu.jpg).
    • Mỗi bài có CTA link giới thiệu + hướng dẫn mở link an toàn.
    • Build Zola xanh (deploy.yml).
    • 5 bài hiển thị tại /baochi/<slug>/, liên kết series hoạt động.
    PR #243 −65 dòng xóa · +1720 dòng thêm · Net +1655 dòng
  295. ci(deps): bật Dependabot (gated CI) + webp sweep tự động hằng ngày

    chore
    • optimize-images.yml: thêm cron hằng ngày 11:00 GMT+7 → quét bắt cả ảnh cũ còn sót chưa có .webp (không chỉ ảnh vừa push). Đã trigger 1 lần thủ công cho 2 ảnh sẵn có.
    • CLAUDE.md: rule WebP nâng thành "LUÔN BẬT".
    • Ecosystems: github-actions (/) + pip (visitor-counter, scripts). Weekly, grouped, giới hạn open-PR.
    • Không gây xung đột build site: Zola binary pin cứng trong deploy.yml, Dependabot không đụng. Nó chỉ mở PR (không push thẳng main).
    • Rule auto-fix (CLAUDE.md): PR Dependabot phải PASS qa-check + build mới merge; nếu bump làm đỏ → chạy ff auto-fix, không fix được thì đóng PR giữ version cũ; không bao giờ merge khi đỏ.
    PR #239 −2 dòng xóa · +76 dòng thêm · Net +74 dòng
  296. Redirect /categories/posting → /categories/tat-ca (tránh 404 URL cũ)

    chore
    • Thêm static/categories/posting/index.html: trang redirect (meta refresh 0s + location.replace + <link rel=canonical> + noindex,follow) chuyển /categories/posting/ → /categories/tat-ca/.
    • Zola copy static/ → public/; vì không còn bài nào dùng category Posting nên không xung đột với taxonomy.
    • Chỉ thêm 1 file tĩnh, không đụng layout/CSS/global.
    • noindex,follow + canonical → Google gộp tín hiệu về trang mới, gỡ URL cũ khỏi index.
    • zola build (0.22.1): 32 pages, 0 lỗi.
    PR #236 −0 dòng xóa · +18 dòng thêm · Net +18 dòng
  297. Bài Liobank — giới thiệu bạn bè nhận thưởng đến 500.000đ

    feat
    • Slug: liobank-gioi-thieu-ban-be-nhan-thuong
    • Category: ["Tất cả", "Báo chí", "Ngân hàng"]
    • SEO QA: 100/100 (A+), 1064 từ
    • Chèn link giới thiệu thật của tác giả: https://liobank.vn/rr/qyAJ
    • Dùng ảnh thật (mascot sư tử Liobank) làm thumbnail + ảnh trong bài (static/img/covers/liobank-gioi-thieu-ban-be-nhan-thuong.png)
    PR #238 −1 dòng xóa · +163 dòng thêm · Net +162 dòng
  298. feat(security+img): WebP pipeline song song + hardening bảo mật blog

    security
    • scripts/to_webp.py: sinh .webp cạnh file gốc (Pillow, fallback cwebp), idempotent, bỏ qua .svg/.gif.
    • .github/workflows/optimize-images.yml: push ảnh raster lên main → tự convert + commit .webp (có [skip ci], paths filter chỉ match raster ⇒ không loop).
    • templates/macros/img.html: macro picture_webp render <picture> ưu tiên webp + fallback.
    • static/robots.txt: Disallow /data/reports/ + /data/ (ẩn khỏi search).
    • ⚠️ Đã ghi rõ trong robots.txt + CLAUDE.md: GitHub Pages là host tĩnh → robots chỉ ẩn khỏi index, KHÔNG chặn truy cập trực tiếp. Muốn chặn thật cần backend auth (chưa làm, chờ user quyết).
    PR #237 −1 dòng xóa · +255 dòng thêm · Net +254 dòng
  299. SEO suite + fix build-related 429 + category scheme (Tất cả/Báo chí/Banking)

    fix
    • build-related.yml fail liên tục vì transformers bản mới gọi HF Hub API online → 429 Too Many Requests.
    • Fix: scripts/build_related.py nạp model từ cache cục bộ (snapshot_download(local_files_only=True)) → transformers coi là local, bỏ qua call online. Cold cache → fallback online + retry backoff.
    • Đổi Posting → Tất cả (mặc định mọi bài); thêm Báo chí (mặc định bài viết qua phím tắt bb/nhánh baochi).
    • Giữ category theo content: Banking, Công nghệ, Du lịch, Ẩm thực.
    • Sửa 2 bài công nghệ bị gắn nhầm Ẩm thực → Công nghệ.
    PR #231 −74 dòng xóa · +2811 dòng thêm · Net +2737 dòng
  300. SEO11 + fix menu: rút 12 title về ≤65 ký tự + Banking→Ngân hàng (hết 404)

    fix
    • zola build ✅ · qa_check.py ✅ All QA checks passed
    • seo_score.py: 100.0/100, 0 trang lỗi
    • Menu: /categories/ngan-hang/ tồn tại, /categories/banking không còn → hết 404
    PR #235 −19 dòng xóa · +129 dòng thêm · Net +110 dòng
  301. SEO: thêm 6 bài backlog (Zola/CI · du lịch Hàn · ẩm thực) + ảnh bìa

    chore
    • tu-dong-deploy-zola-github-actions — giải thích deploy.yml từng dòng
    • zola-vs-hugo — so sánh (định dạng bắt featured snippet)
    • di-han-mua-nao-re-nhat — xếp hạng 12 tháng theo giá/thời tiết (góc ngân sách)
    • di-han-het-bao-nhieu-tien — bóc chi phí Seoul–Busan 6 ngày (content gap)
    • troi-mua-sai-gon-an-gi — seasonal mùa mưa, cạnh tranh thấp
    PR #234 −1 dòng xóa · +600 dòng thêm · Net +599 dòng
  302. feat(baochi): Thêm category "Bảo hiểm" + "Báo chí", gắn "Báo chí" cho mọi bài bb

    chore
    • categories.json: thêm "Bảo hiểm" và "Báo chí".
    • Gắn "Báo chí" vào tất cả bài trong content/baochi/ (9 bài), giữ nguyên category gốc — ví dụ ["Ngân hàng", "Báo chí"], ["Thế giới", "Báo chí"], ["Bảo hiểm", "Báo chí"].
    • Cập nhật rule shortcut bb trong shortcuts.md: từ nay mọi bài bb mặc định có "Báo chí", và nếu category mới chưa có trong categories.json thì tự thêm.
    • Build Zola xanh; trang taxonomy categories/bao-chi gom đủ các bài báo.
    • QA check (qa.yml) pass.
    PR #233 −10 dòng xóa · +15 dòng thêm · Net +5 dòng
  303. Add article — Mức đóng BHYT hộ gia đình từ 01/7/2026

    feat
    • Chủ đề: Mức đóng BHYT hộ gia đình từ ngày 01/7/2026 (lương cơ sở tăng lên 2,53 triệu).
    • Category: Bảo hiểm
    • Giọng văn: ngôi thứ nhất ("mình"), có quan điểm cá nhân, ~1.200 từ.
    • Giữ bảng mức đóng + tỷ lệ giảm trừ (số liệu đã kiểm: người 1 = 1.366.200đ/năm, 70/60/50/40% cho người sau).
    • Có FAQ (extra.faq), description, thumbnail, internal link tới bài BIDV Private Banking.
    PR #232 −0 dòng xóa · +87 dòng thêm · Net +87 dòng
  304. SEO Phase 3: thay picsum bằng ảnh bìa SVG on-brand (giữ OG raster)

    chore
    • *static/img/covers/.svg** — 17 ảnh bìa SVG: gradient theo category (Công nghệ/Du lịch/Ẩm thực/Ngân hàng/Thế giới) + tiêu đề bài + wordmark "DUY NGUYEN". Nhẹ, nhanh, liên quan, không phụ thuộc dịch vụ
    • 17 bài: thumbnail từ picsum.photos → ảnh bìa SVG nội bộ. Hết picsum.
    • base.html: og:image / twitter:image / Article-schema image chỉ nhận ảnh raster — nếu thumbnail là .svg thì fallback img/og-default.jpg (mạng xã hội không render SVG). Thêm hỗ trợ page.extra.og_image đ
    • ✅ Build OK, 17 SVG valid XML
    • ✅ Ảnh bìa hiển thị trên trang (hero + card)
    PR #230 −20 dòng xóa · +280 dòng thêm · Net +260 dòng
  305. Thêm bài: Bên trong MSB Digital Bank — công nghệ và bảo mật

    security
    • Nội dung: nền tảng Backbase, xác thực FIDO, Face authentication, Bshield, eKYC (ePay/Trusting Social/Bộ Công an); phân tích cá nhân hoá theo hành vi, tín dụng duyệt tự động 100%, tối ưu dòng tiền — kè
    • SEO: title 48 ký tự (rendered <title> 61 ≤ 65), meta description ~150 ký tự, 3 khối FAQ → FAQPage schema, 3 internal link @/ tới bài liên quan (MSB migration, BIDV Private Banking, "dưới nắp ca-pô blo
    • categories = ["Ngân hàng"] đồng bộ 2 bài banking hiện có.
    • zola build ✅ (21 pages, internal @/ links resolve, FAQPage JSON-LD render)
    • qa_check.py ✅ All QA checks passed
    PR #229 −0 dòng xóa · +77 dòng thêm · Net +77 dòng
  306. SEO Phase 2: 2 bài mới (Tạo blog Zola A–Z + Lịch trình Busan tự túc)

    chore
    • ✅ Build OK, 2 trang sinh đúng
    • ✅ FAQPage + BreadcrumbList valid (JSON-LD 0 lỗi)
    • ✅ Mọi internal link resolve tới bài có thật
    • ✅ qa_check.py pass
    • ✅ Category đúng (Công nghệ / Du lịch), featured = true
    PR #228 −0 dòng xóa · +340 dòng thêm · Net +340 dòng
  307. SEO Phase 1: FAQ block + FAQPage & BreadcrumbList schema

    chore
    • base.html: thêm 2 khối JSON-LD
    • BreadcrumbList (Trang chủ → Section → Bài) cho mọi trang bài.
    • FAQPage sinh tự động từ page.extra.faq.
    • page.html: render block "Câu hỏi thường gặp" (accordion <details>, không cần JS) cuối bài.
    • sass/_faq.scss: style component FAQ (component mới, không đụng selector global — tuân thủ rule CSS).
    PR #227 −0 dòng xóa · +261 dòng thêm · Net +261 dòng
  308. chiến lược SEO + bộ từ khoá (Công nghệ/Du lịch Hàn/Ẩm thực/Ngân hàng)

    chore
    • Định hướng cốt lõi: bỏ phụ thuộc brand search → xây topical authority + long-tail + E-E-A-T ngôi thứ nhất.
    • Thứ tự ưu tiên: 🥇 Công nghệ (Zola — gần như không đối thủ tiếng Việt) → 🥈 Du lịch Hàn (Busan/Jeju tự túc) → 🥉 Ẩm thực (long-tail ngữ cảnh) → ⚠️ Ngân hàng (YMYL, làm nhẹ).
    • Bộ từ khoá từng mảng: primary + long-tail clusters + content gap + 5 bài nên viết + map bài hiện có.
    • Topic cluster (pillar + cluster + internal link), checklist on-page, SEO kỹ thuật (đã có gì / cần thêm), lộ trình 90 ngày, đo lường.
    • 🐞 cong-nghe-blog-duy-nguyen & sentence-transformers-sbert-deep-dive đang gắn sai category ["Ẩm thực"] (là bài tech).
    PR #226 −20 dòng xóa · +328 dòng thêm · Net +308 dòng
  309. SEO11: Tối ưu SEO toàn site đạt 100/100 (Lighthouse + Starter Guide)

    chore
    • Không đụng layout/scroll desktop: mọi h2→h1 đều trên class đã ghim font-size (section-header__title 0.85rem, scoring__title 1.75rem, bao-cao__title 1.85rem) → render y hệt.
    • .visually-hidden là utility mới (additive), không sửa selector global nào, không overflow/height/position trên html/body.
    • Không thêm hiển thị ngày/giờ mới (rule timezone GMT+7 không phát sinh).
    • Title đổi không đổi slug → URL ổn định, internal link không gãy.
    • seo_score.py: 100.0/100 A+, 114/114 trang A+, hạ tầng đủ.
    PR #222 −889 dòng xóa · +497 dòng thêm · Net -392 dòng
  310. SEO: tự động ping IndexNow (Bing/Yandex/Seznam/Naver/DuckDuckGo) khi đăng bài

    chore
    • scripts/indexnow.py — gom URL (trang chủ + /posting/ + mọi bài posting/ & baochi/) → POST api.indexnow.org (1 endpoint fan-out mọi engine). Best-effort: lỗi mạng/HTTP không làm fail workflow. Có --dry
    • .github/workflows/indexnow.yml — trigger khi push content/posting/ hoặc content/baochi/ vào main (đúng lúc "viết bài xong") + workflow_dispatch để chạy tay.
    • static/<key>.txt — file xác minh sở hữu host cho IndexNow (key đặt dưới / → keyLocation hợp lệ cho mọi URL submit).
    • ✅ Dry-run gom đúng 16 URL; keyLocation = …/zola/<key>.txt
    • ✅ Build serve key file tại /<key>.txt (nội dung == key)
    PR #225 −0 dòng xóa · +156 dòng thêm · Net +156 dòng
  311. Banking category + bài blog MSB Digital Bank ra mắt thay mBank

    feat
    • Tạo category mới "Banking": thêm vào dropdown menu Bài viết trong config.toml (/categories/banking).
    • Viết bài blog SEO về sự kiện MSB chính thức ra mắt MSB Digital Bank thay thế app mBank từ 01/06/2026 — đặt trong content/baochi/msb-digital-bank-ra-mat-thay-mbank.md với categories = ["Banking"] để kí
    • Từ khoá chính MSB Digital Bank đặt ngay H2 đầu tiên.
    • Long-tail làm H2 riêng: cách chuyển từ mBank, xác thực lại CCCD, khi nào mBank ngừng hoạt động.
    • Slug banking, tags: ngân hàng, tài chính, msb, msb-digital-bank, ngân hàng số.
    PR #224 −0 dòng xóa · +55 dòng thêm · Net +55 dòng
  312. SEO: thêm mã xác minh Google Search Console

    chore
    • ✅ zola build OK · qa_check.py pass
    • ✅ Meta xác minh xuất hiện trên trang chủ + bài + /posting/
    PR #223 −1 dòng xóa · +1 dòng thêm · Net +0 dòng
  313. Hiển thị bài ở /posting/ (gộp mọi section) + nút Trang chủ + SEO/Google indexing

    chore
    • templates/section.html — khi render section "posting" → gộp bài từ MỌI section (posting/ + baochi/), sort ngày giảm dần.
    • content/posting/_index.md — bỏ paginate_by (Zola không phân trang xuyên-section) → /posting/ render đủ toàn bộ bài, tránh trang /page/N/ trùng.
    • config.toml — thêm mục "Trang chủ" đầu navbar → https://seomoney.org/.
    • config.toml — extra.google_site_verification + render <meta google-site-verification> khi có mã → mở khoá xác minh Google Search Console.
    • templates/base.html — <meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1"> + publisher.logo trong JSON-LD.
    PR #221 −4 dòng xóa · +35 dòng thêm · Net +31 dòng
  314. Hotfix: trang chủ hiển thị bài viết từ MỌI section (gộp posting/ + baochi/)

    chore
    • templates/index.html — trang chủ hiển thị mọi bài, tối đa 13 bài/trang (hero 1 + hàng 3 + lưới 9). Lưới dùng danh sách rest (loại hero ra) → không trùng, không sót.
    • templates/base.html — sidebar Featured/Random + JSON posts-data + đếm "bài viết live" phản ánh đúng mọi bài.
    • templates/page.html — "bài viết liên quan" lấy từ mọi section.
    • ✅ zola build (v0.22.1) OK, 0 orphan
    • ✅ qa_check.py pass (142 files)
    PR #220 −27 dòng xóa · +61 dòng thêm · Net +34 dòng
  315. Bật lại: banner quảng cáo luân phiên với GitHub status mỗi 3s

    chore
    • Bỏ comment Slide A (.header-ad), đặt data-rotate="true"
    • Chuyển is-active sang Slide A (slide đầu DOM) để nhịp 3s chuẩn ngay từ lần chuyển đầu; gỡ is-active khỏi Slide B (GitHub)
    • interval 3000ms (3 giây) như cũ
    PR #219 −20 dòng xóa · +19 dòng thêm · Net -1 dòng
  316. Cập nhật rule deploy: bật auto-merge + auto-deploy lên production

    chore
    • CLAUDE.md: thêm section canonical "Quy tắc Deploy & Production" (hiệu lực cao nhất, ghi đè mọi rule deploy cũ).
    • shortcuts.md §4.5/§4.6: đảo từ chặn auto-merge sang bật auto-merge + auto-deploy, vô hiệu mọi tham chiếu "(rule 16:00)" rải rác.
    • shortcuts.md: ff step 6 auto-merge + deploy thay vì chờ manual #X.
    PR #218 −36 dòng xóa · +62 dòng thêm · Net +26 dòng
  317. QA dashboard: hiển thị số liệu thật cho card Performance & Security

    security
    • Performance Audit → Cron CN 02:00 UTC
    • Security Scan → pip-audit + gitleaks
    • Performance: đọc điểm Lighthouse từ data/pagespeed.json (ưu tiên desktop, fallback mobile khi free-API throttle về 0) + ngày updated_at.
    • Security: đọc số CVE + secret leak từ data/security.json.
    • PR Activity: sửa ngày ISO rò ra ngoài → dd/mm/yyyy + Asia/Ho_Chi_Minh.
    PR #217 −10 dòng xóa · +89 dòng thêm · Net +79 dòng
  318. Thêm bài: chọn ngách nội dung giữ chân người đọc

    chore
    • Category: Công nghệ
    • Tags: blog, content-strategy, seo, engagement, mobile-ux
    • Độ dài: ~1.450 từ, giọng cá nhân ("mình"), có <!-- more --> summary break
    • Chủ đề: chiến lược chọn ngách nội dung để tăng engagement / giảm bounce rate — 3 nhóm ngách (kỹ thuật-dữ liệu, nghề nghiệp-thương hiệu, đam mê cộng đồng) + bảng so sánh mức độ tương tác + lưu ý UX mob
    • Internal links (3, đúng ngữ cảnh): SBERT · Công nghệ blog · QA Gatekeeper.
    PR #216 −0 dòng xóa · +77 dòng thêm · Net +77 dòng
  319. Trang chủ — hàng 3 card ngang dưới hero (bài 2-4)

    feat
    • Chèn 1 hàng .home-grid (3 cột) gồm 3 bài mới tiếp theo (slice(1,4)) ngay dưới hero, trước 2 block promo.
    • Grid phía dưới re-slice thành slice(4,13) (bài 5+). Pagination khi >13 bài.
    • Dùng lại .home-grid + .home-card, KHÔNG thêm CSS → đồng bộ style top row & grid dưới.
    • Chỉ sửa templates/index.html; không đụng DOM component khác, không đổi CSS.
    • Tera tag cân bằng: if 10/10, for 2/2.
    PR #215 −5 dòng xóa · +36 dòng thêm · Net +31 dòng
  320. Footer 2 cột (QA · GA) + tag cloud text-only ra sidebar

    feat
    • Gỡ tag cloud khỏi footer (bỏ luôn style cũ .tag-grid / .tag-card / .footer-tags-section).
    • Thêm vào sidebar phải dạng .tag-cloud text-only: chữ thuần #tag, nhỏ gọn hết mức, theme-aware (var(--c-*), hover → accent), số bài hiển thị ở title (rê chuột) cho tối giản.
    • Hiển thị trên các trang dùng sidebar mặc định (trang chủ + bài viết).
    • Footer split theo mobile-first: base 1 cột (stack) → @media (min-width: 981px) mới 2 cột. Desktop/mobile tách block rõ ràng.
    • .tag-cloud dùng semantic token → hài hoà light/dark.
    PR #214 −199 dòng xóa · +79 dòng thêm · Net -120 dòng
  321. Footer ổn định dark-mode + nới rộng layout desktop (1500/400)

    fix
    • .site-footer nền: var(--c-text-heading) (đảo #000↔#fff ở dark-mode → nền trắng, chữ trắng biến mất) → #0a0a0a cố định.
    • Footer tag/QA title: bỏ token đảo → màu cố định khớp nền (sáng trên dải tag tối, tối trên QA band trắng).
    • Fix luôn bug có sẵn: tiêu đề TAG CLOUD #000-trên-#000 vô hình ở light-mode.
    • ⚠️ Lưu ý: bản redesign footer #212 trên main redesign layout tag cloud nhưng không sửa bug dark-mode này → fix vẫn cần thiết. Merge đã giữ nguyên redesign #212 (tag-grid compact 840px, canh phải) + ch
    • .container + .navbar__inner: **** → 1500px.
    PR #213 −10 dòng xóa · +22 dòng thêm · Net +12 dòng
  322. Thu nhỏ tag cloud + redesign QA Dashboard footer

    feat
    • Badge gọn lại cỡ chip "Tech Stack" (font 0.62rem, padding nhỏ), card min-height 120px → 52px, grid 5 cột max-width 840px.
    • Canh phải trong footer — scope riêng @media (min-width: 721px) nên mobile giữ nguyên (các @media max-width sẵn có vẫn định nghĩa size mobile).
    • Mỗi card thêm icon chip + 1 dòng mô tả tiếng Việt giải thích chỉ số là gì (giải quyết "chưa hiểu chỉ số") + title tooltip đầy đủ khi hover.
    • Số liệu tô màu accent, card bo góc mềm, viền nhạt, hover nhấc + đổ bóng (đồng bộ với tag card).
    • Toàn bộ dùng Ericsson Blue đơn sắc để khớp hướng brand mới (tag badge + label upstream vừa chuyển xanh) → footer nhất quán 1 tông.
    PR #212 −60 dòng xóa · +170 dòng thêm · Net +110 dòng
  323. Claude/happy newton jaf5qq

    chore
    PR #211 −132 dòng xóa · +144 dòng thêm · Net +12 dòng
  324. remove custom Git/PR workflow rules from CLAUDE.md

    chore
    PR #210 −48 dòng xóa · +0 dòng thêm · Net -48 dòng
  325. Xoá 10 file test-feature-*.txt (rác test auto-merge9)

    chore
    • ✅ Nội dung chỉ là chuỗi demo test, không code/asset thật.
    • ✅ grep toàn repo (.html, .toml, .scss, .js, .md): không file nào tham chiếu tới chúng → xoá không vỡ build/link.
    • ✅ Branch đã sync với main mới nhất nên PR này chỉ chứa 10 phép xoá, không lẫn thay đổi khác.
    PR #209 −10 dòng xóa · +0 dòng thêm · Net -10 dòng
  326. Đồng bộ shortcut prn với rule mới (1 nhánh chung + base main)

    chore
    PR #208 −23 dòng xóa · +20 dòng thêm · Net -3 dòng
  327. Khôi phục menu — dropdown Category → Sub-category (hết ẩn)

    fix
    • config.toml: menu thêm children (inline table lồng, hợp lệ TOML 1.0.0). Item không có children vẫn render link đơn (tương thích ngược).
    • templates/base.html: render <button> trigger + <ul.navbar__submenu> khi có children; thêm include navbar-dropdown.js.
    • sass/_navbar.scss: CSS dropdown, tách 2 block DESKTOP (global) / MOBILE (≤720px).
    • static/js/navbar-dropdown.js (mới): toggle/đóng/bàn phím + đánh dấu nhóm cha active.
    • static/js/navbar-mobile.js: scrollActiveIntoView chỉ xét link top-level (tránh nhảy trang khi child đang ẩn).
    PR #207 −25 dòng xóa · +351 dòng thêm · Net +326 dòng
  328. Cập nhật rule Git — 1 nhánh chung + manual merge

    chore
    • Làm rõ: MỌI thay đổi (kể cả nhỏ) đều phải qua PR, chờ user duyệt tay.
    • Dùng chung 1 nhánh claude/seo-1j0frj cho mọi PR ("10 PR 1 nhánh") — không tạo nhánh lẻ, để user tiện xem/quản lý. Ghi rõ quy trình lặp: reset về origin/main → commit → push → PR → user merge tay → lặp
    • Nhấn mạnh: KHÔNG auto-merge kể cả khi CI xanh. CI xanh không phải tín hiệu merge — luôn chờ user gõ manual #X / prm / gg.
    PR #206 −5 dòng xóa · +11 dòng thêm · Net +6 dòng
  329. Xóa workflow AI Diagnose (tốn phí Anthropic API)

    chore
    • Xóa: .github/workflows/ai-diagnose.yml.
    • GIỮ: scripts/ff.py (+ ff-agent.md, requirements-ff.txt) — dùng cho shortcut ff chạy tay khi user chủ động muốn, không tự động tốn phí.
    • Deploy fail sẽ không còn tự gọi API / tạo issue nữa.
    • 8 issue auto-diagnose cũ sẽ được đóng riêng (cleanup).
    PR #205 −131 dòng xóa · +0 dòng thêm · Net -131 dòng
  330. Shortcut content9 + script check_content_seo.py (soi SEO content/)

    feat
    • Front matter TOML (+++): báo file thiếu title / description.
    • Body: báo ảnh markdown [](...) + <img> thiếu/empty alt.
    • Output danh sách file lỗi + lý do; exit 1 nếu có lỗi (CI gate được).
    • content9 → soi source .md (sửa ngay tại front matter).
    • diemtoiuu → chấm HTML build trong public/.
    PR #204 −0 dòng xóa · +1191 dòng thêm · Net +1191 dòng
  331. Shortcut diemtoiuu — chấm điểm SEO toàn site + báo cáo chi tiết

    feat
    • Quét mọi public/*.html (HTML đã build = thứ crawler thật sự thấy).
    • Tự loại trang alias/redirect của Zola (meta http-equiv=refresh, title "Redirect") để không kéo điểm oan — đây là bug đã phát hiện & fix ngay trong lúc test (loại 100 trang redirect → điểm từ 50 lên 79
    • Chấm 13 tiêu chí/trang (tổng 100): title · meta description · canonical · og:title/description/image/type · twitter:card · JSON-LD · đúng 1 <h1> · viewport · <html lang> · img alt coverage.
    • Cộng hạ tầng site: robots.txt · sitemap.xml · atom.xml · rss.xml (hệ số 0.95–1.00).
    • Báo cáo: điểm site /100 + hạng, thời điểm chấm GMT+7 HH:MM dd/mm/yyyy, phân bố hạng, bảng từng trang (điểm thấp→cao) + vấn đề, top tín hiệu thiếu, gợi ý ưu tiên.
    PR #203 −0 dòng xóa · +382 dòng thêm · Net +382 dòng
  332. Keepalive Scheduler — ép 3 QA workflow chạy đúng 11:00 GMT+7

    feat
    • QA Gatekeeper: schedule runs = 0
    • Security Audit: schedule runs = 0
    • Self-Healing: scheduled run gần nhất là 15/06 19:59 UTC
    • 3 mốc cron dự phòng: 04:00 / 04:10 / 04:25 UTC — chỉ cần 1 mốc fire là đủ.
    • Guard idempotent theo ngày UTC: nếu target đã có run workflow_dispatch trong ngày thì bỏ qua → các mốc dự phòng không kích trùng; user kích tay buổi sáng cũng không bị chạy lại.
    PR #201 −0 dòng xóa · +67 dòng thêm · Net +67 dòng
  333. 🤖 Self-healing: 2 mechanical fix(es)

    fix
    • Normalize tags: lowercase + dedupe + sort
    • Dedupe categories
    • Date format: YYYY/MM/DD → YYYY-MM-DD
    • Trim trailing whitespace trong frontmatter
    • Đảm bảo file kết thúc bằng 1 newline
    PR #200 −2 dòng xóa · +2 dòng thêm · Net +0 dòng
  334. Gộp navbar còn 3 mục (Bài viết · Công cụ · Giới thiệu)

    feat
    • 3 mục: Bài viết (/categories/posting) · Công cụ (/editor) · Giới thiệu (/about)
    • Xoá link chết Z-X (/zx đã 404 sau khi chuyển Hilda-only)
    • "Trang chính" bỏ khỏi nav — logo site-title đã link về home
    • Các mục phụ (Du lịch/Công nghệ/Ẩm thực, Converter, Changelog/Insights/Scoring/BrandingX/Font/Báo cáo) comment-out trong config.toml: giữ nguyên trang + content, bật lại = bỏ #
    • Chỉ sửa config.extra.menu trong config.toml. KHÔNG đụng template/CSS/content.
    PR #202 −16 dòng xóa · +21 dòng thêm · Net +5 dòng
  335. Bật RSS/Atom feed + feed discovery cho SEO

    feat
    • generate_feeds=true + feed_filenames atom.xml/rss.xml (trước đây
    • Sửa taxonomy rss=true -> feed=true (Zola 0.19+ đổi tên key).
    • Thêm <link rel=alternate> Atom+RSS trong <head> để reader/crawler
    • default_language=vi -> feed mang xml:lang vi khớp <html lang=vi>.
    PR #199 −2 dòng xóa · +18 dòng thêm · Net +16 dòng
  336. Claude/affectionate feynman 2s7rh5

    chore
    PR #196 −1974 dòng xóa · +169 dòng thêm · Net -1805 dòng
  337. Add Dân Trí article — Thỏa thuận hòa bình Mỹ Iran

    feat
    • Quá trình từ đối đầu quân sự đến đàm phán
    • Tác động trên thị trường năng lượng toàn cầu
    • Các kỳ vọng khác nhau từ các bên liên quan
    • Hồ sơ hạt nhân như "phép thử quyết định"
    • Triển vọng cho các nước Trung Đông
    PR #198 −0 dòng xóa · +64 dòng thêm · Net +64 dòng
  338. Font Guideline (Ericsson Hilda) — trang specimen + showcase trang chủ

    feat
    • Hero specimen — wordmark "Hilda" cỡ lớn render bằng chính typeface.
    • Câu chuyện & facts — Letters from Sweden (Göran Söderström), hợp tác Stockholm Design Lab, đặt tên theo Hilda (vợ Lars Magnus Ericsson), digital-first, Latin/Greek/Cyrillic.
    • 5 weights — ExtraLight · Light · Medium · Bold · ExtraBold.
    • Type scale, bộ ký tự (uppercase/lowercase/numerals).
    • Type tester trực tiếp (đổi text / weight / size) — JS thuần, không thư viện.
    PR #197 −21 dòng xóa · +1138 dòng thêm · Net +1117 dòng
  339. Remove deprecated BrandingX theme — Z-X + Hilda only

    fix
    • CSS has :root[data-theme="brandingx"] variables
    • JS theme-switcher only supports: "zx" (default) + "hilda"
    • Mismatch causes CSS compilation/validation errors
    • ✅ Remove BrandingX CSS variables completely
    • ✅ Keep Z-X (default) — ZaloPay fintech blue
    PR #191 −28 dòng xóa · +34 dòng thêm · Net +6 dòng
  340. 🔥 HOTFIX: Revert broken theme system — unblock deploy

    fix
    • ❌ 7763c53: Set Z-X as default theme
    • ❌ 4a3d968: Merge conflict resolution
    • ❌ 23e6f13: Original Z-X default feature
    • ✅ Theme dropdown working (Z-X + Hilda)
    • ✅ Dependabot removed cleanly
    PR #189 −69 dòng xóa · +48 dòng thêm · Net -21 dòng
  341. Remove Dependabot automation from project

    chore
    • Removed Dependabot version update configuration
    • Previously configured: Cargo weekly updates, GitHub Actions weekly updates
    • Auto-merge settings for patch/minor versions
    • Removed automated merge workflow triggered by Dependabot PRs
    • Previously auto-approved and merged patch/minor dependency updates
    PR #184 −316 dòng xóa · +373 dòng thêm · Net +57 dòng
  342. Professional theme dropdown menu redesign

    refactor
    • Replaced text-based toggle button with icon-only trigger (🎨 palette icon) for minimal navbar footprint
    • Implemented smooth fade-in animation when dropdown opens
    • Added hover effects on menu items for clear visual feedback
    • Display check-mark (✓) next to the currently active theme
    • Clean, minimal design matching professional standards
    PR #183 −99 dòng xóa · +358 dòng thêm · Net +259 dòng
  343. Claude/test auto merge9

    chore
    PR #179 −0 dòng xóa · +10 dòng thêm · Net +10 dòng
  344. PLANNING: Hilda theme (Option C) — secondary theme for Ericsson branding

    chore
    • sass/_hilda-tokens.scss — Color, spacing, typography variables
    • sass/_hilda-fonts.scss — Google Fonts import (Inter)
    • sass/_hilda-overrides.scss — Component styling per theme
    • sass/_theme-switcher-styles.scss — Toggle button styles
    • sass/_themes.scss — Add Hilda :root[data-theme="hilda"] block
    PR #180 −71 dòng xóa · +908 dòng thêm · Net +837 dòng
  345. Add Branding Guideline page + homepage CTA

    feat
    • Visual color palette (Primary, Accent, Neutral) with hex codes
    • Typography showcase (Ericsson Hilda OTF font, sizes, weights)
    • UI Design System (4px radius, shadows, 8px spacing)
    • Component examples (buttons, badges, contrast tests)
    • WCAG AAA accessibility verification
    PR #182 −0 dòng xóa · +241 dòng thêm · Net +241 dòng
  346. Complete theme switcher — BrandingX ↔ Z-X

    feat
    • Dual theme support: BrandingX (default, MoMo pink) ↔ Z-X (ZaloPay electric blue)
    • Dynamic CSS Variables: :root (BrandingX) vs :root[data-theme="zx"] (Z-X)
    • Persistent storage: localStorage + anti-flash inline script
    • Interactive UI: Dropdown menu with 4 theme options (BrandingX, Z-X, E-X, Hila)
    • Keyboard navigation: Arrow keys, Escape, Home/End support
    PR #181 −35 dòng xóa · +506 dòng thêm · Net +471 dòng
  347. Add Dân Trí article — sự cố F/A-18 và hệ thống an toàn

    feat
    • Original: News report of F/A-18 crash, pilot ejection, investigation details
    • Rewritten: Analysis of safety systems, investigation process, engineering lessons learned
    • Personal reflection on technology, risk management, and system resilience
    PR #178 −0 dòng xóa · +76 dòng thêm · Net +76 dòng
  348. Add Dân Trí article — uranium của Iran và ngoại giao Mỹ

    feat
    • Original: Technical announcement from VP JD Vance about uranium destruction plan
    • Rewritten: Analysis of what the diplomatic language means, context of Iran's stockpile, shift from military to diplomatic approach
    PR #177 −0 dòng xóa · +51 dòng thêm · Net +51 dòng
  349. Add Dân Trí article — thỏa thuận hòa bình Mỹ-Iran

    feat
    • Original article discusses oil price drops, market reactions, and economic implications
    • Rewritten version adds personal narrative and deeper analysis
    • Added internal linking to related economic topics
    • Focuses on practical implications for readers (cost of living, inflation)
    PR #176 −0 dòng xóa · +52 dòng thêm · Net +52 dòng
  350. Add bb shortcut — interactive article processor

    feat
    • User provides article content (copy-paste, no crawling needed)
    • Claude rewrites in personal blog style with unique perspective
    • Auto-detects category and generates frontmatter
    • Creates branch baochi, commits, PR, and merges immediately
    • Network failure fallback: works even when external crawling blocked
    PR #175 −0 dòng xóa · +70 dòng thêm · Net +70 dòng
  351. test: Auto-merge9 test PR #06

    chore
    PR #170 −0 dòng xóa · +1 dòng thêm · Net +1 dòng
  352. test: Auto-merge9 test PR #05

    chore
    PR #169 −0 dòng xóa · +1 dòng thêm · Net +1 dòng
  353. test: Auto-merge9 test PR #01

    chore
    PR #165 −0 dòng xóa · +1 dòng thêm · Net +1 dòng
  354. Phase4 port groups refactoring

    chore
    PR #161 −28 dòng xóa · +278 dòng thêm · Net +250 dòng
  355. Add manu9 PR approval shortcut

    feat
    PR #162 −0 dòng xóa · +204 dòng thêm · Net +204 dòng
  356. Blog Security Guide — Backup, Bảo vệ Editor, Dependabot, DDoS

    chore
    • Git history = tự động backup mỗi commit
    • Recover trong <2 phút nếu sự cố
    • Hiện tại: Static (no login) → An toàn
    • 3 options login nếu cần tương lai (Supabase, Netlify, Custom Backend)
    • .github/dependabot.yml: Cargo + GitHub Actions updates
    PR #160 −0 dòng xóa · +973 dòng thêm · Net +973 dòng
  357. HOTFIX: Guard section.title null (deploy đỏ Phase 1-4)

    chore
    • 27585006562 (Phase 1) — failure
    • 27585147428 (Phase 2) — failure
    • 27585259211 (Phase 3) — failure
    • 27585725939 (Phase 4) — queued (sẽ fail nếu không fix)
    • {% if page %} → {% if page and page.title %}
    PR #159 −3 dòng xóa · +4 dòng thêm · Net +1 dòng
  358. Phase 4: Port theme-overrides.scss — 14 components × 3 themes

    chore
    • Mixin theme-overrides(6 params): chỉ inject non-color tokens
    • $radius-card, $radius-tag (border-radius)
    • $shadow-card, $shadow-card-hover (depth)
    • $kicker-spacing, $heading-ls (typography)
    • *Colors hardcoded var(--c-)** inside mixin (Phase 1 đã set per theme)
    PR #157 −0 dòng xóa · +377 dòng thêm · Net +377 dòng
  359. Phase 3: Update base.html dropdown markup + navbar CSS

    chore
    • Old .navbar__theme button (id="theme-switch-btn") — 2-option toggle
    • data-theme-label icons (sun/moon)
    • .theme-toggle container (data-theme-toggle)
    • .theme-toggle__btn: main button (aria-haspopup, aria-expanded)
    • dot, current theme name, caret
    PR #154 −18 dòng xóa · +221 dòng thêm · Net +203 dòng
  360. Hybrid 4-theme system: Z-X / E-X / Hila Ericsson trên kiến trúc --c-* của main

    chore
    • sass/_themes.scss — extend 2→4 theme + structural tokens (radius, kicker-ls, heading-ls, border-hover)
    • static/js/theme-switcher.js — THEMES array cycle 4, dynamic aria-label, querySelectorAll labels
    • templates/base.html — FOUC accept ex/hila, thêm 2 SVG icon button (E-X square, Hila newspaper)
    • sass/_sidebar.scss (16 instances)
    • sass/_single.scss (4 instances — table, footer dashed border, related title)
    PR #140 −37 dòng xóa · +158 dòng thêm · Net +121 dòng
  361. Phase 2: Refactor theme-switcher.js → 4-option dropdown

    refactor
    • Themes: "" (BrandingX), "zx" (Z-X), "ex" (E-X), "hila" (Hila)
    • THEME_NAMES mapping: theme value → display name
    • ALL_THEMES: ["","zx","ex","hila"]
    • localStorage key: "blog-theme" (KHÔNG đổi)
    • Auto-migration: "default" → "" (normalize old stored values)
    PR #152 −43 dòng xóa · +169 dòng thêm · Net +126 dòng
  362. Phase 1: Extend themes.scss với E-X + Hila Ericsson tokens

    chore
    • E-X (Ericsson Newsroom) theme
    • Map từ PR #140:
    • --theme-primary (#1174E5) → --c-accent
    • --theme-primary-hover (#0058A3) → --c-accent-hover
    • --theme-accent (#FFCD00) → --c-decoration
    PR #150 −0 dòng xóa · +76 dòng thêm · Net +76 dòng
  363. HOTFIX: Guard page.date null trong OG + JSON-LD (deploy đỏ)

    chore
    • Wrap <meta property="article:published_time"> với {% if page.date %}
    • Wrap datePublished JSON-LD với {% if page.date %}
    • dateModified fallback chain: page.updated → page.date → omit field
    PR #148 −2 dòng xóa · +4 dòng thêm · Net +2 dòng
  364. SEO11 phase 1 (clean) + slash commands /phimtat /thememoi

    cleanup
    • Per-page <meta name="description"> chain: page.description → page.summary (truncate 160) → config.description
    • <link rel="canonical"> dùng current_url
    • Open Graph block đầy đủ: og:type / og:title / og:description / og:url / og:image (1200×630) / og:site_name / og:locale=vi_VN + article:published_time / modified_time / author / section / tags
    • Twitter Card summary_large_image
    • JSON-LD Article (post) / WebSite (homepage), dùng json_encode chống injection
    PR #146 −1 dòng xóa · +215 dòng thêm · Net +214 dòng
  365. Staging Queue widget + Timezone GMT+7 (dd/mm/yyyy)

    chore
    • 20f26ef Chuẩn hoá hiển thị thời gian toàn blog → GMT+7 (Asia/Ho_Chi_Minh) + format dd/mm/yyyy. Thêm rule vào CLAUDE.md.
    • 80c927e Thêm widget "Đang xếp hàng deploy" lên trang Changelog — fetch open PRs từ GitHub API + cache sessionStorage 60s.
    PR #145 −12 dòng xóa · +453 dòng thêm · Net +441 dòng
  366. Gỡ phần còn lại của AI pipeline (analyze_topics, build_internal_links, qa_style + data)

    chore
    • scripts/analyze_topics.py — k-means topic map
    • scripts/build_internal_links.py — paragraph link suggester
    • scripts/qa_style.py — style consistency check
    • data/topic_map.json — output 11 bài, 5 cluster
    • data/link_suggestions.json — 84 link suggestion
    PR #144 −1711 dòng xóa · +0 dòng thêm · Net -1711 dòng
  367. ff tooling: thêm pip-tools + pipdeptree + tenacity + pytest-rerunfailures

    chore
    • tenacity 9.1.4
    • pip-tools 7.5.3
    • pipdeptree 3.1.0
    • pytest-rerunfailures 16.3
    PR #142 −5 dòng xóa · +25 dòng thêm · Net +20 dòng
  368. Gỡ AI Content Generation Pipeline (LangChain + LiteLLM)

    chore
    • scripts/content_gen.py — sinh draft từ idea
    • scripts/batch_frontmatter.py — regen frontmatter qua LLM
    • scripts/prompts/ (4 file) — prompt library theo category
    • scripts/requirements-content-gen.txt — langchain-core, langchain-litellm, litellm
    • .github/workflows/ai-pipeline.yml — workflow_dispatch trigger
    PR #143 −897 dòng xóa · +0 dòng thêm · Net -897 dòng
  369. Thêm workflow ai-pipeline chạy 3 bước batch trên Actions

    chore
    • ANTHROPIC_API_KEY chỉ inject vào step 3 (batch_frontmatter), 2 step embedding không đụng
    • HF model cache (~/.cache/huggingface) reuse từ build-related.yml → first run ~2 phút, sau ~30s
    PR #141 −0 dòng xóa · +354 dòng thêm · Net +354 dòng
  370. Expand GA stats with 5 advanced metrics + top country/device chips

    chore
    • Added fetch_extended_30d() to retrieve 5 GA4 advanced metrics for 30-day period
    • Added fetch_top_dimension() to fetch top-1 country and device category (7-day window)
    • Added format_duration() helper to convert seconds to human-readable format (e.g., "1m 23s")
    • Extended JSON output with 7 new fields: month_sessions, month_new_users, month_bounce_rate_pct, month_avg_session_duration_str, month_engagement_rate_pct, top_country, top_device
    • Added error handling for dimension fetches with fallback to "—"
    PR #139 −8 dòng xóa · +233 dòng thêm · Net +225 dòng
  371. Tuần 3: style consistency QA gate

    chore
    • style_score < threshold (default 0.55)
    • HOẶC nearest centroid là category khác (lệch >0.05)
    • Công nghệ 0.587
    • Du lịch 0.412
    • Ẩm thực 0.301
    PR #138 −0 dòng xóa · +247 dòng thêm · Net +247 dòng
  372. Tuần 2: internal linking suggester

    chore
    • data/link_suggestions.json (machine-readable cho tooling)
    • Markdown report stdout, group theo source post, có sẵn excerpt + markdown_hint để paste
    PR #137 −0 dòng xóa · +232 dòng thêm · Net +232 dòng
  373. Tuần 1: batch frontmatter enhancer + topic gap analysis

    chore
    PR #136 −3 dòng xóa · +483 dòng thêm · Net +480 dòng
  374. Bài blog mới: Summer Korea — 4 điểm dừng mùa hè (1480 words)

    chore
    • Body: 1480 words (target 1500w ±5%)
    • Total file: 1570 words (gồm frontmatter)
    • mua-nao-di-han-la-dep-nhat.md — intro liên kết
    • thang-6-di-han-an-gi-lam-gi.md — outro liên kết
    • tet-doan-ngo-han-viet-trung.md — cultural reference
    PR #135 −0 dòng xóa · +211 dòng thêm · Net +211 dòng
  375. Thêm phím tắt topic10: viết 10 bài Du lịch cùng cluster (test topical…

    chore
    • Sinh 10 chủ đề ngẫu nhiên thuộc Du lịch (3 trong nước, 2 nước ngoài, 2 kinh nghiệm, 2 theo mùa, 1 review/so sánh)
    • Cluster pattern pillar + 9 spoke, internal link chéo bắt buộc ≥3 link/bài
    • Tag pillar overlap, stagger date 0-9 ngày tránh batch dump
    • Single commit, không auto-merge — user chủ động prm/gg
    • Bảng tổng kết slug/title/sub-cluster/links/words sau khi push
    PR #132 −0 dòng xóa · +89 dòng thêm · Net +89 dòng
  376. Sửa import: ChatLiteLLM → langchain-litellm package

    fix
    • scripts/content_gen.py: from langchain_litellm import ChatLiteLLM
    • scripts/requirements-content-gen.txt: thay langchain-community>=0.3 bằng langchain-litellm>=0.7
    PR #133 −3 dòng xóa · +4 dòng thêm · Net +1 dòng
  377. Thêm Content Generation Pipeline (LangChain + LiteLLM)

    chore
    • scripts/content_gen.py — pipeline RAG-based dùng LangChain LCEL + LiteLLM wrapper (swap Claude / GPT / OpenRouter qua 1 flag --model)
    • scripts/prompts/ — prompt library 4 file theo category (default / du-lich / cong-nghe / am-thuc), mỗi file encode giọng riêng để tránh AI viết đồng nhất toàn blog
    • scripts/requirements-content-gen.txt — deps tách riêng (LangChain ~200MB không nhét vào requirements.txt của build_related.py)
    • draft — idea rời rạc → bản nháp đầy đủ
    • refine — giữ ý bản nháp tay, chỉ sửa văn phong
    PR #131 −0 dòng xóa · +569 dòng thêm · Net +569 dòng
  378. E-X (Ericsson Newsroom) branding theme — third design system

    feat
    • New design tokens (sass/_ex-tokens.scss):
    • Energy Blue palette (#1174E5 as north star)
    • High-contrast monochrome text hierarchy (#0C0C0C → #707070)
    • Restrained accent colors (yellow for awards, red for breaking news, green for sustainability)
    • Subtle surface tiers (snow, mist, fog, cloud)
    PR #130 −0 dòng xóa · +1647 dòng thêm · Net +1647 dòng
  379. Dynamic Theme Switching — BrandingX ↔ Z-X (4 layer CSS/JS/UI/QA)

    chore
    • --c-bg-page / --c-bg-surface / --c-bg-soft
    • --c-text-heading / --c-text-body / --c-text-muted
    • --c-accent / --c-accent-hover / --c-accent-soft
    • --c-decoration (tag/promo color)
    • --c-border / --c-border-strong
    PR #129 −42 dòng xóa · +409 dòng thêm · Net +367 dòng
  380. Phần 2/2 Z-X: thêm sass/_zx.scss đầy đủ + wire vào site.scss

    chore
    • sass/_zx.scss (NEW, ~900 dòng): full styling cho .zx__* BEM
    • sass/site.scss: @import "zx-tokens"; @import "zx"; thêm sau "branding"
    • .zx-btn — 4 variants: --primary (blue 600), --secondary (outline), --ghost, --promo (orange)
    • .zx-card — radius 14px, hover shadow-lg lift
    • .zx-field + .zx-input — focus ring 3px blue 600 18% alpha
    PR #128 −0 dòng xóa · +901 dòng thêm · Net +901 dòng
  381. thêm link Z-X vào navbar menu (user không thấy được)

    fix
    • BrandingX → quên (PR #122)
    • Báo cáo tổng kết → quên (PR #122)
    • Z-X → quên (PR #125) ← lần này
    • ✅ Route /zx/ LIVE từ PR #125
    • ✅ Template templates/zx.html đầy đủ (Manifesto + Color + Typography
    PR #127 −0 dòng xóa · +1 dòng thêm · Net +1 dòng
  382. Thêm phím tắt morning — macro chuỗi shortcut non-conflict

    chore
    • morning (infinite loop)
    • topic: / manual #X / help (cần argument hoặc no-op)
    • SEO9 + SEO10 (overlap với SEO11 hybrid)
    • healing (overlap với ff)
    • Phase B bm thấy leak → BREAK ngay, escalate user
    PR #126 −10 dòng xóa · +158 dòng thêm · Net +148 dòng
  383. 3-in-1: POSTINGS wordmark + Z-X WIP + cautruc9 shortcut

    chore
    • templates/index.html: thay <nav class="home-tabs"> (Mới nhất +
    • sass/_home-momo.scss:
    • Global desktop: .home-tabs → display: flex; justify-content: space-between;
    • Màu chữ: rgba(214, 61, 61, 0.38) — BrandingX signal red #d63d3d
    • Mobile (@media max-width: 720px): scale font 1.05rem.
    PR #125 −325 dòng xóa · +1756 dòng thêm · Net +1431 dòng
  384. ff Fix: Slack workflow truncate commit message tránh invalid_blocks

    fix
    • name: Truncate commit message
    PR #124 −278 dòng xóa · +341 dòng thêm · Net +63 dòng
  385. Apply BrandingX colors — 10 files còn lại (255 replacements)

    chore
    • _editor.scss (179 colors — internal CMS, không public visibility)
    • _banner.scss (70 colors — deprecated component)
    PR #123 −273 dòng xóa · +320 dòng thêm · Net +47 dòng
  386. thêm link BrandingX vào navbar menu (user không thấy được)

    fix
    • Navbar desktop: hiện tab "BrandingX" giữa Scoring và Giới thiệu
    • Navbar mobile (≤720px): tab horizontal scroll cũng có
    • Click → vào trang BrandingX với 4 sections (Colors / Typography / Components / Grid)
    PR #122 −27 dòng xóa · +74 dòng thêm · Net +47 dòng
  387. Cập nhật quy tắc: TẠM NGƯNG QUYỀN AUTO-MERGE — user manual gatekeeper

    chore
    PR #121 −64 dòng xóa · +929 dòng thêm · Net +865 dòng
  388. gg deploy: Momo Design Tokens + Crawler + help shortcut

    chore
    PR #120 −0 dòng xóa · +451 dòng thêm · Net +451 dòng
  389. HOTFIX (pp): Tera ga_stats._status not found block deploy

    chore
    • {% set is_demo = ga_stats._status == "waiting_for_secret" %}
    PR #119 −1 dòng xóa · +1 dòng thêm · Net +0 dòng
  390. Auto-deploy batch: 10 commits (mobile UX + momo homepage + content + features)

    chore
    PR #118 −156 dòng xóa · +1412 dòng thêm · Net +1256 dòng
  391. Tạo lại: slack-notify.yml với fix toJSON() escape commit message

    fix
    PR #117 −0 dòng xóa · +73 dòng thêm · Net +73 dòng
  392. slack-notify.yml workflow (cài sai)

    chore
    PR #116 −70 dòng xóa · +0 dòng thêm · Net -70 dòng
  393. Test deploy: thêm file diantoi.txt để verify lệnh manual #X

    chore
    PR #112 −0 dòng xóa · +4 dòng thêm · Net +4 dòng
  394. Batch 2: gom commits chờ deploy gộp (rule mới)

    chore
    PR #114 −3 dòng xóa · +818 dòng thêm · Net +815 dòng
  395. Cập nhật shortcuts.md: quy trình Deploy GỘP + lệnh manual #X

    chore
    PR #111 −236 dòng xóa · +700 dòng thêm · Net +464 dòng
  396. SEO optimize: 2 bài blog mới (cong-nghe-day-2 + sentence-transformers)

    chore
    • Title rút gọn từ 88 → 60 chars (Google SERP cut-off 70)
    • description field thêm vào frontmatter
    • 2 internal links cuối bài → cong-nghe-day-2 + cong-nghe-duy-nguyen
    • description field thêm vào frontmatter
    • Internal link section "AI Semantic Related Posts" → sentence-transformers
    PR #110 −1 dòng xóa · +59 dòng thêm · Net +58 dòng
  397. Cập nhật shortcuts.md: thêm phím tắt 'seo' tối ưu bài mới ≤5h

    chore
    PR #109 −0 dòng xóa · +36 dòng thêm · Net +36 dòng
  398. 🤖 Self-healing: 2 mechanical fix(es)

    fix
    • Normalize tags: lowercase + dedupe + sort
    • Dedupe categories
    • Date format: YYYY/MM/DD → YYYY-MM-DD
    • Trim trailing whitespace trong frontmatter
    • Đảm bảo file kết thúc bằng 1 newline
    PR #108 −2 dòng xóa · +2 dòng thêm · Net +0 dòng
  399. HOTFIX KHẨN: Tera literal dict {k:v} block deploy — lỗi LẶP LẠI lần 3

    fix
    • PR #89 scoring.html
    • PR #101 qa_changelog
    • Giờ PR #103 ga_stats
    PR #107 −4 dòng xóa · +332 dòng thêm · Net +328 dòng
  400. Thêm bài research: Sentence Transformers (SBERT) — kiến trúc, training, ứng dụng

    chore
    PR #106 −0 dòng xóa · +326 dòng thêm · Net +326 dòng
  401. 🤖 Self-healing: 2 mechanical fix(es)

    fix
    • Normalize tags: lowercase + dedupe + sort
    • Dedupe categories
    • Date format: YYYY/MM/DD → YYYY-MM-DD
    • Trim trailing whitespace trong frontmatter
    • Đảm bảo file kết thúc bằng 1 newline
    PR #105 −2 dòng xóa · +2 dòng thêm · Net +0 dòng
  402. Thêm bài: Ngày thứ hai của blog — 100 PR và stack công nghệ tự nâng cấp

    chore
    PR #104 −0 dòng xóa · +230 dòng thêm · Net +230 dòng
  403. 🤖 Self-healing: 18 mechanical fix(es)

    fix
    • Normalize tags: lowercase + dedupe + sort
    • Dedupe categories
    • Date format: YYYY/MM/DD → YYYY-MM-DD
    • Trim trailing whitespace trong frontmatter
    • Đảm bảo file kết thúc bằng 1 newline
    PR #97 −29 dòng xóa · +18 dòng thêm · Net -11 dòng
  404. GA Stats footer: luôn render với DEMO placeholder mode

    chore
    • DEMO mode (chưa có data): amber palette + badge ⏳ DEMO + caption hướng dẫn setup
    • LIVE mode (sau khi setup xong): green palette + số thật + "Cập nhật: ... UTC"
    • data/ga-stats.json ban đầu có _status: "waiting_for_secret" → DEMO
    • Workflow chạy thành công → fetch_ga_stats.py overwrite (no _status field) → LIVE tự động
    PR #103 −6 dòng xóa · +51 dòng thêm · Net +45 dòng
  405. Thêm: GA Stats live ở footer — backend cron 1h fetch GA Data API

    chore
    • Name: GA_SERVICE_ACCOUNT_KEY
    • Value: paste JSON content mới
    • Hôm nay: users + pageviews
    • 7 ngày: users + pageviews
    • 30 ngày: users + pageviews
    PR #102 −363 dòng xóa · +411 dòng thêm · Net +48 dòng
  406. HOTFIX KHẨN: Tera literal dict block deploy + PR summary format chuẩn

    chore
    PR #101 −363 dòng xóa · +102 dòng thêm · Net -261 dòng
  407. GA pill ở footer thành link → mở dashboard GA intelligenthome

    chore
    • <span class="ga-status ga-status--active" title="...">
    • </span>
    • Click pill → tab mới với GA dashboard intelligenthome view
    • rel="noopener" bảo mật cho target="_blank"
    • Chỉ user có quyền GA Property 541698865 xem được số liệu
    PR #100 −358 dòng xóa · +76 dòng thêm · Net -282 dòng
  408. Gỡ triệt để visitor counter + GoatCounter (giữ CMS backend)

    chore
    • /cms/save-post (publish post)
    • /cms/author (avatar + bio upload)
    • /cms/posts/bulk-delete (GraphQL batch)
    • /cms/giscus/setup
    • GitHub OAuth flow
    PR #99 −355 dòng xóa · +69 dòng thêm · Net -286 dòng
  409. Auto-throttle build-related cron + shortcut 'll' liệt kê cron 3 workflows

    chore
    • cron: '0 0 16 6 *' # 16/06 00:00 UTC mỗi năm
    PR #98 −0 dòng xóa · +67 dòng thêm · Net +67 dòng
  410. Bật GoatCounter: goatcounter_code = banhang-chogao

    chore
    • Tracking: https://banhang-chogao.goatcounter.com/count
    • Counter badge: https://banhang-chogao.goatcounter.com/counter//TOTAL.svg
    • Dashboard public: https://banhang-chogao.goatcounter.com
    • Visitor counter section HIỆN (trước đó ẨN vì code rỗng)
    • LIVE badge xanh + counter realtime
    PR #96 −17 dòng xóa · +50 dòng thêm · Net +33 dòng
  411. Hotfix: build-related race condition + migrate visitor counter to GoatCounter

    chore
    • Free 100k pageviews/tháng
    • KHÔNG cold-start (luôn live)
    • Privacy-friendly, không cookie, GDPR OK
    • Public dashboard share được
    PR #95 −22 dòng xóa · +891 dòng thêm · Net +869 dòng
  412. Thêm: QA Dashboard footer — 6 card metrics build-time snapshot

    chore
    • data/scores.json (Semantic Scoring count)
    • changelog.json (PR Activity)
    • get_taxonomy(kind="tags") + get_taxonomy(kind="categories") (Tag Network)
    • get_section("posting/_index.md") (Deploy posts count)
    • now() | date() (build timestamp)
    PR #94 −1 dòng xóa · +839 dòng thêm · Net +838 dòng
  413. Thêm: Scoring Card — bảng điểm semantic của tất cả bài viết

    chore
    • Body: Manrope
    • UI (chips, select, table head): Inter
    • Meta (date, neighbors count): Be Vietnam Pro
    • Mono (rank number): system mono
    • Badge score ở top (highlight)
    PR #93 −1 dòng xóa · +608 dòng thêm · Net +607 dòng
  414. Cập nhật shortcuts.md: thêm 'run list' format chuẩn 4 cột

    chore
    • Gộp run ID cùng workflow + cause vào 1 row → giảm clutter
    • Cause: ≤60 ký tự, inline code cho symbol code
    • Status icons:
    • ✅ Resolved by PR #X — fix đã merge
    • ✅ Resolved — không tự trigger nữa
    PR #92 −0 dòng xóa · +22 dòng thêm · Net +22 dòng
  415. Cập nhật shortcuts.md: thêm healing, sec, pef + Workflow Auto-Heal rule

    chore
    • healing: kích hoạt QA-Healing thủ công với baseline qa_check.py + fix + verify
    • sec: trigger security-audit.yml + parse summary + escalate HIGH severity
    • pef: trigger perf-audit.yml + Lighthouse mobile estimate + review auto-fix PR
    • Node.js version phù hợp từng action
    • Hướng xử lý lỗi tối ưu (conservative/aggressive)
    PR #91 −3 dòng xóa · +53 dòng thêm · Net +50 dòng
  416. Cập nhật shortcuts.md: thêm ff + node policy thông minh + nguyên tắc bất biến

    chore
    • KHÔNG force phiên bản cứng cho mọi workflow
    • Smart eval: ưu tiên Node 24+ nếu action support
    • FORCE_JAVASCRIPT_ACTIONS_TO_NODE24 chỉ dùng tạm đến 16/06/2026
    • setup-node@v4 with node-version: '24' chỉ khi workflow có shell node/npm command
    • Verify runner warning log mỗi deploy fail → adapt nếu GitHub đổi guidance
    PR #90 −115 dòng xóa · +105 dòng thêm · Net -10 dòng
  417. HOTFIX KHẨN: fix Tera syntax page.html + restore FORCE Node24 + gỡ qa-failed-handler

    fix
    PR #89 −82 dòng xóa · +11 dòng thêm · Net -71 dòng
  418. Hotfix qa-failed.py: wait run completion + workflow buffer 30s

    chore
    • name: Buffer GitHub API log lag
    • name: Run qa-failed.py
    • Hết retry vẫn in_progress → job hung
    • gh CLI lỗi auth → status unknown
    • Logs fetch OK nhưng KHÔNG match pattern fix → genuinely unknown error
    PR #88 −8 dòng xóa · +64 dòng thêm · Net +56 dòng
  419. Hotfix: chuyển từ FORCE_JS_NODE24 sang setup-node@v4 native opt-in

    refactor
    • uses: actions/checkout@v4
    • uses: actions/setup-python@v5
    • uses: actions/checkout@v4
    • name: Setup Node.js 24
    • uses: actions/setup-python@v5
    PR #87 −15 dòng xóa · +56 dòng thêm · Net +41 dòng
  420. Typography Manrope-first + Inter UI + Be Vietnam Pro meta

    chore
    • Gộp 3 font vào 1 request → 1 round-trip
    • font-display: swap → text hiện ngay với system fallback
    • media=print onload swap → non-blocking FCP/LCP
    • Body: 17px (từ 16) + line-height 1.7 (từ 1.6)
    • letter-spacing 0 (Manrope đã round, không expand)
    PR #86 −56 dòng xóa · +70 dòng thêm · Net +14 dòng
  421. Hotfix: enforce Node.js 24 trên 2 workflow mới thiếu env

    chore
    PR #85 −0 dòng xóa · +8 dòng thêm · Net +8 dòng
  422. Thêm: qa-failed.py auto-healing pipeline cho failed workflows

    chore
    • KHÔNG đoán fix khi không match pattern
    • KHÔNG force-push để giải quyết race (có thể hỏng work)
    • Mọi lỗi unknown → issue chi tiết để user investigate
    PR #84 −1 dòng xóa · +280 dòng thêm · Net +279 dòng
  423. Thêm: shortcuts.md + Security Audit cron + build_tags.py

    security
    • pip-audit: scan services/visitor-counter/requirements.txt + scripts/requirements.txt cho CVE
    • gitleaks: scan toàn repo cho secret leak (PAT, API key, password)
    • Workflow misconfig: kiểm tra mỗi .github/workflows/*.yml có permissions: block không
    • Output artifacts retention 30 ngày
    • KHÔNG tự fix → user review báo cáo
    PR #83 −0 dòng xóa · +207 dòng thêm · Net +207 dòng
  424. Thêm: Semantic Related Posts qua sentence-transformers embeddings

    chore
    • On push: content/posting/*.md thay đổi → rebuild ngay
    • Weekly cron: Sunday 02:00 UTC → đảm bảo "động" theo thời gian
    • Manual: gh workflow run build-related.yml từ tab Actions
    • 384 dimensions, 120MB
    • 50+ languages incl. Vietnamese
    PR #82 −100 dòng xóa · +448 dòng thêm · Net +348 dòng
  425. Tối ưu image: LCP above-the-fold eager + CLS width/height chuẩn 2026

    chore
    • Hiện tại: ảnh từ Unsplash + uploaded CMS (JPG/PNG)
    • Giải pháp: dùng Squoosh.app hoặc CLI cwebp -q 80 input.jpg -o output.webp cho ảnh upload qua CMS
    • Tự động hóa: Cloudflare Image Resizing (free tier 100k req/month) — proxy URL thêm ?format=webp&width=800
    • ✅ KHÔNG đụng CSS overflow/height/position global → scroll desktop an toàn
    • ✅ KHÔNG đụng layout/grid → bố cục giữ nguyên
    PR #81 −92 dòng xóa · +242 dòng thêm · Net +150 dòng
  426. Tag Cloud: grid layout 5 cột với card badge + responsive 4/3/2 cột

    chore
    PR #80 −82 dòng xóa · +197 dòng thêm · Net +115 dòng
  427. Thêm: CLAUDE.md quy tắc CSS/Responsive — tách scope Mobile vs Desktop

    chore
    PR #79 −9 dòng xóa · +83 dòng thêm · Net +74 dòng
  428. HOTFIX: khôi phục scroll trang — gỡ overflow-x hidden trên html

    chore
    • overscroll-behavior-y: contain — chỉ ngăn rubber-band, KHÔNG khoá scroll
    • scroll-behavior: smooth + scroll-padding-top — anchor jump
    • Backdrop blur navbar (Threads-feel)
    • Tap-highlight + tap-active feedback mobile
    PR #78 −9 dòng xóa · +17 dòng thêm · Net +8 dòng
  429. Bật Google Analytics 4: G-REFBXH86Z5 (Property 541698865)

    chore
    • Measurement ID: G-REFBXH86Z5 → set vào config.toml ga_measurement_id
    • Property ID: 541698865 → ghi vào comment (config.toml + HTML comment trong template) để trace
    • HTML comment trong block GA4 active: <!-- GA4 Measurement ID: G-REFBXH86Z5 | Property ID: 541698865 -->
    • Footer pill: ⏳ ĐANG CHỜ MEASUREMENT ID (amber)
    • Trước </body>: chỉ console.info placeholder, không load gtag.js
    PR #77 −2 dòng xóa · +5 dòng thêm · Net +3 dòng
  430. Mobile UX Threads-feel: frosted navbar + tap feedback + smooth scroll

    chore
    • background: rgba(17, 17, 17, 0.88) thay solid #111
    • backdrop-filter: saturate(180%) blur(14px) → trong suốt subtle, blur content phía dưới khi scroll
    • Fallback solid nếu browser không support (Firefox < 103) → vẫn đẹp
    • Shadow 2 lớp: viền sáng 1px trên + bóng đổ dưới → depth giống iOS header
    • scroll-behavior: smooth cho mọi anchor link
    PR #76 −6 dòng xóa · +512 dòng thêm · Net +506 dòng
  431. Bulk Delete posts (GraphQL 1-commit batch + AJAX modal UI)

    remove
    • Auth required (require_session + access_token)
    • Mỗi slug validate qua _SLUG_RE → chống path traversal
    • Path cố định content/posting/{slug}.md → giới hạn scope
    • Dedupe + max 50 slugs/lần
    • GraphQL variables parameterized → KHÔNG injection (giống prepared statement SQL)
    PR #75 −4 dòng xóa · +469 dòng thêm · Net +465 dòng
  432. iPhone Dynamic Island + Home Indicator safe-area-inset

    chore
    • 100% CSS env() — KHÔNG JS detection
    • KHÔNG library, KHÔNG 3rd party
    • Browser cũ ignore env() → fallback base value (work everywhere)
    • env() là CSS computed value, browser tính 1 lần lúc load → KHÔNG runtime layout shift
    • 0 impact LCP/FCP/INP
    PR #74 −7 dòng xóa · +36 dòng thêm · Net +29 dòng
  433. Mobile optimization toàn diện (Momo-style) + ngăn CLS

    chore
    • Container padding: 24 → 16 → 14 → 12px (3 breakpoints)
    • Font base: 15.5px (≤720) / 15px (≤540) → mọi rem auto scale
    • overflow-x: hidden; max-width: 100vw → defense in depth
    • Touch target min 44×44px (Apple/Google guideline) ≤720px
    • 3-col grid → 1-col stack ≤720
    PR #73 −14 dòng xóa · +313 dòng thêm · Net +299 dòng
  434. GA module — visible pill responsive + placeholder ĐANG CHỜ MEASUREMENT ID

    chore
    • ✅ Responsive (mobile + desktop)
    • ✅ Placeholder rõ ràng 'ĐANG CHỜ MEASUREMENT ID' khi chưa có ID
    • ✅ gtag.js chuẩn + CSS
    • Có ID → load gtag.js chuẩn
    • Chưa có ID → render placeholder block:
    PR #72 −2 dòng xóa · +68 dòng thêm · Net +66 dòng
  435. Google Analytics 4 dời từ &lt;head&gt; xuống trước &lt;/body&gt;

    chore
    • Vị trí: chèn vào footer (trước </body>) → tối ưu page load
    • Chuẩn: gtag.js mới nhất (đã đúng)
    • MEASUREMENT_ID: để trống cho user tự điền
    • Bỏ GA block khỏi <head> (sau speed-vitals.js)
    • Thêm GA block ngay trước </body>, sau {% block extra_scripts %}
    PR #71 −13 dòng xóa · +21 dòng thêm · Net +8 dòng
  436. workflow auto commit nhầm log files + xoá rác từ PR #63

    remove
    • perf-fix.txt, perf-scan.txt, perf-summary.txt
    • fix-log.txt, fixed-summary.txt
    • pr-body.md
    • perf-audit: templates/ static/ sass/ content/ config.toml
    • self-healing: content/
    PR #70 −63 dòng xóa · +31 dòng thêm · Net -32 dòng
  437. 🚀 Perf audit: 6 file(s) optimized

    chore
    • Thêm loading="lazy" vào <img> tags thiếu (skip LCP hero có fetchpriority=high)
    • Thêm decoding="async" vào <img> tags thiếu
    • KHÔNG thay đổi: source images, JS/CSS, content, layout
    PR #63 −9 dòng xóa · +53 dòng thêm · Net +44 dòng
  438. Tag Cloud footer với pills colorful + size tier theo popularity

    chore
    • Pills colorful với 3 size tier theo popularity:
    • lg: tag có ≥70% bài (cao nhất)
    • md: 35-70%
    • sm: rest
    • 8 màu palette cycle theo loop.index0 % 8 → mỗi tag có màu cố định không random reload
    PR #69 −0 dòng xóa · +140 dòng thêm · Net +140 dòng
  439. Giscus comment width hẹp → force 100% width

    fix
    PR #68 −3 dòng xóa · +14 dòng thêm · Net +11 dòng
  440. bật Giscus comments với IDs thật

    chore
    • repo_id = "R_kgDOS5xLPw"
    • category_id = "DIC_kwDOS5xLP84C_Fx6"
    • category = "General"
    • Theme preferred_color_scheme (auto sáng/tối theo browser)
    • Mapping pathname (1 thread per URL)
    PR #67 −2 dòng xóa · +2 dòng thêm · Net +0 dòng
  441. JS fallback hardcode prod URL khi meta tag không có

    fix
    PR #66 −6 dòng xóa · +21 dòng thêm · Net +15 dòng
  442. Render backend down — thêm python-multipart vào requirements.txt

    fix
    • /cms/author GET + POST (Author Management form)
    • /cms/giscus/setup (button Setup Giscus)
    • /auth/, /api/, /track, /stats (đều down chung)
    PR #65 −10 dòng xóa · +26 dòng thêm · Net +16 dòng
  443. bỏ link admin footer + workflow fail-soft khi repo chặn PR creation

    fix
    • perf-audit.yml + self-healing.yml: wrap gh pr create với fallback. Repo chặn → print URL tạo tay + KHÔNG exit 1
    • Push branch vẫn thành công như trước
    PR #62 −10 dòng xóa · +23 dòng thêm · Net +13 dòng
  444. nút Setup Giscus trong /admin-author/ → 1 click lấy IDs

    chore
    • <details> block "🔧 Setup Giscus comments" (collapse)
    • Click "Fetch repo_id + category_id" → JS gọi endpoint với Authorization header
    • Render config TOML snippet vào dark output box (terminal feel)
    • User copy/paste vào config.toml + push
    • 401: chưa login
    PR #61 −0 dòng xóa · +106 dòng thêm · Net +106 dòng
  445. Author Management self-service + Web Vitals footer link + Giscus auto-fetch IDs

    chore
    • GET /cms/author — trả author.json
    • POST /cms/author — multipart {avatar?, name?, url?, bio?}. Validate MIME image/{jpeg,png,webp,gif}, max 5MB
    • Helpers: _gh_get_sha() + _gh_put_binary() reuse cho mọi binary upload tương lai
    • Form 2 cột: avatar block (input file + preview FileReader) + meta block (name + url + bio textarea char count)
    • Pattern auth giống /editor/ /baochi/
    PR #60 −19 dòng xóa · +788 dòng thêm · Net +769 dòng
  446. Performance audit — qa_check perf check + workflow tự tạo PR review

    chore
    • python3 qa_check.py --perf — báo cáo warnings
    • python3 qa_check.py --perf --fix perf — apply auto-fix img tags
    • Cron Chủ nhật 02:00 UTC (= 09:00 VN), 1 lần/tuần
    • workflow_dispatch để chạy thủ công ngay
    • Quy trình:
    PR #59 −7 dòng xóa · +264 dòng thêm · Net +257 dòng
  447. SCSS syntax check + Zola build smoke test + bỏ menu Báo chí/Điện ảnh

    chore
    PR #58 −38 dòng xóa · +267 dòng thêm · Net +229 dòng
  448. SCSS _editor.scss btn--success thiếu body → deploy fail (HOTFIX)

    fix
    PR #57 −35 dòng xóa · +151 dòng thêm · Net +116 dòng
  449. Giscus comments macro + auto light/dark theme

    chore
    • templates/macros/giscus.html — macro {% macro comments() %} silent skip nếu config thiếu
    • templates/page.html — {% import %} + {{ giscus::comments() }} cuối article (sau Related Articles)
    • templates/base.html CSP: script-src + https://giscus.app, frame-src https://giscus.app
    • config.toml [extra.giscus]: repo/repo_id/category/category_id
    • sass/_single.scss .giscus-section: header pill design system + dark mode adaptive
    PR #56 −35 dòng xóa · +123 dòng thêm · Net +88 dòng
  450. Author Box bỏ social + bio Vietnamese 150 từ về công nghệ và du lịch

    chore
    • Social icons (FB/IG/YT/GitHub) nhìn rối → bỏ hoàn toàn
    • author_avatar trỏ /img/author-avatar.jpg (user upload sau)
    • author_url → blog chính seomoney.org
    • author_bio Vietnamese ~150 từ chủ đề công nghệ + du lịch
    • Developer VN khám phá điểm chung công nghệ + du lịch
    PR #55 −34 dòng xóa · +17 dòng thêm · Net -17 dòng
  451. Author Box + Related Articles cuối mỗi bài viết

    chore
    • Name có verified badge inline (Meta blue check)
    • URL italic màu đỏ
    • 4 social icons (FB, IG, YT, GitHub) — SVG inline, hover gradient đỏ + lift -2px
    • author_avatar, author_url, author_bio
    • Iterate section posting → filter cùng category đầu, exclude bài hiện tại, slice 3
    PR #54 −131 dòng xóa · +1053 dòng thêm · Net +922 dòng
  452. Category management — categories.json + auto-sync khi save post

    chore
    • GET /api/categories/list (auth) — fetch fresh categories từ repo
    • POST /api/categories/add (auth) — append + PUT categories.json. Idempotent: đã có → {added: false}
    • Validate Unicode: tiếng Việt có dấu OK, 100 chars max
    • cms_save_post tích hợp _ensure_category: nếu post có category mới (parse từ frontmatter [taxonomies]) → auto-append vào categories.json best-effort
    • editor.html: nút "💾 Lưu" inline cạnh input "Tên category mới" + message feedback
    PR #53 −131 dòng xóa · +717 dòng thêm · Net +586 dòng
  453. /baochi/ không auto-run + retry 1 lần + thông báo provider rõ ràng

    fix
    PR #52 −68 dòng xóa · +426 dòng thêm · Net +358 dòng
  454. IMDB Calendar direct scrape + Trip.com debug endpoint

    chore
    • imdb.com → curl_cffi impersonate=chrome131 fetch HTML + extract __NEXT_DATA__ + walker recursive
    • khác → httpx JSON, walker direct (proxy services)
    • titleText.text, primaryTitle.text → title
    • primaryImage.url → thumbnail
    • id (tconst), node.id (GraphQL edges) → link
    PR #51 −52 dòng xóa · +378 dòng thêm · Net +326 dòng
  455. IMDB walker không nhận diện schema #-prefix (imdb.iamidiotareyoutoo.com)

    fix
    PR #50 −9 dòng xóa · +18 dòng thêm · Net +9 dòng
  456. /api/movies từ TMDB sang IMDB scraper proxy (URL configurable env)

    chore
    PR #49 −109 dòng xóa · +165 dòng thêm · Net +56 dòng
  457. trang /dien-anh/ TMDB phim phổ biến (Redis 24h cache)

    chore
    • TMDB v3 API: /movie/popular?language=vi-VN&region=VN
    • Fallback en-US chỉ khi vi-VN thiếu overview (1 conditional fetch, không waste request)
    • Map TMDB fields → schema chung: title/link/summary/published(year)/thumbnail(poster w500)/rating(vote_average)
    • Redis cache 24h (TMDB_CACHE_TTL) — phim popular ổn định, giảm hit rate limit free 40 req/10s
    • Graceful: empty/error → trả 200 với error field, FE fallback
    PR #48 −0 dòng xóa · +333 dòng thêm · Net +333 dòng
  458. OAuth callback double base path / → 404

    fix
    • BLOG_URL env var = https://seomoney.org (có sẵn base path /zola)
    • Client gửi return_to = location.pathname trên blog đã bao gồm /zola luôn (vd /baochi/)
    • Backend cộng BLOG_URL + return_to → https://seomoney.org/baochi/
    PR #47 −164 dòng xóa · +703 dòng thêm · Net +539 dòng
  459. nút Đăng lên blog + grid 4 cột Du lịch + Trip.com curl_cffi

    chore
    • OAuth scope thêm public_repo (cần để PUT)
    • Slug regex chống path traversal, content cap 200KB
    • GET sha hiện trạng → create or update đúng
    • Status banner xanh hiển thị link commit + ETA
    PR #46 −163 dòng xóa · +683 dòng thêm · Net +520 dòng
  460. meta vipzone-auth-api không render khi cms_auth_url = ""

    fix
    PR #45 −27 dòng xóa · +83 dòng thêm · Net +56 dòng
  461. cache key news include source ID → auto-invalidate khi đổi config

    fix
    PR #44 −25 dòng xóa · +78 dòng thêm · Net +53 dòng
  462. /du-lich/ Trip.com scrape empty → fallback VnExpress RSS + extract thumbnail

    fix
    • CURATED_FEEDS['du-lich'] đổi URL → https://vnexpress.net/rss/du-lich.rss
    • type: rss dùng feedparser (chuẩn, 100% ổn định)
    • source: VnExpress, cache 30 phút
    • du-lich.html header: "Tin tức Du lịch từ VnExpress" + verified badge
    • du-lich.js cache info: "refresh mỗi 30 phút"
    PR #43 −24 dòng xóa · +73 dòng thêm · Net +49 dòng
  463. di chuyển render.yaml ra repo root cho Blueprint default path

    fix
    • git mv services/visitor-counter/render.yaml → render.yaml
    • rootDir: services/visitor-counter giữ nguyên (path relative repo root)
    • README.md update reference path
    PR #42 −3 dòng xóa · +3 dòng thêm · Net +0 dòng
  464. trang /du-lich/ chuyển từ Znews RSS sang Trip.com scrape

    refactor
    • requirements.txt: thêm beautifulsoup4 4.12.3 + lxml 5.3.0
    • CURATED_FEEDS dict mở rộng với type (rss|scrape) + cache_ttl per-feed → du-lich type=scrape, ttl=86400 (24h)
    • SCRAPER_HEADERS: User-Agent giả Chrome 131 + Accept-Language vi-VN
    • _extract_jsonld_items(): ưu tiên parse JSON-LD ItemList schema → selector ổn định, không đổi theo CSS class. Lấy name/url/description/image/aggregateRating
    • _extract_fallback_items(): dự phòng tìm article/li/div + heading + link khi không có JSON-LD
    PR #40 −36 dòng xóa · +291 dòng thêm · Net +255 dòng
  465. Render Blueprint deploy + Visitor demo mode + fix changelog double-prefix

    fix
    • services/visitor-counter/render.yaml: khai báo 2 service (Redis + Web), Render tự dựng + inject REDIS_URL từ Redis service
    • Region singapore cho latency tốt với user VN
    • 6 env vars bake (CORS, BLOG_URL, ADMIN_EMAILS, TTLs), 3 vars sync:false (BACKEND_URL, GH_CLIENT_ID, GH_CLIENT_SECRET) → user fill khi apply
    • README.md mục mới "⚡ Quick deploy" 3 bước rõ ràng
    • Badge "🚧 DEMO" thay "LIVE" (amber palette phân biệt)
    PR #39 −11 dòng xóa · +181 dòng thêm · Net +170 dòng
  466. Thêm tính năng: GitHub OAuth CMS + RSS Checker + Du lịch (Znews) + UI sync + commit msg chuẩn

    chore
    • Backend services/visitor-counter/main.py: 4 endpoint mới GET /auth/login, GET /auth/callback, GET /auth/me, POST /auth/logout
    • Email white-list ADMIN_EMAILS=292648126+Banhang-Chogao@users.noreply.github.com (server-side, không bypass client)
    • access_token GitHub giữ Redis-side, client chỉ có opaque sid 32-byte
    • Session Redis TTL 2h idle timeout
    • sessionStorage trên client (KHÔNG localStorage, KHÔNG cookie)
    PR #38 −262 dòng xóa · +2283 dòng thêm · Net +2021 dòng
  467. Style: mở rộng /insights/ full-width (gấp đôi diện tích) + responsive

    chore
    • .layout-grid:has(.insights) → kill 340px sidebar column (insights vốn empty {% block sidebar %} nhưng grid vẫn allocate)
    • main.container:has(.insights) → nâng max-width **** → 1800px
    • Bỏ max-width: 1100px trên .insights, dùng width: 100%
    • insights__grid 1.4fr 1fr → 2fr 1fr, gap 1.5 → 2rem
    • Timeline rộng hơn → PR title 1 dòng, Overview side breathing
    PR #37 −6 dòng xóa · +37 dòng thêm · Net +31 dòng
  468. Real-time Visitor Counter (FastAPI + Redis + JS frontend)

    feat
    • FastAPI async + redis.asyncio singleton, INCR atomic counter (concurrent-safe không cần lock)
    • POST /track — tăng count nếu UA không phải bot, GET /stats — trả tổng
    • Regex single-pass bot filter (search engines, social previews, libs)
    • CORS chỉ allow CORS_ORIGIN (mặc định blog GitHub Pages URL)
    • Procfile + runtime.txt + .env.example sẵn sàng cho Render hoặc Railway free tier
    PR #36 −10 dòng xóa · +748 dòng thêm · Net +738 dòng
  469. trang /insights — GitHub Insights 2 cột (timeline + overview)

    feat
    • LEFT (60%) — Timeline: PR list từ changelog.json, vertical line gradient + dot tím nhô ra, title link tới PR
    • RIGHT (40%) — Overview: Active bar PRs/Issues + 4 stat cards (Merged/Open/Closed/New) + Summary card + Top Committers bar chart
    • ≤960px: 2 cột → stack 1 cột
    • ≤640px: stat cards thu nhỏ, bottom cards stack
    • Dark mode adaptive qua prefers-color-scheme: dark
    PR #35 −0 dòng xóa · +609 dòng thêm · Net +609 dòng
  470. CMS editor: DRAFT-ONLY mode (bỏ hoàn toàn PAT)

    chore
    • Bỏ HOÀN TOÀN PAT lifecycle: PAT_SESSION_KEY, helpers, prompt, 401 handler
    • api() unauth: read-only via 60/h IP limit (đủ cho cá nhân)
    • putPost(): tải file .md về máy thay vì PUT
    • deletePost(): alert hướng dẫn git rm thủ công
    • Button: 💾 Lưu lên GitHub → 📥 Tải file .md
    PR #34 −79 dòng xóa · +58 dòng thêm · Net -21 dòng
  471. Verified Badge cạnh tên tác giả mọi nơi

    feat
    • New: templates/macros/verified.html — Tera macro {{ v::badge() }} (single inline SVG, reusable)
    • Edit: 4 templates + 1 SCSS — import macro + apply badge
    • width/height: 1em → scale theo line-height container (chiều cao chữ 'n')
    • vertical-align: -0.12em → căn middle với chữ thường
    • margin-left: 0.25em → khoảng cách subtle với tên
    PR #33 −4 dòng xóa · +37 dòng thêm · Net +33 dòng
  472. bài 'Hành trình công nghệ — Dưới nắp ca-pô của blog'

    feat
    • Path: content/posting/cong-nghe-blog-duy-nguyen.md
    • Slug: /cong-nghe-blog-duy-nguyen (theo yêu cầu user)
    • Title: "Hành trình công nghệ: Dưới nắp ca-pô của blog cá nhân Duy Nguyen"
    • Zola 420ms · 15 pages (+1 post mới)
    • QA exit 0 · post body ~800 từ, qua threshold ≥50 chars dễ dàng
    PR #32 −0 dòng xóa · +164 dòng thêm · Net +164 dòng
  473. OTP plaintext → SHA-256 hash trong source (Web Crypto API)

    security
    • Build Zola 520ms · QA pass
    • grep -rn "<raw value>" trên source = 0 matches (clean)
    • Test sha256Hex: input đúng → match, input sai → reject, empty → reject
    • SHA-256 của 4-digit value có 10000 tổ hợp → brute-force trivially <1s
    • Hash chỉ obfuscation chống casual viewer (mở DevTools thấy hash thay vì plaintext)
    PR #31 −28 dòng xóa · +46 dòng thêm · Net +18 dòng
  474. gitignore __pycache__ + *.pyc

    chore
    PR #30 −13 dòng xóa · +65 dòng thêm · Net +52 dòng
  475. PAT cache + mask OTP/secret patterns trong changelog

    security
    • changelog.json: mã OTP cũ → **** (PR #27 entry)
    • update_changelog.py: thêm mask_secrets() áp dụng trên title + highlights
    • 6 patterns: ghp_, github_pat_, sk-, AIzaSy, AKIA, OTP/mã/code+digits
    PR #29 −13 dòng xóa · +63 dòng thêm · Net +50 dòng
  476. Header layout v2: deploy card sang LEFT cùng title, GitHub box full right

    chore
    • Build Zola 336ms · QA pass · 11 elements site-header__left | header-deploy-card trong HTML output
    • GitHub box giờ có TOÀN BỘ right column → không còn bị "lệch do co lại"
    • Deploy card 300px cố định left → "vừa đủ đừng quá dài"
    PR #28 −37 dòng xóa · +41 dòng thêm · Net +4 dòng
  477. CMS auth: OTP modal thay PAT login, PAT JIT in-memory

    chore
    • Bỏ login PAT form, dùng OTP modal 4 số (****)
    • PAT chỉ in-memory, KHÔNG localStorage / cookies
    • OTP session trong sessionStorage → đóng tab là mất → nhập lại
    • autocomplete="off"
    • data-lpignore="true" (LastPass)
    PR #27 −264 dòng xóa · +476 dòng thêm · Net +212 dòng
  478. Restructure header: DEPLOYED INSIDE GitHub box + github-pages card bên phải

    chore
    • 2 element [data-deploy-status] → JS dùng querySelectorAll update đồng bộ
    • Share 1 fetch, 1 cache 60s → 0 extra API call
    • Mobile <900px: stack column như cũ (deploy card full width)
    PR #26 −215 dòng xóa · +280 dòng thêm · Net +65 dòng
  479. Header: Meta Verified badge + bold label + audit/fix version logic

    fix
    • SVG inline scalloped 12-lobe (style Meta Verified)
    • Gradient #60A5FA → #1D4ED8
    • White checkmark + drop-shadow nhẹ
    • 26px desktop, 22px mobile
    • Restructure CSS: chip styling tách khỏi base strong selector
    PR #25 −5 dòng xóa · +62 dòng thêm · Net +57 dòng
  480. auto-update changelog.json mỗi khi PR merge (real-time)

    feat
    • PR body empty → highlights: []
    • changelog.json missing → tạo skeleton {items: []}
    • Push conflict (concurrent deploy bot) → pull-rebase + retry 3 lần
    • Workflow re-trigger → idempotent: skip nếu PR đã có trong items
    • Concurrency group queue → tránh race condition nếu nhiều PR merge gần nhau
    PR #24 −0 dòng xóa · +306 dòng thêm · Net +306 dòng
  481. Latest Deployment Status card cho /changelog

    feat
    • Card mô phỏng UI 'Latest deployments from pinned environments' của GitHub
    • 3 dòng: icon + github-pages + external link · Last deployed · URL
    • Refactor deploy-status.js: querySelectorAll handle nhiều container (header + card share 1 fetch)
    • Dark mode adaptive, mobile responsive (≤480px)
    PR #22 −35 dòng xóa · +261 dòng thêm · Net +226 dòng
  482. Move deploy status real-time từ /changelog → header (mọi page)

    refactor
    • Rename changelog-deploy.js → deploy-status.js (generic)
    • Refactor JS target [data-deploy-badge] + [data-deploy-text] thay innerHTML rewrite
    • base.html: data-* attrs vào .deploy-queue + load JS
    • Xoá 137 dòng .changelog__deploy* styles không còn dùng
    PR #21 −253 dòng xóa · +123 dòng thêm · Net -130 dòng
  483. Changelog page + Meta Verified badge + line stats per PR

    feat
    • Trang /changelog render từ changelog.json qua load_data
    • Meta Verified-style badge inline SVG gradient #60A5FA → #1D4ED8
    • Stats row '−X · +Y · Net Z' mỗi entry, font mono
    • Dark mode auto + mobile responsive + 7 tag colors
    • Bonus: deploy status box real-time embedded trong page
    PR #20 −0 dòng xóa · +749 dòng thêm · Net +749 dòng
  484. Remove google-stats + fix marked CDN unversioned

    cleanup
    • Xoá hoàn toàn google-stats + pagespeed.js + dependencies
    • Đổi marked CDN sang unversioned (latest stable) — fix lỗi không load
    • CSP thắt chặt: bỏ pagespeedonline.googleapis.com khỏi connect-src
    PR #19 −1045 dòng xóa · +10 dòng thêm · Net -1035 dòng
  485. Korean Number Converter + menu link

    feat
    • Tool /converter/ chuyển số sang chữ Hán Hàn (Sino-Korean)
    • Hỗ trợ tới 16 chữ số (hàng 경) qua BigInt
    • 2 style song song: Formal (정식) + Natural (자연)
    • Real-time + Copy button + dark mode auto
    PR #18 −0 dòng xóa · +467 dòng thêm · Net +467 dòng
  486. Banner timestamp lệch 7h UTC vs Việt Nam

    fix
    • Thêm timezone="Asia/Ho_Chi_Minh" vào filter date()
    • Đổi author.date → committer.date (chính xác hơn cho cherry-pick)
    • today_count tính theo midnight VN (UTC+7 offset)
    PR #17 −4 dòng xóa · +12 dòng thêm · Net +8 dòng
  487. Preview render fallback khi marked CDN không load

    fix
    • Visible warning + raw text fallback khi !window.marked
    • Auto-retry 500ms nếu marked chưa load
    • Trigger render khi window 'load' event fire
    PR #16 −2 dòng xóa · +54 dòng thêm · Net +52 dòng
  488. Remove tính năng Đọc báo (doc-bao)

    remove
    • Xoá templates/doc-bao.html + macros/news.html
    • Xoá static/js/news.js + sass/_news.scss
    • Bỏ allorigins.win khỏi CSP connect-src
    PR #15 −421 dòng xóa · +8 dòng thêm · Net -413 dòng
  489. Security hardening: XSS sanitize + CSP + SRI

    security
    • sanitizeHtml() strip script/iframe/on* trước innerHTML preview
    • news.js dùng DOM createElement thay innerHTML concat
    • CSP meta tag với frame-ancestors 'none' chống clickjacking
    • security.txt RFC 9116 + Referrer-Policy
    PR #14 −17 dòng xóa · +112 dòng thêm · Net +95 dòng
  490. Self-healing QA: --fix mode + cron 6h auto-PR

    feat
    • qa_check.py --fix mode: normalize tags + dedupe + trailing newline
    • GitHub Actions cron 6h tự fix + mở PR cho user review
    • Single rolling branch fix/auto-qa, concurrency group queue
    PR #13 −5 dòng xóa · +291 dòng thêm · Net +286 dòng
  491. CMS Lite redesign: toolbar + split + slash + QA + OTP

    feat
    • Markdown toolbar 10 nút SVG + Ctrl+S/B/I/K/E shortcuts
    • Live split-preview + autosave draft + recovery banner
    • Slash command menu / với mirror div caret tracking
    • QA Gatekeeper Python + pre-commit hook
    • Footer OTP gate cho /editor/
    PR #12 −60 dòng xóa · +1320 dòng thêm · Net +1260 dòng
  492. CMS list view bake metadata + search/sort realtime

    feat
    • Bake metadata vào <script id=posts-metadata> → 0ms render
    • Background refresh diff với GitHub API, badge 🆕 cho bài mới
    • Search debounce 100ms + normalize tiếng Việt + sort 3 mode
    PR #11 −26 dòng xóa · +321 dòng thêm · Net +295 dòng

S-DNA · CI/CD Monitor

Live TheoDoi8

🔄 running
theodoi8@github-actions

Đang tải terminal theodoi8…