Docs

Flujo de Check-in con QR

Generacion automatica de pases QR, escaneo en tiempo real y validacion con soporte offline para check-in de invitados el dia del evento.

Tabla de Contenidos

  1. Vision General
  2. Generacion de Pases QR
  3. Tipos de Pase
  4. Pre-carga para Modo Offline
  5. Escaneo de Codigos QR
  6. Validacion del Pase
  7. Flujo Completo: Generar, Escanear, Validar
  8. Cola Offline y Sincronizacion
  9. Casos de Error
  10. Archivos Clave

1. Vision General

El check-in con QR es la funcionalidad central del dia del evento. Permite al anfitrion (o a un colaborador con rol HOST) verificar la entrada de cada invitado escaneando un codigo QR unico desde la app movil o la PWA.

El sistema esta disenado para funcionar incluso sin conexion a internet, un escenario comun en salones de eventos, haciendas o locaciones rurales. Los pases se pre-cargan con anticipacion y las validaciones se ejecutan localmente, encolandose para sincronizacion posterior cuando la conexion se restablezca.

Numeros clave

ConceptoDetalle
Tiempo de validacion online< 200ms
Tiempo de validacion offline< 50ms (local)
Vigencia del paseConfigurable, por defecto hasta fin del evento
Formato del codigo QRString alfanumerico de 24 caracteres
Formato de imagenPNG Base64, 300x300px

2. Generacion de Pases QR

La generacion de pases QR es automatica y se dispara en dos momentos:

  1. Al agregar invitados: Cuando se importan invitados via CSV o se crean manualmente desde el admin, el sistema genera automaticamente un pase QR para cada uno
  2. Bajo demanda: El anfitrion puede regenerar pases desde el admin o la app movil

Proceso de generacion

  1. El admin o la app llama a POST /v1/qr-passes/generate con { guestId, eventId, type }
  2. QRPassesService.generate() ejecuta:
    • Verifica que el guest existe y pertenece al evento
    • Genera un codigo unico de 24 caracteres alfanumericos con crypto.randomBytes()
    • Genera la imagen QR en formato PNG Base64 (300x300px) usando la libreria qrcode
    • Crea el registro QRPass en la base de datos con estado ACTIVE
  3. Retorna el pase con codigo e imagen al cliente

Modelo QRPass

CampoTipoDescripcion
idUUIDIdentificador unico
guestIdUUIDInvitado propietario del pase
eventIdUUIDEvento asociado
codeString (24)Codigo alfanumerico unico
typeEnumENTRY, EXIT, VIP
imageBase64TextImagen QR en PNG Base64
isUsedBooleanSi el pase ya fue escaneado
usedAtDateTime (nullable)Momento del escaneo
scannedByUUID (nullable)ID del HOST que escaneo
checkInMethodEnumQR_SCAN, MANUAL, OFFLINE_SYNC
expiresAtDateTimeMomento de expiracion
createdAtDateTimeMomento de creacion

3. Tipos de Pase

El sistema soporta tres tipos de pase QR, cada uno con un proposito diferente:

TipoPropositoValidacion especial
ENTRYEntrada general al eventoNinguna adicional
EXITRegistro de salidaSolo valido si el guest ya hizo check-in
VIPAcceso a areas restringidas (mesa VIP, backstage)Verifica atributo VIP del guest

El tipo mas comun es ENTRY, que se genera automaticamente para todos los invitados. Los tipos EXIT y VIP se configuran manualmente por el anfitrion.

4. Pre-carga para Modo Offline

Para garantizar el funcionamiento sin conexion, los pases QR se pre-cargan en el dispositivo con anticipacion.

En la app nativa (nvito-client)

  • useQRPasses hook con staleTime: 10 * 60 * 1000 (10 minutos) y gcTime: 7 * 24 * 60 * 60 * 1000 (7 dias)
  • Los pases se almacenan en SecureStore con persistencia entre sesiones
  • React Query mantiene los datos en cache incluso sin conexion
  • El hook se ejecuta al entrar a la pantalla de scanner, precargando todos los pases del evento

En la PWA (nvito-pwa)

  • Los pases se almacenan en IndexedDB usando la tabla qr-passes
  • useOfflineData hook sincroniza los pases desde el BFF cuando hay conexion
  • La PWA puede funcionar como Service Worker para interceptar requests offline

Estructura del cache offline

Cada pase en cache contiene:

  • code: El codigo de 24 caracteres (para busqueda local)
  • guestId: Para actualizar el estado del invitado
  • guestName: Para mostrar en la UI de confirmacion
  • type: Tipo de pase
  • isUsed: Estado actual
  • tableNumber: Mesa asignada (si existe)
  • dietaryRestrictions: Restricciones alimentarias (para informar al staff)

5. Escaneo de Codigos QR

El escaneo utiliza tecnologias diferentes segun la plataforma:

App nativa: expo-camera

La app usa expo-camera con el modo de escaneo de codigos de barras:

  • Escaneo continuo en tiempo real
  • Feedback háptico via expo-haptics al detectar un codigo
  • Overlay visual con guia de encuadre
  • Linterna integrada para escaneo en condiciones de poca luz
  • StatsHeader muestra conteo en tiempo real: total invitados, checked-in, pendientes

PWA: html5-qrcode

La PWA usa la libreria html5-qrcode que accede a la camara via WebRTC:

  • Compatible con todos los navegadores modernos (Chrome, Safari, Firefox)
  • Seleccion de camara frontal/trasera
  • Misma UX de overlay y feedback que la app nativa
  • Fallback a input de archivo si la camara no esta disponible

