Arquitectura del Motor
El motor de invitaciones es el nucleo de generación de HTML en Nvito. Su responsabilidad es tomar la configuración de una invitación (secciones, estilos, datos del evento, transiciones, loaders) y producir un documento HTML completo, autocontenido y listo para servir desde CDN. El resultado final se almacena en S3 (MinIO en desarrollo, Cloudflare R2 en producción) como un conjunto de archivos HTML, CSS y JavaScript.
Flujo de Generación HTML
Flujo de Generacion HTML
Componentes del Motor
| Componente | Responsabilidad |
|---|---|
| DocumentGeneratorService | Orquestador principal. Coordina la compilacion de secciones, inyección de transiciones, loaders y particulas. Produce el documento HTML final y lo sube a S3. |
| TemplateCompilerService | Motor de compilacion de templates. Resuelve variables ({{eventName}}), loops ({{#each items}}), condicionales ({{#if condition}}), e iconos ({{icon:calendar}}). Procesa en orden: loops primero, luego condicionales, luego iconos, y finalmente variables. |
| HtmlGenerationModule | Modulo que toma las secciones individuales ya compiladas y las ensambla en un documento HTML completo con <head>, estilos globales, scripts, y la estructura de secciones fullpage. |
| TransitionEngine | Genera el CSS y JavaScript necesario para las transiciones entre secciones. Soporta tanto transiciones CSS puras como transiciones Canvas 2D cinematograficas. |
| LoaderGenerator | Produce el HTML, CSS y JavaScript de la pantalla de carga que se muestra mientras la invitación carga sus recursos. |
| ParticleGenerator | Genera el código Canvas 2D para los 26 tipos de particulas utilizados por transiciones y loaders. |
Almacenamiento en S3
El motor sube los archivos generados a un bucket S3 con la siguiente estructura:
invitations/
{organizationId}/
{invitationId}/
index.html # Documento HTML principal
styles.css # Estilos compilados del tema
scripts.js # JavaScript interactivo (RSVP, gallery, etc.)
transitions.js # Motor de transiciones (si aplica)
loader.js # Pantalla de carga (si aplica)
En desarrollo se utiliza MinIO como implementación local compatible con S3. En producción se utiliza Cloudflare R2, que ofrece compatibilidad con la API de S3 sin costos de egress.
Orden de Compilacion del TemplateCompiler
El TemplateCompilerService procesa el template en un orden estricto para evitar conflictos entre las distintas directivas:
- resolveLoops — Expande
{{#each items}}...{{/each}}iterando sobre arrays del contexto. Resuelve{{this.campo}}dentro del loop. - resolveConditionals — Evalua
{{#if condición}}...{{/if}}y{{#unless condición}}...{{/unless}}. Remueve bloques no aplicables. - resolveIcons — Reemplaza
{{icon:nombre}}por el SVG correspondiente del catálogo de iconos. - resolveVariables — Sustituye
{{variable}}por el valor del contexto de datos del evento.
Este orden es critico: los loops deben resolverse primero porque pueden contener iconos anidados (por ejemplo {{icon:{{this.icon}}}} dentro de un {{#each}}). El loop resuelve {{this.icon}} a un nombre concreto, dejando {{icon:calendar}} que el paso de iconos procesa correctamente.
Secciones de Invitación
Cada invitación está compuestá por múltiples secciones, donde cada sección representa un bloque visual con un tipo específico, configuración JSON y un orden de aparicion. Las secciones son la unidad fundamental de composición del motor.
Tipos de Sección
| Tipo | Descripción | Configuración tipica |
|---|---|---|
| Hero | Sección principal con imagen de fondo, nombres de los anfitriones y fecha | Imagen, overlay, tipografia, layout |
| RSVP | Formulario de confirmación de asistencia | Campos habilitados, texto de botones, opciones de acompanantes |
| Location | Mapa y direccion del evento | Coordenadas, nombre del lugar, indicaciones, mapa embebido |
| Itinerary | Agenda del evento con horarios y actividades | Array de items con hora, título, descripción, icono |
| Gallery | Galería de fotos | Array de URLs de imagenes, layout (grid/carousel/masonry) |
| Countdown | Cuenta regresiva al evento | Fecha objetivo, formato de display, estilo visual |
| Story | Historia de la pareja o contexto del evento | Texto enriquecido, imagenes opcionales |
| Dress Code | Código de vestimenta | Nivel de formalidad, colores, notas adicionales |
| Gift Registry | Mesa de regalos con enlaces externos | Array de items con nombre, URL, imagen |
| Accommodation | Información de hospedaje | Array de hoteles con nombre, direccion, URL de reserva |
| Custom | Sección personalizada con HTML libre | HTML del usuario, estilos custom |
Modelo de Datos
Cada sección se almacena en la tabla InvitationSection con los siguientes campos principales:
| Campo | Tipo | Descripción |
|---|---|---|
id | UUID | Identificador único |
invitationId | UUID | Referencia a la invitación padre |
type | enum | Tipo de sección (Hero, RSVP, etc.) |
config | JSON | Configuración específica del tipo |
order | number | Posición en la secuencia de secciones |
visible | boolean | Si la sección se incluye en el render |
title | string | Titulo opcional mostrado en la navegación |
Restricciones
- El número máximo de secciones depende del plan contratado por la organización.
- Solo las secciones con
visible: truese incluyen en el HTML generado. - La sección Hero siempre debe ser la primera (order = 0) y no puede ocultarse.
- Las secciones se renderizan como páginas fullpage, donde cada sección ocupa el 100% del viewport y se navega entre ellas con scroll o transiciones.
Sistema de Transiciones Fullpage
El sistema de transiciones controla como se anima el cambio entre secciones cuando el usuario navega la invitación. Nvito ofrece 27 transiciones divididas en dos categorías: clasicas (CSS puro) y cinematograficas (Canvas 2D con motor de 3 fases).
Catálogo de Transiciones
Transiciones Clasicas (10) — CSS Only
| Nombre | Descripción | Duracion Total |
|---|---|---|
fade | Desvanecimiento suave entre secciones | ~1.1s |
slide | Deslizamiento horizontal/vertical | ~1.3s |
curtain | Efecto cortina que se abre/cierra | ~1.5s |
wipe | Barrido lineal que revela la siguiente sección | ~1.3s |
zoom | Zoom in/out con desvanecimiento | ~1.4s |
morph | Transformacion fluida entre formas | ~1.5s |
reveal | Revelado desde el centro hacia los bordes | ~1.3s |
parallax-shift | Movimiento parallax con profundidad | ~1.5s |
star-wipe | Barrido en forma de estrella | ~1.7s |
dissolve | Disolución pixelada progresiva | ~1.4s |
Transiciones Cinematograficas (17) — Canvas 2D + 3 Fases
| Nombre | Descripción | Tipo de Efecto |
|---|---|---|
celestial-veil | Velo de estrellas que cubre y descubre | Particulas naturales |
golden-sweep | Barrido dorado con particulas brillantes | Particulas naturales |
petal-drift | Petalos flotando durante la transición | Particulas naturales |
confetti-burst | Explosion de confeti colorido | Tematico (__tc) |
leaf-cascade | Cascada de hojas cayendo | Particulas naturales |
sacred-glow | Resplandor sagrado con halo de luz | Particulas naturales |
butterfly-waltz | Mariposas volando entre secciones | Particulas naturales |
shimmer-veil | Velo brillante con destellos | Tematico (__tc) |
bubble-rise | Burbujas ascendentes | Particulas naturales |
firework-bloom | Fuegos artificiales que florecen | Tematico (__tc) |
feather-fall | Plumas cayendo suavemente | Particulas naturales |
aurora-wave | Onda de aurora boreal | Particulas naturales |
neon-grid | Rejilla neon que se ilumina | Tematico (__tc) |
rose-bloom | Petalos de rosa abriendose | Particulas naturales |
geometric-reveal | Formas geometricas que revelan (CSS-only) | CSS |
ink-bleed | Efecto de tinta expandiendose (CSS-only) | CSS |
ribbon-unfurl | Cintas desenrollandose (CSS-only) | CSS |
Motor de 3 Fases
Las transiciones cinematograficas siguen un ciclo de 3 fases ejecutado por el TransitionEngine:
Motor de 3 Fases — Transiciones Cinematograficas
idle→closeUsuario navega a otra seccionclose→stampOverlay cubre viewportstamp→openMonograma mostradoopen→doneSeccion nueva visibleDetalle de las Fases
Fase CLOSE (IN: 0.9s)
El overlay comienza a cubrir el viewport. Si la transición tiene Canvas, el efecto visual se inicia simultaneamente sobre el overlay. El usuario ya no puede interactuar con la sección actual. El Canvas se inicializa con requestAnimationFrame para renderizar el efecto a 60fps.
Fase STAMP (1.0s total) Una vez que el viewport está completamente cubierto, aparece el monograma del evento (iniciales de los anfitriones) con una animación de entrada (0.7s). Debajo del monograma se muestra el nombre de la sección destino. El monograma se mantiene visible brevemente y luego sale con una animación de desvanecimiento (0.6s).
Fase OPEN (OUT: 0.85s)
El overlay sale de escena revelando la sección destino ya posicionada debajo. El Canvas se detiene y se limpia (cancelAnimationFrame + clear del contexto). Los event listeners temporales se remueven.
Timing Comparativo
| Aspecto | Clasicas | Cinematograficas |
|---|---|---|
| Duracion total | ~1.1 - 1.7s | ~2.75s |
| IN (entrada) | 0.55 - 0.9s | 0.9s |
| STAMP | No aplica | 1.0s |
| OUT (salida) | 0.5 - 0.8s | 0.85s |
| Easing | cubic-bezier(0.4, 0, 0.2, 1) | cubic-bezier(0.4, 0, 0.2, 1) |
| Canvas | No | Si (excepto geometric-reveal, ink-bleed, ribbon-unfurl) |
Modelo TransitionStyleDefinition
Cada transición se define como un objeto TransitionStyleDefinition con los siguientes campos:
| Campo | Tipo | Descripción |
|---|---|---|
name | string | Identificador único de la transición |
category | 'classic' | 'cinematic' | Categoría de la transición |
suggestedFor | string[] | Tipos de evento recomendados |
overlayJs | string | Código JavaScript del efecto Canvas (solo cinematograficas) |
overlayHtml | string | HTML adicional para el overlay |
stampHoldMs | number | Duracion del hold del monograma en milisegundos |
hasCanvas | boolean | Si la transición usa Canvas 2D |
sectionLabel | boolean | Si muestra el nombre de la sección destino |
Pantallas de Carga (Loaders)
Las pantallas de carga se muestran mientras la invitación carga sus recursos (imagenes, fuentes, scripts). El loader debe dar una experiencia visual atractiva que mantenga la atencion del usuario durante los segundos iniciales.
Catálogo de Loaders
CSS Clasicos (8)
| Nombre | Descripción | Estilo Visual |
|---|---|---|
gold-calligraphy | Texto caligrafico dorado con animación de escritura | Elegante, bodas |
celestial-stars | Estrellas parpadeando sobre fondo oscuro | Nocturno, misterioso |
mínimal-elegant | Linea mínimalista con progreso | Moderno, limpio |
festive-burst | Explosion festiva de colores | Fiestas, cumpleaños |
romantic-petals | Petalos cayendo con suavidad | Romantico, bodas |
dark-cinematic | Barra cinematografica con efecto filmico | Sofisticado, galas |
royal-ornament | Ornamentos reales con filigrana | Formal, ceremonias |
modern-glitch | Efecto glitch digital con distorsion | Moderno, tech |
Canvas 2D Cinematograficos (17)
| Nombre | Tipo de Color | Descripción |
|---|---|---|
diamond-cascade | Tematico (__tc) | Cascada de diamantes brillantes |
spiral-galaxy | Tematico (__tc) | Galaxia espiral girando |
watercolor-bloom | Tematico (__tc) | Manchas de acuarela expandiendose |
electric-pulse | Tematico (__tc) | Pulsos electricos neon |
sakura-wind | Natural (fijo) | Flores de sakura en el viento |
golden-dust | Tematico (__tc) | Polvo dorado flotando |
geometric-rain | Tematico (__tc) | Lluvia de formas geometricas |
lantern-glow | Tematico (__tc) | Linternas flotantes brillando |
confetti-shower | Tematico (__tc) | Lluvia de confeti |
ink-drops | Natural (fijo) | Gotas de tinta expandiendose en agua |
northern-lights | Natural (fijo) | Aurora boreal ondulante |
heartbeat-pulse | Natural (fijo) | Pulso de corazon con ondas |
firefly-meadow | Natural (fijo) | Luciernagas en un prado nocturno |
wave-horizon | Natural (fijo) | Olas en el horizonte |
stained-glass | Natural (fijo) | Vitral iluminandose progresivamente |
ticker-tape | Tematico (__tc) | Cinta de teletipo cayendo |
cross-of-light | Natural (fijo) | Cruz de luz expandiendose |
Generación de Loaders
La función generateLoaderJs recibe un objeto LoaderStyleDefinition completo (no solo la duracion) y produce el código JavaScript que inicializa el loader. Para loaders Canvas, el código generado incluye:
- Inicializacion del Canvas — Crea el elemento
<canvas>, lo dimensiona al viewport y obtiene el contexto 2D. - Loop de animación — Usa
requestAnimationFramepara renderizar particulas o efectos a 60fps. - Barra de progreso — Superpuestá al efecto, muestra el porcentaje de carga real.
- Cleanup — Al completar la carga, detiene el loop, remueve el canvas y ejecuta la animación de salida.
Modelo LoaderStyleDefinition
| Campo | Tipo | Descripción |
|---|---|---|
name | string | Identificador único del loader |
category | 'classic' | 'cinematic' | Categoría |
hasCanvas | boolean | Si usa Canvas 2D |
canvasJs | string | Código JavaScript del efecto Canvas |
css | string | Estilos CSS del loader |
html | string | HTML del loader (estructura base) |
progressBar | object | Configuración de la barra de progreso (color, posición, estilo) |
Responsividad y Accesibilidad
Los loaders Canvas implementan dos mecanismos de fallback para garantizar una buena experiencia en todos los dispositivos:
Mobile fallback: En pantallas menores a 640px de ancho, el Canvas se oculta y solo se muestra la versión CSS del loader. Esto evita problemas de rendimiento en dispositivos moviles con GPUs limitadas y reduce el consumo de bateria.
Reduced motion: Cuando el usuario tiene activada la preferencia prefers-reduced-motion: reduce en su sistema operativo, el Canvas se oculta completamente. La barra de progreso y el texto del loader se mantienen visibles pero sin animaciones, respetando la preferencia de accesibilidad del usuario.
Particulas Canvas 2D
El motor de particulas es un subsistema compartido por transiciones y loaders que proporciona 26 tipos de particulas con fisica, ciclo de vida y funciones de dibujo independientes. Cada tipo de particula está disenado para representar un elemento visual específico con comportamiento fisico realista.
Arquitectura del Motor de Particulas
Cada tipo de particula se define como un objeto con tres responsabilidades:
- init() — Inicializa la particula con posición, velocidad, tamano, color y propiedades específicas del tipo (rotación, opacidad, forma).
- update(dt) — Actualiza la fisica de la particula en cada frame: gravedad, resistencia del aire, rotación, desvanecimiento. Recibe
dt(delta time) para animación independiente del framerate. - draw(ctx) — Dibuja la particula en el contexto Canvas 2D usando las primitivas apropiadas (arcos, paths, bezier curves, imagenes).
Catálogo de 26 Tipos de Particulas
| # | Tipo | Descripción | Usado por |
|---|---|---|---|
| 1 | Petalo | Petalos de flor con rotación 3D simulada | petal-drift, rose-bloom |
| 2 | Hoja | Hojas de arbol con caida realista | leaf-cascade |
| 3 | Estrella | Estrellas de 5 puntas con brillo pulsante | celestial-veil, celestial-stars |
| 4 | Confeti | Rectangulos de colores con giro biaxial | confetti-burst, confetti-shower |
| 5 | Mariposa | Mariposas con aleteo sinusoidal | butterfly-waltz |
| 6 | Burbuja | Esferas translucidas con reflejo | bubble-rise |
| 7 | Pluma | Plumas con caida flotante y balanceo | feather-fall |
| 8 | Destello | Puntos de luz con parpadeo aleatorio | golden-sweep, golden-dust |
| 9 | Fuego artificial | Explosion radial con trails | firework-bloom |
| 10 | Rosa | Petalos de rosa con apertura progresiva | rose-bloom |
| 11 | Neon | Segmentos de linea con glow | neon-grid |
| 12 | Shimmer | Fragmentos brillantes con ondulacion | shimmer-veil |
| 13 | Sakura | Flor de cerezo con 5 petalos definidos | sakura-wind |
| 14 | Diamante | Poligonos facetados con refracción | diamond-cascade |
| 15 | Galaxia | Puntos orbitales en espiral | spiral-galaxy |
| 16 | Acuarela | Manchas difusas con blending | watercolor-bloom |
| 17 | Pulso | Ondas concentricas expandiendose | electric-pulse, heartbeat-pulse |
| 18 | Geometria | Triangulos, circulos y cuadrados | geometric-rain |
| 19 | Linterna | Ovalo luminoso con halo suave | lantern-glow |
| 20 | Tinta | Gotas con expansion radial difusa | ink-drops |
| 21 | Aurora | Bandas ondulantes con gradiente | northern-lights, aurora-wave |
| 22 | Luciernaga | Puntos con trail fosforescente | firefly-meadow |
| 23 | Ola | Curvas sinusoidales con crestá | wave-horizon |
| 24 | Vitral | Poligonos con bordes oscuros y relleno translucido | stained-glass |
| 25 | Ticker | Rectangulos estrechos cayendo en cascada | ticker-tape |
| 26 | Cruz de luz | Rayos cruzados con expansion gradual | cross-of-light |
Ciclo de Vida de una Particula
Ciclo de Vida de una Particula
spawn→activePrimera iteracion del loopactive→activeupdate(dt) + draw(ctx) cada frameactive→fadingopacity < threshold o fuera de boundsfading→deadopacity llega a 0Cuando una particula "muere" (opacidad llega a 0 o sale completamente del viewport), se marca como inactiva y se remueve del array de particulas activas. El motor puede opcionalmente reciclar particulas muertas (respawn) si la transición o loader lo requiere para mantener una densidad visual constante.
Theme Color Bridge
El Theme Color Bridge es el subsistema que conecta los colores del tema de la invitación con los efectos Canvas 2D. Su proposito es que las transiciones y loaders cinematograficos se integren visualmente con el esquema de colores elegido por el usuario, manteniendo coherencia estetica sin sacrificar la identidad visual de particulas naturales.
Arquitectura
Theme Color Bridge
Funcionamiento
El archivo utils/theme-color-bridge.ts se ejecuta al iniciar la invitación y realiza las siguientes operaciones:
- Lectura de CSS variables — Lee las variables CSS del tema (
--t-overlay,--t-accent,--t-accent-light,--t-background,--t-primary) del elemento root del documento. - Conversión a RGB arrays — Convierte cada color hexadecimal o HSL a un array
[R, G, B](valores 0-255) para uso directo en el Canvas 2D. - Exposición global — Almacena los colores en
window.__tc(theme colors) como un objeto con propiedades:overlay,accent,accentLight,background,primary. Cada propiedad es un array[number, number, number].
El bridge se inyecta en dos puntos:
loader-base.js.ts— Para que los Canvas loaders accedan a__tcdurante su inicialización.transition-engine.ts— Para que las Canvas transiciones accedan a__tcal crear particulas.
Principio de Diseño: Paleta Derivada con Identidad Preservada
El bridge sigue un principio de diseño fundamental: las particulas que representan elementos naturales reconocibles mantienen sus colores reales, mientras que los elementos artificiales o abstractos adoptan la paleta del tema.
La razon es cognitiva: un petalo rosa, una hoja verde o una luciernaga amarilla son reconocibles por su color natural. Cambiar esos colores para "encajar" con el tema romperia la ilusion y haria que las particulas se vean genericas. En cambio, el confeti, las formas geometricas, las ondas neon o los destellos no tienen un color "correcto" inherente, por lo que se benefician de adoptar la paleta del tema para crear una experiencia visualmente integrada.
Clasificación de Canvas Loaders
9 loaders tematicos (usan __tc del tema):
| Loader | Por que es tematico |
|---|---|
diamond-cascade | Diamantes abstractos, sin color natural inherente |
spiral-galaxy | Galaxia estilizada, colores arbitrarios |
watercolor-bloom | Manchas de acuarela, cualquier color es válido |
electric-pulse | Pulsos electricos, color definido por estetica |
golden-dust | Polvo brillante, adaptable a cualquier paleta |
geometric-rain | Formas geometricas puras, sin referente natural |
lantern-glow | Linternas estilizadas, color ambiental |
confetti-shower | Confeti, inherentemente multicolor y adaptable |
ticker-tape | Cinta de papel, sin color fijo |
8 loaders con colores naturales fijos (NO usan __tc):
| Loader | Por que es natural |
|---|---|
sakura-wind | Flores de cerezo: siempre rosa palido |
firefly-meadow | Luciernagas: siempre amarillo-verde fosforescente |
northern-lights | Aurora boreal: siempre verde-azul-violeta |
heartbeat-pulse | Latido de corazon: siempre rojo |
cross-of-light | Luz: siempre blanco-dorado |
wave-horizon | Olas del mar: siempre azul-turquesa |
ink-drops | Tinta: siempre negro-gris oscuro |
stained-glass | Vitral: paleta fija multi-color clasica |
Clasificación de Canvas Transiciones
4 transiciones tematicas (usan __tc):
shimmer-veil— Destellos abstractos, color adaptableneon-grid— Rejilla neon, color definido por el temafirework-bloom— Fuegos artificiales, multicolor adaptableconfetti-burst— Explosion de confeti, inherentemente tematico
10 transiciones con colores naturales fijos (NO usan __tc):
petal-drift— Petalos: rosa y blancoleaf-cascade— Hojas: verdes y marronesbutterfly-waltz— Mariposas: colores de alas naturalesfeather-fall— Plumas: blancas y cremabubble-rise— Burbujas: translucidas con reflejo azuladorose-bloom— Rosa: rojo y rosasacred-glow— Luz sagrada: dorado y blancocelestial-veil— Estrellas: blanco y plateadogolden-sweep— Destellos dorados: siempre doradoaurora-wave— Aurora: verde-azul-violeta natural
Integración con CSS
Además del bridge para Canvas, los componentes CSS de transiciones y loaders utilizan variables CSS directamente con fallbacks:
/* Ejemplo de transición CSS tematizada */
.overlay-background {
background-color: var(--t-overlay, #0a0a0a);
}
.accent-glow {
color: var(--t-accent, #d4af37);
box-shadow: 0 0 20px var(--t-accent-light, rgba(212, 175, 55, 0.3));
}
/* Barra de progreso tematizada en todos los loaders */
.progress-bar {
background-color: var(--t-accent, #d4af37);
}
Esto garantiza que incluso si el JavaScript del bridge no se ejecuta (por ejemplo, con JavaScript deshabilitado), los estilos CSS tienen fallbacks razonables que mantienen la coherencia visual.
Personalización por Invitado
El motor soporta personalización de contenido por invitado a nivel de loader (pantalla de carga) y sección RSVP, utilizando un sistema de shortCodes únicos que vincula cada URL de invitación con un invitado específico.
Arquitectura
Cada invitado puede recibir una URL personalizada con el parametro ?t={shortCode}, donde shortCode es un identificador de 12 caracteres generado con crypto.randomBytes (71 bits de entropia, URL-safe). El shortCode se almacena en el modelo GuestAccessToken (campo shortCode, único por invitación).
Al abrir la invitación, el JavaScript inyectado en el HTML ejecuta el siguiente flujo:
- Extracción del shortCode — Lee el parametro
?t=de la URL actual. - Llamada al endpoint público —
GET /v1/invitations/public/guest/{shortCode}retorna datos NO sensibles del invitado:firstName,lastName,title,groupSize. - Inyección en el loader — El nombre con título formal (ej: "Bienvenido, Ing. Juan") se muestra durante la pantalla de carga usando
textContent(prevencion XSS). - Inyección en la sección RSVP — Un saludo personalizado (ej: "Ing. Juan, confirma tu asistencia") se muestra en la cabecera del formulario RSVP.
- Fallback generico — Si no hay shortCode, si el endpoint falla, o si el invitado no se encuentra, se muestran textos genericos configurables desde el editor.
Textos Configurables
Los textos de personalización son editables desde nvito-admin a traves del editor de invitaciones:
| Sección | Campo | Ejemplo con invitado | Fallback generico |
|---|---|---|---|
| Loader | loaderGreeting | "Bienvenido, Ing. Juan" | "Bienvenido" |
| RSVP | rsvpGreeting | "Ing. Juan, confirma tu asistencia" | "Confirma tu asistencia" |
Los templates de texto soportan el placeholder {guestName} que se resuelve en el cliente con el nombre completo del invitado (incluyendo título si existe).
Restricciones de Personalización
- El nombre del invitado solo se muestra en el loader y la sección RSVP. Las secciones hero y welcome NO muestran datos del invitado.
- Solo se exponen campos no sensibles: nombre, apellido, título y tamano de grupo. Email y teléfono nunca se envian al cliente.
- La personalización es 100% client-side: el HTML generado es identico para todos los invitados, y la resolución del nombre ocurre en JavaScript.
- Si el shortCode es invalido, está inactivo o ha expirado, el endpoint retorna 404 y se usan los textos de fallback.
- La inyección de texto usa
textContenten lugar deinnerHTMLpara prevenir XSS.
Botón "Agregar al Calendario"
El motor genera un botón flotante de tipo position: fixed en la esquina inferior derecha de la invitación que permite al invitado agregar el evento a su calendario. El botón muestra el texto "Agendar" con contraste dinámico calculado a partir del color de fondo del tema. El color se determina en tiempo de ejecución para garantizar legibilidad (WCAG AA).
Retrocompatibilidad
La feature es 100% retrocompatible. Las invitaciones que no incluyen ?t= en la URL funcionan normalmente mostrando los textos de fallback generico. El endpoint público de resolución de shortCode no afecta el rendimiento de invitaciones sin personalización porque la llamada solo se ejecuta si el parametro ?t= está presente.
Invitaciones Externas
Las invitaciones externas permiten a los usuarios subir HTML disenado fuera de Nvito y publicarlo a traves de la misma infraestructura de entrega (CDN, analiticas, RSVP). El motor diferencia entre invitaciones internas y externas a traves del enum InvitationSource.
Enum InvitationSource
| Valor | Descripción |
|---|---|
INTERNAL | Invitación creada con el motor de templates y el editor visual de Nvito (default) |
EXTERNAL | HTML disenado externamente, cargado por el usuario |
HtmlValidatorService
El HtmlValidatorService ejecuta 9 pasos de validación sobre el HTML externo antes de permitir su almacenamiento:
| Paso | Validación | Motivo |
|---|---|---|
| 1 | Tamano máximo | El archivo no puede exceder 5MB |
| 2 | HTML valido | El documento debe tener estructura HTML básica (html, head, body) |
| 3 | Sin scripts peligrosos | Rechaza script tags con src externo y llamadas a funciones de ejecución dinámica de código |
| 4 | Sin iframes externos | Rechaza iframes apuntando a dominios no permitidos |
| 5 | Sin formularios externos | Rechaza forms con action apuntando a dominios no permitidos |
| 6 | Sin event handlers inline | Rechaza onclick, onerror, onload y otros event handlers en atributos HTML |
| 7 | Sin CSS imports externos | Rechaza @import url() apuntando a dominios no permitidos |
| 8 | Encoding correcto | El documento debe estar en UTF-8 |
| 9 | Sin contenido ofensivo | Validación básica de contenido (opcional, configurable) |
Flujo de Upload
Flujo de Upload — Invitaciones Externas
Comportamiento Condicional en Publicación
Cuando una invitación externa se aprueba y publica, el flujo de publicación tiene una diferencia clave respecto a las invitaciones internas:
- INTERNAL: El
DocumentGeneratorServicegenera el HTML completo a partir de las secciones, lo compila, le inyecta transiciones/loaders/analiticas, y lo sube a S3. - EXTERNAL: El motor omite la generación HTML (ya existe en S3). Solo inyecta el snippet de analiticas en el HTML existente para tracking de visitas y RSVP.
Otros comportamientos condicionales:
- Edicion de secciones: Bloqueada para invitaciones externas (no tienen secciones editables).
- Versiónamiento: Deshabilitado (siempre versión 1). Para actualizar, el usuario hace re-upload del HTML completo.
- Transiciones y loaders: No aplican (el HTML externo maneja su propia navegación).
- IA conversacional: No disponible para invitaciones externas.
Testing
El motor de invitaciones cuenta con una cobertura de tests exhaustiva que cubre transiciones, loaders, integración tematica, el validador HTML y el compilador de templates.
Resumen de Tests
| Area | Tests | Cobertura |
|---|---|---|
| Transiciones (clasicas + cinematograficas) | 278 | Todas las 27 transiciones, timing, fases, Canvas init/cleanup |
| Loaders (CSS + Canvas) | 351 | Todos los 25 loaders, barra de progreso, responsividad, reduced motion |
| Integración tematica | 200 | Bridge __tc, 9 loaders tematicos, 8 naturales, 4 transiciones tematicas, 10 naturales |
| Total motor de invitaciones | 829 | - |
Que se Prueba
Transiciones:
- Cada transición genera CSS/JS valido
- Las fases CLOSE/STAMP/OPEN respetan el timing configurado
- Canvas init y cleanup se ejecutan correctamente
- El monograma y el label de sección se renderizan
- Los 14 tipos de evento de Nvito tienen al menos una transición sugerida
Loaders:
- Cada loader genera HTML/CSS/JS valido
- La barra de progreso refleja el porcentaje de carga
- Mobile fallback oculta Canvas en pantallas menores a 640px
- Reduced motion oculta Canvas con prefers-reduced-motion
- generateLoaderJs recibe LoaderStyleDefinition completo
Integración tematica:
- El bridge lee correctamente las CSS variables --t-*
- Los 9 loaders tematicos usan __tc para sus colores
- Los 8 loaders naturales NO usan __tc (colores fijos verificados)
- Las 4 transiciones tematicas usan __tc
- Las 10 transiciones naturales NO usan __tc
- Los 14 tipos de evento tienen cobertura tematica
HtmlValidatorService:
- 37 tests cubriendo los 9 pasos de validación
- Vectores de ataque XSS reales
- HTML malformado, encoding incorrecto, tamano excesivo
Referencias
Motor de Generación
- DocumentGeneratorService:
src/modules/invitations/services/document-generator.service.ts - TemplateCompilerService:
src/modules/invitations/services/template-compiler.service.ts - HtmlGenerationModule:
src/modules/invitations/html-generation/
Transiciones
- TransitionEngine:
src/modules/invitations/transitions/transition-engine.ts - Definiciones de transiciones:
src/modules/invitations/transitions/definitions/ - Tests:
src/modules/invitations/transitions/__tests__/
Loaders
- LoaderGenerator:
src/modules/invitations/loaders/loader-generator.ts - Definiciones de loaders:
src/modules/invitations/loaders/definitions/ - Tests:
src/modules/invitations/loaders/__tests__/
Particulas
- ParticleGenerator:
src/modules/invitations/particles/ - 26 tipos:
src/modules/invitations/particles/types/
Theme Bridge
- theme-color-bridge.ts:
src/modules/invitations/utils/theme-color-bridge.ts
Personalización por Invitado
- GuestAccessToken:
prisma/schema.prisma— Modelo con camposhortCode - Endpoint público:
src/modules/invitations/controllers/invitations.controller.ts—GET /v1/invitations/public/guest/:shortCode - Dispatchers:
src/modules/invitations/services/— Generación de shortCodes y URLs personalizadas
Invitaciones Externas
- HtmlValidatorService:
src/modules/invitations/services/html-validator.service.ts - ExternalInvitationService:
src/modules/invitations/services/external-invitation.service.ts - ExternalInvitationController:
src/modules/invitations/controllers/external-invitation.controller.ts
Documentación Relacionada
- Sistema de Invitaciones — Maquina de estados, flujos de creación, versionamiento
- Notificaciones y Comunicaciones — Envio de campanas relacionadas con invitaciones
- Invitaciones Publicas — Renderizado de invitaciones en nvito-invitations