Plataforma de Citas en Vivo
Un producto de citas por suscripción solo para miembros: dos clientes en un solo backend, con verdaderas videollamadas y llamadas de voz en la aplicación. Registro e incorporación (onboarding) con fotos moderadas, un sistema de deslizamiento (swipe deck) con filtrado por distancia y preferencias, emparejamiento a prueba de condiciones de carrera, chat en tiempo real, llamadas WebRTC y facturación recurrente; todo esto envuelto en un stack de confianza y seguridad que la mayoría de las aplicaciones de citas añaden demasiado tarde.
01Visión general
Una plataforma de citas solo para miembros construida como dos clientes sobre un único backend: una aplicación web completa en Next.js (miembros y el panel de administración) y una aplicación en Expo / React Native que se comunica con la misma API mediante tokens Bearer. Un mismo recorrido para el miembro (registrarse, crear un perfil, pasar la foto principal por moderación, explorar, hacer match, chatear y llamar cara a cara) se ejecuta de manera idéntica en la web y en su bolsillo, y la misma suscripción recurrente controla el acceso a las funciones de pago en ambas.
La parte interesante no es el sistema de deslizamiento. Es que un producto de consumo que maneja fotos privadas de usuarios, pagos, mensajería entre desconocidos y llamadas peer-to-peer en vivo, fue construido con controles de confianza, seguridad y abuso (moderación con IA, medios privados, aplicación de baneos/bloqueos, limitación de tasa, verificación) diseñados desde el esquema inicial, en lugar de ser adaptados después del primer incidente.
02El problema que resuelve
Una aplicación de citas es engañosamente compleja. Detrás de la interfaz se encuentran la seguridad de la identidad y de la sesión, los pagos, un motor de emparejamiento que no puede duplicar las acciones bajo carga, la mensajería en tiempo real, las llamadas en vivo que deben atravesar NAT, y (la parte que hunde a la mayoría de los lanzamientos de redes sociales de consumo) una superficie de seguridad: moderación antes de que el contenido se publique, medios privados que nunca se filtren, bloqueos y reportes que realmente funcionen, límites de tasa que frenen el abuso, y un camino hacia la verdadera verificación de edad e identidad. Si se construye todo esto como una ocurrencia tardía, se estará lanzando un riesgo.
Resultado un producto de citas por suscripción que se lanza con la maquinaria de llamadas, moderación, seguridad y pagos normalmente postergada: web y nativo desde el primer día, en un solo backend.
03Lo que construimos
Cuentas e identidad
Autenticación de credenciales desarrollada a medida (bcrypt más un JWT firmado (jose) en una cookie httpOnly) que falla de manera segura (fails closed) si el secreto de autenticación no está configurado. Los tokens llevan un tokenVersion para que "cerrar sesión en todas partes" y los baneos revoquen cada sesión activa instantáneamente. Los tokens de un solo uso, hasheados y con fecha de expiración impulsan la verificación de correo electrónico y el restablecimiento de contraseña seguro contra la enumeración. OAuth (Google, Facebook, Instagram) utiliza el flujo de código de autorización con protección CSRF mediante cookie de estado y vincula las identidades por correo electrónico: sin SDK. La eliminación de la cuenta es una ventana de gracia de borrado lógico (soft-delete): se oculta y se cierra sesión de inmediato, se puede restaurar volviendo a iniciar sesión y se purga definitivamente más tarde mediante un cron diario.
Perfiles, descubrimiento y emparejamiento
Perfiles ricos (pronombres, altura, tipo de cuerpo, orientación, objetivos, intereses y tarjetas de preguntas) con una foto principal moderada restringida por estados PENDING / APPROVED / REJECTED y un banner visible para el miembro que explica su visibilidad. El descubrimiento se filtra mutuamente según el género y el rango de edad, respeta las preferencias (objetivos, tipos de cuerpo, altura, fumadores) y geocodifica cada ciudad a coordenadas para el filtrado por distancia. El sistema de deslizamiento admite me gusta / pasar / súper me gusta y rebobinar; los emparejamientos se forman en una clave de par canónica a prueba de condiciones de carrera para que un me gusta mutuo simultáneo nunca pueda crear dos emparejamientos. Alrededor de esto: quién-te-dio-me-gusta, quién-te-vio, selecciones diarias (una mezcla determinista por día), deshacer emparejamiento y un modo vacaciones/pausa.
Chat en tiempo real y llamadas en vivo
Las conversaciones por emparejamiento se transmiten a través de Server-Sent Events en la web (la aplicación nativa hace polling), con indicadores de escritura, insignias de no leído, marcadores de lectura y mensajes de voz y video junto al texto. Sobre el mismo canal por emparejamiento se encuentran verdaderas videollamadas y llamadas de voz WebRTC: un endpoint de señalización transmite la oferta/respuesta SDP y los candidatos ICE entre los dos pares, un endpoint de configuración ICE distribuye STUN más credenciales TURN HMAC por tiempo limitado (para que las llamadas se conecten incluso detrás de NAT simétrico), y una llamada entrante despierta al otro dispositivo mediante notificaciones push. El cliente nativo ejecuta una RTCPeerConnection completa con silenciamiento, encendido/apagado de cámara y cambio entre cámara frontal/trasera; cualquiera de las partes puede colgar con un motivo tipificado (rechazada / ocupada / finalizada / tiempo de espera agotado).
Moderación y procesamiento de medios
Cada imagen subida pasa por una moderación de IA enchufable (el modelo omni-moderation de OpenAI): las violaciones graves de la política se rechazan de plano, cualquier otra cosa recibe una puntuación de riesgo y pasa a una cola de revisión humana; y el sistema falla de forma abierta hacia la revisión humana en lugar de bloquear cargas legítimas. Las imágenes aceptadas se recodifican con sharp: se rotan automáticamente a partir del EXIF, se les elimina el EXIF por privacidad, y se escriben como una imagen principal compacta más una miniatura.
Suscripciones y facturación
Stripe Checkout para el plan mensual recurrente, un portal de facturación y un webhook que sincroniza el estado de la suscripción (incluyendo PAST_DUE) de vuelta con el miembro. Tres niveles (FREE / PLUS / PREMIUM) impulsan una matriz de capacidades: súper me gusta por día, quién-te-vio, selecciones diarias, rebobinar, confirmaciones de lectura, filtros avanzados y un modo de navegación de incógnito. El nivel se rastrea independientemente del estado de la suscripción, por lo que un miembro que cancela mantiene su nivel hasta el final del período. Un bypass para desarrolladores y códigos promocionales locales permiten que todo el flujo se ejecute sin claves reales de Stripe.
04Confianza, seguridad y el panel de administración
Las fotos de los miembros viven fuera de la raíz web y se sirven solo a través de una ruta autenticada que vuelve a verificar la sesión (los usuarios baneados/revocados son rechazados) y autoriza por foto: el propietario siempre, de lo contrario solo un miembro activo que no esté bloqueado ni baneado — private, nosniff, nunca legibles por el público general, seguras contra ataques de path-traversal. Las cargas se validan por magic bytes, no por el MIME declarado por el cliente, a través de imágenes, audio y video, eliminando la suplantación del tipo de contenido y los trucos con scripts SVG. El CSRF se aplica mediante una verificación del mismo origen en cada ruta de mutación además de SameSite=Lax; los límites de tasa cubren el inicio de sesión, registro, carga, me gusta, mensajes, bloqueos, reportes y señalización de llamadas. Un único guardia hace cumplir los bloqueos y baneos en todas partes: exploración, me gusta, emparejamientos, chat, llamadas y medios. Los miembros pueden bloquear (en ambos sentidos) y reportar; la verificación de edad y foto selfie lista para KYC aparecen como insignias en el perfil. Los administradores obtienen un área separada, con respuesta 404 para no administradores, protegida contra CSRF: tablero de control, una cola de moderación para fotos principales, revisión de verificación de fotos, clasificación (triage) de reportes (descartar / resolver / resolver y banear) y herramientas de usuario (banear / desbanear / revocar sesiones), y cada acción del administrador aterriza en un registro de auditoría inmutable.
05Tecnología
06Puntos destacados
- Videollamadas y llamadas de voz WebRTC en la aplicación: señalización SDP/ICE a través del canal de emparejamiento, credenciales TURN HMAC por tiempo limitado, llamadas entrantes despertadas por notificaciones push, conexión de pares nativa con silenciamiento y cambio de cámara.
- Dos clientes, un backend: recorrido completo del miembro en la web con Next.js y en una aplicación Expo/React Native a través de una API con tokens Bearer.
- Moderación de imágenes con IA en cada subida (rechazo directo + cola de revisión humana basada en puntuación de riesgo), fallando de forma abierta hacia la revisión en lugar de bloquear.
- Medios privados con control de acceso: almacenados fuera de la raíz web, autorización por foto, pipeline con
sharpque elimina el EXIF, validación por magic-byte para imagen/audio/video. - Emparejamiento a prueba de condiciones de carrera en una clave de par canónica; me gusta / pasar / súper me gusta, rebobinar, quién-te-dio-me-gusta, quién-te-vio y selecciones diarias.
- Chat en tiempo real a través de SSE con indicadores de escritura, marcadores de lectura y mensajes de voz/video; manejo elegante de bloqueos/baneos/expiración.
- Suscripciones de Stripe con sincronización de estado vía webhook y manejo de PAST_DUE; matriz de capacidades FREE/PLUS/PREMIUM incluyendo modo incógnito.
- Autenticación por credenciales que falla de manera segura (fails closed); revocación de sesión mediante
tokenVersion; panel de administración con un registro de auditoría inmutable; borrado lógico con restauración + cron de purga.