Plataforma de reseñas de videojuegos. Proyecto Integrador IFTS24.
| Tecnología | Versión | Rol |
|---|---|---|
| Next.js | 16 | Framework (App Router) |
| React | 19 | UI |
| TypeScript | 5 | Tipado estático |
| Tailwind CSS | 4 | Estilos |
| Zustand | 5 | Estado global |
| React Hook Form + Zod | 7 / 4 | Formularios + validación |
| @phosphor-icons/react | 2 | Iconografía |
| next-themes / sonner | – | Tema claro/oscuro · Toasts |
# 1. Instalar dependencias
npm install
# 2. Crear variables de entorno
echo "NEXT_PUBLIC_API_URL=http://localhost:3333" > .env.local
# 3. Correr en desarrollo
npm run dev # → http://localhost:3000Otros scripts:
npm run build # Build de producción
npm run lint # ESLint
npm run lint:fix # ESLint con autocorrección
npm run format # Prettier
npx tsc --noEmit # Verificar tipos sin compilarrank_app/
├── app/ # Rutas (Next.js App Router)
│ ├── layout.tsx # Layout raíz — fuentes, ThemeProvider, SEO global
│ ├── (landing)/
│ │ ├── (home)/page.tsx # /
│ │ └── (auth)/ # /login /register /forgot-password /change-password
│ └── (user)/dashboard/
│ ├── page.tsx # /dashboard
│ ├── explorar/ # /dashboard/explorar
│ ├── juegos/ # /dashboard/juegos
│ ├── perfil/ # /dashboard/perfil
│ ├── ayuda/ # /dashboard/ayuda
│ ├── acerca-de-rank/ # /dashboard/acerca-de-rank
│ ├── sobre-nosotros/ # /dashboard/sobre-nosotros
│ ├── (admin)/ # Guard → solo rol admin
│ │ ├── banners/ # /dashboard/banners
│ │ ├── sponsors/ # /dashboard/sponsors
│ │ └── usuarios/ # /dashboard/usuarios
│ └── (reviewer)/ # Guard → solo rol moderator
│ └── resenias/ # /dashboard/resenias
│
├── features/ # Lógica de negocio por dominio
│ ├── auth/ # Login, registro, recuperación de contraseña
│ ├── admin/ # Backoffice: usuarios, banners, sponsors, reseñas
│ ├── landing/ # Página pública de inicio
│ ├── user/
│ │ ├── explorer/ # Búsqueda y detalle de juegos
│ │ └── review/ # Crear y gestionar reseñas
│ └── shared/ # Código transversal
│ ├── about/ # Sub-módulo: páginas y componentes de "Sobre nosotros" / "Acerca de"
│ ├── help/ # Sub-módulo: tickets de ayuda (componentes, hooks, schemas, servicios)
│ ├── profile/ # Sub-módulo: perfil de usuario (store, componentes, schemas)
│ ├── components/ # Componentes transversales sin sub-carpetas (AdBanner, GameSearchField…)
│ ├── services/ # banners, sponsors, stats, games, reviews, users…
│ ├── store/ # useModalsStore, banners.store, sponsors.store, view-mode.store
│ ├── types/ # User, ApiResponse, UserRole, Game, Review…
│ ├── hooks/ # useAuthRouteGuard, useAuthHydration, useTableQueryParams
│ ├── constants/ # modals.constants, nav.constants
│ ├── providers/ # ThemeProvider
│ └── utils/ # user.utils
│
├── ui/ # Sistema de diseño — ver ui/README.md
└── public/ # Assets estáticos (logos, privacy, terms)
Cada feature sigue la misma estructura interna:
pages/·components/·services/·store/·schemas/·hooks/
type UserRole = 'user' | 'moderator' | 'admin'| Rol | Rutas disponibles |
|---|---|
user |
/dashboard · explorar · juegos · perfil · ayuda · acerca · sobre-nosotros |
moderator |
Todo lo de user + /dashboard/resenias |
admin |
/dashboard · perfil · sobre-nosotros · banners · sponsors · usuarios |
El layout de cada route group ((admin), (reviewer)) usa useAuthRouteGuard para redirigir si el rol no coincide. El Sidebar filtra los ítems automáticamente.
| Store | Path | Qué maneja |
|---|---|---|
useAuthStore |
features/auth/store/auth.store |
Usuario autenticado, token, login/logout |
useModalsStore |
features/shared/store/modals.store |
Apertura/cierre de modales por ID |
useProfileStore |
features/shared/profile/store/profile.store |
Perfil cargado, reseñas, loading |
MODAL_IDS está en features/shared/constants/modals.constants.
Alias @/ apunta a la raíz del proyecto:
import { Button, Heading } from '@/ui' // sistema de diseño
import { useAuthStore } from '@/features/auth/store/auth.store' // store
import type { User } from '@/features/shared/types/user.types' // tiposNunca usar rutas relativas que atraviesen features (../../shared/).
Todos los formularios usan React Hook Form + Zod vía @hookform/resolvers/zod.
Los schemas viven en features/<nombre>/schemas/.
// Patrón estándar
const form = useForm({ resolver: zodResolver(schema), defaultValues })
<Input
errorMessage={errors.campo?.message}
id="campo"
label="Label"
state={errors.campo ? 'error' : 'default'}
{...register('campo')}
/>
<Button loading={form.formState.isSubmitting} type="submit">Guardar</Button>Todos los componentes visuales viven en ui/ y son agnósticos (sin stores, sin roles).
Importar siempre desde el barrel:
import { Button, CardWrapper, Heading, Text, SpinLoader } from '@/ui'Ver ui/README.md para el catálogo completo de componentes.