Changelog
Lịch sử cập nhật & PR của blog · gần đây nhất ở trên
-
fix(links): bỏ placeholder  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
-
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)
-
CMS: bỏ Featured cũ khi chọn 'viet-blog-bang-local-terminal-khi-ai-het-credit'
chore -
CMS: bỏ Featured cũ khi chọn 'viet-blog-bang-local-terminal-khi-ai-het-credit'
chore -
CMS: bỏ Featured cũ khi chọn 'viet-blog-bang-local-terminal-khi-ai-het-credit'
chore -
CMS: bỏ Featured cũ khi chọn 'viet-blog-bang-local-terminal-khi-ai-het-credit'
chore -
CMS: bỏ Featured cũ khi chọn 'viet-blog-bang-local-terminal-khi-ai-het-credit'
chore -
CMS: cập nhật bài 'Viết blog bằng local terminal khi AI hết credit'
chore -
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.
-
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).
-
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)
-
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ó
-
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).
-
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)
-
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.
-
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"
-
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
-
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.
-
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.
-
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
-
vaccine cheat sheet to static for public deployment
refactor -
README.md
chore -
Remove broken link to non-existent f-dashboard page
fix -
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)
-
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
-
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
-
fix(content-routing): remove duplicate Auto Fixer article from baochi/
remove -
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)
-
Claude/ecstatic mccarthy s0v1ar
chore -
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)
-
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
-
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
-
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)
-
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)
-
fix(seo): shorten VssID BHXH article title
fix -
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
-
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.
-
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)
-
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).
-
chore(vaccine): Daily Vaccine Autofixer run
chore -
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).
-
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).
-
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).
-
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
-
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).
-
replace Tera unsupported default(value=[]) with conditional assignment
fix -
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
-
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.
-
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
-
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)
-
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).
-
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)
-
fix(assets): restore shared assets causing repeated 404s
fix -
chore(git): ignore private AI notes and local QA artifacts
chore -
docs(ci): define tiered QA architecture
chore -
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).
-
feat(tools): add PR Sentinel CI radar
chore -
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)
-
feat(security): add Turnstile footer and setup guide
security -
feat(security): add Turnstile footer and setup guide
security -
CMS: cập nhật bài 'AI lập kế hoạch du lịch: thay đổi cách đi'
chore -
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)
-
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
-
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.
-
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).
-
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
-
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).
-
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)
-
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)
-
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)
-
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.
-
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).
-
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.
-
chore(momo): update default paid-content link → y5eVvzz2nlXXeEP
chore -
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
-
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.
-
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)
-
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
-
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)
-
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
-
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.
-
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
-
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,
-
fix(vaccine-v18): stop runtime artifact conflicts in concurrent hotfix PRs
fix -
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.
-
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)
-
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
-
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
-
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).
-
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)
-
docs(shortcuts): wip8 output dạng bảng markdown trực quan
chore -
Claude/hello j5dp4s
chore -
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
-
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.
-
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)
-
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)
-
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"
-
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"
-
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"
-
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
-
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.
-
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á.
-
fix(ui): canh giãn ảnh placeholder đồng đều trên mobile
fix -
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
-
chore(vaccine): Daily Vaccine Autofixer run
chore -
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.
-
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
-
Feat/super admin session clean
cleanup -
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).
-
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 ✓
-
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.
-
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.
-
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.
-
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).
-
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.
-
Chore/vipzone api url
chore -
docs(shortcuts): add wip8 — read-only workspace tracker
chore -
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
-
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)
-
chore(seo): add GSC HTML-file verification google359ea2ec9d73ed9c
chore -
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).
-
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
-
docs(shortcuts): add fixrule8 conflict scanner shortcut
chore -
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.
-
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).
-
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.
-
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
-
merged PR summary rule — no watch loop, vaccine on fail
chore -
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
-
content: add 19 topic authority cluster articles
chore -
feat(flight-db): add seed data generator script
chore -
feat(flight-db): add client-side app.js
chore -
feat(flight-db): add styles, JS, seed data and generator script
chore -
feat(flight-db): add Flight DB template
chore -
feat(flight-db): S-DNA Flight DB dashboard tool
chore -
ShortenSEA auth flow and add public/VIP/admin pages
fix -
docs(shortensea): add Render deploy guide
chore -
Merge remote-tracking branch 'origin/feat/h-dashboard-multi-upload-10' into merge-h-dashboard-multi
chore -
feat(shortensea): S-DNA short URL manager — pages, API, redirect
chore -
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.
-
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
-
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.
-
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.
-
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)
-
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
-
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.
-
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
-
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)
-
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)
-
feat(insights): add Ad-Report V2 daily monetization + UI analysis
chore -
fix(gsc): pin property to https://seomoney.org/
fix -
feat(seo): connect Google Search Console API to SEO Reality Check
chore -
fix(h-dashboard): load Coffee Analytics module before initialization
fix -
unhide premium posts and add momo support CTA
fix -
chore(ui): temporarily hide QA dashboard from public UI
chore -
Merge branch 'hotfix/remove-ad-slots-keep-placeholders'
remove -
feat(s-dna): make page visually demonstrate Sembcorp design DNA
chore -
feat(h-dashboard): Coffee Life Analytics V2 — S-DNA redesign
chore -
publish adsense report as ad-report page
feat -
publish adsense report as ad-report page
feat -
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
-
feat(tools): add S-DNA documentation page under /tools/s-dna/
chore -
feat(footer): move categories to compact footer navigation grid
refactor -
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
-
feat(stats): Sembcorp investor-slide UI + bugfixes for /stats/
chore -
chore(vaccine): Daily Vaccine Autofixer run
chore -
docs(reports): báo cáo vị trí AdSense + tổng hợp tính năng phiên 18–19/06
chore -
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).
-
CMS: cập nhật bài 'Ngày 27 — Câu điều kiện & nghĩa vụ tiếng Hàn'
chore -
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.
-
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)
-
🔬 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
-
CMS: cập nhật author info
chore -
CMS: cập nhật bài 'Fintech 2026: Paywall premium trên blog cá nhân'
chore -
CMS: thêm category 'premium'
chore -
CMS: bỏ Featured cũ khi chọn 'premium-fintech-paywall-demo'
chore -
CMS: cập nhật bài 'Fintech 2026: Paywall premium trên blog cá nhân'
chore -
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.
-
CMS: cập nhật footer countdown
chore -
feat(insights): paginate timeline PR list (10 rows per page)
chore -
docs(rules): thêm GLOBAL WRITING RULES (human-first, anti-AI, E-E-A-T)
chore -
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).
-
fix(ci): vaccine V6/V7 — bot data stash conflict + remediation tự đỏ
fix -
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ị đè)
-
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.
-
feat(seo): cover SVG → twin .og.webp cho og:image (social hiện đúng ảnh bài)
chore -
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).
-
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 ✓
-
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).
-
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
-
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
-
CMS: cập nhật footer countdown
chore -
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+
-
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
-
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ờ
-
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á.
-
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)
-
CMS: cập nhật bài 'Những Quy Định Cấm Từ Shopee Affiliate 2026 Mới Nhất'
chore -
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
-
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.
-
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ừ.
-
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
-
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).
-
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
-
O-Dashboard — Liobank by OCB PDF statement dashboard
feat -
content+feat: bb tax article + richer rule-based insights engine
chore -
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.
-
fix(img): resolve 3 missing-image 404s (header/banner/premium thumbnail)
fix -
content-based domain selector + offline-safe qa-404-checker
feat -
PREVIEW: Phase-4 dashboard analytics + Insights pagination refactor
refactor -
qa-domain-selector — domain suggestions on Insights (2h cron)
feat -
fix(seo-badge): score all posts so SEO badge renders on every post
fix -
fix(references): / double-prefix 404 in post References blocks
fix -
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
-
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.
-
footer contrast, AdSense privacy link, version badge SHA, L-Dashboard upload crash
fix -
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
-
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
-
content(series): Bài 4–6 — Uranium 5/5 + AdSense/SEO 6/15
chore -
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
-
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)
-
feat(sidebar): add Google Rank SEO authority widget
chore -
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)
-
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
-
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
-
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
-
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
-
fix(links): repair 11 broken external URLs flagged by zola check
fix- zola check — 0 broken links
-
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"]
-
feat(footer): countdown box + admin config page
chore -
feat(insights): build history snapshots every 5 minutes
chore -
SEO11 phase 2 iter 1: h1 on static asset indexes
chore -
fix(ci): auto-trigger deploy after bot push_to_main
fix -
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
-
fix(ci): correct gh pr view --jq syntax in changelog workflow
fix -
fix(ci): stash local changes before pull in push_to_main.sh
fix -
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
-
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
-
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
-
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
-
refresh Google Trends VN hot search
chore -
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
-
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
-
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-*
-
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)
-
chore: refresh Build Dashboard data
chore- data/build-dashboard.json — refresh sau #313, giữ status_normalized
-
qa: Compliance Score audit + auto-fix
fix- data/compliance-score.json — 100/100 A+ sau #309
-
fix: compliance internal links — root cause + diagnostics
fix- compliance-link-report.json, compliance_audit.py, insights broken-link UI
-
fix(dashboard): phân loại cancelled deploy runs — Build #387/#388
fix- fetch_build_dashboard.py status_normalized, cancelled UI styles
-
qa: Compliance Score audit + auto-fix
fix- Workflow: Compliance Score Audit
- Branch: qa/compliance-auto
- KHÔNG auto-merge
-
changelog after PR #300
chore- Workflow: Auto-update changelog.json
- Branch: chore/changelog-sync
- KHÔNG auto-merge
-
refresh Build Dashboard data
chore- Workflow: Fetch Build Dashboard
- Branch: chore/build-dashboard-data
- KHÔNG auto-merge
-
🤖 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
-
refresh Build Dashboard data
chore- Workflow: Fetch Build Dashboard
- Branch: chore/build-dashboard-data
- KHÔNG auto-merge
-
qa: Compliance Score audit + auto-fix
fix- Workflow: Compliance Score Audit
- Branch: qa/compliance-auto
- KHÔNG auto-merge
-
qa: Compliance Score audit + auto-fix
fix- Workflow: Compliance Score Audit
- Branch: qa/compliance-auto
- KHÔNG auto-merge
-
changelog after PR #272
chore- Workflow: Auto-update changelog.json
- Branch: chore/changelog-sync
- KHÔNG auto-merge
-
Feat/devops no dependabot batch 10
chore -
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
-
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
-
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
-
Feature/seo foundation series
chore -
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
-
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/..." ✓
-
feature: auto-generate references section at end of posts
chore -
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
-
Feat/devops no dependabot batch 10
chore -
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
-
ci: remove Dependabot; enforce feature branch PR batch-of-10 merge
remove -
🤖 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
-
🤖 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
-
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.
-
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.
-
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.
-
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:
-
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).
-
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.
-
perf-audit fixer bỏ qua <img> 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.
-
🚀 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
-
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).
-
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.
-
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.
-
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).
-
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)
-
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)
-
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
-
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.
-
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.
-
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.
-
docs(bb9): cú pháp phím tắt thành `bb9 <topic>`
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.
-
deps(scripts): bump the pip-all group in /scripts with 15 updates
chore -
docs(bb9): bắt buộc cú pháp bb9 <tên chủ đề>
chore- Đọc shortcuts.md mục bb9 → có block "Cú pháp gọi (BẮT BUỘC)".
-
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ờ".
-
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.
-
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 đỏ.
-
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.
-
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)
-
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).
-
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ệ.
-
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
-
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
-
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.
-
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.
-
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)
-
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
-
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
-
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).
-
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).
-
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 đủ.
-
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)
-
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ố.
-
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/
-
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.
-
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)
-
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ũ
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
Claude/happy newton jaf5qq
chore -
remove custom Git/PR workflow rules from CLAUDE.md
chore -
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.
-
Đồng bộ shortcut prn với rule mới (1 nhánh chung + base main)
chore -
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).
-
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.
-
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).
-
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/.
-
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.
-
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.
-
🤖 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
-
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.
-
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>.
-
Claude/affectionate feynman 2s7rh5
chore -
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
-
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.
-
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
-
🔥 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
-
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
-
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
-
Claude/test auto merge9
chore -
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
-
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
-
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
-
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
-
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
-
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)
-
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
-
test: Auto-merge9 test PR #06
chore -
test: Auto-merge9 test PR #05
chore -
test: Auto-merge9 test PR #01
chore -
Phase4 port groups refactoring
chore -
Add manu9 PR approval shortcut
feat -
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
-
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 %}
-
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)
-
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
-
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)
-
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)
-
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
-
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
-
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
-
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.
-
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
-
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
-
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
-
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
-
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 "—"
-
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
-
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
-
Tuần 1: batch frontmatter enhancer + topic gap analysis
chore -
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
-
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
-
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
-
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
-
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)
-
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
-
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
-
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
-
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
-
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.
-
ff Fix: Slack workflow truncate commit message tránh invalid_blocks
fix- name: Truncate commit message
-
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)
-
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)
-
Cập nhật quy tắc: TẠM NGƯNG QUYỀN AUTO-MERGE — user manual gatekeeper
chore -
gg deploy: Momo Design Tokens + Crawler + help shortcut
chore -
HOTFIX (pp): Tera ga_stats._status not found block deploy
chore- {% set is_demo = ga_stats._status == "waiting_for_secret" %}
-
Auto-deploy batch: 10 commits (mobile UX + momo homepage + content + features)
chore -
Tạo lại: slack-notify.yml với fix toJSON() escape commit message
fix -
slack-notify.yml workflow (cài sai)
chore -
Test deploy: thêm file diantoi.txt để verify lệnh manual #X
chore -
Batch 2: gom commits chờ deploy gộp (rule mới)
chore -
Cập nhật shortcuts.md: quy trình Deploy GỘP + lệnh manual #X
chore -
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
-
Cập nhật shortcuts.md: thêm phím tắt 'seo' tối ưu bài mới ≤5h
chore -
🤖 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
-
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
-
Thêm bài research: Sentence Transformers (SBERT) — kiến trúc, training, ứng dụng
chore -
🤖 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
-
Thêm bài: Ngày thứ hai của blog — 100 PR và stack công nghệ tự nâng cấp
chore -
🤖 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
-
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
-
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
-
HOTFIX KHẨN: Tera literal dict block deploy + PR summary format chuẩn
chore -
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
-
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
-
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
-
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
-
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
-
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)
-
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)
-
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
-
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)
-
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
-
HOTFIX KHẨN: fix Tera syntax page.html + restore FORCE Node24 + gỡ qa-failed-handler
fix -
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
-
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
-
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)
-
Hotfix: enforce Node.js 24 trên 2 workflow mới thiếu env
chore -
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
-
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
-
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
-
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
-
Tag Cloud: grid layout 5 cột với card badge + responsive 4/3/2 cột
chore -
Thêm: CLAUDE.md quy tắc CSS/Responsive — tách scope Mobile vs Desktop
chore -
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
-
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
-
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
-
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)
-
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
-
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
-
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:
-
Google Analytics 4 dời từ <head> xuống trước </body>
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 %}
-
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/
-
🚀 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
-
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
-
Giscus comment width hẹp → force 100% width
fix -
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)
-
JS fallback hardcode prod URL khi meta tag không có
fix -
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)
-
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
-
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
-
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/
-
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:
-
SCSS syntax check + Zola build smoke test + bỏ menu Báo chí/Điện ảnh
chore -
SCSS _editor.scss btn--success thiếu body → deploy fail (HOTFIX)
fix -
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
-
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
-
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
-
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
-
/baochi/ không auto-run + retry 1 lần + thông báo provider rõ ràng
fix -
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
-
IMDB walker không nhận diện schema #-prefix (imdb.iamidiotareyoutoo.com)
fix -
/api/movies từ TMDB sang IMDB scraper proxy (URL configurable env)
chore -
trang /dien-anh/ TMDB phim phổ biến (Redis 24h cache)
chore- TMDB v3 API: /movie/popular?language=vi-VN®ion=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
-
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/
-
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
-
meta vipzone-auth-api không render khi cms_auth_url = ""
fix -
cache key news include source ID → auto-invalidate khi đổi config
fix -
/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"
-
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
-
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
-
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)
-
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)
-
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
-
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
-
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
-
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
-
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
-
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
-
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)
-
gitignore __pycache__ + *.pyc
chore -
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
-
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"
-
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)
-
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)
-
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
-
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
-
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)
-
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
-
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
-
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
-
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
-
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)
-
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
-
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
-
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
-
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
-
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/
-
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