6. Validacion del Pase

Una vez escaneado el codigo, la validacion sigue un proceso estricto.

Validacion online

  1. La app envia POST /v1/qr-passes/validate con { code, eventId }
  2. QRCheckInService.validate() ejecuta:
    • Busca el pase por code en la tabla qr_passes
    • Verifica que eventId coincida
    • Verifica que isUsed === false
    • Verifica que expiresAt > now()
    • Marca el pase como usado: isUsed = true, usedAt = now(), scannedBy = hostUserId, checkInMethod = QR_SCAN
  3. Actualiza el estado del guest: checkedIn = true, checkedInAt = now()
  4. Emite el evento de dominio GuestCheckedInEvent
  5. Crea un registro en AuditLog con tipo GUEST_CHECK_IN
  6. Retorna la confirmacion con datos del invitado (nombre, mesa, restricciones)

Validacion offline

  1. La app busca el codigo en el cache local (SecureStore o IndexedDB)
  2. Verifica isUsed === false y expiresAt > now() localmente
  3. Marca el pase como usado en el cache local
  4. Muestra la confirmacion al anfitrion
  5. Encola la operacion en la cola offline para sincronizacion posterior

Respuesta de validacion exitosa

CampoDescripcion
validtrue
guest.nameNombre completo del invitado
guest.tableNumberNumero de mesa asignada
guest.companionCountNumero de acompanantes
guest.dietaryRestrictionsRestricciones alimentarias
guest.notesNotas adicionales
checkInTimeTimestamp del check-in

7. Flujo Completo: Generar, Escanear, Validar

8. Cola Offline y Sincronizacion

La cola offline garantiza que ningun check-in se pierda aunque no haya conexion en el momento del escaneo.

Estructura de la cola

Cada operacion encolada contiene:

CampoDescripcion
idUUID unico de la operacion
typeQR_CHECK_IN
payload{ code, eventId, scannedAt, scannedBy }
createdAtMomento del escaneo offline
retryCountNumero de intentos de sincronizacion

Proceso de sincronizacion

Manejo de conflictos

El escenario de conflicto mas comun es: dos dispositivos escanean el mismo pase offline. Cuando ambos sincronizan, el segundo recibe un 409 Conflict. En ese caso:

  1. El sistema mantiene el primer check-in como valido (el que llego primero al servidor)
  2. El segundo dispositivo recibe una notificacion de conflicto con el timestamp del check-in original
  3. El conflicto se registra en AuditLog para revision posterior

Almacenamiento segun plataforma

PlataformaTecnologiaClave de almacenamiento
App nativaAsyncStoragenvito_offline_queue
PWAIndexedDBTabla offline-queue

Hook de sincronizacion

En la app nativa, useOfflineSync monitorea el estado de conectividad:

  • Escucha cambios de red via ConnectivityContext
  • Cuando isConnected cambia de false a true, inicia sincronizacion
  • Procesa items en orden FIFO (primero el mas antiguo)
  • Muestra un badge con el conteo de items pendientes en la UI del scanner

9. Casos de Error

El sistema maneja multiples escenarios de error con mensajes claros para el anfitrion:

EscenarioCodigo HTTPMensaje al HOSTDetalle
Pase ya utilizado409"Pase ya escaneado"Muestra usedAt y nombre de quien lo escaneo
Pase expirado410"Pase expirado"Muestra expiresAt y opcion de regenerar
Pase no encontrado404"Codigo QR invalido"Posible QR falso o de otro sistema
Evento no activo403"Evento no activo"El evento no esta en estado ACTIVE
Guest eliminado404"Invitado no encontrado"El guest fue removido de la lista
Tipo VIP sin permiso403"Acceso VIP no autorizado"El guest no tiene atributo VIP

UI de error

Cada error muestra un indicador visual distinto en la pantalla del scanner:

  • Pase valido: Fondo verde, nombre del invitado, numero de mesa, efecto haptico suave
  • Pase ya usado: Fondo amarillo, nombre del invitado, hora del primer escaneo
  • Pase invalido/expirado: Fondo rojo, mensaje de error, sin datos de invitado

10. Archivos Clave

nvito-api (Backend)

ArchivoResponsabilidad
qr-passes.service.tsOrquestador: generacion, listado, regeneracion de pases
qr-generation.service.tsGeneracion de codigo unico e imagen QR
qr-check-in.service.tsValidacion de pases y registro de check-in
qr-passes.controller.tsEndpoints REST para pases QR

nvito-client (App Nativa)

ArchivoResponsabilidad
app/(app)/(host)/scanner.tsxPantalla principal del scanner
scanner/hooks/use-scanner.tsLogica de escaneo y validacion
scanner/stats-header.tsxConteo en tiempo real de check-ins
src/hooks/queries/use-qr-passes.tsHook de React Query para pases
src/storage/offline-queue.tsCola FIFO en AsyncStorage
src/hooks/use-offline-sync.tsSincronizacion automatica al reconectar

nvito-pwa (Progressive Web App)

ArchivoResponsabilidad
src/app/(app)/(host)/scanner/page.tsxPantalla del scanner PWA
src/hooks/use-qr-scanner.tsWrapper de html5-qrcode
src/lib/offline/indexed-db.tsAcceso a IndexedDB
src/lib/offline/offline-queue.tsCola offline en IndexedDB
Esta pagina fue util?