Sistema de Rutas (App Router)
El sistema de rutas de Creative Minds utiliza el moderno App Router de Next.js, aprovechando al máximo las capacidades de Server Components y una estructura organizada por grupos de rutas.
Estructura del App Router
src/app/
├── (auth)/ # Grupo de rutas de autenticación
│ ├── login/
│ │ ├── page.tsx # /login
│ │ └── error.tsx # Manejo de errores específico
│ └── register/
│ └── page.tsx # /register
├── (core)/ # Grupo de rutas protegidas/principales
│ ├── layout.tsx # Layout compartido para core
│ ├── loading.tsx # Loading compartido para core
│ └── dashboard/
│ ├── layout.tsx # Layout específico del dashboard
│ └── page.tsx # /dashboard
├── (landing)/ # Grupo de rutas públicas
│ └── page.tsx # /
└── api/ # Rutas de API
└── auth/
└── callback/ # /api/auth/callbackGrupos de Rutas
Los grupos de rutas (indicados con paréntesis) organizan las páginas por su propósito y comportamiento compartido:
-
(auth): Rutas relacionadas con autenticación- No requieren autenticación
- Comparten UI/UX similar
- Redirigen si el usuario ya está autenticado
-
(core): Rutas principales de la aplicación- Requieren autenticación
- Comparten layout (sidebar, navbar)
- Tienen protección de ruta
-
(landing): Rutas públicas/marketing- Accesibles sin autenticación
- UI/UX orientada a conversión
- Layout específico de landing
Protección de Rutas
La protección de rutas se implementa en múltiples niveles:
1. Middleware Global
// src/middleware.ts
import { NextRequest } from 'next/server'
import { updateSession } from '@/providers/database/supabase/middleware'
export async function middleware(request: NextRequest) {
return await updateSession(request)
}
export const config = {
matcher: [
// Excluye archivos estáticos y recursos
'/((?!_next/static|_next/image|favicon.ico).*)',
],
}2. Guards de Módulo
Los guards proporcionan protección específica por dominio:
// modules/auth/guards/auth.guard.ts
class AuthGuard extends Guard {
async protectByAuth({ redirectTo }: { redirectTo: string }) {
const { sub } = await this.authService.getCurrentUser();
this.protect({
redirectTo,
condition: !sub,
});
}
async protectByAuthAndRole({ roles, redirectTo }: ProtectByRoleProps) {
const { sub, role } = await this.authService.getCurrentUser();
// Verifica autenticación
this.protect({
redirectTo: redirectTo || "/login",
condition: !sub,
});
// Verifica rol
this.protect({
redirectTo: redirectTo || "/login",
condition: !role || !roles.includes(role),
});
}
}3. Layouts Protegidos
Los layouts pueden implementar protección adicional:
// app/(core)/dashboard/layout.tsx
export default async function DashboardLayout({
children,
}: {
children: React.ReactNode
}) {
// Protección de autenticación
await authGuard.protectByAuth({
redirectTo: "/login",
});
// Protección de onboarding
await onboardingGuard.protectByOnboarding({
redirectTo: "/onboarding",
});
return (
<div className="flex h-screen">
<SidebarFeat />
<div className="flex-1">
<InAppNavbarFeat />
{children}
</div>
</div>
);
}Patrones de Routing
1. Co-location de Recursos
Cada ruta puede contener sus recursos específicos:
login/
├── page.tsx # UI principal
├── loading.tsx # Estado de carga
├── error.tsx # Manejo de errores
└── not-found.tsx # 404 personalizado2. Layouts Anidados
Los layouts se heredan y combinan:
// Global layout (app/layout.tsx)
export default function RootLayout({ children }) {
return (
<html>
<body>{children}</body>
</html>
)
}
// Core layout (app/(core)/layout.tsx)
export default function CoreLayout({ children }) {
return (
<div className="admin-layout">
{children}
</div>
)
}3. Rutas Dinámicas
Para rutas con parámetros:
app/(core)/users/[id]/
├── page.tsx # /users/123
└── settings/
└── page.tsx # /users/123/settingsMejores Prácticas
-
Grupos Lógicos: Usar grupos de rutas para organizar páginas con comportamiento similar
-
Protección por Capas: Implementar seguridad en middleware, guards y layouts
-
Error Boundaries: Cada ruta debe manejar sus propios errores
-
Loading States: Implementar estados de carga específicos por ruta
-
Recursos Co-locados: Mantener recursos relacionados junto a sus rutas
-
Layouts Reutilizables: Compartir layouts entre rutas similares
Esta estructura de routing proporciona una base sólida para aplicaciones escalables y mantenibles, con una clara separación de responsabilidades y protección robusta.