/** * Notifications Controller * * API endpoints for managing in-app notifications. */ import { Controller, Get, Post, Param, Query, Req, UseGuards } from "@nestjs/common"; import { RateLimit, RateLimitGuard } from "@bff/core/rate-limiting/index.js"; import type { RequestWithUser } from "@bff/modules/auth/auth.types.js"; import { NotificationService } from "./notifications.service.js"; import { notificationListResponseSchema, notificationUnreadCountResponseSchema, notificationIdParamSchema, type NotificationListResponse, } from "@customer-portal/domain/notifications"; import { notificationQuerySchema } from "@customer-portal/domain/notifications"; import { apiSuccessAckResponseSchema, type ApiSuccessAckResponse, } from "@customer-portal/domain/common"; import { createZodDto, ZodResponse } from "nestjs-zod"; class NotificationQueryDto extends createZodDto(notificationQuerySchema) {} class NotificationIdParamDto extends createZodDto(notificationIdParamSchema) {} class NotificationListResponseDto extends createZodDto(notificationListResponseSchema) {} class NotificationUnreadCountResponseDto extends createZodDto( notificationUnreadCountResponseSchema ) {} class ApiSuccessAckResponseDto extends createZodDto(apiSuccessAckResponseSchema) {} @Controller("notifications") @UseGuards(RateLimitGuard) export class NotificationsController { constructor(private readonly notificationService: NotificationService) {} /** * Get notifications for the current user */ @Get() @RateLimit({ limit: 60, ttl: 60 }) @ZodResponse({ description: "Get notifications", type: NotificationListResponseDto }) async getNotifications( @Req() req: RequestWithUser, @Query() query: NotificationQueryDto ): Promise { const parsedQuery = notificationQuerySchema.parse(query as unknown); return this.notificationService.getNotifications(req.user.id, { limit: Math.min(parsedQuery.limit, 50), // Cap at 50 offset: parsedQuery.offset, includeRead: parsedQuery.includeRead, }); } /** * Get unread notification count for the current user */ @Get("unread-count") @RateLimit({ limit: 120, ttl: 60 }) @ZodResponse({ description: "Get unread count", type: NotificationUnreadCountResponseDto }) async getUnreadCount(@Req() req: RequestWithUser): Promise<{ count: number }> { const count = await this.notificationService.getUnreadCount(req.user.id); return { count }; } /** * Mark a specific notification as read */ @Post(":id/read") @RateLimit({ limit: 60, ttl: 60 }) @ZodResponse({ description: "Mark as read", type: ApiSuccessAckResponseDto }) async markAsRead( @Req() req: RequestWithUser, @Param() params: NotificationIdParamDto ): Promise { await this.notificationService.markAsRead(params.id, req.user.id); return { success: true }; } /** * Mark all notifications as read */ @Post("read-all") @RateLimit({ limit: 10, ttl: 60 }) @ZodResponse({ description: "Mark all as read", type: ApiSuccessAckResponseDto }) async markAllAsRead(@Req() req: RequestWithUser): Promise { await this.notificationService.markAllAsRead(req.user.id); return { success: true }; } /** * Dismiss a notification (hide from UI) */ @Post(":id/dismiss") @RateLimit({ limit: 60, ttl: 60 }) @ZodResponse({ description: "Dismiss notification", type: ApiSuccessAckResponseDto }) async dismiss( @Req() req: RequestWithUser, @Param() params: NotificationIdParamDto ): Promise { await this.notificationService.dismiss(params.id, req.user.id); return { success: true }; } }