Docs

Sistema de Eventos

Gestión completa de eventos en Nvito - maquina de estados, tipos de evento, servicios modulares, paquetes, invitados, RSVP, mesas, QR passes, check-in y más.

PublicadoMarzo 2026Equipo de desarrollo, arquitectos, stakeholders

1. Maquina de Estados

Cada evento transita por un ciclo de vida controlado por EventStatus. Las transiciones se validan en EventLifecycleService y mediante guards de NestJS.

Transiciones y validaciones

TransiciónTriggerEfecto colateral
DRAFT -> ACTIVEInvitación aprobada y publicadaSe registra activatedAt y auditoria
ACTIVE -> COMPLETEDCron diario (medianoche, America/Mexico_City)Invitaciones PUBLISHED/UNPUBLISHED -> CLOSED
DRAFT -> CANCELLEDPOST /events/:id/cancelSe registra cancelledAt y cancellationReason
ACTIVE -> CANCELLEDPOST /events/:id/cancelInvitaciones activas pasan a CLOSED

Estado visual derivado: EXPIRED (Expirado) no es una transición de BD. Se calcula en el frontend cuando COMPLETED + activatedAt === null (nunca se público invitación). Tiene el mismo bloqueo que COMPLETED/CANCELLED.

Campos de auditoria

CampoTipoDescripción
activatedAtDateTimeFecha en que el evento paso a ACTIVE
cancelledAtDateTimeFecha de cancelación
completedAtDateTimeFecha de auto-completado por cron
statusChangedByUUIDUsuario que realizo el cambio de estado
cancellationReasonStringRazon proporcionada al cancelar

2. Tipos de Evento

El modelo EventType es un catálogo dinámico en base de datos. Cada tipo define un slug, icon y un arreglo JSON defaultSections con la estructura [{ "type": "Hero", "order": 0 }, ...] que precarga secciones al crear una invitación.

#SlugNombreSecciones por defecto
1weddingBodaHero, Couple, Itinerary, Location, RSVP
2xv-anosXV AñosHero, Quinceañera, Itinerary, Location, RSVP
3baptismBautizoHero, Details, Location, RSVP, Gallery
4birthdayCumpleañosHero, Details, Location, RSVP, Gallery
5first-communionPrimera ComuniónHero, Details, Location, RSVP, Gallery
6baby-showerBaby ShowerHero, Details, Location, RSVP, GiftRegistry
7graduationGraduaciónHero, Details, Location, RSVP, Gallery
8corporateEvento CorporativoHero, Details, Itinerary, Location, RSVP
9otherOtroHero, Details, Location, RSVP

3. Servicios por Evento

Nvito utiliza un sistema modular de 18 servicios controlado por EventServiceType. Cada evento tiene un EventServiceConfig con el array enabledServices y un JSON serviceSettings para configuración granular (ej: { "GALLERY": { "maxPhotos": 50 } }).

CategoríaServicioClave
CoreInvitación digitalINVITATION
CoreUbicaciones con GPSLOCATIONS
InvitadosLista de invitadosGUEST_LIST
InvitadosConfirmaciones (RSVP)RSVP
InvitadosGrupos de invitadosGUEST_GROUPS
Dia del eventoItinerario / timelineITINERARY
Dia del eventoAsignación de mesasTABLES
Dia del eventoPases QR de entradaQR_PASSES
Dia del eventoCheck-in con camara QRCHECK_IN
MediaGalería de fotosGALLERY
MediaLibro de audio (mensajes de voz)AUDIO_GUESTBOOK
MediaFotos subidas por invitadosGUEST_UPLOADS
DiseñoDominio personalizadoCUSTOM_DOMAIN
DiseñoMúsica de fondoBACKGROUND_MUSIC
ExtrasMesa de regalosGIFT_REGISTRY
ExtrasHospedaje y transporteACCOMMODATION
ContenidoPadrinos / Corte de HonorSPONSORS
ContenidoOración / sección religiosaPRAYER
ContenidoAgradecimientosTHANK_YOU
ContenidoCódigo de vestimentaDRESS_CODE

Los servicios INVITATION y LOCATIONS son core y siempre estan activos. El resto se habilita según el paquete contratado o configuración manual.


4. Paquetes

Los paquetes son un catálogo dinámico (ServicePackage) administrado por el Super Admin. Al asignar un paquete, sus services se copian al enabledServices del evento, permitiendo personalización posterior.

