Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Iris

Buscador inverso de viajes que compara vuelos, alojamiento y transporte para descubrir las mejores escapadas según origen, fechas, presupuesto y viajeros.

Node.js React TypeScript Vercel

Iris cambia la pregunta habitual de un buscador de viajes. En vez de pedir un destino concreto, el usuario indica desde dónde sale, cuándo quiere viajar, cuántas personas viajan y cuánto quiere gastar. El sistema explora un catálogo de destinos, combina transporte y alojamiento, puntúa cada alternativa y muestra primero las escapadas con mejor equilibrio entre coste, distancia y tiempo.

Puede probar vuelos y alojamientos con datos simulados y deterministas o conectarse a Duffel, Google Routes y Redis para trabajar con información real. Los modos terrestres sólo aparecen cuando Google Routes está configurado.

Qué ofrece

  • Búsqueda inversa por origen, fechas, viajeros y presupuesto.
  • Comparación de vuelo, coche y transporte público cuando sus proveedores reales están disponibles.
  • Precios de vuelos y alojamientos mediante Duffel.
  • Rutas y tiempos de coche o transporte público mediante Google Routes.
  • Detalle de vuelos: horarios, escalas, aeropuertos, terminales, operadores, avión, cabina, equipaje, tarifa, emisiones y condiciones de la oferta.
  • Resultados destacados, tarjetas, tabla, filtros y ordenación.
  • Enlaces de vuelos y paquetes en Skyscanner.
  • Caché Redis opcional, fallback LRU en memoria, control de concurrencia y rate limiting.
  • Interfaz oscura, responsive y preparada para escritorio y móvil.
  • Despliegue full-stack en Vercel.

Cómo funciona

flowchart LR
    U[Usuario] --> F[React]
    F --> A[API Express]
    A --> C[Catálogo de destinos]
    C --> P[Pool de concurrencia]
    P --> D[Duffel Flights y Stays]
    P --> G[Google Routes]
    D --> S[Normalización y score]
    G --> S
    S --> R[(Redis o caché LRU)]
    S --> F
    F --> K[Skyscanner]
Loading
  1. La API valida la búsqueda y calcula las noches de estancia.
  2. Recorre el catálogo de destinos candidatos con concurrencia limitada.
  3. Para cada destino obtiene transporte, alojamiento, distancia y duración.
  4. Normaliza las respuestas para que mocks y proveedores reales compartan el mismo contrato.
  5. Calcula el Iris Score, filtra por presupuesto y ordena los resultados.
  6. Guarda la respuesta en caché y genera enlaces externos de reserva.

El catálogo de IDs de Skyscanner es independiente del catálogo de búsqueda. Por eso se pueden añadir enlaces para más ciudades sin multiplicar las consultas de pago realizadas a Duffel.

Stack

Capa Tecnología
Frontend React 19, TypeScript 6, Vite 8, Tailwind CSS 4, Lucide
Backend Node.js, Express, CommonJS, Fetch API nativa
Vuelos y hoteles Duffel Flights y Duffel Stays
Rutas Google Routes API
Caché Redis o LRU en memoria
Despliegue Vercel Static + Functions
Pruebas Node Test Runner

Inicio rápido

Requisitos

  • Node.js 20 o posterior.
  • npm.
  • Ninguna API key para usar el modo simulado.

Instalación

npm install
npm --prefix frontend install
cp .env.example .env
npm run dev

La configuración de ejemplo utiliza mocks para vuelo y hotel, por lo que arranca sin cuentas externas. Sin Google Routes, la interfaz muestra únicamente vuelos.

Servicio URL local
Frontend http://localhost:5173
API http://localhost:3001

Vite redirige automáticamente las peticiones /api hacia Express.

Producción local

npm run build
npm start

Express sirve el frontend compilado y la API desde http://localhost:3001.

API keys y servicios externos

Iris no necesita credenciales para probar la búsqueda de vuelos y hoteles en modo mock. Los modos coche y transporte público permanecen ocultos hasta configurar Google Routes.

Variable Necesaria para Obligatoria
DUFFEL_ACCESS_TOKEN Vuelos y alojamientos reales Sí para Duffel
GOOGLE_MAPS_API_KEY Coche y transporte público reales Sí para Google Routes
REDIS_URL Caché compartida entre instancias No

1. Duffel

