Câu chuyện về báo cáo tuần — Weekly Monitor Skill *, *::before, *::after { box-sizing: border-box; } body { margin: 0; background: #f9f8f6; color: #1c1c1e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; font-size: 17px; line-height: 1.75; } /* ── Hero — AWS blue tone ── */ .hero { background: linear-gradient(135deg, #0d1117, #146eb4, #232f3e); color: #fff; padding: 72px 24px 60px; text-align: center; } .hero .kicker { display: inline-block; background: rgba(255,255,255,0.12); border: 1px solid rgba(255,255,255,0.25); border-radius: 100px; font-size: 12px; letter-spacing: 1.5px; text-transform: uppercase; padding: 4px 14px; margin-bottom: 20px; } .hero h1 { font-size: clamp(1.8rem, 5vw, 3rem); font-weight: 800; margin: 0 0 16px; line-height: 1.2; color: #fff !important; } .hero .sub { max-width: 600px; margin: 0 auto; color: rgba(255,255,255,0.78); font-size: 1rem; } /* ── Page layout ── */ .page-layout { display: grid; grid-template-columns: 210px minmax(0, 720px); max-width: 980px; margin: 0 auto; align-items: start; padding: 0 24px; } @media (max-width: 860px) { .page-layout { grid-template-columns: 1fr; padding: 0; } } /* ── TOC Sidebar ── */ .toc-sidebar { position: sticky; top: 32px; padding: 48px 20px 48px 0; align-self: start; } @media (max-width: 860px) { .toc-sidebar { display: none; } } .toc-label { font-size: 10px; font-weight: 700; letter-spacing: 1.5px; text-transform: uppercase; color: #999; margin-bottom: 12px; } .toc-list { list-style: none; padding: 0; margin: 0; } .toc-list li { margin-bottom: 2px; } .toc-list a { display: block; font-size: 0.8rem; color: #888; text-decoration: none; padding: 5px 10px 5px 12px; border-left: 2px solid transparent; border-radius: 0 4px 4px 0; transition: color 0.15s, border-color 0.15s, background 0.15s; line-height: 1.35; } .toc-list a:hover { color: #1c1c1e; background: rgba(0,0,0,0.04); } .toc-list a.active { color: #146eb4; border-left-color: #146eb4; font-weight: 600; background: rgba(20,110,180,0.06); } .toc-num { display: inline-block; font-size: 9px; font-weight: 700; letter-spacing: 0.5px; color: #bbb; margin-right: 4px; vertical-align: middle; } .toc-list a.active .toc-num { color: #146eb4; } /* ── Article ── */ article { padding: 48px 24px 80px; min-width: 0; } .chapter { display: flex; align-items: center; gap: 12px; margin: 56px 0 20px; } .chapter:first-child { margin-top: 0; } .chapter-num { background: #232f3e; color: #fff; font-size: 11px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase; padding: 4px 10px; border-radius: 4px; white-space: nowrap; } .chapter-line { flex: 1; height: 1px; background: #e0ddd8; } h2.section-title { font-size: 1.5rem; font-weight: 700; margin: 0 0 20px; color: #1c1c1e; } h3 { font-size: 1.1rem; font-weight: 700; margin: 32px 0 8px; color: #1c1c1e; } p { margin: 0 0 1.1em; } .scene { background: #fff; border-left: 4px solid #ff9900; border-radius: 0 8px 8px 0; padding: 20px 24px; margin: 28px 0; font-style: italic; color: #444; font-size: 1.05rem; } .callout { background: #fff8e6; border-left: 4px solid #ff9900; border-radius: 0 8px 8px 0; padding: 16px 20px; margin: 24px 0; font-size: 0.95rem; color: #5a4000; } .callout strong { color: #3a2800; } .insight { background: #eaf4ff; border-left: 4px solid #146eb4; border-radius: 0 8px 8px 0; padding: 16px 20px; margin: 24px 0; font-size: 0.95rem; color: #003a66; } pre { background: #1e1e2e; color: #cdd6f4; border-radius: 8px; padding: 18px 20px; overflow-x: auto; font-size: 0.85rem; line-height: 1.6; margin: 20px 0; } code { font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace; } p code, li code, td code { background: #f0ede8; padding: 2px 6px; border-radius: 4px; font-size: 0.88em; color: #c0392b; } .story-img { width: 100%; border-radius: 10px; margin: 28px 0; box-shadow: 0 4px 24px rgba(0,0,0,0.12); } .img-caption { text-align: center; font-size: 0.82rem; color: #888; margin: -18px 0 28px; } /* ── Domain cards ── */ .domain-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 12px; margin: 24px 0; } .domain-card { background: #fff; border: 1px solid #e0ddd8; border-radius: 10px; padding: 18px 16px; } .domain-card .domain-badge { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase; padding: 3px 10px; border-radius: 100px; margin-bottom: 8px; } .badge-a { background: #eaf4ff; color: #146eb4; } .badge-b { background: #fde8e8; color: #c0392b; } .badge-c { background: #fef3e2; color: #d35400; } .domain-card h4 { font-size: 0.95rem; font-weight: 700; margin: 0 0 6px; } .domain-card .domain-report { font-size: 0.82rem; color: #555; margin-bottom: 6px; } .domain-card .domain-source { font-size: 0.78rem; color: #888; margin: 0; } /* ── Flow diagram ── */ .flow-diagram { background: #fff; border: 1px solid #e0ddd8; border-radius: 12px; padding: 28px 24px; margin: 28px 0; } .flow-title { text-align: center; font-size: 0.75rem; font-weight: 700; letter-spacing: 1.5px; text-transform: uppercase; color: #888; margin-bottom: 20px; } .flow-prompt { text-align: center; background: linear-gradient(135deg, #232f3e, #146eb4); color: #fff; border-radius: 8px; padding: 12px 20px; font-size: 0.9rem; font-weight: 600; margin-bottom: 20px; } .flow-domains { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-bottom: 16px; } @media (max-width: 600px) { .flow-domains { grid-template-columns: 1fr; } } .flow-domain { border-radius: 8px; padding: 14px; text-align: center; font-size: 0.82rem; } .flow-domain-a { background: #eaf4ff; border: 1px solid #b8d4f0; color: #146eb4; } .flow-domain-b { background: #fde8e8; border: 1px solid #f0c0c0; color: #c0392b; } .flow-domain-c { background: #fef3e2; border: 1px solid #f0d8a8; color: #d35400; } .flow-domain .fd-label { font-weight: 700; font-size: 0.75rem; letter-spacing: 0.5px; text-transform: uppercase; margin-bottom: 4px; } .flow-domain .fd-steps { font-size: 0.78rem; color: inherit; opacity: 0.85; line-height: 1.5; } .flow-arrow { text-align: center; color: #bbb; font-size: 1.2rem; margin: 8px 0; } .flow-outputs { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; } @media (max-width: 600px) { .flow-outputs { grid-template-columns: 1fr; } } .flow-output { background: #e8f8f0; border: 1px solid #b8e0c8; border-radius: 8px; padding: 10px 12px; text-align: center; font-size: 0.78rem; color: #1a6640; font-weight: 600; } /* ── Pipeline steps ── */ .pipeline { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin: 24px 0; } @media (max-width: 520px) { .pipeline { grid-template-columns: 1fr; } } .pipe-step { background: #fff; border: 1px solid #e0ddd8; border-radius: 10px; padding: 18px 16px; text-align: center; } .pipe-step .pipe-num { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; background: #232f3e; color: #fff; border-radius: 50%; font-size: 0.8rem; font-weight: 700; margin-bottom: 8px; } .pipe-step h4 { font-size: 0.95rem; margin: 0 0 6px; } .pipe-step p { font-size: 0.82rem; color: #555; margin: 0; line-height: 1.45; } /* ── Problem list ── */ .problem-list { background: #fff; border: 1px solid #e8e4de; border-radius: 10px; padding: 20px 24px; margin: 24px 0; } .problem-list ol { margin: 0; padding-left: 1.2rem; } .problem-list li { margin-bottom: 8px; font-size: 0.95rem; color: #444; } .problem-list li:last-child { margin-bottom: 0; } /* ── Finding cards ── */ .finding { background: #fff; border: 1px solid #e8e4de; border-radius: 10px; padding: 24px 24px 20px; margin: 28px 0; } .finding-tag { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: 1.2px; text-transform: uppercase; padding: 3px 10px; border-radius: 100px; margin-bottom: 10px; } .tag-critical { background: #fde8e8; color: #c0392b; } .tag-high { background: #fef3e2; color: #d35400; } .tag-medium { background: #e8f4fd; color: #1a6fa8; } .tag-warning { background: #fff8e6; color: #b8860b; } .finding h4 { font-size: 1rem; font-weight: 700; margin: 0 0 10px; color: #1c1c1e; } .finding p { margin: 0 0 10px; font-size: 0.95rem; color: #444; } .finding .finding-note { margin: 0; font-size: 0.85rem; color: #888; } .domain-label { display: block; font-size: 10px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase; color: #888; margin: 28px 0 8px; } /* ── Prompt table ── */ .prompt-table { width: 100%; border-collapse: collapse; margin: 20px 0; font-size: 0.88rem; } .prompt-table th, .prompt-table td { border: 1px solid #e0ddd8; padding: 10px 14px; text-align: left; } .prompt-table th { background: #f5f3f0; font-weight: 700; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.5px; color: #555; } .prompt-table tr:nth-child(even) td { background: #faf9f7; } /* ── Time comparison ── */ .time-compare { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin: 24px 0; } @media (max-width: 480px) { .time-compare { grid-template-columns: 1fr; } } .time-card { border-radius: 8px; padding: 16px 18px; font-size: 0.88rem; } .time-card .tc-label { font-weight: 700; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 4px; } .time-card .tc-num { font-size: 1.4rem; font-weight: 800; margin-bottom: 2px; } .time-good { background: #e8f8f0; color: #1a6640; } .time-bad { background: #fde8e8; color: #7b1a1a; } /* ── Compare table ── */ .compare-table { width: 100%; border-collapse: collapse; margin: 20px 0; font-size: 0.88rem; } .compare-table th, .compare-table td { border: 1px solid #e0ddd8; padding: 10px 14px; text-align: left; } .compare-table th { background: #232f3e; color: #fff; font-weight: 600; font-size: 0.82rem; } .compare-table tr:nth-child(even) td { background: #faf9f7; } /* ── CTA ── */ .cta-block { background: linear-gradient(135deg, #0d1117, #146eb4, #232f3e); color: #fff; border-radius: 12px; padding: 36px 28px; margin: 48px 0 0; text-align: center; } .cta-block h2 { margin: 0 0 8px; font-size: 1.4rem; color: #fff !important; } .cta-block p { color: rgba(255,255,255,0.75); margin: 0 0 20px; font-size: 0.95rem; } .cta-steps { text-align: left; background: rgba(255,255,255,0.08); border-radius: 8px; padding: 16px 20px; margin: 0 auto 20px; max-width: 520px; } .cta-steps p { color: rgba(255,255,255,0.85); margin: 0 0 6px; font-size: 0.88rem; } .cta-steps p:last-child { margin: 0; } .cta-steps .step-label { display: inline-block; background: rgba(255,255,255,0.2); border-radius: 4px; font-size: 10px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase; padding: 1px 7px; margin-right: 6px; } .cta-block code { background: rgba(255, 255, 255, 0.22) !important; color: #ffe08a !important; padding: 2px 8px; border-radius: 4px; font-weight: 600; } ul, ol { padding-left: 1.4rem; margin: 0 0 1em; } li { margin-bottom: 4px; } strong { font-weight: 700; } em { font-style: italic; } hr.divider { border: none; border-top: 1px solid #e0ddd8; margin: 40px 0; } Weekly Monitor Skill · Câu chuyện thực tế Skill AI làm báo cáo hạ tầng mỗi tuần Một câu chat, nhận 3 file Excel: tình trạng Alarm, Metric (CloudWatch); lỗ hổng dependency (CVE); và version sắp hết hạn (EOL) — review rồi gửi khách. Mục lục 01Báo cáo tuần đang làm tay thế nào 02Làm tay thì dễ thiếu, khó đều 03Ý tưởng: 1 prompt, 3 báo cáo 04Skill hoạt động như thế nào 05Những vấn đề skill đã phát hiện 06Cách chạy báo cáo mỗi tuần 07Cần chuẩn bị gì trước khi dùng Chương 1 Cứ thứ Hai lại ngồi vào làm báo cáo Mỗi tuần, infra team mở CloudWatch Console, lọc alarm, copy số vào Excel, viết tay assessment, gửi khách. Làm xong tuần này — tuần sau lặp lại từ đầu. Quy trình trông đơn giản, nhưng thực tế mất nhiều thời gian hơn dự kiến: Mở 3–4 tab AWS Console song song — alarm ở region này, metric ở region kia Copy số liệu bằng tay → dễ nhầm lẫn, dễ thiếu metric Assessment viết đi viết lại y chang tuần trước → mất thời gian mà không thêm giá trị Quên nhìn tuần trước để phát hiện trend → báo cáo chỉ mô tả hiện tại, không cảnh báo sớm Báo cáo gửi muộn → khách phải nhắc "Tuần nào cũng vậy — mở Console, kéo số, điền Excel. Gần xong rồi lại phát hiện thiếu một metric phải quay lại từ đầu." Khi team phải quản lý nhiều dự án cùng lúc, bài toán còn nặng hơn: mỗi dự án một file Excel, một format hơi khác nhau, một người phụ trách khác nhau. Không có ai đảm bảo tuần nào cũng đủ metric, đủ alarm history, đủ trend so với tuần trước. Chương 2 Vấn đề không phải ở người — là ở quy trình Chúng tôi ngồi lại và nhận ra: khi scale ra nhiều dự án, bài toán không còn là "làm nhanh hơn" mà là làm đúng và nhất quán. Mỗi người viết assessment theo style khác nhau. Khách nhận báo cáo mỗi tuần khác định dạng. Trend bị bỏ qua vì không ai nhớ số liệu tuần trước. Consistency — Assessment cần theo chuẩn, không phụ thuộc vào người viết Completeness — Không bỏ sót metric, không quên nhìn alarm history Coverage — Hạ tầng ngày nay không chỉ là CloudWatch: còn có CVE trong dependencies, còn có component sắp hết EOL Một dự án có package đã EOL 3 tháng mà không ai biết — vì chưa bao giờ có báo cáo lifecycle. Không phải vì team thiếu năng lực, mà vì quy trình chưa bao phủ góc nhìn đó. Câu hỏi đặt ra: liệu AI có thể tự động hóa toàn bộ pipeline — từ thu thập số liệu, đánh giá theo tiêu chí chuẩn, đến xuất Excel — để infra team chỉ cần trigger một lần mỗi tuần? Chương 3 Ý tưởng: 1 prompt, 3 báo cáo, 3 góc nhìn Chúng tôi xác định ba góc nhìn mà mỗi báo cáo tuần cần có — và thiết kế skill chạy cả ba cùng lúc từ một prompt duy nhất. Domain A Infrastructure CloudWatch alarm + metric Nguồn: AWS CloudWatch API Domain B Security CVE / dependency vulnerability Nguồn: Trivy lockfile scan Domain C Lifecycle Version / EOL của OS, runtime, DB Nguồn: endoflife.date + curated dataset 1 prompt → 3 domain song song → 3 file Excel. Domain nào fail chỉ skip, không abort cả báo cáo. Chương 4 Bên trong skill hoạt động như thế nào Mỗi domain đi qua 3 bước: script thu thập fact, AI giải thích ý nghĩa, script render Excel. Collect số liệu → Assess theo evaluation rules → Generate Excel template chuẩn 1 Collect AWS API / Trivy / endoflife.date → JSON 2 Assess AI viết assessment tiếng Anh từ data đã có 3 Generate Render JSON + assessment ra Excel Phân công rõ ràng: script thu thập data — AI không gọi CloudWatch, không chạy Trivy, không bịa số liệu hay ngày EOL. AI chỉ viết assessment từ JSON. Nguyên tắc AI tuân theo Không bịa số liệu — chỉ viết từ data đã collect So sánh tuần trước — đọc báo cáo kỳ trước (nếu có) để phát hiện trend và persistent issue Escalate — issue ≥ 2 tuần liên tiếp thì dùng ngôn ngữ mạnh hơn Config-driven — áp dụng cho mọi dự án Toàn bộ skill đọc từ một file monitoring.config.yaml trong project root: AWS profile/region, alarm names, metric names, security targets, lifecycle components. Thêm dự án mới = thêm config, không sửa skill. # monitoring.config.yaml — khai báo một lần project: client_name: "Project" environment: "production" alarms: [...] # Domain A metrics: [...] # Domain A security: # Domain B (tùy chọn) enabled: true targets: [...] lifecycle: # Domain C (tùy chọn) enabled: true components: [...] Chương 5 Những gì báo cáo thực sự phát hiện Dưới đây là những vấn đề thực tế skill phát hiện trong quá trình chạy trên các dự án. Deliverable mỗi tuần: Excel theo template chuẩn, có status và assessment từng dòng Domain A — Infrastructure High · Trend Alarm thoáng qua nhưng lặp lại — không ai nhận ra pattern API Error alarm trigger 4 lần trong tuần, metric Max = 0 (đã recover trong 1-hour window). Tuần trước: 2 lần. Trend tăng → assessment escalate, khuyến nghị điều tra logs tại timestamp alarm. Nếu không có báo cáo trend: tuần nào cũng ghi "OK, đã recover" mà không ai nhận ra pattern lặp lại nhiều tuần. Critical · Monitoring gap Metric null suốt tuần — dashboard vẫn xanh ECS service không gửi metric cả tuần (Max/Avg/Min = null). CloudWatch agent stop sau deploy. Dashboard không alarm vì no data ≠ no alarm. Domain B — Security High · Persistent Package HIGH tồn tại 3 tuần — không có áp lực fix Lodash 4.17.15, CVE HIGH, đã có fix. Tuần 1: new → Tuần 2: persistent → Tuần 3: "unpatched 3 weeks; escalate if not resolved". Không so sánh tuần trước: cứ báo "new" mãi. Domain C — Lifecycle Critical · Past EOL RDS PostgreSQL 13.x đã EOL — không ai biết PostgreSQL 13.x reached EOL 2026-02-28. Không có ai khai báo track → không ai biết → không có plan upgrade. Sau khi thêm vào lifecycle.components: phát hiện ngay tuần đầu, action plan được lên. Critical · Past EOL Amazon Linux 2 trên bastion đã EOL hơn 1 tháng Amazon Linux 2 reached EOL 2026-06-30 — bastion hosts vẫn chạy AL2 hơn 1 tháng sau ngày hết hỗ trợ. Không còn security patch từ AWS sau EOL → bề mặt tấn công tăng, không còn trong phạm vi hỗ trợ chuẩn. Assessment: Critical — schedule upgrade sang Amazon Linux 2023; không chờ forced upgrade. Những vấn đề này không phải sự cố bất ngờ — chúng là blind spot tích lũy vì quy trình thủ công thiếu góc nhìn và thiếu trend. Skill làm đúng việc đó, mỗi tuần. Chương 6 Cách sử dụng trong thực tế Setup một lần: tạo monitoring.config.yaml trong project root. Mỗi tuần, nhắn: Làm báo cáo monitoring tuần, 2026-08-11 đến 2026-08-17. AI hỏi kỳ nếu thiếu — rồi chạy hết domain đang bật, báo đường dẫn Excel khi xong Trước — thủ công 2–3 giờ Copy số, viết assessment, format Excel Sau — với skill 5–10 phút 1 prompt → 3 file Excel — review và gửi khách Các biến thể hay dùng Tình huống Prompt Chỉ CloudWatch "Chỉ làm monitoring tuần này" Chỉ CVE "Chỉ làm security/CVE tuần này" Chỉ lifecycle "Chỉ làm lifecycle/version tuần này" Regen Excel "Dùng data có sẵn, chỉ regen Excel monitoring" Chương 7 Những điều cần lưu ý khi bắt đầu Skill mạnh khi config đúng. Cần AWS quyền CloudWatch, lockfile trong repo (Domain B), và khai báo version đủ minor (vd: 13.15 thay vì 13). AWS credentials có quyền CloudWatch:GetMetricStatistics, CloudWatch:DescribeAlarmHistory Khai báo lifecycle.components đúng minor version (vd: 13.15 thay vì chỉ 13) để tra EOL chính xác Lockfile có trong repo để Domain B chạy được (hoặc Docker để chạy Trivy container) Giới hạn của skill AI không tự biết component nào đang chạy trên infra — user phải khai báo trong config Domain B chỉ scan lockfile — không scan running containers EOL date lấy từ endoflife.date: nếu product chưa có trong dataset thì status: Unknown Chất lượng báo cáo tỉ lệ thuận với chất lượng config. Khai báo đúng và đủ → báo cáo chính xác và hữu ích. Thiếu component trong lifecycle config → blind spot vẫn còn đó. Bắt đầu ngay Workspace weekly-monitor-skills — đã có trên ☞ Kari Bước 1 Tạo monitoring.config.yaml trong project root Bước 2 Nhắn AI: "Làm báo cáo monitoring tuần, [start] đến [end]" Bước 3 Nhận 3 file Excel — review và gửi khách Prompt mặc định chạy full tất cả domain đang bật — không cần chỉ định thêm (function () { const links = document.querySelectorAll('.toc-list a'); const sections = Array.from(links).map(a => document.querySelector(a.getAttribute('href'))); function setActive(index) { links.forEach((a, i) => a.classList.toggle('active', i === index)); } function onScroll() { const scrollY = window.scrollY + 120; let active = 0; sections.forEach((sec, i) => { if (sec && sec.offsetTop <= scrollY) active = i; }); setActive(active); } window.addEventListener('scroll', onScroll, { passive: true }); onScroll(); links.forEach(a => { a.addEventListener('click', function (e) { e.preventDefault(); const target = document.querySelector(this.getAttribute('href')); if (target) target.scrollIntoView({ behavior: 'smooth', block: 'start' }); }); }); })();