PaquetePrecioIncluye
Essential$1,499 MXNInvitación, ubicaciones, lista de invitados, RSVP, grupos
Plus$2,999 MXNEssential + itinerario, galería, mesa de regalos, hospedaje, música
VIP$4,999 MXNPlus + mesas, QR passes, check-in, subidas, libro de audio, dominio
Elite$9,999 MXNLos 18 servicios sin restriccion
PersonalizadoCotizacionSeleccion manual de servicios individuales

Modelo ServicePackage

CampoTipoDescripción
slugVARCHAR(50) UNIQUEIdentificador único del paquete
name / displayNameVARCHAR(100)Nombre interno y nombre visible en la UI
priceDECIMAL(10,2)Precio referencial del paquete
currencyVARCHAR(3)Moneda (default: MXN)
servicesEventServiceType[]Servicios incluidos en el paquete
colorVARCHAR(20)Color de presentación en la UI
isRecommendedBOOLEANMarcado como recomendado
isActiveBOOLEANSi el paquete está disponible
sortOrderINTOrden de visualización

5. Gestión de Invitados

El controlador GuestsController expone CRUD completo con autorización RBAC y soporte de importación masiva via Excel.

Endpoints

MetodoRutaPermiso
POST /guestsCrear invitadoguests:create:assigned
POST /guests/import/generate-templateGenerar template Excelguests:import:assigned
POST /guests/import/excelImportar Excelguests:import:assigned
GET /guests/event/:eventIdListar (páginado)guests:read:assigned
GET /guests/event/:eventId/dietaryResumen dieteticoguests:read:assigned
GET /guests/:idDetalleguests:read:assigned
PATCH /guests/:idActualizarguests:update:assigned
DELETE /guests/:idSoft deleteguests:delete:assigned

Campos principales del Guest

firstName, lastName, email (único por evento), phone, title (título formal, max 30 chars), groupId (FK a GuestGroup), groupSize, status (GuestStatus), dietaryRestrictions (array de DietaryRestriction), dietaryNotes, allergyInformation, mobilityNeeds, relationship.

Estados del invitado (GuestStatus)

EstadoDescripción
PENDINGRegistrado, sin respuesta RSVP
CONFIRMEDConfirmo asistencia
DECLINEDDeclino la invitación
ATTENDEDAsistio al evento (check-in registrado)

Importacion masiva via Excel

El sistema de importación masiva genera un archivo Excel (.xlsx) dinámico personalizado según los servicios contratados del evento (EventServiceConfig.enabledServices[]).

Flujo:

  1. El admin genera el template Excel desde el dialog de importación
  2. El ExcelTemplateService crea un archivo con hoja "Instrucciones" (leyenda de colores y reglas) y hoja "Invitados" (headers coloreados por sección con data validations/dropdowns)
  3. El archivo se sube a S3 con URL firmada de 7 dias
  4. El admin descarga el template y se lo envia al cliente
  5. El cliente llena el Excel con datos de invitados
  6. El admin sube el Excel completado
  7. El ExcelImportService procesa el archivo en una transacción atomica: crea grupos, mesas, invitados y asignaciones automáticamente
  8. Deduplicacion por email (hash), validación fila por fila, limite de 1000 filas

Columnas dinámicas según servicio:

ServicioColumnasColor
GUEST_LIST (siempre)Nombre, Apellido, Titulo, Email, Telefono, Pases#0B3D5A
GUEST_GROUPSGrupo#F17F3A
TABLESMesa, Capacidad Mesa, Asiento#005587
Siempre (dietarios)Restricciones Dietarias, Alergias, Movilidad, Notas Dieta#9C27B0
SiempreRelación#FF9800

Grupos (GuestGroup)

Permiten organizar invitados en categorías (ej: "Familia del novio"). Campos: name, description, color (hex). Un invitado pertenece a un solo grupo opcional.

Restricciones alimentarias

Enum DietaryRestriction: VEGETARIAN, VEGAN, GLUTEN_FREE, HALAL, KOSHER, NUT_FREE, DAIRY_FREE, OTHER.


6. RSVP

El RSVP es un endpoint público (sin autenticación) para que los invitados confirmen asistencia. La consulta y estadisticas requieren autenticación.

Diagrama de secuencia

Endpoints

MetodoRutaAuth
POST /rsvpCrear/actualizar RSVPPublico
GET /rsvp/event/:eventIdListar RSVPsAutenticado
GET /rsvp/event/:eventId/statsEstadisticasAutenticado

Estados (RSVPStatus)

PENDING (sin respuesta), CONFIRMED (asistira), DECLINED (no asistira), MAYBE (posible asistencia).

Modelo RSVP - campos clave

guestId, invitationId, status, attendeesCount, dietaryInfo (JSON con restricciones), message, respondedAt, ipAddress, userAgent, rsvpOpenedAt, responseTime (segundos), remindersSentCount.

