Frederick Garcia
← Volver al Inicio

Lumera Learning Group

Lumera Learning Group (lumera-spa)

Una Single Page Application (SPA) de alto rendimiento, moderna y optimizada para SEO con Renderizado del Lado del Servidor (SSR) construida para Lumera Learning Group. La plataforma ofrece clases interactivas de aprendizaje de idiomas (español e inglés) para niños y adolescentes (de 4 a 18 años) impartidas por profesores nativos.


🌟 Resumen del Proyecto

Esta aplicación web sirve como el portal principal de Lumera Learning Group. Está construida para ofrecer una experiencia de usuario rápida y fluida en múltiples dispositivos, destacando:

  • Programación Dinámica de Clases: Integración en tiempo real con la API de Calendly para obtener, almacenar en caché y mostrar las categorías de clases disponibles.
  • Experiencia Completamente Traducida (i18n): Soporte nativo para inglés (en) y español (es) utilizando localización compilada de Angular, completa con enrutamiento de idiomas optimizado para SEO.
  • Formularios de Contacto Directo: Integración del lado del cliente con EmailJS para capturar de forma segura las consultas de los padres y los rangos de edad de los niños.
  • Rendimiento Altamente Optimizado: Aprovechamiento de la carga diferida basada en el viewport (@defer) y la hidratación de Angular para maximizar las métricas Core Web Vitals.

🛠️ Stack Tecnológico e Integraciones

El proyecto utiliza una arquitectura de frontend y servidor moderna:

1. Framework Principal y Entorno de Ejecución

  • Angular 21 (v21.2.0): Aprovecha las últimas innovaciones del framework, incluyendo componentes standalone, Signals, propiedades computadas, DestroyRef y la nueva sintaxis de plantillas @defer.
  • Angular Hydration y SSR: Renderizado del Lado del Servidor impulsado por @angular/ssr y Express para pre-renderizar rutas y servir HTML rápido y amigable para los rastreadores (crawlers).

2. Estilos y Sistema de Diseño

  • Tailwind CSS v4 (@tailwindcss/postcss & tailwindcss v4.1.12): Construido usando el nuevo compilador @theme de Tailwind CSS v4 y propiedades personalizadas de CSS dentro de src/styles.css para una paleta en tonos pastel personalizada, micro-animaciones fluidas y diseños responsivos.
  • Tipografía: Integración de Google Fonts (Nunito) configurada globalmente para una estética de interfaz legible y amigable para los niños.

3. Integraciones de API de Terceros

  • API de Calendly: Obtiene los eventos de clases activas de forma dinámica. Incluye una caché automática (warm-up cache) en la capa de servicios e inicia el Widget de Reservas de Calendly al hacer clic.
  • EmailJS (@emailjs/browser): Procesa los envíos de los formularios de contacto en el lado del cliente sin necesidad de un backend de base de datos personalizado, manteniendo una baja sobrecarga operativa.

4. Herramientas de Calidad y Construcción

  • Vitest: Reemplaza a Karma/Jasmine como el ejecutor de pruebas, ofreciendo tiempos de ejecución más rápidos durante las pruebas unitarias.
  • Postcss & Prettier: Garantiza activos de estilo limpios y auto-formateados.

📂 Estructura de Directorios del Proyecto

A continuación se presenta el diseño de los archivos fuente, reflejando un diseño altamente modular:

