Tách hai khái niệm: audit log ghi lại hành động nghiệp vụ của con người (khác application log dùng để debug). Audit log phải append-only — chỉ thêm, không sửa không xoá.
Bảng tối thiểu:
CREATE TABLE audit_logs (
id bigserial PRIMARY KEY,
actor_id uuid, -- ai; null nếu là job hệ thống
actor_type text, -- user | admin | system
action text NOT NULL, -- order.update, order.refund
entity_type text NOT NULL,
entity_id text NOT NULL,
changes jsonb, -- { field: { from, to } }
request_id text,
ip inet,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX ON audit_logs (entity_type, entity_id, created_at DESC);Ghi ở đâu: ghi trong cùng transaction với thay đổi dữ liệu, để không có cảnh sửa thành công mà log mất. Nếu muốn không bỏ sót do lập trình viên quên, dùng trigger DB ghi tự động; đổi lại trigger không biết được ai là actor trừ khi truyền qua biến session (SET LOCAL app.actor_id).
Chỉ lưu diff, không snapshot nguyên bản ghi mỗi lần — bảng sẽ tăng rất nhanh. Với thực thể quan trọng thì lưu thêm bản snapshot theo mốc thời gian.
Ba điểm hay bị hỏi thêm:
- Không ghi dữ liệu nhạy cảm vào diff: mật khẩu, token, số thẻ. Che trước khi ghi.
- Phân vùng theo tháng và có chính sách lưu trữ (giữ nóng 6-12 tháng, còn lại đẩy sang lưu trữ lạnh).
- Quyền đọc audit log phải tách riêng, và thao tác xem log cũng nên được ghi lại.