El campo dietaryInfo sigue el formato: { "vegetarian": 1, "vegan": 0, "allergies": ["nuts"] }. El campo remindersSentCount permite rastrear recordatorios automáticos enviados a invitados con status PENDING.


7. Mesas y Asientos

El servicio TABLES permite planificar la distribución fisica de invitados.

EventTable

Campos: name (ej: "Mesa Principal"), capacity (default 10), shape (TableShape), positionX/positionY (coordenadas en el plano), metadata (JSON).

Formas (TableShape): ROUND (defecto), SQUARE, RECTANGLE, OVAL.

TableAssignment

Asigna un invitado a una mesa con asiento opcional. La restriccion UNIQUE en guestId garantiza que cada invitado solo puede estar en una mesa. Campos: tableId, guestId, seatNumber (opcional).

Acceso Mobile (read-only)

El anfitrion (HOST) puede visualizar la distribución y asignación de mesas desde la app movil en modo lectura. La app ofrece dos vistas: Lista (cards con barra de ocupacion) y Plano visual (pinch-to-zoom, mismas coordenadas que el admin web). La gestión completa de mesas (crear, editar, asignar invitados, redistribuir) se realiza exclusivamente desde el admin web.

Endpoints mobile: GET /v1/mobile/events/:eventId/tables (lista con asignaciones) y GET /v1/mobile/events/:eventId/tables/stats (estadisticas de ocupacion).


8. QR Passes y Check-in

Modelo QRPass

Cada invitado puede tener pases QR vinculados al evento. Campos: code (VARCHAR UNIQUE), type (default "entry"), isUsed, usedAt, scannedBy, expiresAt, attendeesCheckedIn (para check-in parcial).

Flujo de check-in

  1. Generación - Al habilitar QR_PASSES, se genera un QRPass por invitado con código unico.
  2. Distribucion - El QR se incluye en la invitación digital o se envia por separado.
  3. Escaneo - El servicio CHECK_IN proporciona una vista con camara QR.
  4. Validación - La API verifica existencia, expiración y uso previo del código.
  5. Registro - Se marca isUsed = true, se registra usedAt/scannedBy, el invitado cambia a ATTENDED.
  6. Check-in parcial - attendeesCheckedIn permite registrar llegadas parciales del grupo.

9. Acceso App Movil

El módulo de Acceso App Movil permite a los organizadores generar códigos de acceso para que los anfitriones (HOST) inicien sesion en la app movil y gestiónen el evento el día del evento (check-in, estadisticas, invitados).

Modelo EventAccessCode

Cada código de acceso vincula un evento con credenciales de autenticación movil. Campos principales:

CampoTipoDescripción
idUUID PKIdentificador único
eventIdUUID FKEvento al que pertenece
codeVARCHAR(8) UNIQUECódigo alfanumerico de 8 caracteres (ej: KWZDR4VD)
pinVARCHAR(255)PIN de 6 digitos hasheado con bcrypt (salt rounds: 10)
roleMobileRoleRol del acceso (default: HOST)
isActiveBOOLEANSi el código está activo
expiresAtDateTime?Fecha de expiración opcional
createdAtDateTimeFecha de creación
updatedAtDateTimeUltima actualización

Flujo de gestión de códigos

  1. Prerequisito — El evento debe estar en estado ACTIVE (invitación publicada). No se pueden generar códigos para eventos en DRAFT, CANCELLED o COMPLETED.
  2. Generación — Desde la página "Acceso App Movil" en nvito-admin, el organizador genera un código. Se crea un EventAccessCode con código alfanumerico aleatorio y PIN de 6 digitos.
  3. Reveal único del PIN — El PIN se muestra una sola vez en un dialog persistente al crear o regenerar. Se almacena hasheado con bcrypt y no puede recuperarse.
  4. Distribucion — El organizador comparte el código y PIN con el anfitrion (por cualquier medio externo).
  5. Login — El anfitrion ingresa código + PIN en la app movil. El API valida con bcrypt.compare() y crea una MobileSession.
  6. Gestión — Desde el admin se puede: activar/desactivar, regenerar PIN (genera uno nuevo), o eliminar el código.

Limite de códigos activos

Máximo 3 códigos activos simultaneos por evento (MAX_ACTIVE_CODES = 3). Los códigos inactivos o eliminados no cuentan contra este limite.