lumera-spa/
├── public/                       # Activos públicos estáticos
│   ├── assets/                   # Imágenes y gráficos de la marca
│   ├── _redirects                # Mapeo de redirecciones para Netlify / CDN
│   ├── robots.txt                # Directivas para rastreadores (crawlers)
│   └── sitemap.xml               # Sitemap SEO con etiquetas alternate hreflang
├── src/
│   ├── app/                      # Raíz principal de la aplicación Angular
│   │   ├── components/           # Componentes de UI reutilizables
│   │   │   ├── benefits-section.component.ts/.html
│   │   │   ├── class-gallery.component.ts/.html
│   │   │   ├── contact-form.component.ts/.html
│   │   │   ├── contact-section.component.ts/.html
│   │   │   ├── footer.component.ts/.html
│   │   │   ├── hero-section.component.ts/.html
│   │   │   ├── navbar.component.ts/.html
│   │   │   ├── testimonials-section.component.ts/.html
│   │   │   └── whatsapp-button.component.ts/.html
│   │   ├── models/               # Interfaces TypeScript
│   │   │   └── calendly.model.ts
│   │   ├── pages/                # Componentes de página de alto nivel (vistas)
│   │   │   ├── blog/             # Componentes de entradas de blog individuales
│   │   │   ├── blog-hub/         # Tablero de listado del blog
│   │   │   ├── home/             # Vista de la página de inicio (carga diferida de secciones)
│   │   │   └── pricing/          # Opciones de productos y listas de precios de cursos
│   │   ├── services/             # Servicios de API y utilidades del DOM
│   │   │   ├── calendly-api.service.ts
│   │   │   └── external-scripts.service.ts
│   │   ├── app.config.ts         # Proveedores principales de configuración CSR/Hydration
│   │   ├── app.config.server.ts  # Configuraciones específicas del servidor
│   │   ├── app.routes.ts         # Definiciones de enrutamiento de navegación
│   │   ├── app.ts                # Componente raíz (gestiona las etiquetas SEO y JSON-LD)
│   │   ├── app.html / app.css
│   │   └── tokens.ts             # Tokens de inyección de URL base para SSR
│   ├── environments/             # Configuraciones de entorno
│   │   ├── environment.ts        # Valores de desarrollo local (incluye tokens locales)
│   │   └── environment.prod.ts   # Valores de producción
│   ├── locale/                   # Recursos de localización i18n XLF
│   │   ├── messages.xlf          # Diccionario de origen base extraído
│   │   ├── messages.en.xlf       # Archivo de traducción al inglés
│   │   └── messages.es.xlf       # Archivo de traducción al español
│   ├── main.ts                   # Punto de entrada de inicio del cliente
│   ├── main.server.ts            # Punto de entrada de inicio del servidor
│   ├── server.ts                 # Configuración del servidor SSR de Express
│   └── styles.css                # Estilos globales y configuración de Tailwind
├── angular.json                  # Archivo de configuración de Angular CLI
├── package.json                  # Definición de dependencias y scripts
├── tailwind.config.js            # Configuración heredada de Tailwind (si se necesita compatibilidad)
└── tsconfig.json                 # Configuración del compilador TypeScript

📊 Modelos de Datos

Modelo de Integración con Calendly (src/app/models/calendly.model.ts)

Interfaces estandarizadas que modelan la carga útil (payload) proveniente del endpoint de Tipos de Eventos de Calendly:

export interface CalendlyEventType {
  name: string;
  description_plain: string;
  description_html: string;
  scheduling_url: string;
  duration: number;
  color: string;
  active: boolean;
}

export interface CalendlyResponse {
  collection: CalendlyEventType[];
  pagination: {
    count: number;
    next_page: string | null;
  };
}

🔒 Configuración de Seguridad y Rendimiento

La base de código se adhiere a estrictas prácticas recomendadas de seguridad y rendimiento de frontend:

1. Salvaguardias de Seguridad

  • Inyección Segura Renderer2: La aplicación inyecta esquemas JSON-LD estructurados dentro del <head> del HTML utilizando Renderer2 de Angular para prevenir vulnerabilidades de secuencias de comandos entre sitios (XSS).
  • Saneamiento de Entradas: El formulario de contacto impone límites de tamaño (validación maxLength en nombres, edad del niño, correo electrónico y mensajes) y restricciones de tipo estrictas a través de ReactiveFormsModule de Angular.
  • Lógica de Servidor Desacoplada: La integración en el lado del cliente con EmailJS y Calendly asegura que ninguna credencial de base de datos o tokens de sesión estén expuestos al cliente o almacenados en bases de datos personalizadas, eliminando los vectores de explotación de bases de datos del lado del servidor.
  • Protección de Plataforma (Platform Guarding): Los servicios que verifican la manipulación del DOM (como la carga de scripts de Calendly o el seguimiento de tamaños de pantalla) envuelven las ejecuciones en comprobaciones isPlatformBrowser, previniendo bloqueos o fugas de datos en la capa del servidor SSR.