Duffel utiliza un único token para Flights y Stays.

  1. Crea una cuenta en Duffel.
  2. En el Dashboard abre More > Developers > Access tokens.
  3. Crea primero un test access token.
  4. Copia el token en DUFFEL_ACCESS_TOKEN.
  5. Solicita acceso a Duffel Stays desde tu cuenta si todavía no aparece habilitado. El acceso a vuelos y el acceso a alojamientos pueden tener permisos comerciales distintos.

Los tokens de prueba sirven para integrar y desarrollar, pero no emiten reservas reales. Para operar en producción, Duffel debe aprobar la cuenta y habilitar el modo live correspondiente. Consulta la guía oficial de Flights.

2. Google Routes API

  1. Abre Google Cloud Console.
  2. Crea o selecciona un proyecto.
  3. Vincula una cuenta de facturación. Google Maps Platform requiere billing aunque el consumo pueda quedar dentro de sus créditos o límites vigentes.
  4. Habilita Routes API.
  5. Ve a APIs & Services > Credentials > Create credentials > API key.
  6. Restringe la clave a Routes API. Añade una restricción por IP sólo si el backend dispone de salida estática; las Functions de Vercel no la garantizan por defecto.
  7. Guarda la clave en GOOGLE_MAPS_API_KEY.

La clave se utiliza sólo en el backend. No debe llevar restricciones de referrer pensadas para JavaScript en navegador. Configura cuotas, alertas de presupuesto y monitorización en Google Cloud para controlar el consumo. Consulta la configuración oficial de Routes API.

3. Redis

Redis es opcional. Sin REDIS_URL, Iris usa una caché LRU en memoria de hasta 500 entradas. En Vercel esa memoria no se comparte entre instancias ni persiste durante nuevos despliegues.

Para una caché compartida:

  1. Añade Upstash desde Vercel Marketplace o crea una base en Upstash Console.
  2. Elige una región próxima a tu despliegue.
  3. Copia la URL de conexión Redis con TLS proporcionada por el servicio.
  4. Guárdala como REDIS_URL.

También funciona cualquier proveedor compatible que entregue una URL redis:// o rediss:// aceptada por el cliente oficial de Redis para Node.js.

Configuración real recomendada

FLIGHT_PROVIDER=duffel
HOTEL_PROVIDER=duffel
DUFFEL_ACCESS_TOKEN=duffel_test_xxxxxxxxx

ROUTE_PROVIDER=google
GOOGLE_MAPS_API_KEY=xxxxxxxxx

REDIS_URL=rediss://default:password@host:port

No publiques estos valores, no los incluyas en commits y no antepongas VITE_ a las claves: hacerlo expondría las credenciales al navegador.

Variables de entorno

Variable Por defecto Descripción
PORT 3001 Puerto de Express
CURRENCY EUR Moneda esperada en el ranking
FLIGHT_PROVIDER auto mock o duffel
HOTEL_PROVIDER auto mock o duffel
ROUTE_PROVIDER disabled disabled, auto o google
PROVIDER_TIMEOUT_MS 15000 Timeout por petición externa
SEARCH_CONCURRENCY 5 Máximo de tareas simultáneas
CACHE_TTL_SECONDS 900 Duración de una búsqueda cacheada
REDIS_URL vacío Activa la caché Redis compartida
RATE_LIMIT_WINDOW_MS 60000 Ventana del rate limit
RATE_LIMIT_MAX 60 Peticiones permitidas por IP y ventana
CORS_ORIGIN cualquier origen Orígenes permitidos, separados por comas

Si vuelos u hoteles permanecen en auto, Iris activa Duffel al encontrar su credencial y utiliza el mock en caso contrario. Para rutas, auto activa Google únicamente cuando existe GOOGLE_MAPS_API_KEY; sin ella el proveedor queda deshabilitado y la API rechaza modos terrestres.

Consulta .env.example para partir de una configuración segura.

Uso de la API

POST /api/search

{
  "origin": "SVQ",
  "startDate": "2026-09-04",
  "endDate": "2026-09-06",
  "passengers": 2,
  "budget": 350,
  "transportModes": ["FLIGHT", "DRIVE", "TRANSIT"]
}

DRIVE y TRANSIT sólo se aceptan cuando Google Routes está activo. Sin GOOGLE_MAPS_API_KEY, utiliza "transportModes": ["FLIGHT"].

