import { redirect } from 'next/navigation'; import { PathnameInterpreter } from './PathnameInterpreter'; import { RouteAccessPolicy } from './RouteAccessPolicy'; import { SessionGateway } from '../gateways/SessionGateway'; import { AuthRedirectBuilder } from './AuthRedirectBuilder'; import type { AuthSessionDTO } from '../types/generated/AuthSessionDTO'; import { ConsoleLogger } from '../infrastructure/logging/ConsoleLogger'; const logger = new ConsoleLogger(); export class RouteGuard { constructor( private readonly interpreter: PathnameInterpreter, private readonly policy: RouteAccessPolicy, private readonly gateway: SessionGateway, private readonly builder: AuthRedirectBuilder ) {} async enforce({ pathname }: { pathname: string }): Promise { logger.info('[RouteGuard] enforce called', { pathname }); // Step 1: Interpret the pathname const { logicalPathname } = this.interpreter.interpret(pathname); logger.info('[RouteGuard] logicalPathname', { logicalPathname }); // Step 2: Check if public non-auth page if (this.policy.isPublic(logicalPathname) && !this.policy.isAuthPage(logicalPathname)) { logger.info('[RouteGuard] Public non-auth page, allowing access'); return; // Allow access } // Step 3: Handle auth pages if (this.policy.isAuthPage(logicalPathname)) { logger.info('[RouteGuard] Auth page detected'); const session = await this.gateway.getSession(); if (session) { // User is logged in, redirect away from auth page const redirectPath = this.builder.awayFromAuthPage({ session, currentPathname: pathname }); logger.info('[RouteGuard] Redirecting away from auth page', { redirectPath }); redirect(redirectPath); } // No session, allow access to auth page logger.info('[RouteGuard] No session, allowing access to auth page'); return; } // Step 4: Handle protected pages const session = await this.gateway.getSession(); logger.info('[RouteGuard] Protected page, session', { hasSession: !!session, role: session?.user?.role, sessionData: JSON.stringify(session, null, 2) }); // No session, redirect to login if (!session) { const loginPath = this.builder.toLogin({ currentPathname: pathname }); logger.info('[RouteGuard] No session, redirecting to login', { loginPath }); redirect(loginPath); } // Check required roles const reqRoles = this.policy.requiredRoles(logicalPathname); logger.info('[RouteGuard] Checking required roles', { reqRoles, userRole: session.user?.role }); if (reqRoles && session.user?.role && !reqRoles.includes(session.user.role)) { const loginPath = this.builder.toLogin({ currentPathname: pathname }); logger.info('[RouteGuard] Role mismatch, redirecting to login', { loginPath, reqRoles, userRole: session.user.role }); redirect(loginPath); } // All checks passed, allow access logger.info('[RouteGuard] All checks passed, allowing access'); return; } }