chore: update project documentation, audit reports, and initialize IDE configuration files
Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 29s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 2m42s
Deploy / Build Web Image (push) Failing after 27s
Deploy / Build AI Services Image (push) Failing after 29s
E2E Tests / Playwright E2E (push) Failing after 43s
Deploy / Build API Image (push) Failing after 1m31s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 6s
Security Scanning / Trivy Scan — API Image (push) Failing after 5m35s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 3m45s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Deploy / Rollback Staging (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
Security Scanning / Trivy Scan — Web Image (push) Failing after 13m51s
Security Scanning / Trivy Filesystem Scan (push) Failing after 14m46s
Security Scanning / Security Gate (push) Has been cancelled

This commit is contained in:
Ho Ngoc Hai
2026-04-19 03:12:54 +07:00
parent 3be106074d
commit 11f2bf26e6
101 changed files with 21312 additions and 20672 deletions

View File

@@ -1,21 +1,21 @@
# CQRS Handler Error Handling Guide
## GoodGo Platform Implementation Standards
# Hướng Dẫn Xử Lý Lỗi cho CQRS Handler
## Tiêu Chuẩn Triển Khai của Nền Tảng GoodGo
---
## 📌 Quick Reference
## 📌 Tham Chiếu Nhanh
| Status | Count | Modules |
| Trạng thái | Số lượng | Modules |
|--------|-------|---------|
| ✓ Has Error Handling | 11 | auth (5), listings (2), admin, notifications, payments, search |
| ✗ Needs Error Handling | 66 | All other handlers + 6 auth handlers |
| **Total** | **77** | **All modules** |
| ✓ Đã có Xử Lý Lỗi | 11 | auth (5), listings (2), admin, notifications, payments, search |
| ✗ Cần Xử Lý Lỗi | 66 | Tất cả các handler còn lại + 6 auth handler |
| **Tổng cộng** | **77** | **Tất cả các module** |
---
## 🎯 Pattern 1: Standard Command Handler with Error Handling
## 🎯 Pattern 1: Command Handler Chuẩn với Xử Lý Lỗi
Use this pattern for **most command handlers**:
Sử dụng pattern này cho **hầu hết các command handler**:
```typescript
import { Logger } from '@nestjs/common';
@@ -33,19 +33,19 @@ export class YourCommandHandler implements ICommandHandler<YourCommand> {
async execute(command: YourCommand): Promise<YourResult> {
try {
// Load aggregate
// Tải aggregate
const aggregate = await this.repository.findById(command.id);
if (!aggregate) {
throw new NotFoundException('Aggregate', command.id);
}
// Execute domain logic
// Thực thi logic domain
aggregate.doSomething(command.data);
// Save state
// Lưu trạng thái
await this.repository.save(aggregate);
// Publish events
// Phát hành sự kiện
const events = aggregate.clearDomainEvents();
for (const event of events) {
this.eventBus.publish(event);
@@ -53,17 +53,17 @@ export class YourCommandHandler implements ICommandHandler<YourCommand> {
return { id: aggregate.id, status: 'success' };
} catch (error) {
// Always re-throw domain exceptions
// Luôn ném lại các domain exception
if (error instanceof DomainException) throw error;
// Log unexpected errors
// Ghi log các lỗi không mong đợi
this.logger.error(
`Command execution failed: ${error instanceof Error ? error.message : String(error)}`,
error instanceof Error ? error.stack : undefined,
this.constructor.name,
);
// Throw generic HTTP exception
// Ném exception HTTP chung
throw new InternalServerErrorException('Operation failed, please try again');
}
}
@@ -72,9 +72,9 @@ export class YourCommandHandler implements ICommandHandler<YourCommand> {
---
## 🎯 Pattern 2: Standard Query Handler with Error Handling
## 🎯 Pattern 2: Query Handler Chuẩn với Xử Lý Lỗi
Use this pattern for **all query handlers**:
Sử dụng pattern này cho **tất cả các query handler**:
```typescript
import { Logger } from '@nestjs/common';
@@ -108,9 +108,9 @@ export class YourQueryHandler implements IQueryHandler<YourQuery> {
---
## 🎯 Pattern 3: Bulk Operation with Per-Item Error Handling
## 🎯 Pattern 3: Thao Tác Hàng Loạt với Xử Lý Lỗi Theo Từng Mục
Use this pattern for **batch operations** (like `bulk-moderate-listings`):
Sử dụng pattern này cho **các thao tác batch** (như `bulk-moderate-listings`):
```typescript
@CommandHandler(BulkCommand)
@@ -130,7 +130,7 @@ export class BulkCommandHandler implements ICommandHandler<BulkCommand> {
continue;
}
// Process item
// Xử lý từng mục
item.update(command.data);
await this.repository.save(item);
@@ -138,7 +138,7 @@ export class BulkCommandHandler implements ICommandHandler<BulkCommand> {
} catch (itemError) {
const message = itemError instanceof Error ? itemError.message : 'Unknown error';
failed.push({ id, reason: message });
// Continue processing other items
// Tiếp tục xử lý các mục khác
}
}
@@ -157,18 +157,18 @@ export class BulkCommandHandler implements ICommandHandler<BulkCommand> {
---
## 🎯 Pattern 4: Graceful Degradation (Non-Critical Services)
## 🎯 Pattern 4: Giảm Cấp Duyên Dáng (Dịch Vụ Không Quan Trọng)
Use this pattern when **secondary services can fail without blocking** the main operation (like duplicate detection in `create-listing`):
Sử dụng pattern này khi **các dịch vụ thứ cấp có thể thất bại mà không chặn** thao tác chính (như phát hiện trùng lặp trong `create-listing`):
```typescript
async execute(command: CreateListingCommand): Promise<CreateListingResult> {
try {
// Critical path - must succeed
// Luồng quan trọng - phải thành công
const listing = await this.createListing(command);
await this.repository.save(listing);
// Non-critical: Duplicate detection
// Không quan trọng: Phát hiện trùng lặp
let duplicates = [];
try {
duplicates = await this.duplicateDetector.find({
@@ -180,10 +180,10 @@ async execute(command: CreateListingCommand): Promise<CreateListingResult> {
'Duplicate detection failed, continuing without warnings',
'CreateListingHandler'
);
// Continue - duplicates are optional
// Tiếp tục - danh sách trùng lặp là tùy chọn
}
// Non-critical: Price validation
// Không quan trọng: Xác thực giá
let priceWarning: PriceWarning | undefined;
try {
const result = await this.priceValidator.validate(command);
@@ -195,7 +195,7 @@ async execute(command: CreateListingCommand): Promise<CreateListingResult> {
'Price validation failed, continuing without warning',
'CreateListingHandler'
);
// Continue - price warning is optional
// Tiếp tục - cảnh báo giá là tùy chọn
}
return {
@@ -217,9 +217,9 @@ async execute(command: CreateListingCommand): Promise<CreateListingResult> {
---
## 🎯 Pattern 5: Authorization/Authentication Errors
## 🎯 Pattern 5: Lỗi Phân Quyền/Xác Thực
Use this pattern when **authentication can fail** (like `login-user`):
Sử dụng pattern này khi **xác thực có thể thất bại** (như `login-user`):
```typescript
@CommandHandler(LoginUserCommand)
@@ -241,7 +241,7 @@ export class LoginUserHandler implements ICommandHandler<LoginUserCommand> {
error instanceof Error ? error.stack : undefined,
'LoginUserHandler'
);
// Use specific exception for authentication
// Sử dụng exception cụ thể cho xác thực
throw new UnauthorizedException('Unable to create session, please try again');
}
}
@@ -250,21 +250,21 @@ export class LoginUserHandler implements ICommandHandler<LoginUserCommand> {
---
## ❌ Common Mistakes to Avoid
## ❌ Những Lỗi Phổ Biến Cần Tránh
### ❌ Mistake 1: Silent Catch Block
### ❌ Lỗi 1: Khối Catch Im Lặng
```typescript
// BAD
// XẤU
try {
await this.repository.save(entity);
} catch (error) {
// Silent - no logging, no error thrown
// Im lặng - không ghi log, không ném lỗi
}
```
**Fix:**
**Cách sửa:**
```typescript
// GOOD
// TỐT
try {
await this.repository.save(entity);
} catch (error) {
@@ -275,9 +275,9 @@ try {
---
### ❌ Mistake 2: Swallowing Domain Exceptions
### ❌ Lỗi 2: Nuốt Domain Exception
```typescript
// BAD
// XẤU
try {
const result = entity.validate();
if (result.isErr) {
@@ -285,14 +285,14 @@ try {
}
// ...
} catch (error) {
// This swallows the validation error
// Điều này nuốt mất lỗi validation
throw new InternalServerErrorException('Failed');
}
```
**Fix:**
**Cách sửa:**
```typescript
// GOOD
// TỐT
try {
const result = entity.validate();
if (result.isErr) {
@@ -300,7 +300,7 @@ try {
}
// ...
} catch (error) {
// Re-throw domain exceptions
// Ném lại các domain exception
if (error instanceof DomainException) throw error;
this.logger.error(`Unexpected: ${error}`, error?.stack);
@@ -310,20 +310,20 @@ try {
---
### ❌ Mistake 3: Logging to Console
### ❌ Lỗi 3: Ghi Log ra Console
```typescript
// BAD
// XẤU
try {
// ...
} catch (error) {
console.error(error); // Not structured, not captured by logging system
console.error(error); // Không có cấu trúc, không được hệ thống logging ghi nhận
throw error;
}
```
**Fix:**
**Cách sửa:**
```typescript
// GOOD
// TỐT
try {
// ...
} catch (error) {
@@ -338,20 +338,20 @@ try {
---
### ❌ Mistake 4: Partial Logging
### ❌ Lỗi 4: Ghi Log Không Đầy Đủ
```typescript
// BAD
// XẤU
try {
// ...
} catch (error) {
this.logger.error(error.message); // Missing stack trace!
this.logger.error(error.message); // Thiếu stack trace!
throw error;
}
```
**Fix:**
**Cách sửa:**
```typescript
// GOOD
// TỐT
try {
// ...
} catch (error) {
@@ -366,78 +366,78 @@ try {
---
### ❌ Mistake 5: Publishing Events Before Confirming Success
### ❌ Lỗi 5: Phát Hành Sự Kiện Trước Khi Xác Nhận Thành Công
```typescript
// BAD
// XẤU
try {
aggregate.apply(command);
this.eventBus.publish(aggregate.events); // Before save!
this.eventBus.publish(aggregate.events); // Trước khi lưu!
await this.repository.save(aggregate);
} catch (error) {
// Event published but entity not saved!
// Sự kiện đã được phát hành nhưng entity chưa được lưu!
}
```
**Fix:**
**Cách sửa:**
```typescript
// GOOD
// TỐT
try {
aggregate.apply(command);
await this.repository.save(aggregate); // Save first
await this.repository.save(aggregate); // Lưu trước
// Publish events only after successful save
// Chỉ phát hành sự kiện sau khi lưu thành công
const events = aggregate.clearDomainEvents();
for (const event of events) {
this.eventBus.publish(event);
}
} catch (error) {
// No events published - data is consistent
// Không có sự kiện nào được phát hành - dữ liệu nhất quán
}
```
---
## 🔍 Audit Checklist for Each Handler
## 🔍 Danh Sách Kiểm Tra Khi Kiểm Tra Từng Handler
When reviewing error handling, verify:
Khi xem xét xử lý lỗi, hãy kiểm tra:
- [ ] **Try-Catch Block**: Wraps entire execute method logic
- [ ] **Domain Exception Re-throw**: `if (error instanceof DomainException) throw error;`
- [ ] **Error Logging**: Includes message, stack trace, and context
- [ ] **Logger Usage**: Uses injected logger, not console
- [ ] **Appropriate Exception**: Throws correct HTTP exception type
- [ ] **No Silent Catches**: Every catch block has logging or throw
- [ ] **Event Publishing**: Only after successful state persistence
- [ ] **Transaction Rollback**: Handled by try-catch (implicit or explicit)
- [ ] **User Message**: Meaningful error response (not technical details)
- [ ] **Logging Context**: Includes handler class name
- [ ] **Khối Try-Catch**: Bao bọc toàn bộ logic của phương thức execute
- [ ] **Ném Lại Domain Exception**: `if (error instanceof DomainException) throw error;`
- [ ] **Ghi Log Lỗi**: Bao gồm thông báo, stack trace và ngữ cảnh
- [ ] **Sử Dụng Logger**: Dùng logger được inject, không dùng console
- [ ] **Exception Phù Hợp**: Ném đúng loại HTTP exception
- [ ] **Không Có Catch Im Lặng**: Mỗi khối catch đều có ghi log hoặc ném lỗi
- [ ] **Phát Hành Sự Kiện**: Chỉ sau khi lưu trạng thái thành công
- [ ] **Rollback Transaction**: Được xử lý bởi try-catch (ngầm định hoặc tường minh)
- [ ] **Thông Báo Cho Người Dùng**: Phản hồi lỗi có ý nghĩa (không phải chi tiết kỹ thuật)
- [ ] **Ngữ Cảnh Logging**: Bao gồm tên lớp handler
---
## 📋 Implementation Checklist for Handlers Needing Error Handling
## 📋 Danh Sách Triển Khai cho Các Handler Cần Xử Lý Lỗi
1. **Review existing pattern** in well-implemented handlers:
- `auth/commands/login-user` (auth patterns)
- `listings/commands/create-listing` (graceful degradation)
- `admin/commands/bulk-moderate-listings` (batch operations)
1. **Xem lại pattern hiện có** trong các handler được triển khai tốt:
- `auth/commands/login-user` (các pattern xác thực)
- `listings/commands/create-listing` (giảm cấp duyên dáng)
- `admin/commands/bulk-moderate-listings` (các thao tác batch)
2. **Add to execute method**:
2. **Thêm vào phương thức execute**:
```typescript
async execute(command: YourCommand): Promise<YourResult> {
try {
// existing logic
// logic hiện có
} catch (error) {
// error handling
// xử lý lỗi
}
}
```
3. **Check if domain exception should be re-thrown**:
3. **Kiểm tra xem domain exception có nên được ném lại không**:
```typescript
if (error instanceof DomainException) throw error;
```
4. **Add appropriate logging**:
4. **Thêm ghi log phù hợp**:
```typescript
this.logger.error(
`Message: ${error instanceof Error ? error.message : String(error)}`,
@@ -446,100 +446,100 @@ When reviewing error handling, verify:
);
```
5. **Throw appropriate HTTP exception**:
5. **Ném HTTP exception phù hợp**:
```typescript
throw new InternalServerErrorException();
// or
// hoặc
throw new NotFoundException();
// or
// hoặc
throw new BadRequestException();
```
6. **Test error scenarios**:
- Repository returns null/error
- Domain validation fails
- Database save fails
- Event publishing fails
6. **Kiểm thử các tình huống lỗi**:
- Repository trả về null hoặc lỗi
- Xác thực domain thất bại
- Lưu cơ sở dữ liệu thất bại
- Phát hành sự kiện thất bại
---
## 🚀 Priority Implementation Order
## 🚀 Thứ Tự Ưu Tiên Triển Khai
### TIER 1 - Do First (33 handlers)
- **admin**: 14 handlers
- **leads**: 5 handlers
- **inquiries**: 4 handlers
- **reviews**: 5 handlers
- **subscriptions**: 5 handlers
### BẬC 1 - Làm Trước (33 handler)
- **admin**: 14 handler
- **leads**: 5 handler
- **inquiries**: 4 handler
- **reviews**: 5 handler
- **subscriptions**: 5 handler
**Effort**: ~2 developer-days
**Công sức**: ~2 ngày-lập trình viên
### TIER 2 - Do Second (18 handlers)
- **payments**: 4 handlers
- **search**: 8 handlers
- **listings**: 5 handlers (2 already done)
- **agents**: 3 handlers
### BẬC 2 - Làm Tiếp (18 handler)
- **payments**: 4 handler
- **search**: 8 handler
- **listings**: 5 handler (đã hoàn thành 2)
- **agents**: 3 handler
**Effort**: ~1 developer-day
**Công sức**: ~1 ngày-lập trình viên
### TIER 3 - Do Last (8 handlers)
- **analytics**: 8 handlers
- **auth**: 6 handlers (5 already done)
### BẬC 3 - Làm Cuối (8 handler)
- **analytics**: 8 handler
- **auth**: 6 handler (đã hoàn thành 5)
**Effort**: ~1 developer-day
**Công sức**: ~1 ngày-lập trình viên
---
## 📞 FAQ
## 📞 Câu Hỏi Thường Gặp
**Q: Should every handler have error handling?**
A: Yes. Every async operation can fail - databases go down, networks fail, etc.
**H: Mỗi handler có cần xử lý lỗi không?**
Đ: Có. Mọi thao tác bất đồng bộ đều có thể thất bại — cơ sở dữ liệu có thể ngừng hoạt động, mạng có thể lỗi, v.v.
**Q: Should I catch and swallow domain exceptions?**
A: No. Re-throw them using `if (error instanceof DomainException) throw error;`
**H: Tôi có nên bắt và nuốt domain exception không?**
Đ: Không. Hãy ném lại chúng bằng `if (error instanceof DomainException) throw error;`
**Q: What if the handler has no database calls?**
A: Still add error handling. External service calls, calculations, and I/O all need try-catch.
**H: Nếu handler không có lời gọi cơ sở dữ liệu thì sao?**
Đ: Vẫn thêm xử lý lỗi. Các lời gọi dịch vụ bên ngoài, phép tính và I/O đều cần try-catch.
**Q: Can I use generic Exception handling?**
A: No. Import and use NestJS exceptions like `InternalServerErrorException`, `NotFoundException`, etc.
**H: Tôi có thể dùng xử lý Exception chung không?**
Đ: Không. Hãy import và sử dụng các exception của NestJS như `InternalServerErrorException`, `NotFoundException`, v.v.
**Q: Should I log to console?**
A: No. Inject and use the NestJS Logger service for structured logging.
**H: Tôi có nên ghi log ra console không?**
Đ: Không. Hãy inject và sử dụng dịch vụ NestJS Logger để ghi log có cấu trúc.
**Q: What about promise rejection handling?**
A: Async/await with try-catch handles all promise rejections. That's why we wrap the entire execute method.
**H: Còn việc xử lý promise rejection thì sao?**
Đ: Async/await kết hợp với try-catch xử lý tất cả các promise rejection. Đó là lý do tại sao chúng ta bao bọc toàn bộ phương thức execute.
---
## 🎓 Reference: Exemplary Handlers
## 🎓 Tham Khảo: Các Handler Mẫu
### 1. **Login User Handler** (Excellent)
Location: `apps/api/src/modules/auth/application/commands/login-user/login-user.handler.ts`
### 1. **Login User Handler** (Xuất sắc)
Vị trí: `apps/api/src/modules/auth/application/commands/login-user/login-user.handler.ts`
Clear error message for user
Proper exception type (UnauthorizedException)
✓ Stack trace logged
Handler context included
Thông báo lỗi rõ ràng cho người dùng
Loại exception phù hợp (UnauthorizedException)
✓ Stack trace được ghi log
Ngữ cảnh handler được bao gồm
### 2. **Create Listing Handler** (Advanced)
Location: `apps/api/src/modules/listings/application/commands/create-listing/create-listing.handler.ts`
### 2. **Create Listing Handler** (Nâng cao)
Vị trí: `apps/api/src/modules/listings/application/commands/create-listing/create-listing.handler.ts`
Critical path is protected
Non-critical services can degrade gracefully
Continues operation even if secondary services fail
Warnings still provided when possible
Luồng quan trọng được bảo vệ
Các dịch vụ không quan trọng có thể giảm cấp duyên dáng
Tiếp tục hoạt động ngay cả khi các dịch vụ thứ cấp thất bại
Cảnh báo vẫn được cung cấp khi có thể
### 3. **Bulk Moderate Handler** (Batch Pattern)
Location: `apps/api/src/modules/admin/application/commands/bulk-moderate-listings/bulk-moderate-listings.handler.ts`
### 3. **Bulk Moderate Handler** (Pattern Batch)
Vị trí: `apps/api/src/modules/admin/application/commands/bulk-moderate-listings/bulk-moderate-listings.handler.ts`
Per-item error collection
Processing continues for other items
Complete result returned with failures
Individual error tracking
Thu thập lỗi theo từng mục
Tiếp tục xử lý các mục khác
Trả về kết quả đầy đủ kèm danh sách thất bại
Theo dõi lỗi từng mục riêng biệt
---
**Last Updated**: April 11, 2026
**Audit Coverage**: 77 handlers across 12 modules
**Compliance**: 14.3% currently implemented
**Cập Nhật Lần Cuối**: 11 tháng 4 năm 2026
**Phạm Vi Kiểm Tra**: 77 handler trên 12 module
**Tuân Thủ**: Hiện tại đã triển khai 14,3%