Files
goodgo-platform/apps/api/src/modules/notifications/notifications.module.ts
Ho Ngoc Hai 8c6e3b92d0 feat(notifications): R2.8 residential WS events (TEC-2759)
- Add emitResidentialEvent helper on NotificationsGateway that fans
  residential:price-drop, residential:new-listing-in-project, and
  residential:inquiry-reply to the user's /notifications room.
- Wire three CQRS @EventsHandler listeners on ListingPriceChangedEvent
  (only when newPrice < oldPrice, match saved searches),
  ListingApprovedEvent (match saved searches with filters.projectId
  against property.projectDevelopmentId), and InquiryReadEvent
  (notify inquiry author).
- Redis pub/sub fan-out already handled by RedisIoAdapter from
  TEC-2766, so these broadcasts work across API instances.
- Unit tests for all three listeners and the new gateway helper.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-18 15:28:40 +07:00

91 lines
4.4 KiB
TypeScript

import { Module } from '@nestjs/common';
import { CqrsModule } from '@nestjs/cqrs';
import { AuthModule } from '@modules/auth';
import { MetricsModule } from '@modules/metrics';
import { SendNotificationHandler } from './application/commands/send-notification/send-notification.handler';
import { AgentVerifiedListener } from './application/listeners/agent-verified.listener';
import { EmailChangeRequestedListener } from './application/listeners/email-change-requested.listener';
import { InquiryReceivedListener } from './application/listeners/inquiry-received.listener';
import { ListingApprovedListener } from './application/listeners/listing-approved.listener';
import { ListingRejectedListener } from './application/listeners/listing-rejected.listener';
import { ListingSoldListener } from './application/listeners/listing-sold.listener';
import { PaymentCompletedListener } from './application/listeners/payment-completed.listener';
import { PaymentFailedListener } from './application/listeners/payment-failed.listener';
import { PaymentRefundedListener } from './application/listeners/payment-refunded.listener';
import { PhoneChangeRequestedListener } from './application/listeners/phone-change-requested.listener';
import { QuotaExceededListener } from './application/listeners/quota-exceeded.listener';
import {
ResidentialInquiryReplyListener,
ResidentialNewListingInProjectListener,
ResidentialPriceDropListener,
} from './application/listeners/residential-events.listener';
import { SubscriptionExpiredListener } from './application/listeners/subscription-expired.listener';
import { SubscriptionExpiringListener } from './application/listeners/subscription-expiring.listener';
import { SubscriptionRenewedListener } from './application/listeners/subscription-renewed.listener';
import { UserKycUpdatedListener } from './application/listeners/user-kyc-updated.listener';
import { UserRegisteredListener } from './application/listeners/user-registered.listener';
import { NOTIFICATION_PREFERENCE_REPOSITORY } from './domain/repositories/notification-preference.repository';
import { NOTIFICATION_REPOSITORY } from './domain/repositories/notification.repository';
import { PrismaNotificationPreferenceRepository } from './infrastructure/repositories/prisma-notification-preference.repository';
import { PrismaNotificationRepository } from './infrastructure/repositories/prisma-notification.repository';
import { EmailService } from './infrastructure/services/email.service';
import { FcmService } from './infrastructure/services/fcm.service';
import { StringeeSmsService } from './infrastructure/services/stringee-sms.service';
import { TemplateService } from './infrastructure/services/template.service';
import { ZaloOaService } from './infrastructure/services/zalo-oa.service';
import { NotificationsController } from './presentation/controllers/notifications.controller';
import { ZaloOaWebhookController } from './presentation/controllers/zalo-oa-webhook.controller';
import { NotificationsGateway } from './presentation/gateways/notifications.gateway';
const CommandHandlers = [SendNotificationHandler];
const EventListeners = [
UserRegisteredListener,
AgentVerifiedListener,
QuotaExceededListener,
ListingApprovedListener,
ListingRejectedListener,
PaymentCompletedListener,
PaymentFailedListener,
PaymentRefundedListener,
SubscriptionExpiringListener,
SubscriptionExpiredListener,
SubscriptionRenewedListener,
InquiryReceivedListener,
ListingSoldListener,
UserKycUpdatedListener,
EmailChangeRequestedListener,
PhoneChangeRequestedListener,
ResidentialPriceDropListener,
ResidentialNewListingInProjectListener,
ResidentialInquiryReplyListener,
];
@Module({
imports: [CqrsModule, AuthModule, MetricsModule],
controllers: [NotificationsController, ZaloOaWebhookController],
providers: [
// Repositories
{ provide: NOTIFICATION_REPOSITORY, useClass: PrismaNotificationRepository },
{ provide: NOTIFICATION_PREFERENCE_REPOSITORY, useClass: PrismaNotificationPreferenceRepository },
// Services
EmailService,
FcmService,
StringeeSmsService,
ZaloOaService,
TemplateService,
// WebSocket Gateway
NotificationsGateway,
// CQRS
...CommandHandlers,
// Event Listeners
...EventListeners,
],
exports: [EmailService, FcmService, StringeeSmsService, ZaloOaService, TemplateService, NotificationsGateway],
})
export class NotificationsModule {}