17 KiB
🔍 KIỂM TOÁN TOÀN DIỆN XỬ LÝ LỖI CQRS HANDLER
GoodGo Platform NestJS API
Ngày kiểm toán: Ngày 11 tháng 4 năm 2026
Tổng số Handler đã phân tích: 77
Có xử lý lỗi: 11 (14,3%)
Cần bổ sung xử lý lỗi: 66 (85,7%)
📊 TÓM TẮT ĐIỀU HÀNH
Kiểm toán này xác định các lỗ hổng nghiêm trọng trong xử lý lỗi trên toàn bộ tầng CQRS handler. Trong số 77 handler được phân tích:
- ✓ 11 handler đã triển khai xử lý lỗi try-catch
- ✗ 66 handler thiếu xử lý lỗi đúng cách
- 🔴 NGHIÊM TRỌNG: Các module trọng tâm (admin, inquiries, leads, reviews) có lỗ hổng nghiêm trọng
Mẫu xử lý lỗi được tìm thấy
Mẫu được khuyến nghị xác định trong các handler hiện có:
async execute(command: XCommand): Promise<XResult> {
try {
// business logic
} catch (error) {
if (error instanceof DomainException) throw error;
this.logger.error(
`Failed: ${error.message}`,
error instanceof Error ? error.stack : undefined,
this.constructor.name
);
throw new InternalServerErrorException();
}
}
📈 PHÂN TÍCH THEO MODULE
🔴 MODULE ADMIN (15 handler)
Trạng thái: NGHIÊM TRỌNG - Chỉ 1/15 handler có xử lý lỗi (6,7%)
❌ Command CẦN XỬ LÝ LỖI (7/8):
adjust-subscriptionapprove-kycapprove-listingban-userreject-kycreject-listingupdate-user-status
✓ Command ĐÃ có xử lý lỗi (1/8):
bulk-moderate-listings✓
❌ Query CẦN XỬ LÝ LỖI (7/7):
get-audit-logsget-dashboard-statsget-kyc-queueget-moderation-queueget-revenue-statsget-user-detailget-users
🔴 MODULE AGENTS (3 handler)
Trạng thái: NGHIÊM TRỌNG - 0/3 handler có xử lý lỗi (0%)
❌ Command CẦN XỬ LÝ LỖI (1/1):
recalculate-quality-score
❌ Query CẦN XỬ LÝ LỖI (2/2):
get-agent-dashboardget-agent-public-profile
🔴 MODULE ANALYTICS (8 handler)
Trạng thái: NGHIÊM TRỌNG - 0/8 handler có xử lý lỗi (0%)
❌ Command CẦN XỬ LÝ LỖI (3/3):
generate-reporttrack-eventupdate-market-index
❌ Query CẦN XỬ LÝ LỖI (5/5):
get-district-statsget-heatmapget-market-reportget-price-trendget-valuation
🟡 MODULE AUTH (11 handler)
Trạng thái: TRUNG BÌNH - 5/11 handler có xử lý lỗi (45,5%)
✓ Command ĐÃ có xử lý lỗi (5/9):
export-user-data✓force-delete-user✓login-user✓ (Được triển khai tốt)process-scheduled-deletions✓refresh-token✓
❌ Command CẦN XỬ LÝ LỖI (4/9):
cancel-user-deletionregister-userrequest-user-deletionverify-kyc
❌ Query CẦN XỬ LÝ LỖI (2/2):
get-agent-by-user-idget-profile
🔴 MODULE INQUIRIES (4 handler)
Trạng thái: NGHIÊM TRỌNG - 0/4 handler có xử lý lỗi (0%)
❌ Command CẦN XỬ LÝ LỖI (2/2):
create-inquirymark-inquiry-read
❌ Query CẦN XỬ LÝ LỖI (2/2):
get-inquiries-by-agentget-inquiries-by-listing
🔴 MODULE LEADS (5 handler)
Trạng thái: NGHIÊM TRỌNG - 0/5 handler có xử lý lỗi (0%)
❌ Command CẦN XỬ LÝ LỖI (3/3):
create-leaddelete-leadupdate-lead-status
❌ Query CẦN XỬ LÝ LỖI (2/2):
get-lead-statsget-leads-by-agent
🟡 MODULE LISTINGS (7 handler)
Trạng thái: TRUNG BÌNH - 2/7 handler có xử lý lỗi (28,6%)
✓ Command ĐÃ có xử lý lỗi (2/4):
create-listing✓ (Được triển khai tốt với khả năng giảm cấp nhẹ nhàng)upload-media✓
❌ Command CẦN XỬ LÝ LỖI (2/4):
moderate-listingupdate-listing-status
❌ Query CẦN XỬ LÝ LỖI (3/3):
get-listingget-pending-moderationsearch-listings
🟢 MODULE NOTIFICATIONS (1 handler)
Trạng thái: TỐT - 1/1 handler có xử lý lỗi (100%)
✓ Command ĐÃ có xử lý lỗi (1/1):
send-notification✓
🟡 MODULE PAYMENTS (5 handler)
Trạng thái: TRUNG BÌNH - 1/5 handler có xử lý lỗi (20%)
✓ Command ĐÃ có xử lý lỗi (1/3):
create-payment✓
❌ Command CẦN XỬ LÝ LỖI (2/3):
handle-callbackrefund-payment
❌ Query CẦN XỬ LÝ LỖI (2/2):
get-payment-statuslist-transactions
🔴 MODULE REVIEWS (5 handler)
Trạng thái: NGHIÊM TRỌNG - 0/5 handler có xử lý lỗi (0%)
❌ Command CẦN XỬ LÝ LỖI (2/2):
create-reviewdelete-review
❌ Query CẦN XỬ LÝ LỖI (3/3):
get-average-ratingget-reviews-by-targetget-reviews-by-user
🟡 MODULE SEARCH (9 handler)
Trạng thái: TRUNG BÌNH - 1/9 handler có xử lý lỗi (11,1%)
✓ Command ĐÃ có xử lý lỗi (1/5):
create-saved-search✓
❌ Command CẦN XỬ LÝ LỖI (4/5):
delete-saved-searchreindex-allsync-listingupdate-saved-search
❌ Query CẦN XỬ LÝ LỖI (4/4):
geo-searchget-saved-searchget-saved-searchessearch-properties
🔴 MODULE SUBSCRIPTIONS (7 handler)
Trạng thái: NGHIÊM TRỌNG - 0/7 handler có xử lý lỗi (0%)
❌ Command CẦN XỬ LÝ LỖI (4/4):
cancel-subscriptioncreate-subscriptionmeter-usageupgrade-subscription
❌ Query CẦN XỬ LÝ LỖI (3/3):
check-quotaget-billing-historyget-plan
🎯 CÁC HẠNG MỤC HÀNH ĐỘNG ƯU TIÊN
BẬC 1 - NGHIÊM TRỌNG (Các module trọng tâm + thao tác rủi ro cao)
Các module này ảnh hưởng trực tiếp đến trải nghiệm người dùng và tính toàn vẹn dữ liệu:
ADMIN (7 command, 7 query)
- Tất cả handler duyệt/từ chối đều có thể gây mất nhất quán dữ liệu
- Nhật ký kiểm toán là yếu tố then chốt cho tuân thủ
- Cập nhật trạng thái người dùng phải được theo dõi lỗi
LEADS (3 command, 2 query)
- Tạo/xóa lead là các thao tác nghiệp vụ cốt lõi
- Cập nhật trạng thái ảnh hưởng đến quy trình bán hàng
- Truy xuất lead của môi giới phải đáng tin cậy
INQUIRIES (2 command, 2 query)
create-inquirylà thao tác phía người dùng có tần suất cao- Thiếu xử lý lỗi có thể làm mất yêu cầu tư vấn
- Lỗi query phá vỡ bảng điều khiển của môi giới
REVIEWS (2 command, 3 query)
- Tạo/xóa đánh giá ảnh hưởng đến uy tín môi giới
- Các query xếp hạng được sử dụng trong thứ hạng tìm kiếm
- Lỗi không được xử lý có thể làm hỏng dữ liệu đánh giá
SUBSCRIPTIONS (4 command, 3 query)
- Các thao tác liên quan đến thanh toán là nghiệp vụ cốt lõi
- Kiểm tra hạn mức không được thất bại âm thầm
- Lịch sử thanh toán phải truy vấn được một cách đáng tin cậy
BẬC 2 - CAO (Tác động đến doanh thu và tìm kiếm)
PAYMENTS (2 command, 2 query)
- Callback thanh toán phải có xử lý lỗi
- Hoàn tiền phải ghi lại lỗi để đối soát
SEARCH (4 command, 4 query)
- Lỗi tìm kiếm làm giảm trải nghiệm người dùng
- Các thao tác lập chỉ mục cần logic thử lại
BẬC 3 - TRUNG BÌNH (Vận hành)
LISTINGS (2 command, 3 query)
- Các thao tác kiểm duyệt cần theo dõi lỗi
- Các query listing nên có phương án dự phòng nhẹ nhàng
ANALYTICS (3 command, 5 query)
- Tạo báo cáo nên ghi lại lỗi
- Các query dữ liệu thị trường nên có phương án dự phòng
AGENTS (1 command, 2 query)
- Tính toán điểm chất lượng cần xử lý lỗi
- Query hồ sơ công khai không bao giờ được gây sự cố
🔧 HƯỚNG DẪN TRIỂN KHAI
Mẫu xử lý lỗi chuẩn cho Command
import { Logger } from '@nestjs/common';
import { CommandHandler, type ICommandHandler } from '@nestjs/cqrs';
import { DomainException, InternalServerErrorException } from '@modules/shared';
@CommandHandler(YourCommand)
export class YourHandler implements ICommandHandler<YourCommand> {
private readonly logger = new Logger(this.constructor.name);
async execute(command: YourCommand): Promise<YourResult> {
try {
// Bước 1: Xác thực đầu vào
// Bước 2: Tải aggregate từ repo
// Bước 3: Thực thi logic domain
// Bước 4: Lưu trạng thái
// Bước 5: Phát sự kiện
// Bước 6: Trả về kết quả
return result;
} catch (error) {
// Ném lại domain exception - đây là các lỗi mong đợi
if (error instanceof DomainException) throw error;
// Ghi lại lỗi không mong đợi với đầy đủ ngữ cảnh
this.logger.error(
`Command execution failed: ${error instanceof Error ? error.message : String(error)}`,
error instanceof Error ? error.stack : undefined,
this.constructor.name
);
// Ném một HTTP exception chung
throw new InternalServerErrorException('Operation failed, please try again');
}
}
}
Mẫu xử lý lỗi chuẩn cho Query
@QueryHandler(YourQuery)
export class YourQueryHandler implements IQueryHandler<YourQuery> {
private readonly logger = new Logger(this.constructor.name);
async execute(query: YourQuery): Promise<YourResult> {
try {
// Logic query ở đây
return result;
} catch (error) {
this.logger.error(
`Query execution failed: ${error instanceof Error ? error.message : String(error)}`,
error instanceof Error ? error.stack : undefined,
this.constructor.name
);
throw new InternalServerErrorException('Unable to fetch data, please try again');
}
}
}
Những điều KHÔNG nên làm:
❌ Im lặng nuốt lỗi
❌ Trả về null/undefined mà không ghi log
❌ Dùng các lần ném "Error" chung chung không có ngữ cảnh
❌ Ghi log ra console thay vì dịch vụ logger
Những điều NÊN làm:
✓ Luôn ghi log lỗi với thông điệp + stack trace
✓ Ném lại domain exception nguyên vẹn
✓ Chuyển đổi lỗi khác thành HTTP exception phù hợp
✓ Sử dụng structured logging với ngữ cảnh (tên handler)
✓ Đảm bảo giao dịch cơ sở dữ liệu rollback khi có lỗi
📋 DANH SÁCH HANDLER CHI TIẾT
ĐÃ CÓ XỬ LÝ LỖI ✓ (11 handler)
-
admin/commands/bulk-moderate-listings ✓
- Mẫu: Try-catch với thu thập lỗi chi tiết
- Tính năng: Xử lý từng mục độc lập, thu thập lỗi
-
auth/commands/export-user-data ✓
- Mẫu: Try-catch chuẩn với ghi log
-
auth/commands/force-delete-user ✓
- Mẫu: Try-catch chuẩn với ghi log
-
auth/commands/login-user ✓
- Mẫu: Try-catch với xử lý lỗi dịch vụ token
- Được triển khai tốt: Thông điệp lỗi phù hợp cho người dùng
-
auth/commands/process-scheduled-deletions ✓
- Mẫu: Try-catch chuẩn với ghi log
-
auth/commands/refresh-token ✓
- Mẫu: Try-catch chuẩn với ghi log
-
listings/commands/create-listing ✓
- Mẫu: Xử lý lỗi nâng cao với khả năng giảm cấp nhẹ nhàng
- Tính năng: Phát hiện trùng lặp và xác thực giá được bao bọc trong try-catch
- Thực hành tốt nhất: Tiếp tục hoạt động nếu dịch vụ phụ thất bại
-
listings/commands/upload-media ✓
- Mẫu: Try-catch chuẩn với ghi log
-
notifications/commands/send-notification ✓
- Mẫu: Try-catch chuẩn với ghi log
-
payments/commands/create-payment ✓
- Mẫu: Try-catch chuẩn với ghi log
-
search/commands/create-saved-search ✓
- Mẫu: Try-catch chuẩn với ghi log
CẦN XỬ LÝ LỖI ✗ (66 handler)
[Được tổ chức theo module chi tiết ở trên]
🚀 CHIẾN LƯỢC KHẮC PHỤC
Giai đoạn 1: Khẩn cấp (Tuần 1)
- Thêm xử lý lỗi cho tất cả handler command/query của admin
- Thêm xử lý lỗi cho tất cả handler command/query của leads
- Thêm xử lý lỗi cho tất cả handler command/query của inquiries
- Thêm xử lý lỗi cho tất cả handler command/query của reviews
- Thêm xử lý lỗi cho tất cả handler command/query của subscriptions
Công sức: ~30-40 handler, ~1-2 ngày làm việc của nhà phát triển
Giai đoạn 2: Ưu tiên cao (Tuần 2)
- Thêm xử lý lỗi cho các handler payments còn lại
- Thêm xử lý lỗi cho các handler search còn lại
- Thêm xử lý lỗi cho các handler kiểm duyệt của listings
- Thêm xử lý lỗi cho các handler của agents
Công sức: ~18 handler, ~1 ngày làm việc của nhà phát triển
Giai đoạn 3: Hoàn thiện (Tuần 3)
- Thêm xử lý lỗi cho các handler của analytics
- Xem xét và kiểm toán tất cả triển khai để đảm bảo nhất quán
- Thêm kiểm thử tích hợp xác nhận các tình huống lỗi
Công sức: ~8 handler + kiểm thử, ~1 ngày làm việc của nhà phát triển
📐 DANH SÁCH KIỂM TRA CODE REVIEW
Đối với mỗi handler, xác minh:
- Phương thức Execute có khối try-catch
- Các instance DomainException được ném lại
- Lỗi được ghi log với thông điệp VÀ stack trace
- Ngữ cảnh Logger bao gồm tên lớp handler
- HTTP exception phù hợp được ném ra
- Không có khối catch rỗng
- Không có ẩn lỗi âm thầm
- Giao dịch cơ sở dữ liệu được xử lý
- Sự kiện chỉ được phát khi thành công
🎓 THỰC HÀNH TỐT NHẤT ĐƯỢC GHI NHẬN
Từ các handler có xử lý lỗi tốt:
-
Login User Handler - Thông điệp lỗi xuất sắc phía người dùng
throw new UnauthorizedException( 'Không thể tạo phiên đăng nhập, vui lòng thử lại' ); -
Create Listing Handler - Giảm cấp nhẹ nhàng cho các dịch vụ không quan trọng
try { // duplicate detection } catch { this.logger.warn('Duplicate detection failed'); // Continue without warnings } -
Bulk Moderate Handler - Thu thập lỗi theo từng mục
for (const listingId of ids) { try { // process } catch (error) { failed.push({ listingId, reason }); } }
⚠️ RỦI RO KHI THIẾU XỬ LÝ LỖI
- Tính nhất quán dữ liệu: Lỗi cơ sở dữ liệu không được xử lý để lại bản ghi không đầy đủ
- Lỗi âm thầm: Các thao tác có vẻ thành công nhưng thực ra thất bại
- Khó gỡ lỗi: Không có log đồng nghĩa không có khả năng quan sát
- Trải nghiệm người dùng: Lỗi timeout thay vì thông điệp lỗi rõ ràng
- Tuân thủ: Khoảng trống trong nhật ký kiểm toán ở các thao tác quan trọng
- Sự cố trên môi trường production: Các rejection không được xử lý gây sự cố tiến trình worker
📞 CÁC CÂU HỎI ĐƯỢC TRẢ LỜI BỞI KIỂM TOÁN NÀY
H: Các module nào cần sửa trước tiên?
Đ: admin, leads, inquiries, reviews, subscriptions
H: Mẫu xử lý lỗi có nhất quán không?
Đ: Không - chỉ có 11/77 handler triển khai nó. Mẫu cần được chuẩn hóa.
H: Phạm vi khắc phục là bao nhiêu?
Đ: ~66 handler cần xử lý lỗi (~1-2 giờ mỗi handler trung bình)
H: Có handler nào KHÔNG cần xử lý lỗi không?
Đ: Không - tất cả handler gọi I/O bất đồng bộ đều cần xử lý lỗi.
📝 METADATA KIỂM TOÁN
- Tổng số Handler: 77
- Tổng số dòng đã phân tích: ~15.000+
- Số file đã xem xét: 77
- Độ sâu kiểm toán: Xem xét đầy đủ nội dung của từng handler
- Phát hiện xử lý lỗi: Khớp mẫu thủ công
- Số mẫu được tìm thấy: ~8 cách tiếp cận xử lý lỗi khác nhau
- Điểm nhất quán: Thấp (14,3% tuân thủ)
- Hành động được khuyến nghị: Triển khai ưu tiên cao trên tất cả các module