← Vibe coding với Next.js

Bài 15 · Nâng cao · 26 phút

Metrics, audit log & báo cáo

Biên soạn bởi Nguyễn Anh Tuấn

Audit log mọi action admin & auth event; metrics báo cáo toàn diện: sức khoẻ hệ thống, rủi ro user/business/hàng, tiền vào ra (đối soát SePay) và cảnh báo khi vượt ngưỡng.

Sản phẩm đã chạy: khách đăng nhập, nạp tiền, mua hàng; admin quản lý. Nhưng nếu không đo và ghi lại, mèo con mù: hệ thống đang khoẻ hay đang chảy máu tiền, có ai đang dò tài khoản, kho có đang âm không - đều không biết cho tới khi khách kêu.

Khả năng nhìn vào trong hệ thống gọi là observability, dựng từ hai thứ: log (ghi từng sự kiện) và metrics (số đo gom lại), rồi từ đó ra báo cáocảnh báo.

Tầng nền là audit log - nhật ký nghiệp vụ ghi "ai làm gì, trên cái gì, khi nào, từ đâu". Ghi cho mọi action admin (đổi giá, khoá tài khoản, cộng/trừ số dư) và mọi auth event (đăng nhập, thất bại, đổi mật khẩu, bật/tắt 2FA). Đây là bằng chứng khi có sự cố hay tranh chấp:

📝 Action admin/ Auth eventAudit logappend-only📊 MetricsBáo cáo+ cảnh báo
Mọi action admin và auth event được ghi vào audit log (append-only), gom thành metrics, rồi dựng báo cáo và cảnh báo.
  • Append-only: log chỉ thêm, KHÔNG sửa/xoá - mới là bằng chứng tin được.
  • Ghi đủ: ai (user id), hành động, đối tượng, thời gian, IP/thiết bị, kết quả.
  • TUYỆT ĐỐI không ghi mật khẩu, mã 2FA/OTP, số thẻ, token - che (mask) hoặc bỏ.

Tới lượt mèo con (build). Bật plan mode, đưa mô tả, duyệt rồi cho dựng:

gõ trong ô Claude Code (sau khi bật plan mode)

Tạo bảng audit_log (user_id, hành động, đối tượng, thời gian, IP, kết quả),
append-only. Ghi MỘT dòng cho mọi action admin (đổi giá, khoá tài khoản,
cộng/trừ số dư) và mọi auth event (đăng nhập, login_failed, đăng xuất,
đổi mật khẩu, bật/tắt 2FA). KHÔNG ghi mật khẩu/mã 2FA/số thẻ vào log.

Bạn đã xong bước này khi

Làm một action admin bất kỳ → xuất hiện đúng một dòng audit log đủ ai/gì/khi nào/IP. Đăng nhập sai vài lần → có các dòng login_failed; bật 2FA → có dòng 2fa_enabled.

Từ log và metrics, dựng báo cáo theo bốn nhóm để nhìn bao quát sức khoẻ và rủi ro của cả sản phẩm:

🩺 Sức khoẻ hệ thốnguptime · lỗi · độ trễ · hàng đợi👤 Rủi ro userđăng nhập fail · nạp/rút bất thường📦 Rủi ro hàng & businessâm kho · hoàn tiền cao · đơn lỗi💰 Tiền vào / ranạp · mua/rút · đối soát SePay
Bốn nhóm báo cáo: sức khoẻ hệ thống, rủi ro user, rủi ro hàng & business, và tiền vào/ra (kèm đối soát SePay).
  • 🩺 Sức khoẻ hệ thống: uptime, tỉ lệ lỗi, độ trễ, hàng đợi BullMQ tồn, webhook lỗi.
  • 👤 Rủi ro user: đăng nhập thất bại dồn dập, nhiều thiết bị lạ, nạp/rút bất thường.
  • 📦 Rủi ro hàng & business: kho âm/sắp hết, đơn lỗi, tỉ lệ hoàn tiền cao.
  • 💰 Tiền vào/ra: tổng nạp, tổng mua/rút, số dư hệ thống - và đối soát với SePay.

Tới lượt mèo con

Nhờ Claude dựng trang báo cáo gồm: metrics sức khoẻ hệ thống (hàng đợi BullMQ tồn, tỉ lệ webhook lỗi) và một bảng rủi ro user - liệt kê tài khoản đăng nhập thất bại nhiều, hoặc nạp/rút bất thường (mới tạo đã rút lớn). Xong khi có một danh sách "top rủi ro" kèm lý do cho từng tài khoản.

Phần nhạy nhất là tiền. Báo cáo phải trả lời gọn: hôm nay vào bao nhiêu (nạp), ra bao nhiêu (mua/rút), số dư toàn hệ thống là bao nhiêu. Và quan trọng: đối soát (reconciliation) - tổng tiền đã cộng vào ví khách phải khớp tổng giao dịch SePay báo về.

