Files
goodgo-platform/docs/audits/ADMIN_AUDIT_QUICK_FILES.md
Ho Ngoc Hai 11f2bf26e6
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
chore: update project documentation, audit reports, and initialize IDE configuration files
2026-04-19 03:12:54 +07:00

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(...))

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(...))

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:

  1. PATCH /admin/users/status - Cập nhật trạng thái hoạt động của người dùng
  2. POST /admin/users/ban - Cấm/bỏ cấm người dùng
  3. POST /admin/subscriptions/adjust - Điều chỉnh gói đăng ký

Hành động của AdminModerationController:

  1. POST /admin/moderation/approve - Duyệt tin đăng
  2. POST /admin/moderation/reject - Từ chối tin đăng
  3. POST /admin/moderation/bulk - Kiểm duyệt hàng loạt tin đăng
  4. POST /admin/kyc/approve - Duyệt KYC
  5. POST /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ầ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

  1. 'user.banned' - từ UserBannedEvent
  2. 'user.unbanned' - từ UserUnbannedEvent
  3. 'listing.approved' - từ ListingApprovedEvent
  4. 'listing.rejected' - từ ListingRejectedEvent
  5. 'kyc.approved' - từ KycApprovedEvent
  6. 'kyc.rejected' - từ KycRejectedEvent
  7. 'subscription.adjusted' - từ SubscriptionAdjustedEvent
  8. '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.)