Este documento describe la arquitectura técnica completa, organización del código, flujo de datos, y prácticas de desarrollo para el frontend de Play2Learn (React + TypeScript + Vite).
- Arquitectura Técnica
- Estructura del Proyecto
- Módulos Principales
- Sistema de Autenticación y Roles
- Routing y Navegación
- Gestión de Estado
- Componentes Compartidos
- Testing Strategy
- Deployment
- Code Quality
Play2Learn es una SPA (Single Page Application) educativa construida con:
- Framework: React 19.1.0
- Build Tool: Vite 6.3.5
- Lenguaje: TypeScript 5.8.3
- Routing: React Router DOM 7.6.2
- Animaciones: Framer Motion 12.18.1
- HTTP Client: Axios 1.10.0
- Testing: Vitest 3.2.4
La aplicación se estructura en tres aplicaciones separadas según el rol del usuario:
App.tsx
└── AppShell.tsx (Router + Auth Check)
├── AdminApp.tsx (ROLE_ADMIN)
├── TeacherApp.tsx (ROLE_TEACHER)
└── StudentApp.tsx (ROLE_STUDENT)
Cada aplicación tiene su propio conjunto de:
- Providers (Context API)
- Routes (React Router)
- Views (Páginas/Vistas)
- Componentes específicos del rol
El proyecto sigue un patrón de organización por dominio/funcionalidad:
src/
├── [module]/
│ ├── components/ # Componentes UI específicos
│ ├── views/ # Vistas/páginas principales
│ ├── hooks/ # Custom hooks
│ ├── contexts/ # Context API providers
│ ├── services/ # Llamadas a API
│ ├── types/ # TypeScript types
│ ├── utils/ # Utilidades del módulo
│ └── constants/ # Constantes
src/
├── activity/ # Módulo de actividades educativas (juegos)
├── admin/ # Módulo de administración
├── apps/ # Aplicaciones por rol (AdminApp, TeacherApp, StudentApp)
├── App.tsx # Componente raíz con routing global
├── AppShell.tsx # Shell que decide qué app cargar según rol
├── benefit/ # Módulo de beneficios
├── investments/ # Módulo de inversiones (Plazo Fijo, Acciones)
├── main.tsx # Entry point de la aplicación
├── shared/ # Código compartido entre módulos
├── student/ # Módulo de estudiante
├── teacher/ # Módulo de profesor
├── user/ # Módulo de autenticación/usuarios
└── test/ # Tests
Propósito: Gestión de actividades educativas interactivas (juegos).
Tipos de Actividades:
- Ahorcado
- Árbol de Decisión
- Completar Oración
- Desafío de Clasificación
- Memorama
- No Lúdica
- Ordenar Secuencia
- Preguntados
Estructura:
activity/
├── components/ # Componentes de creación/configuración
├── contexts/ # Context providers por tipo de actividad
├── hooks/ # Hooks de creación y configuración
├── services/ # Servicios API por tipo de actividad
├── types/ # Types específicos de cada actividad
├── utils/ # Utilidades (mapeo de componentes, datos)
└── views/ # Vistas de creación y configuración
Flujo:
- Profesor crea/configura actividad →
create*ViewoconfigurationView - Estudiante juega actividad → Componentes de juego en
shared/components/Games/ - Sistema registra resultados → Context API + Services
Propósito: Panel de administración para gestión de entidades del sistema.
Entidades Gestionadas:
- Cursos (Courses)
- Estudiantes (Students)
- Materias (Subjects)
- Profesores (Teachers)
- Años (Years)
- Estadísticas (Statistics)
Estructura:
admin/
├── components/ # Componentes UI (Sidebar, Overview)
├── contexts/ # Context providers por entidad
├── hooks/ # Custom hooks (useCourse, useStudent, etc.)
├── pages/ # Dashboard principal
├── routes/ # Definición de rutas
├── services/ # Servicios API
├── types/ # Types de estadísticas
└── views/ # Vistas CRUD (List, Create)
Patrón CRUD:
List*View: Lista paginada con filtrosCreate*View: Formulario de creación/edición (reutilizable)
Propósito: Experiencia del estudiante (actividades, wallet, beneficios, tienda, inversiones).
Funcionalidades:
- Dashboard/Overview
- Actividades (listar, jugar, revisar completadas)
- Perfil y Avatar
- Wallet (balance, transacciones)
- Beneficios
- Tienda (Store)
- Ranking
- Educación Financiera
- Inversiones (Acciones, Plazo Fijo)
Estructura:
student/
├── adapters/ # Adaptadores de datos
├── components/ # Componentes UI específicos
├── constants/ # Constantes
├── context/ # Context providers (CurrentStudent, Wallet, Activity, etc.)
├── hooks/ # Custom hooks
├── pages/ # Dashboard
├── routes/ # Rutas del estudiante
├── services/ # Servicios API
├── types/ # Types
├── utils/ # Utilidades
└── views/ # Vistas principales
Propósito: Panel del profesor para crear actividades y gestionar beneficios.
Funcionalidades:
- Dashboard/Overview
- Crear/Configurar Actividades
- Gestionar Beneficios (listar, crear)
- Estadísticas
Estructura:
teacher/
├── components/ # Componentes UI
├── constants/ # Constantes
├── contexts/ # Context providers (Benefits, Statistics)
├── hooks/ # Custom hooks
├── pages/ # Dashboard
├── routes/ # Rutas
├── services/ # Servicios API
├── types/ # Types
├── utils/ # Utilidades
└── views/ # Vistas (Activities, Benefits, Overview)
Propósito: Sistema de inversiones (Plazo Fijo y Acciones).
Funcionalidades:
- Vista de inversiones (overview)
- Plazo Fijo (crear, listar, filtrar por estado)
- Acciones (listar, ver detalles)
Estructura:
investments/
├── components/ # Componentes (PlazoFijoView, ActionsView, etc.)
├── contexts/ # Context providers (PlazoFijo, Actions)
├── hooks/ # Custom hooks (usePlazoFijo, useActions)
├── services/ # Servicios API
├── types/ # Types (plazoFijo, actions)
├── utils/ # Utilidades
└── views/ # Vistas principales
Flujo Plazo Fijo:
- Estudiante ve lista →
PlazoFijoView - Filtra por estado →
PlazoFijoFilter→ actualizapaginationParams - Crea nuevo plazo fijo →
CreatePlazoFijoForm→registerPlazoFijo - Sistema refresca lista manteniendo filtros
Propósito: Autenticación y gestión de usuarios.
Estructura:
user/
├── contexts/ # UserContext (auth state)
├── hooks/ # useAuth
├── pages/ # LoginPage
└── services/ # Servicios de autenticación
Propósito: Código reutilizable entre módulos.
Componentes:
- UI básicos:
Button,Input,Card,DataTable,Pagination - Juegos:
AhorcadoGame,CompletarOracionGame,PreguntadosGame, etc. - Utilidades:
LoadingSpinner,Toaster,ConfirmationModal,Tooltip
Hooks:
usePaginateParams: Gestión de paginación, filtros, búsqueda, ordenamientouseHandleApiError: Manejo centralizado de errores APIuseToaster: Notificaciones toastuseConfirmation: Modales de confirmación- Hooks de juegos:
useAhorcadoGame,usePreguntadosGame, etc.
Contexts:
ToasterProvider: Notificaciones globalesConfirmationProvider: Modales de confirmaciónGamesContext: Estados de juegos (por tipo)
Utils:
api.ts,apiAuth.ts,apiFormData.ts: Clientes HTTPProtectedRoute.tsx: Protección de rutas por rolcreateFilterHandler.ts: Utilidad para filtros
Registry/Strategies:
- Sistema de registro de juegos y renderers configurables
- Patrón Strategy para renderizado de configuraciones de juegos
type Role = "ROLE_ADMIN" | "ROLE_TEACHER" | "ROLE_STUDENT";- Login (
/login) →LoginPage - Verificación →
UserProvidervalida token/credenciales - Routing →
AppShellredirige según rol:ROLE_ADMIN→/dashboard/*→AdminAppROLE_TEACHER→/dashboard/teacher/*→TeacherAppROLE_STUDENT→/dashboard/student/*→StudentApp
ProtectedRoute verifica:
- Autenticación (
isAuthenticated) - Rol permitido (
allowedRoles) - Muestra loading durante verificación
/dashboard/overview
/dashboard/courses/list
/dashboard/courses/create
/dashboard/courses/edit/:id
/dashboard/students/list
/dashboard/students/create
/dashboard/students/edit/:id
/dashboard/subjects/list
/dashboard/subjects/create
/dashboard/subjects/edit/:id
/dashboard/teachers/list
/dashboard/teachers/create
/dashboard/teachers/edit/:id
/dashboard/years/list
/dashboard/years/create
/dashboard/years/edit/:id
/dashboard/teacher/overview
/dashboard/teacher/actividades/list
/dashboard/teacher/actividades/configuration/:code_game
/dashboard/teacher/actividad/configuration/:code_game
/dashboard/teacher/beneficio/list
/dashboard/teacher/beneficio/create
/dashboard/student/overview
/dashboard/student/profile
/dashboard/student/profile/avatar
/dashboard/student/wallet
/dashboard/student/actividades/list
/dashboard/student/actividades/:id/view
/dashboard/student/actividades/:id/play
/dashboard/student/actividades/:id/review
/dashboard/student/beneficios/list
/dashboard/student/store
/dashboard/student/ranking/list
/dashboard/student/wallet/financial-education
/dashboard/student/investmests/list
/dashboard/student/actions/list
/dashboard/student/actions/details/:id
/dashboard/student/plazo-fijo/list
Todas las apps usan framer-motion para transiciones:
AnimatePresencepara transiciones entre rutasmotion.divconinitial,animate,exitpara efectos
Cada módulo usa Context API para estado compartido:
Estructura típica:
contexts/
├── [Entity]Context.ts # Definición del contexto
├── [Entity]Context.type.ts # Types del contexto
└── [Entity]Provider.tsx # Provider component
Ejemplo: PlazoFijoContext
// Estado
- loading: boolean
- plazoFijos: PaginatedData<PlazoFijoResponse> | null
- statistics: StatisticsPlazoFijoResponse | null
// Acciones
- getPaginatedPlazoFijo(params)
- registerPlazoFijo(data)
- getStatisticsPlazoFijo()Los hooks exponen la lógica de negocio y estado:
Ejemplo: usePlazoFijoView
const {
// Paginación
paginationParams,
paginationInfo,
handlePageChange,
handlePageSizeChange,
handleFilter,
// Datos
plazoFijos,
statistics,
userBalance,
// Acciones
handleCreatePlazoFijo,
filterStatus,
setFilterStatus,
} = usePlazoFijoView();usePaginateParams gestiona:
page,page_sizeorder_by,order_typesearchfilters,filtersValues
Handlers:
handlePageChange(page)handlePageSizeChange(size)handleSort(column)handleSearch(value)handleFilter(filters, values)
Formularios:
Input,TextArea,BooleanInput,Label
Layout:
Card,FlexBox,Badge
Navegación:
Pagination,PaginateComponent
Feedback:
LoadingSpinner,Toaster,ConfirmationModal,Tooltip
Tablas:
DataTable(con paginación, ordenamiento, filtros)
Juegos (shared/components/Games/):
AhorcadoGame,CompletarOracionGame,PreguntadosGame, etc.
Estructura típica:
ComponentName/
├── ComponentName.tsx
├── ComponentName.module.css
└── index.ts (opcional)
Props tipadas con TypeScript:
type Props = {
// Props aquí
};
const ComponentName = ({ ...props }: Props) => {
// Implementación
};- Framework: Vitest 3.2.4
- UI Testing: @testing-library/react 16.3.0
- DOM Testing: @testing-library/jest-dom 6.7.0
test/
├── admin/ # Tests de módulo admin
├── student/ # Tests de módulo student
└── setupTests.ts # Configuración global
- Unit Tests: Hooks, utils, funciones puras
- Component Tests: Componentes UI aislados
- Integration Tests: Flujos completos (ej: crear plazo fijo → refrescar lista)
npm test # Ejecutar tests
npm test --ui # UI de Vitestnpm run build # TypeScript check + Vite buildOutput: dist/ (archivos estáticos)
Dockerfile multi-stage:
- Build: Node 18 → Instalar dependencias →
npm run build - Serve: Node 16 → Instalar
serve→ Servirdist/en puerto 3000
Variables esperadas (.env):
VITE_API_BASE_URL=https://api.example.com
Artefactos estáticos pueden desplegarse en:
- Netlify
- Vercel
- AWS S3 + CloudFront
- Docker container (con
serve)
- Strict Mode: Habilitado
- Tipos explícitos: En props, funciones públicas, contextos
- Evitar
any: Usarunknowno tipos específicos
- ESLint 9.25.0 con plugins:
eslint-plugin-react-hookseslint-plugin-react-refreshtypescript-eslint
Ejecución:
npm run lintNaming Conventions:
- Componentes:
PascalCase(ej:PlazoFijoView) - Hooks:
camelCasecon prefijouse(ej:usePlazoFijoView) - Types:
PascalCasecon sufijo.type.ts(ej:plazoFijo.type.ts) - Utils:
camelCase(ej:createFilterHandler)
Organización de Imports:
- React/React DOM
- Librerías externas
- Imports internos (shared primero, luego módulos)
- Types
- Estilos
Ejemplo:
import { useState, useEffect } from "react";
import { motion } from "framer-motion";
import { usePlazoFijoView } from "../../hooks/usePlazoFijo/usePlazoFijoView";
import type { FIXED_TERM_STATES } from "../../types/plazoFijo.type";
import styles from "./PlazoFijoView.module.css";-
Memoización:
useMemopara cálculos costososuseCallbackpara handlers pasados como props
-
Dependencias de Efectos:
- Incluir todas las dependencias en arrays de
useEffect - Evitar dependencias faltantes (causa bugs)
- Incluir todas las dependencias en arrays de
-
Accesibilidad:
aria-label,aria-presseden botonesroleen contenedores semánticostype="button"en botones no-submit
-
Manejo de Errores:
- Usar
useHandleApiErrorpara errores API - Mostrar feedback con
useToaster
- Usar
-
Loading States:
- Mostrar
LoadingSpinnerdurante operaciones async - Deshabilitar botones durante submit
- Mostrar
- Estudiante selecciona actividad →
StudentActivitiesView - Click "Jugar" → Navega a
StudentPlayActivityView - Carga juego → Componente de juego (
AhorcadoGame, etc.) - Usuario completa → Submit resultados
- Sistema registra → Actualiza wallet/balance
- Redirige a review →
StudentCompletedActivityView
- Profesor navega a actividades →
ActivitiesView - Selecciona tipo → Navega a
ConfigureActivityView - Completa configuración → Submit
- Sistema crea actividad → Disponible para estudiantes
- Testing: Aumentar cobertura de tests (especialmente hooks y flujos críticos)
- Performance: Implementar React.memo en componentes pesados
- Error Boundaries: Añadir error boundaries para capturar errores de render
- Documentación: Añadir JSDoc a funciones/hooks públicos
- Type Safety: Revisar y fortalecer tipos en servicios API
Última actualización: 2025-11-06