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
25 KiB
25 KiB
Inquiries Module - Chỉ Mục File Đầy Đủ
Tạo lúc: Ngày 11 tháng 4 năm 2026
Module: apps/api/src/modules/inquiries/
Tổng số file: 25
📋 DANH SÁCH FILE ĐẦY ĐỦ THEO ĐƯỜNG DẪN
1. TẦNG ỨNG DỤNG (APPLICATION LAYER)
Commands (4 files)
📄 apps/api/src/modules/inquiries/application/commands/create-inquiry/create-inquiry.command.ts
Type: Command (CQRS)
Purpose: Input DTO cho use case tạo yêu cầu tư vấn
Exports: CreateInquiryCommand class
Properties: userId, listingId, message, phone
Lines: ~8
📄 apps/api/src/modules/inquiries/application/commands/create-inquiry/create-inquiry.handler.ts
Type: Command Handler (CQRS)
Purpose: Điều phối quá trình tạo yêu cầu tư vấn
Implements: ICommandHandler<CreateInquiryCommand>
Returns: CreateInquiryResult { id, listingId, createdAt }
Key Logic:
• Xác thực tin đăng tồn tại (Prisma.listing.findUnique)
• Tạo InquiryEntity qua phương thức factory
• Lưu vào repository
• Phát sự kiện InquiryCreatedEvent qua EventBus
Lines: ~60
Dependencies:
• INQUIRY_REPOSITORY (injected)
• EventBus (injected)
• PrismaService (injected)
• LoggerService (injected)
📄 apps/api/src/modules/inquiries/application/commands/mark-inquiry-read/mark-inquiry-read.command.ts
Type: Command (CQRS)
Purpose: Input DTO để đánh dấu yêu cầu tư vấn đã đọc
Exports: MarkInquiryReadCommand class
Properties: inquiryId, agentUserId
Lines: ~6
📄 apps/api/src/modules/inquiries/application/commands/mark-inquiry-read/mark-inquiry-read.handler.ts
Type: Command Handler (CQRS)
Purpose: Điều phối thao tác đánh dấu đã đọc
Implements: ICommandHandler<MarkInquiryReadCommand>
Returns: void (không có giá trị trả về)
Key Logic:
• Tải entity yêu cầu tư vấn từ repository
• Tải tin đăng và xác minh quyền sở hữu của môi giới
• Gọi inquiry.markAsRead() để cập nhật trạng thái
• Lưu qua repository.markAsRead()
• Phát sự kiện InquiryReadEvent qua EventBus
Authorization Checks:
• Yêu cầu tư vấn tồn tại
• Tin đăng tồn tại
• Người dùng đã đăng ký làm môi giới
• ID môi giới khớp với listing.agentId
Lines: ~50
Dependencies:
• INQUIRY_REPOSITORY (injected)
• EventBus (injected)
• PrismaService (injected)
• LoggerService (injected)
Queries (4 files)
📄 apps/api/src/modules/inquiries/application/queries/get-inquiries-by-agent/get-inquiries-by-agent.query.ts
Type: Query (CQRS)
Purpose: Input DTO để lấy danh sách yêu cầu tư vấn của môi giới
Exports: GetInquiriesByAgentQuery class
Properties: agentUserId, page, limit
Lines: ~6
📄 apps/api/src/modules/inquiries/application/queries/get-inquiries-by-agent/get-inquiries-by-agent.handler.ts
Type: Query Handler (CQRS)
Purpose: Phân giải danh sách yêu cầu tư vấn phân trang cho một môi giới
Implements: IQueryHandler<GetInquiriesByAgentQuery>
Returns: PaginatedResult<InquiryReadDto>
Key Logic:
• Phân giải ID môi giới từ userId qua Prisma
• Ném NotFoundException nếu người dùng không phải môi giới
• Ủy quyền cho repository.findByAgent()
Lines: ~30
Dependencies:
• INQUIRY_REPOSITORY (injected)
• PrismaService (injected)
📄 apps/api/src/modules/inquiries/application/queries/get-inquiries-by-listing/get-inquiries-by-listing.query.ts
Type: Query (CQRS)
Purpose: Input DTO để lấy danh sách yêu cầu tư vấn của tin đăng
Exports: GetInquiriesByListingQuery class
Properties: listingId, page, limit
Lines: ~6
📄 apps/api/src/modules/inquiries/application/queries/get-inquiries-by-listing/get-inquiries-by-listing.handler.ts
Type: Query Handler (CQRS)
Purpose: Phân giải danh sách yêu cầu tư vấn phân trang cho một tin đăng
Implements: IQueryHandler<GetInquiriesByListingQuery>
Returns: PaginatedResult<InquiryReadDto>
Key Logic:
• Ủy quyền trực tiếp cho repository.findByListing()
Lines: ~20
Dependencies:
• INQUIRY_REPOSITORY (injected)
Application Tests (4 files)
📄 apps/api/src/modules/inquiries/application/__tests__/create-inquiry.handler.spec.ts
Type: Unit Tests (Jest/Vitest)
Test Framework: Vitest với hàm Mock (vi.fn)
Test Count: 4
Tests:
✓ tạo yêu cầu tư vấn thành công
✓ ném NotFoundException khi không tìm thấy tin đăng
✓ phát sự kiện domain sau khi lưu
Mocks:
• mockInquiryRepo (IInquiryRepository implementation)
• mockEventBus
• mockPrisma.listing.findUnique
Lines: ~98
📄 apps/api/src/modules/inquiries/application/__tests__/mark-inquiry-read.handler.spec.ts
Type: Unit Tests (Jest/Vitest)
Test Count: 5
Tests:
✓ đánh dấu yêu cầu tư vấn là đã đọc thành công
✓ ném NotFoundException khi không tìm thấy yêu cầu tư vấn
✓ ném NotFoundException khi không tìm thấy tin đăng
✓ ném ForbiddenException khi người dùng không phải môi giới của tin đăng
✓ ném ForbiddenException khi không tìm thấy môi giới cho người dùng
Mocks:
• mockInquiryRepo
• mockEventBus
• mockPrisma.listing.findUnique
• mockPrisma.agent.findUnique
Lines: ~130
📄 apps/api/src/modules/inquiries/application/__tests__/get-inquiries-by-listing.handler.spec.ts
Type: Unit Tests (Jest/Vitest)
Test Count: 2
Tests:
✓ trả về kết quả phân trang
✓ trả về dữ liệu rỗng khi không tìm thấy yêu cầu tư vấn nào
Mocks:
• mockInquiryRepo.findByListing
Lines: ~69
📄 apps/api/src/modules/inquiries/application/__tests__/get-inquiries-by-agent.handler.spec.ts
Type: Unit Tests (Jest/Vitest)
Test Count: 2
Tests:
✓ trả về kết quả phân trang
✓ ném NotFoundException khi không tìm thấy môi giới cho người dùng
Mocks:
• mockInquiryRepo.findByAgent
• mockPrisma.agent.findUnique
Lines: ~77
2. TẦNG DOMAIN (DOMAIN LAYER)
Entities (1 file)
📄 apps/api/src/modules/inquiries/domain/entities/inquiry.entity.ts
Type: Aggregate Root (DDD)
Extends: AggregateRoot<string>
Purpose: Logic nghiệp vụ cốt lõi cho yêu cầu tư vấn
Properties (Private):
• _listingId: string
• _userId: string
• _message: string
• _phone: string | null
• _isRead: boolean
Getters (Read-only):
• listingId: string
• userId: string
• message: string
• phone: string | null
• isRead: boolean
Factory Method:
• static createNew(id, listingId, userId, message, phone): InquiryEntity
- Tạo yêu cầu tư vấn mới với isRead=false
- Phát InquiryCreatedEvent
- Trả về instance của entity
Domain Methods:
• markAsRead(): void
- Đặt _isRead thành true
- Phát InquiryReadEvent
Lines: ~63
Dependencies:
• AggregateRoot from @modules/shared
• InquiryCreatedEvent
• InquiryReadEvent
Events (2 files)
📄 apps/api/src/modules/inquiries/domain/events/inquiry-created.event.ts
Type: Domain Event (DDD)
Implements: DomainEvent interface
Purpose: Báo hiệu rằng một yêu cầu tư vấn đã được tạo
Properties:
• eventName: string = 'inquiry.created'
• occurredAt: Date = new Date()
• aggregateId: string
• listingId: string
• userId: string
Lines: ~13
📄 apps/api/src/modules/inquiries/domain/events/inquiry-read.event.ts
Type: Domain Event (DDD)
Implements: DomainEvent interface
Purpose: Báo hiệu rằng một yêu cầu tư vấn đã được đánh dấu là đã đọc
Properties:
• eventName: string = 'inquiry.read'
• occurredAt: Date = new Date()
• aggregateId: string
• listingId: string
• userId: string
Lines: ~13
Repositories (2 files)
📄 apps/api/src/modules/inquiries/domain/repositories/inquiry.repository.ts
Type: Repository Interface + Symbol (DDD)
Purpose: Định nghĩa hợp đồng persistence
Exports:
• INQUIRY_REPOSITORY: Symbol (DI token)
• IInquiryRepository: Interface
• PaginatedResult<T>: Interface
IInquiryRepository Methods:
• findById(id: string): Promise<InquiryEntity | null>
• save(inquiry: InquiryEntity): Promise<void>
• markAsRead(id: string): Promise<void>
• findByListing(listingId, page, limit): Promise<PaginatedResult<InquiryReadDto>>
• findByAgent(agentId, page, limit): Promise<PaginatedResult<InquiryReadDto>>
• countUnreadByAgent(agentId): Promise<number>
PaginatedResult<T> Interface:
• data: T[]
• total: number
• page: number
• limit: number
• totalPages: number
Lines: ~22
📄 apps/api/src/modules/inquiries/domain/repositories/inquiry-read.dto.ts
Type: Data Transfer Object (Read Model)
Purpose: DTO cho kết quả truy vấn
Exports: InquiryReadDto interface
InquiryReadDto Properties:
• id: string
• listingId: string
• listingTitle: string
• userId: string
• userName: string
• userPhone: string
• message: string
• phone: string | null
• isRead: boolean
• createdAt: string
Lines: ~13
Domain Tests (1 file)
📄 apps/api/src/modules/inquiries/domain/__tests__/inquiry-domain.spec.ts
Type: Unit Tests (Jest/Vitest)
Test Count: 5
Tests:
✓ createNew() tạo yêu cầu tư vấn với các thuộc tính đúng
✓ createNew() tạo yêu cầu tư vấn với phone là null
✓ createNew() phát InquiryCreatedEvent
✓ markAsRead() đặt isRead thành true
✓ markAsRead() phát InquiryReadEvent
Focus: Hành vi entity và việc phát sự kiện domain
Lines: ~96
3. TẦNG HẠ TẦNG (INFRASTRUCTURE LAYER)
Repository Implementation (1 file)
📄 apps/api/src/modules/inquiries/infrastructure/repositories/prisma-inquiry.repository.ts
Type: Repository Implementation (Service)
Implements: IInquiryRepository
Decorator: @Injectable()
Purpose: Persistence dựa trên Prisma
Methods:
1. findById(id: string): Promise<InquiryEntity | null>
- Query: prisma.inquiry.findUnique({ where: { id } })
- Returns: InquiryEntity | null
2. save(entity: InquiryEntity): Promise<void>
- Query: prisma.inquiry.create({ data: {...} })
- Ánh xạ thuộc tính entity sang Prisma model
3. markAsRead(id: string): Promise<void>
- Query: prisma.inquiry.update({ where: { id }, data: { isRead: true } })
4. findByListing(listingId, page, limit): Promise<PaginatedResult<InquiryReadDto>>
- Query: prisma.inquiry.findMany() với joins
- Includes: listing.property.title, user.fullName, user.phone
- Pagination: mô hình skip/take
- Sorting: orderBy: { createdAt: 'desc' }
- Returns: Mảng InquiryReadDto đã ánh xạ kèm thông tin phân trang
5. findByAgent(agentId, page, limit): Promise<PaginatedResult<InquiryReadDto>>
- Query: prisma.inquiry.findMany() lọc theo listing.agentId
- Cùng includes và phân trang như findByListing
- Filter: { listing: { agentId } }
6. countUnreadByAgent(agentId): Promise<number>
- Query: prisma.inquiry.count()
- Filter: { isRead: false, listing: { agentId } }
Helper Method:
• toDomain(raw: PrismaInquiry): InquiryEntity
- Ánh xạ bản ghi cơ sở dữ liệu sang domain entity
Lines: ~146
Dependencies:
• PrismaService (injected)
• InquiryEntity
• IInquiryRepository (implements)
4. TẦNG TRÌNH BÀY (PRESENTATION LAYER)
Controller (1 file)
📄 apps/api/src/modules/inquiries/presentation/controllers/inquiries.controller.ts
Type: NestJS Controller
Decorator: @Controller('inquiries')
Decorator: @ApiTags('inquiries')
Purpose: Các endpoint HTTP API
Endpoints:
1. POST /inquiries
Decorator: @Post()
Auth: @UseGuards(JwtAuthGuard)
Method: createInquiry(dto: CreateInquiryDto, user: JwtPayload)
Body: CreateInquiryDto { listingId, message, phone? }
Returns: CreateInquiryResult { id, listingId, createdAt }
Status Codes: 201 Created, 400 Bad Request, 401 Unauthorized, 404 Not Found
Logic:
• Điều phối CreateInquiryCommand qua CommandBus
• Truyền user.sub làm userId
2. GET /inquiries/listing/:listingId
Decorator: @Get('listing/:listingId')
Auth: @UseGuards(JwtAuthGuard)
Method: getByListing(listingId: string, dto: ListInquiriesDto)
Query: page?, limit?
Returns: PaginatedResult<InquiryReadDto>
Status Codes: 200 OK, 401 Unauthorized
Logic:
• Điều phối GetInquiriesByListingQuery qua QueryBus
• Mặc định page=1, limit=20
3. GET /inquiries/agent/me
Decorator: @Get('agent/me')
Auth: @UseGuards(JwtAuthGuard, RolesGuard)
Decorator: @Roles('AGENT')
Method: getMyInquiries(user: JwtPayload, dto: ListInquiriesDto)
Query: page?, limit?
Returns: PaginatedResult<InquiryReadDto>
Status Codes: 200 OK, 401 Unauthorized, 403 Forbidden
Logic:
• Điều phối GetInquiriesByAgentQuery qua QueryBus
• Truyền user.sub làm agentUserId
• Mặc định page=1, limit=20
4. PATCH /inquiries/:id/read
Decorator: @Patch(':id/read')
Auth: @UseGuards(JwtAuthGuard, RolesGuard)
Decorator: @Roles('AGENT')
Method: markAsRead(id: string, user: JwtPayload)
Returns: { success: boolean }
Status Codes: 200 OK, 401 Unauthorized, 403 Forbidden, 404 Not Found
Logic:
• Điều phối MarkInquiryReadCommand qua CommandBus
• Truyền user.sub làm agentUserId
• Trả về { success: true }
Lines: ~121
Dependencies:
• CommandBus (injected)
• QueryBus (injected)
• @nestjs/swagger decorators
• @modules/auth guards and decorators
DTOs (2 files)
📄 apps/api/src/modules/inquiries/presentation/dto/create-inquiry.dto.ts
Type: Data Transfer Object (Validation)
Purpose: Xác thực body của request POST /inquiries
Decorators: @ApiProperty, @ApiPropertyOptional
Properties:
• listingId: string (required)
Validators: @IsString(), @IsNotEmpty()
API Doc: "ID of the listing"
• message: string (required)
Validators: @IsString(), @IsNotEmpty(), @MaxLength(2000)
API Doc: "Tin nhắn yêu cầu tư vấn" (Consultation request message)
Max: 2000 ký tự
• phone?: string (optional)
Validators: @IsOptional(), @IsString()
API Doc: "Số điện thoại liên hệ" (Contact phone number)
Lines: ~21
Dependencies: class-validator, @nestjs/swagger
📄 apps/api/src/modules/inquiries/presentation/dto/list-inquiries.dto.ts
Type: Data Transfer Object (Validation)
Purpose: Xác thực query parameter cho các endpoint danh sách
Decorators: @ApiPropertyOptional, @Type
Properties:
• page?: number (optional)
Validators: @IsOptional(), @IsInt(), @Min(1), @Type(() => Number)
API Doc: "Số trang", mặc định: 1
Example: 1
• limit?: number (optional)
Validators: @IsOptional(), @IsInt(), @Min(1), @Max(100), @Type(() => Number)
API Doc: "Số mục mỗi trang", mặc định: 20
Example: 20
Max: 100
Lines: ~21
Dependencies: class-validator, @nestjs/swagger, class-transformer
Presentation Tests (1 file)
📄 apps/api/src/modules/inquiries/presentation/__tests__/inquiries.controller.spec.ts
Type: Unit Tests (Jest/Vitest)
Test Count: 6
Tests:
✓ POST /inquiries điều phối CreateInquiryCommand với tham số đúng
✓ POST /inquiries truyền phone là null khi không được cung cấp
✓ GET /listing/:id điều phối GetInquiriesByListingQuery với giá trị mặc định
✓ GET /listing/:id truyền phân trang tùy chỉnh
✓ GET /agent/me điều phối GetInquiriesByAgentQuery với người dùng hiện tại
✓ PATCH /:id/read điều phối MarkInquiryReadCommand và trả về thành công
Mocks:
• mockCommandBus với hàm mock execute()
• mockQueryBus với hàm mock execute()
• mockBuyer user object (sub='buyer-1', role='BUYER')
• mockAgent user object (sub='agent-1', role='AGENT')
Lines: ~105
5. TẦNG MODULE (MODULE LAYER)
📄 apps/api/src/modules/inquiries/inquiries.module.ts
Type: NestJS Module
Decorator: @Module()
Purpose: Cấu hình module, khai báo phụ thuộc, xuất khẩu
Imports: [CqrsModule]
Controllers: [InquiriesController]
Providers:
• { provide: INQUIRY_REPOSITORY, useClass: PrismaInquiryRepository }
- Ánh xạ token dependency injection
• CommandHandlers array: [CreateInquiryHandler, MarkInquiryReadHandler]
• QueryHandlers array: [GetInquiriesByListingHandler, GetInquiriesByAgentHandler]
Exports: [INQUIRY_REPOSITORY]
- Cung cấp repository cho các module khác
Lines: ~29
Dependencies:
• @nestjs/common
• @nestjs/cqrs
• All handlers, repository, controller
📄 apps/api/src/modules/inquiries/index.ts
Type: Barrel Export (Public API)
Purpose: Định nghĩa giao diện công khai của module
Exports:
• InquiriesModule (default export for app imports)
• INQUIRY_REPOSITORY (DI token)
• IInquiryRepository (interface type)
• InquiryEntity (for external access)
Lines: ~4
📊 THỐNG KÊ FILE
Theo Tầng
| Tầng | Files | Loại | Mục đích |
|---|---|---|---|
| Presentation | 5 | Controller + DTOs + Tests | Endpoint HTTP và xác thực đầu vào |
| Application | 8 | Commands/Queries + Handlers + Tests | Điều phối use case |
| Domain | 6 | Entities + Events + Repository Interface + Tests | Logic nghiệp vụ và hợp đồng |
| Infrastructure | 1 | Repository Implementation | Lưu trữ cơ sở dữ liệu |
| Module | 2 | Module + Exports | Cấu hình và API công khai |
| TỔNG | 25 | - | - |
Theo Loại
| Loại | Số lượng |
|---|---|
| File nguồn (.ts, không phải test) | 19 |
| File test (.spec.ts) | 6 |
| Tổng | 25 |
Theo Mục Đích
| Mục đích | Số lượng | Files |
|---|---|---|
| Controllers | 1 | inquiries.controller.ts |
| DTOs | 2 | create-inquiry.dto.ts, list-inquiries.dto.ts |
| Commands | 2 | create-inquiry.command.ts, mark-inquiry-read.command.ts |
| Queries | 2 | get-inquiries-by-*.query.ts (2 files) |
| Handlers | 4 | 2 command handlers + 2 query handlers |
| Entities | 1 | inquiry.entity.ts |
| Events | 2 | inquiry-created.event.ts, inquiry-read.event.ts |
| Repositories | 3 | interface + 2 DTOs + 1 implementation |
| Tests | 6 | 5 bộ test trải rộng các tầng |
| Module | 2 | inquiries.module.ts, index.ts |
🔍 HƯỚNG DẪN TÌM KIẾM FILE
Tìm kiếm Logic Nghiệp Vụ?
→ domain/entities/inquiry.entity.ts - Quy tắc nghiệp vụ cốt lõi
→ domain/events/*.event.ts - Sự kiện nghiệp vụ
Tìm kiếm Use Case?
→ application/commands/*/ - Thao tác ghi
→ application/queries/*/ - Thao tác đọc
→ application/[type]/__tests__/ - Các test case
Tìm kiếm HTTP Endpoint?
→ presentation/controllers/inquiries.controller.ts - Toàn bộ 4 endpoint
Tìm kiếm Xác Thực Đầu Vào?
→ presentation/dto/ - Tất cả DTOs kèm validator
Tìm kiếm Logic Cơ Sở Dữ Liệu?
→ infrastructure/repositories/prisma-inquiry.repository.ts - Tất cả Prisma query
Tìm kiếm Tests?
→ domain/__tests__/ - Hành vi domain
→ application/__tests__/ - Test handler
→ presentation/__tests__/ - Test controller
🔗 ĐỒ THỊ PHỤ THUỘC (DEPENDENCY GRAPH)
presentation/controllers/inquiries.controller.ts
├── application/commands/create-inquiry/create-inquiry.handler.ts
├── application/commands/mark-inquiry-read/mark-inquiry-read.handler.ts
├── application/queries/get-inquiries-by-*/[name].handler.ts
└── CommandBus/QueryBus (NestJS CQRS)
application/commands/*/[name].handler.ts
├── domain/entities/inquiry.entity.ts
├── domain/repositories/inquiry.repository.ts (interface)
├── domain/events/*.event.ts
└── @modules/shared (AggregateRoot, exceptions)
application/queries/*/[name].handler.ts
├── domain/repositories/inquiry.repository.ts
└── domain/repositories/inquiry-read.dto.ts
domain/entities/inquiry.entity.ts
├── @modules/shared (AggregateRoot)
└── domain/events/*.event.ts
infrastructure/repositories/prisma-inquiry.repository.ts
├── domain/entities/inquiry.entity.ts
├── domain/repositories/inquiry.repository.ts (implements)
├── domain/repositories/inquiry-read.dto.ts
└── @prisma/client (Prisma)
inquiries.module.ts
├── All handlers
├── All repositories
├── InquiriesController
└── CqrsModule (NestJS)
📝 THAM CHIẾU CHÉO FILE
Các File Sử Dụng Symbol INQUIRY_REPOSITORY
inquiries.module.ts- Cung cấp implementationapplication/commands/create-inquiry/create-inquiry.handler.ts- Injectsapplication/commands/mark-inquiry-read/mark-inquiry-read.handler.ts- Injectsapplication/queries/get-inquiries-by-agent/get-inquiries-by-agent.handler.ts- Injectsapplication/queries/get-inquiries-by-listing/get-inquiries-by-listing.handler.ts- Injects
Các File Tạo/Chỉnh Sửa InquiryEntity
domain/entities/inquiry.entity.ts- Định nghĩaapplication/commands/create-inquiry/create-inquiry.handler.ts- Tạo mớiapplication/commands/mark-inquiry-read/mark-inquiry-read.handler.ts- Chỉnh sửainfrastructure/repositories/prisma-inquiry.repository.ts- Ánh xạ đến/từ
Các File Phát Sự Kiện
domain/entities/inquiry.entity.ts- Phát ra (qua addDomainEvent)application/commands/create-inquiry/create-inquiry.handler.ts- Xuất bảnapplication/commands/mark-inquiry-read/mark-inquiry-read.handler.ts- Xuất bản
Các File Có Tests
domain/entities/inquiry.entity.ts→domain/__tests__/inquiry-domain.spec.tsapplication/commands/create-inquiry/create-inquiry.handler.ts→application/__tests__/create-inquiry.handler.spec.tsapplication/commands/mark-inquiry-read/mark-inquiry-read.handler.ts→application/__tests__/mark-inquiry-read.handler.spec.tsapplication/queries/get-inquiries-by-listing/→application/__tests__/get-inquiries-by-listing.handler.spec.tsapplication/queries/get-inquiries-by-agent/→application/__tests__/get-inquiries-by-agent.handler.spec.tspresentation/controllers/inquiries.controller.ts→presentation/__tests__/inquiries.controller.spec.ts
🎯 ĐIỂM VÀO CHO VIỆC CHỈNH SỬA
Thêm Endpoint Mới
- Thêm phương thức vào
presentation/controllers/inquiries.controller.ts - Tạo command/query trong
application/[type]/[name]/ - Tạo handler:
[name].handler.ts - Thêm tests trong
application/__tests__/ - Tuỳ chọn: Cập nhật domain nếu cần logic nghiệp vụ mới
Thêm Command Mới
- Tạo
application/commands/[name]/[name].command.ts(DTO) - Tạo
application/commands/[name]/[name].handler.ts(@CommandHandler) - Đăng ký trong mảng CommandHandlers của
inquiries.module.ts - Thêm tests trong
application/__tests__/[name].handler.spec.ts - Tuỳ chọn: Định nghĩa sự kiện domain mới trong
domain/events/
Thêm Logic Domain
- Chỉnh sửa
domain/entities/inquiry.entity.ts - Thêm phương thức hoặc thuộc tính công khai mới
- Phát sự kiện mới nếu cần:
domain/events/[name].event.ts - Cập nhật tests trong
domain/__tests__/inquiry-domain.spec.ts - Cập nhật các handler sử dụng entity
Thêm Thao Tác Cơ Sở Dữ Liệu
- Thêm phương thức vào
infrastructure/repositories/prisma-inquiry.repository.ts - Cập nhật interface trong
domain/repositories/inquiry.repository.ts - Gọi từ các handler liên quan
Tổng số dòng code: 1.212
Cập nhật lần cuối: Ngày 11 tháng 4 năm 2026