Đối soát - mã giả minh hoạ (Claude viết bằng code Next.js)

tong_da_cong = SUM(giao_dich.so_tien WHERE loai='nap' AND trang_thai='hoan_tat')
tong_sepay   = SUM(sepay.so_tien WHERE da_xac_nhan)
if tong_da_cong != tong_sepay:
    canh_bao("Lệch tiền nạp", tong_da_cong - tong_sepay)  # tìm ngay

Trung thực

Lệch một đồng cũng phải tìm ra: lệch nghĩa là cộng trùng/thiếu (bug idempotency) hoặc có gian lận. Đối soát đều đặn là cách phát hiện sớm trước khi mất nhiều.

Tới lượt mèo con

Nhờ Claude dựng báo cáo tổng nạptổng mua/rút theo ngày, kèm phần đối soát tổng đã cộng số dư với tổng giao dịch SePay. Xong khi thấy được tiền vào/ra theo ngày, và khi cố tình tạo một giao dịch lệch thì báo cáo đối soát chỉ ra chênh.

Báo cáo đẹp nhưng không ai ngồi xem 24/7. Với vài metrics quan trọng, đặt ngưỡng cảnh báo để hệ thống tự báo khi có bất thường - xử lý kịp thay vì đợi khách kêu.

  • Ví dụ ngưỡng: webhook lỗi > 5% trong 10 phút; một tài khoản rút > X trong 1 giờ; kho âm.
  • Vượt ngưỡng thì báo qua email/Zalo/Slack, kèm đường dẫn tới chi tiết.
  • Đừng đặt quá nhiều cảnh báo vụn - nhiễu thì người ta bỏ qua cả cái quan trọng.

Tới lượt mèo con

Đặt một cảnh báo vượt ngưỡng (vd "webhook lỗi tăng vọt trong 10 phút"). Xong khi cố tình làm vượt ngưỡng thì mèo con nhận được một cảnh báo (email hoặc một dòng log nổi bật), không phải ngồi canh báo cáo.

Log là con dao hai lưỡi: ghi đủ để truy vết, nhưng ghi bừa thì thành kho bí mật cho kẻ tấn công. Nguyên tắc: không bao giờ log mật khẩu, mã 2FA, số thẻ, token; che bớt dữ liệu cá nhân; và giữ log không sửa được để còn là bằng chứng.

Tới lượt mèo con

Rà lại audit log và auth log: đảm bảo không chứa mật khẩu, mã 2FA/OTP, số thẻ (đã che hoặc bỏ), rồi gọi subagent bảo mật rà phần log + báo cáo. Xong khi log không lộ dữ liệu nhạy cảm và subagent không còn cảnh báo về log lộ bí mật.

Bước tiếp theo

Cho subagent bảo mật rà phần log (không lộ bí mật) và phần báo cáo (đúng số). Sản phẩm đã có "đôi mắt"; giờ tới trái tim của khoá - tự chủ hạ tầng: Deploy tự chủ trên VPS riêng.

Câu hỏi thường gặp

Log thường (application log) là nhật ký kỹ thuật để gỡ lỗi. Audit log là nhật ký NGHIỆP VỤ ghi "ai làm gì, trên cái gì, khi nào, từ đâu (IP)" - nhất là các action admin và auth event. Nó là bằng chứng truy vết khi có sự cố hay tranh chấp, nên phải append-only (chỉ thêm, không sửa/xoá).

Ghi: ai (user id), hành động (đổi giá, khoá tài khoản, cộng số dư), đối tượng, thời gian, IP/thiết bị, kết quả. KHÔNG ghi: mật khẩu, mã 2FA/OTP, số thẻ, token - log lộ thì thành kho bí mật cho kẻ tấn công. Dữ liệu nhạy cảm thì che (mask) hoặc bỏ.

Log là từng dòng sự kiện riêng lẻ. Metrics là SỐ ĐO gom lại theo thời gian: số đăng nhập thất bại/giờ, tổng tiền nạp/ngày, số đơn lỗi, hàng đợi tồn bao nhiêu. Báo cáo và biểu đồ dựng từ metrics; log để soi chi tiết khi cần truy ngược.

Là so số liệu của mình với số liệu nguồn ngoài để chắc không lệch. Vd: tổng tiền đã cộng vào ví khách phải khớp với tổng giao dịch SePay báo về. Lệch là dấu hiệu bug (cộng trùng/thiếu) hay gian lận - phải tìm ra ngay vì đây là tiền.

Thay vì ngồi canh báo cáo, mèo con đặt ngưỡng cho vài metrics quan trọng - vd "webhook lỗi > 5% trong 10 phút", "một tài khoản rút > X trong 1 giờ", "kho âm". Vượt ngưỡng thì hệ thống tự báo (email/Zalo/Slack) để xử lý kịp, không đợi tới lúc khách kêu.