import { Injectable, CanActivate, ExecutionContext, ServiceUnavailableException, } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { PrismaService } from '../../prisma/prisma.service'; import { JwtService } from '@nestjs/jwt'; @Injectable() export class MaintenanceGuard implements CanActivate { constructor( private reflector: Reflector, private prisma: PrismaService, private jwtService: JwtService, ) {} async canActivate(context: ExecutionContext): Promise { // Check if route is exempt from maintenance mode (auth, health, admin routes) const isExempt = this.reflector.get('skipMaintenance', context.getHandler()); const isControllerExempt = this.reflector.get('skipMaintenance', context.getClass()); if (isExempt || isControllerExempt) { return true; } // Get maintenance mode status from config const maintenanceConfig = await this.prisma.appConfig.findUnique({ where: { key: 'maintenance_mode' }, }); const isMaintenanceMode = maintenanceConfig?.value === 'true'; if (!isMaintenanceMode) { return true; } // Try to extract user from JWT token (if exists) const request = context.switchToHttp().getRequest(); const authHeader = request.headers.authorization; if (authHeader && authHeader.startsWith('Bearer ')) { try { const token = authHeader.substring(7); const payload = this.jwtService.verify(token); // If user is admin, allow access if (payload.role === 'admin') { return true; } } catch (error) { // Invalid token, continue to block } } // Get maintenance message const messageConfig = await this.prisma.appConfig.findUnique({ where: { key: 'maintenance_message' }, }); const message = messageConfig?.value || 'System is under maintenance. Please try again later.'; throw new ServiceUnavailableException({ statusCode: 503, message: message, maintenanceMode: true, }); } }