2. Ingeniería de Rendimiento

  • Capa de Caché: El servicio CalendlyApiService almacena en caché la lista de tipos de eventos utilizando shareReplay(1) de RxJS. Cuando el usuario está en la página de precios, se llama al servicio en la inicialización (ngOnInit), preparando la caché para que el widget se cargue instantáneamente cuando se solicite.
  • Carga Diferida de Scripts: En lugar de bloquear la carga de la página con scripts en el archivo index principal, ExternalScriptsService monta dinámicamente scripts y hojas de estilo (ej. widgets de Calendly) en el DOM solo cuando el usuario abre la sección correspondiente.
  • Aplazamientos del Viewport (@defer): El pie de página, los testimonios, el contacto y las secciones de beneficios se renderizan de forma diferida solo cuando entran en el viewport (@defer (on viewport)), mejorando drásticamente las métricas iniciales de carga de página.
  • Optimización de Change Detection: Los componentes esenciales utilizan ChangeDetectionStrategy.OnPush para evitar re-renderizados innecesarios del árbol de componentes, reduciendo la sobrecarga de la CPU.

🌐 SEO e Internacionalización (i18n)

El SEO es un pilar principal de la implementación de la aplicación:

1. Meta Etiquetas Dinámicas y Enlaces

  • Enlace Canónico (Canonical Linking): Durante la navegación, la aplicación actualiza el elemento <link rel="canonical"> en el encabezado, apuntando a la página actual exacta con barras finales (trailing slashes) para alinearse con los sitemaps y los CDN.
  • Mapeo Multi-Idioma (hreflang): Configura el mapeo <link rel="alternate" hreflang="xx"> para español, inglés y x-default (apuntando a la versión en inglés) para resolver problemas de redirección en los motores de búsqueda.

2. Datos Estructurados (Esquemas JSON-LD)

  • Esquema de Organización (Organization Schema): Implementado en la vista de inicio para identificar el negocio, los nombres de marca, la URL web, el logotipo, la descripción y las propiedades oficiales en redes sociales.
  • Esquema de Lista de Artículos y Cursos (ItemList & Course Schema): Incrustado en la vista de precios para estructurar la información sobre los programas de idiomas para niños y adolescentes, incluyendo nombres, proveedores y precios (USD) para los Rich Snippets de Google.

3. Compilaciones Multi-Idioma

Debido a que Angular compila carpetas estáticas por separado para cada idioma (/en y /es), el enrutamiento se configura mediante redirecciones de Netlify (public/_redirects):

/ /en/ 301
/es/* /es/index.html 200
/en/* /en/index.html 200

Esto fuerza una recarga completa cuando se cambia de idioma en el NavbarComponent, asegurando que el cliente descargue el paquete de JavaScript traducido correcto.


🧪 Validación de Implementación y Pruebas

Durante la auditoría de validación de la implementación, hemos verificado:

  1. Compilación de Producción Exitosa: El pipeline de construcción compila y genera correctamente los recursos del servidor SSR y 12 rutas estáticas localizadas para SSG.
  2. Ejecución de Vitest: Las pruebas unitarias están configuradas a través de Vitest. Las ejecuciones de pruebas iniciales fallan debido a la falta de contexto en los specs básicos por defecto.

Brechas de Pruebas Conocidas y Cómo Solucionarlas

Las pruebas unitarias predeterminadas fallan en:

  • ɵNotFound: NG0201: No provider found for ActivatedRoute: Componentes como App o Home importan RouterLink / NavbarComponent pero las configuraciones de prueba no proporcionan los módulos de enrutamiento.
  • Solución: Importar RouterModule y proporcionar los proveedores de enrutamiento usando provideRouter([]) dentro del bloque beforeEach de los archivos spec.
  • expect(compiled.querySelector('h1')?.textContent).toContain('Hello, lumera-spa'): La prueba aún espera el encabezado de plantilla por defecto, el cual ha sido eliminado.
  • Solución: Actualizar la aserción para consultar los componentes o textos actuales.

⚙️ Comandos de Desarrollo

Usa los siguientes scripts durante el desarrollo local y las compilaciones:

Ejecutar Servidor de Desarrollo Local

Para lanzar la aplicación localmente (por defecto en inglés):

npm run dev

Para ejecutarla específicamente en la configuración en inglés:

npm run dev:en

Construir para Producción

Para iniciar la doble compilación (en/es), pre-renderizar las vistas HTML estáticas y copiar las reglas de redirección/SEO a la salida pública:

npm run build

Servir la Compilación SSR

Para previsualizar la aplicación con Renderizado del Lado del Servidor en el localhost (puerto 4000):

npm run serve

Ejecutar Pruebas Unitarias con Vitest

Para ejecutar los specs de Vitest localmente:

npm run test