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
10 KiB
10 KiB
Tài liệu Tham chiếu Nhanh cho Ghi nhật ký Kiểm toán Module Admin
ĐỌC TRƯỚC (tổng cộng 15 phút)
1. Các Controller Chính (Xác định những hành động cần kiểm toán)
-
✅
apps/api/src/modules/admin/presentation/controllers/admin.controller.ts(155 dòng)- Quản lý người dùng: cấm, cập nhật trạng thái, điều chỉnh gói đăng ký
- Tất cả các endpoint đều có decorator @CurrentUser() để ghi lại ID admin
-
✅
apps/api/src/modules/admin/presentation/controllers/admin-moderation.controller.ts(157 dòng)- Duyệt/từ chối tin đăng
- Duyệt/từ chối KYC
- Kiểm duyệt hàng loạt
2. Các Command Handler (Nơi để gắn ghi nhật ký kiểm toán)
Mỗi command phát ra một sự kiện domain. Listener ghi nhật ký kiểm toán nên lắng nghe các sự kiện này.
Luồng Cấm Người Dùng:
- Đầu vào:
apps/api/src/modules/admin/presentation/dto/ban-user.dto.ts - Command:
apps/api/src/modules/admin/application/commands/ban-user/ban-user.command.ts - Handler:
apps/api/src/modules/admin/application/commands/ban-user/ban-user.handler.ts(70 dòng)- Dòng 62:
this.eventBus.publish(new UserBannedEvent(...))
- Dòng 62:
Luồng Duyệt Tin Đăng:
- Đầu vào:
apps/api/src/modules/admin/presentation/dto/approve-listing.dto.ts - Command:
apps/api/src/modules/admin/application/commands/approve-listing/approve-listing.command.ts - Handler:
apps/api/src/modules/admin/application/commands/approve-listing/approve-listing.handler.ts(52 dòng)- Dòng 42-44:
this.eventBus.publish(new ListingApprovedEvent(...))
- Dòng 42-44:
3. Các Sự kiện Domain (Thông tin được phát ra)
apps/api/src/modules/admin/domain/events/
├── user-banned.event.ts
├── user-unbanned.event.ts
├── listing-approved.event.ts
├── listing-rejected.event.ts
├── subscription-adjusted.event.ts
├── kyc-approved.event.ts
└── kyc-rejected.event.ts
Mỗi sự kiện có:
eventName(ví dụ: 'user.banned')occurredAt(dấu thời gian)aggregateId(userId hoặc listingId)adminId(admin đã thực hiện hành động)- Ngữ cảnh bổ sung (lý do, ghi chú, v.v.)
4. Mẫu Event Listener Hiện có (Template)
- ✅
apps/api/src/modules/admin/application/listeners/user-banned.listener.ts(52 dòng)- Minh hoạ decorator @OnEvent()
- Minh hoạ cách truy cập dữ liệu sự kiện
- Minh hoạ các hiệu ứng phụ (vô hiệu hoá tin đăng, gửi thông báo)
- ĐÂY LÀ TEMPLATE CHO AUDIT LOGGING LISTENER CỦA BẠN
5. Logger Service (Nơi ghi log)
- ✅
apps/api/src/modules/shared/infrastructure/logger.service.ts(65 dòng)- Ghi log có cấu trúc dựa trên Pino
- Tự động che giấu thông tin PII
- Các phương thức: log(), error(), warn(), debug(), verbose()
6. Exception Filter (Để ghi log lỗi)
- ✅
apps/api/src/modules/shared/infrastructure/filters/global-exception.filter.ts(145 dòng)- Bắt tất cả các ngoại lệ
- Ghi log kèm correlationId
- Có thể ghi lại các hành động admin thất bại
THAM CHIẾU KIẾN TRÚC
Mẫu Repository
- Giao diện Domain:
apps/api/src/modules/admin/domain/repositories/admin-query.repository.ts - Triển khai Prisma:
apps/api/src/modules/admin/infrastructure/repositories/prisma-admin-query.repository.ts - TUÂN THEO MẪU NÀY cho AuditLog repository
Khởi tạo Module
apps/api/src/modules/admin/admin.module.ts(64 dòng)- Minh hoạ cách đăng ký repository qua DI
- Minh hoạ cách đăng ký listener
- Minh hoạ cách import CQRS module
Cấu hình App Toàn cục
apps/api/src/app.module.ts(100+ dòng)- Minh hoạ đăng ký APP_FILTER, APP_GUARD, APP_INTERCEPTOR
- Minh hoạ cấu hình CqrsModule.forRoot()
- Minh hoạ cấu hình middleware
PRISMA SCHEMA
Các Model Hiện tại (Những gì chúng ta đang kiểm toán)
prisma/schema.prisma(602 dòng tổng cộng)
User Model (dòng 34-71):
- Các trường cần kiểm toán: isActive, kycStatus, role
Listing Model (dòng 227-276):
- Các trường cần kiểm toán: status, moderationScore, moderationNotes
CHƯA CÓ AUDIT MODEL - Cơ hội để tạo từ đầu
CÁC ENDPOINT CẦN KIỂM TOÁN (Từ Controllers)
Hành động của AdminController:
PATCH /admin/users/status- Cập nhật trạng thái hoạt động của người dùngPOST /admin/users/ban- Cấm/bỏ cấm người dùngPOST /admin/subscriptions/adjust- Điều chỉnh gói đăng ký
Hành động của AdminModerationController:
POST /admin/moderation/approve- Duyệt tin đăngPOST /admin/moderation/reject- Từ chối tin đăngPOST /admin/moderation/bulk- Kiểm duyệt hàng loạt tin đăngPOST /admin/kyc/approve- Duyệt KYCPOST /admin/kyc/reject- Từ chối KYC
Mỗi hành động:
- Đã ghi lại ID admin từ JWT
- Đã phát ra sự kiện domain
- Đã có command handler
- Cần: Audit logging listener để lưu vào cơ sở dữ liệu
CÁC PHỤ THUỘC ĐÃ ĐƯỢC IMPORT
Trong AdminModule:
// Đã sẵn sàng:
- CqrsModule (from @nestjs/cqrs)
- AuthModule (auth guards/decorators)
- ListingsModule (for listing operations)
- SubscriptionsModule (for subscription operations)
// Trong providers:
- CommandHandlers (8 tổng cộng)
- QueryHandlers (6 tổng cộng)
- Event Listeners (2 hiện có + cần thêm AuditLoggingListener)
Từ SharedModule:
PrismaService(cơ sở dữ liệu)LoggerService(ghi log)- Các loại ngoại lệ (NotFoundException, ValidationException, v.v.)
DANH SÁCH KIỂM TRA TRIỂN KHAI
Giai đoạn 1: Cơ sở dữ liệu & Repository
- Tạo AuditLog Prisma model trong schema.prisma
- Tạo interface IAuditLogRepository
- Tạo triển khai PrismaAuditLogRepository
- Thêm vào providers của AdminModule
Giai đoạn 2: Events & Listeners
- Tạo AuditEvent domain event (nếu cần làm wrapper)
- Tạo AuditLoggingListener để @OnEvent() cho tất cả các sự kiện admin
- Inject AuditLogRepository vào listener
- Lưu bản ghi kiểm toán khi có sự kiện
Giai đoạn 3: Query & API
- Tạo GetAuditLogsQuery
- Tạo GetAuditLogsHandler
- Tạo phương thức IAuditLogQueryRepository
- Thêm vào QueryHandlers trong module
Giai đoạn 4: Endpoint Controller
- Thêm endpoint GET /admin/audit-logs
- Thêm các DTO lọc (dateRange, adminId, actionType, resourceId)
- Thêm hỗ trợ phân trang
Giai đoạn 5: Kiểm thử
- Unit tests cho AuditLoggingListener
- Integration tests cho việc lưu kiểm toán
- E2E tests cho việc truy xuất nhật ký kiểm toán
CÁC MẪU QUAN TRỌNG CẦN TUÂN THEO
1. Command Pattern (Đã được sử dụng)
// DTO xác thực đầu vào
// Command đóng gói ý định nghiệp vụ
// Handler thực thi + phát sự kiện
// Event kích hoạt hiệu ứng phụ qua listener
2. Cấu trúc Tầng DDD
Presentation (xác thực DTO)
↓
Application (thực thi Command/Query + phát Event)
↓
Domain (định nghĩa Event, giao diện Repository)
↓
Infrastructure (triển khai cơ sở dữ liệu)
3. Dependency Injection
// Luôn dùng Symbol cho token:
export const AUDIT_LOG_REPOSITORY = Symbol('AUDIT_LOG_REPOSITORY');
// Đăng ký trong module:
{ provide: AUDIT_LOG_REPOSITORY, useClass: PrismaAuditLogRepository }
// Inject vào service:
constructor(
@Inject(AUDIT_LOG_REPOSITORY) private readonly auditRepo: IAuditLogRepository,
) {}
4. Mẫu Event Listener
@Injectable()
export class AuditLoggingListener {
constructor(
@Inject(AUDIT_LOG_REPOSITORY) private readonly auditRepo: IAuditLogRepository,
private readonly logger: LoggerService,
) {}
@OnEvent('user.banned', { async: true })
async handleUserBanned(event: UserBannedEvent): Promise<void> {
// Trích xuất dữ liệu từ sự kiện
// Lưu vào cơ sở dữ liệu
// Ghi log nếu thành công/thất bại
}
}
NƠI THÊM CODE
apps/api/src/modules/admin/
├── domain/
│ ├── events/
│ │ └── audit-logged.event.ts (MỚI - wrapper tuỳ chọn)
│ └── repositories/
│ ├── audit-log.repository.ts (MỚI - interface)
│ └── index.ts (cập nhật exports)
│
├── application/
│ ├── queries/
│ │ ├── get-audit-logs/ (MỚI)
│ │ │ ├── get-audit-logs.query.ts
│ │ │ └── get-audit-logs.handler.ts
│ │ └── index.ts (cập nhật exports)
│ │
│ └── listeners/
│ ├── audit-logging.listener.ts (MỚI)
│ └── index.ts (cập nhật nếu cần)
│
├── infrastructure/
│ └── repositories/
│ ├── prisma-audit-log.repository.ts (MỚI)
│ └── index.ts (cập nhật exports)
│
└── presentation/
├── controllers/
│ ├── admin.controller.ts (THÊM ENDPOINT)
│ └── admin-moderation.controller.ts (CẬP NHẬT nếu cần)
│
└── dto/
├── get-audit-logs-query.dto.ts (MỚI)
└── index.ts (cập nhật exports)
prisma/
└── schema.prisma (THÊM AuditLog MODEL)
CÁC SỰ KIỆN CẦN LẮNG NGHE
- 'user.banned' - từ UserBannedEvent
- 'user.unbanned' - từ UserUnbannedEvent
- 'listing.approved' - từ ListingApprovedEvent
- 'listing.rejected' - từ ListingRejectedEvent
- 'kyc.approved' - từ KycApprovedEvent
- 'kyc.rejected' - từ KycRejectedEvent
- 'subscription.adjusted' - từ SubscriptionAdjustedEvent
- 'user.deactivated' - (nếu tồn tại trong auth module)
Mỗi sự kiện được ghi lại kèm:
- ID Admin (từ sự kiện)
- ID Tài nguyên (aggregateId từ sự kiện)
- Loại Tài nguyên (suy ra từ eventName)
- Dấu thời gian (từ event.occurredAt)
- Ngữ cảnh bổ sung (lý do, ghi chú, v.v.)