Seguridad

  • PIN hasheado: Se almacena con bcrypt.hash(pin, 10), nunca en texto plano
  • One-time reveal: El PIN solo es visible al crear o regenerar — no se puede consultar después
  • Validación de estado: El backend rechaza la creación si el evento no está en estado ACTIVE (ValidationException, HTTP 400)
  • Separacion de auth: El sistema de autenticación movil es independiente de Clerk (admin web)

Endpoints (admin)

MetodoRutaDescripción
GET/events/:eventId/access-codesListar códigos del evento (sin PIN)
POST/events/:eventId/access-codesCrear código con PIN auto-generado
PATCH/events/:eventId/access-codes/:codeIdActivar/desactivar código
POST/events/:eventId/access-codes/:codeId/regenerate-pinRegenerar PIN
DELETE/events/:eventId/access-codes/:codeIdEliminar código

Panel de administración (nvito-admin)

La página /events/[eventId]/mobile-access muestra:

  • Badge de conteo: Códigos activos vs máximo permitido
  • Tarjetas por código: Código visible con botón copiar, estado (activo/inactivo/expirado), fecha de creación
  • Menu de acciones: Regenerar PIN, activar/desactivar, eliminar
  • Bloqueo por estado: Si el evento no está activo, se muestra un StatusAlert con mensaje contextual y las acciones se deshabilitan

10. Mesa de Regalos y Hospedaje

Mesa de Regalos (GiftRegistry)

Configuración por evento con: message, note, y un fondo en efectivo (cashFundEnabled, cashFundGoal en centavos, cashFundCurrent, cashFundPaymentMethods).

Items (GiftRegistryItem): Enlaces a tiendas con type (GiftRegistryType: AMAZON, LIVERPOOL, PALACIO_HIERRO, SANBORNS, COPPEL, SEARS, OTHER), storeName, registryUrl, logoUrl.

También soporta cuentas bancarias (GiftBankAccount) para transferencias directas.

Hospedaje (Accommodation)

Configuración por evento con: message, travelTips, travelParkingInfo, travelNearestAirport.

Hoteles (AccommodationHotel): name, address, phone, distance, websiteUrl, bookingUrl (reservacion directa).

Transporte (AccommodationTransportOption): Opciones con type (Uber/DiDi, Taxi, Autobus), description, icon.


11. Colaboradores

El sistema permite invitar usuarios para co-gestionar un evento mediante EventCollaboratorInvitation.

Modelo

Campos: email, role (RoleType), invitedBy, status (CollaboratorInvitationStatus), token (UNIQUE), expiresAt.

Estados de invitación

EstadoDescripción
PENDINGInvitación enviada, esperando respuesta
ACCEPTEDColaborador tiene acceso al evento
DECLINEDColaborador rechazo
EXPIREDToken expiro
CANCELLEDOrganizador cancelo la invitación

Roles asignables

RolAcceso
EVENT_MANAGERControl completo sobre el evento asignado
EVENT_EDITOREdicion de eventos e invitados, sin eliminar
EVENT_COLLABORATORAcceso limitado: agregar/editar invitados y ver info
EVENT_VIEWERSolo lectura del evento asignado

El permiso collaborators:manage:assigned está asignado a SUPER_ADMIN (wildcard), PLATFORM_ADMIN, ORG_OWNER, ORG_ADMIN y EVENT_MANAGER. Los roles EVENT_EDITOR, EVENT_COLLABORATOR y EVENT_VIEWER no pueden gestionar colaboradores.

Flujo

  1. El organizador invita a un colaborador proporcionando su email y el rol deseado.
  2. El sistema genera un token único con fecha de expiración y envia la invitación por correo.
  3. El colaborador abre el enlace con el token.
  4. Si el colaborador ya tiene cuenta en Nvito, se le asigna el rol en el evento automáticamente.
  5. Si no tiene cuenta, se le invita a registrarse y al completar el registro se le asigna el rol.
  6. El organizador puede cancelar invitaciones pendientes en cualquier momento.

Referencias

Archivos fuente

ArchivoDescripción
events.controller.tsControlador de eventos: CRUD y cancelación
event-lifecycle.service.tsMaquina de estados y transiciones automáticas
guests.controller.tsCRUD de invitados con importación Excel
rsvp.controller.tsEndpoints de RSVP (público y autenticado)
event-service.types.tsEnum TypeScript de los 18 servicios
schema.prismaModelos de datos de todo el sistema

Guards de autorización

  1. ClerkAuthGuard - Autenticación JWT via Clerk.
  2. PermissionsGuard - Verificacion de permisos RBAC con @RequirePermission().
  3. EventAccessGuard - Acceso al evento específico con @RequireEventAccess().
  4. InvitationStateGuard - Bloquea edicion si la invitación está publicada o cerrada.
Esta pagina fue util?