import { CanActivate, ExecutionContext, ForbiddenException, Injectable, } from '@nestjs/common'; import { forTenant } from '../prisma/prisma-tenant.extension'; import { PrismaService } from '../prisma/prisma.service'; /** * Runs AFTER JwtAuthGuard (guard execution order follows APP_GUARD registration order). * At this point req.user is populated — middleware ran too early to access it. * * Sets req.tenantId and req.tenantPrisma for downstream controllers. * Super-Admin can override tenant via x-tenant-id header (D-10). */ @Injectable() export class TenantGuard implements CanActivate { constructor(private readonly prisma: PrismaService) {} canActivate(context: ExecutionContext): boolean { const req = context.switchToHttp().getRequest(); const user = req.user; if (!user) { // Public route (login, health) — skip tenant context return true; } let tenantId: string | undefined = user.tenantId; if (user.role === 'SUPER_ADMIN' && req.headers['x-tenant-id']) { tenantId = req.headers['x-tenant-id'] as string; } if (!tenantId && user.role !== 'SUPER_ADMIN') { throw new ForbiddenException('No tenant context'); } if (tenantId) { req.tenantPrisma = forTenant(this.prisma, tenantId); req.tenantId = tenantId; } else { req.tenantPrisma = this.prisma; req.tenantId = null; } return true; } }