La respuesta contiene:

  • results: alternativas ordenadas por score.
  • highlights: mejor escapada, más barata, más rápida y mejor valor.
  • meta: noches, candidatos evaluados y modos utilizados.
  • transport: precio, fuente, itinerario y detalle completo de la oferta.
  • hotel: precio, proveedor y alojamiento cuando esté disponible.
  • bookingLinks: enlaces de vuelo y paquete en Skyscanner.

La cabecera X-Cache indica MISS o HIT.

Otros endpoints

Método Endpoint Descripción
GET /api/origins Orígenes disponibles
GET /api/config Moneda, modos y proveedores activos
GET /api/health Estado de la API

Iris Score

El ranking pondera precio, distancia y duración con pesos 0.6 / 0.2 / 0.2. Antes de aplicar los pesos, normaliza cada variable mediante min-max dentro del conjunto actual de resultados:

$$ S = 0.6P_{norm} + 0.2D_{norm} + 0.2T_{norm} $$

Un score menor representa una escapada más conveniente. La normalización evita que las diferentes escalas de euros, kilómetros y minutos distorsionen el peso definido para cada factor.

Skyscanner

Iris genera dos enlaces por resultado:

  • flightUrl: búsqueda de vuelos construida con códigos IATA.
  • packageUrl: búsqueda de paquete con IDs internos verificados.

El mapa src/data/skyscannerPlaces.js contiene 78 códigos IATA verificados y no se usa para lanzar búsquedas a Duffel. Si no existe una pareja de IDs válida, packageLinkType vale manual y el enlace lleva a la búsqueda general; Iris nunca inventa identificadores.

El formato de Package Holidays no es una API pública contractual de Skyscanner y puede cambiar. Para un producto comercial deben revisarse su programa de afiliación, atribución y condiciones de uso.

Despliegue en Vercel

El repositorio está preparado para desplegarse desde su raíz:

  1. Importa el repositorio en Vercel.
  2. No selecciones un framework manualmente; vercel.json define el build y el directorio de salida.
  3. Añade las credenciales en Project Settings > Environment Variables para Production, Preview y Development según corresponda.
  4. Despliega.

Vercel compila frontend/dist, publica los archivos estáticos en su CDN y convierte src/app.js en una Function con un máximo de 60 segundos.

La configuración utiliza estos comandos; Vercel no necesita un Start Command:

Install Command: npm ci && npm --prefix frontend ci
Build Command:   npm run build
Output Directory: frontend/dist

En producción se recomienda REDIS_URL. El rate limiter actual también opera por instancia; si se necesita un límite global debe complementarse con Vercel Firewall o un almacén distribuido para rate limiting.

Estructura

.
├── frontend/
│   └── src/
│       ├── App.tsx              # búsqueda, resultados y detalle de vuelos
│       └── App.css              # diseño responsive
├── src/
│   ├── app.js                   # Express, CORS, rate limit y frontend
│   ├── config.js                # selección de proveedores y límites
│   ├── data/                    # orígenes, destinos e IDs externos
│   ├── routes/search.js         # validación, endpoints y caché
│   ├── services/
│   │   ├── providers/           # Duffel y Google Routes
│   │   ├── cache.js             # Redis con fallback LRU
│   │   ├── scoring.js           # Iris Score
│   │   └── searchEngine.js      # concurrencia y ranking multimodal
│   └── utils/concurrencyPool.js
├── test/api.test.js             # pruebas HTTP de integración
└── vercel.json                  # despliegue full-stack

Comprobaciones

npm test
npm run lint
npm run build

La suite cubre salud, validación, ocultación de rutas no configuradas, ranking, caché, enlaces externos y el contrato normalizado de itinerarios.

Límites actuales

  • Los precios reales dependen de permisos, cobertura y disponibilidad de los proveedores externos.
  • Las ofertas de Duffel caducan y deben volver a consultarse antes de reservar.
  • Coche y transporte público no aparecen sin Google Routes; Iris no genera datos terrestres simulados.
  • Iris genera enlaces externos, pero no implementa todavía checkout ni emisión de reservas dentro de la aplicación.
  • Sin Redis, caché y rate limiting son locales a cada instancia.

Seguridad

  • Mantén .env fuera de Git.
  • Usa tokens de prueba durante el desarrollo.
  • Restringe las claves de Google por API y entorno.
  • Rota inmediatamente cualquier credencial que se haya publicado.
  • Configura secretos desde el panel del proveedor de despliegue.

About

Buscador inverso de viajes que compara vuelos, alojamiento y transporte para descubrir las mejores escapadas según origen, fechas, presupuesto y viajeros.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages