Files
vuelato/README.md
Alejandro Martinez b8906efc80
Some checks failed
ci / ci (22, ubuntu-latest) (push) Has been cancelled
Initial commit: Vuelato - buscador de vuelos
Nuxt 4 + Supabase + Flightics API. Incluye búsqueda de vuelos,
inspiraciones, watchlist, tracking de precios y mapa interactivo.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:37:06 +02:00

12 KiB

Vuelato

Buscador de vuelos con fechas flexibles, seguimiento de precios y exploracion de destinos en mapa. Construido con Nuxt 4, Supabase y la API de Flightics.

Stack

Capa Tecnologia
Framework Nuxt 4 (Vue 3, file-based routing)
UI @nuxt/ui v4 + Tailwind CSS v4
Iconos Lucide via @iconify-json/lucide (i-lucide-*)
Auth + DB Supabase (PostgreSQL, GoTrue, RLS) en Docker
Mapas Leaflet via @vue-leaflet/vue-leaflet
Graficos Chart.js via vue-chartjs
API de vuelos Flightics (proxy via server routes)
Vuelos en vivo Flightradar24 (endpoint no oficial, cache 5 min)
Runtime Nitro (server routes, cached handlers)

Arrancar

# 1. Instalar dependencias
pnpm install

# 2. Copiar variables de entorno
cp .env.example .env

# 3. Levantar Supabase local
pnpm supabase:up

# 4. Arrancar Nuxt
pnpm dev

# 5. Sincronizar aeropuertos (3300+) y paises (223) desde Flightics
curl -X POST http://localhost:3000/api/sync/locations

# 6. (Opcional) Sincronizar aerolineas desde Wikidata
curl -X POST http://localhost:3000/api/sync/airlines

URLs

Servicio URL
App http://localhost:3000
Supabase Studio http://localhost:3100
Supabase API (Kong) http://localhost:8000
PostgreSQL localhost:54322 (user: postgres, pass: postgres)

Comandos

Comando Descripcion
pnpm dev Servidor de desarrollo (localhost:3000)
pnpm build Build de produccion
pnpm preview Preview del build
pnpm lint ESLint
pnpm typecheck Comprobacion de tipos Vue
pnpm supabase:up Levantar Supabase Docker
pnpm supabase:down Parar Supabase
pnpm supabase:reset Reset completo (borra datos y volumenes)

Funcionalidades

Busqueda de vuelos

  • 5 modos de busqueda: ida y vuelta, solo ida, multi-ciudad, fin de semana, explorar destinos
  • Origenes y destinos multiples: selecciona varios aeropuertos con pills (badges)
  • Validacion de fechas: "hasta" no puede ser anterior a "desde", no se permiten fechas pasadas; correccion automatica si se cambia "desde" a una fecha posterior a "hasta"
  • Filtros avanzados: precio maximo (slider + input numerico editable), numero de escalas (botones rapidos + input numerico), aerolineas (filtrado exclusivo: solo vuelos operados exclusivamente por las seleccionadas), hora de salida
  • Nombres de aerolineas: diccionario integrado de 50+ aerolineas comunes (AF = Air France, IB = Iberia, etc.) ya que la API no devuelve nombres
  • Ordenacion: por precio, hora de salida, duracion de vuelo o numero de escalas
  • Info por tarjeta de vuelo:
    • Duracion de cada tramo (centrada en la linea de vuelo con icono de avion)
    • Tiempo total de vuelo (suma de todos los tramos)
    • Tiempo efectivo en destino (descontando vuelos)
    • Noches en destino
    • Dias totales del viaje (de salida a llegada, inclusive — util para vacaciones)
  • Hora en origen: opcion (guardada en cuenta) para ver entre parentesis la hora equivalente en tu aeropuerto de salida, solo cuando hay diferencia de huso horario
  • Vista completa o compacta de resultados
  • Creacion de seguimiento directamente desde resultados

Exploracion de destinos

  • Mapa interactivo con Leaflet mostrando destinos baratos desde tu aeropuerto
  • Tarjetas de destino con imagenes (Unsplash) y atribucion de fotografo
  • Filtro por presupuesto y vuelos directos
  • Click en destino navega a la ruta detallada

Seguimiento de precios

  • Crea seguimientos automaticos de busquedas de vuelos
  • Configura frecuencia: cada 6h, 12h, diario, cada 2 dias, semanal
  • Edicion completa: nombre, origenes, destinos (con pills), fechas (con validacion), estancia, frecuencia, fecha de expiracion, activo/pausado
  • Grafico de evolucion de precios historico (7, 14, 30, 60 dias)
  • Estadisticas: precio actual, minimo, maximo, media, tendencia
  • Historial de ejecuciones con estado y duracion

Multi-ciudad

  • Inspiracion para itinerarios con varias paradas
  • Seleccion de aeropuertos de origen multiples (con pills)

Watchlist

  • Guarda vuelos individuales con seguimiento de precio
  • Verificacion de precios (badges: bajo/subio/no disponible)
  • Replay de busquedas recientes
  • Conversion de busquedas guardadas a seguimiento automatico

Preferencias de usuario (/settings)

  • Busquedas: aeropuertos de origen habituales (se aplican como defecto), pasajeros por defecto (adultos/menores/bebes)
  • Visualizacion: mostrar hora en origen (sincronizado con la cuenta, fallback a cookie para anonimos)
  • Cuenta: email del usuario
  • Accesible desde el dropdown del menu de usuario > "Preferencias"

Autenticacion

  • Login con email/contrasena via Supabase GoTrue
  • Login con Google (OAuth)
  • Perfil creado automaticamente al registrarse (trigger PostgreSQL)

Paginas (13)

Ruta Funcion
/ Home: buscador compacto, inspiraciones, budget explorer, multi-city, busquedas recientes
/search Buscador dedicado con 5 modos
/results Resultados con sort, filtros, seguimiento, vista dual, hora en origen
/detail/[token] Itinerario completo, verificacion de precio, watchlist, compartir, tracking FR24
/explore Mapa Leaflet con destinos baratos, imagenes Unsplash, filtros
/route/[from]-[to] Vuelos de una ruta agrupados por aerolinea
/multi-city Inspiraciones multi-ciudad con origenes multiples
/tracking Lista de seguimientos de precios
/tracking/[id] Detalle y edicion de seguimiento, grafico de precios, historial
/watchlist Vuelos guardados, verificacion de precios, busquedas recientes
/settings Preferencias de usuario (busquedas, visualizacion, cuenta)
/auth Login / registro
/auth/confirm Callback OAuth

Estructura del proyecto

app/
  pages/                  # 13 paginas (file-based routing)
  components/             # 33 componentes por dominio
    auth/                 #   LoginForm, UserMenu
    search/               #   AirportInput, DateRangePicker, ModeTabs, etc.
    results/              #   ResultsToolbar, ResultsFilters, TripCardCompact
    detail/               #   SegmentCard, ItineraryTimeline, WatchlistToggle, etc.
    map/                  #   FlightMap, MapControls
    inspiration/          #   BudgetExplorer, MultiCityCard
    tracking/             #   TrackingConfig, CreateTrackingForm, TrackedSearchCard, etc.
    SearchForm.vue        #   Formulario principal (5 modos)
    TripCard.vue          #   Tarjeta de vuelo con toda la info de tiempos
    FlightLeg.vue         #   Tramo con duracion por segmento
    PassengerPicker.vue   #   Selector adultos/menores/bebes
    InspirationGrid.vue   #   Grid de inspiraciones
  composables/            # 12 composables
    useFlightSearch.ts    #   Busqueda con polling (hasta 3 rondas)
    useResultFilters.ts   #   Filtrado exclusivo y ordenacion
    useAirlineNames.ts    #   Diccionario de 50+ aerolineas + cache API
    useOriginTime.ts      #   Preferencia hora en origen (cuenta + cookie)
    useUserPreferences.ts #   Perfil via /api/profile (useState singleton)
    useTrackedSearches.ts #   CRUD seguimientos de precios
    useDestinationImages.ts # Imagenes Unsplash de destinos
    useWatchlist.ts       #   Vuelos guardados
    useRecentSearches.ts  #   Busquedas recientes
    useLocations.ts       #   Aeropuertos y paises
    useRouteFlights.ts    #   Vuelos entre dos aeropuertos
    useAuth.ts            #   Login/logout/registro
server/
  api/                    # 22 endpoints Nitro
    search.post.ts        #   Proxy busqueda Flightics
    detail.post.ts        #   Detalle de vuelo
    check.post.ts         #   Verificar precio
    inspirations.get.ts   #   Inspiraciones por aeropuerto
    locations.get.ts      #   Aeropuertos (cache 24h)
    countries.get.ts      #   Paises (cache 24h)
    airlines.get.ts       #   Aerolineas (cache 24h)
    flight-info.get.ts    #   Info vuelo FR24 (cache 5min)
    destination-image.get.ts # Imagenes Unsplash
    profile.get.ts        #   Obtener perfil de usuario
    profile.patch.ts      #   Actualizar perfil de usuario
    route-flights.post.ts #   Vuelos entre dos aeropuertos
    weekend-search.post.ts #  Busqueda de fin de semana
    multi-city-inspirations.post.ts
    sync/locations.post.ts #  Sincronizar aeropuertos
    sync/airlines.post.ts  #  Sincronizar aerolineas (Wikidata)
    tracking/             #   CRUD seguimientos + historial + ejecuciones
  utils/
    flightics.ts          #   Cliente API Flightics (tipos + funciones)
    wikidata.ts           #   Cliente SPARQL Wikidata
supabase/
  migrations/
    00001_init.sql        #   profiles, watchlist, recent_searches, airports, countries
    00002_search_queue.sql #  tracked_searches, search_runs, price_snapshots
    00003_profile_preferences.sql # show_origin_time en profiles
docker-compose.yml        # Supabase stack (6 servicios)

Base de datos

Tablas publicas (SELECT para anon y authenticated)

  • airports — 3300+ aeropuertos con IATA, nombre, lat/lon, ciudad, pais
  • countries — 223 paises con codigo, nombre, idiomas
  • airlines — aerolineas con IATA, ICAO y nombre

Tablas de usuario (RLS: auth.uid() = user_id)

  • profiles — aeropuertos habituales, pasajeros por defecto, locale, show_origin_time
  • watchlist — vuelos guardados con precio original/actual y estado
  • recent_searches — busquedas recientes con params y route_summary
  • tracked_searches — seguimientos con frecuencia, estado, parametros de busqueda
  • search_runs — ejecuciones de seguimientos
  • price_snapshots — historico de precios por seguimiento

Resetear y re-sincronizar

pnpm supabase:reset
pnpm dev
curl -X POST http://localhost:3000/api/sync/locations
curl -X POST http://localhost:3000/api/sync/airlines

Notas de desarrollo

Auto-import de componentes (Nuxt 4)

Nuxt deduplica el prefijo del directorio cuando el nombre del archivo ya empieza con el nombre del directorio:

  • results/ResultsFilters.vue<ResultsFilters> (no <ResultsResultsFilters>)
  • tracking/TrackingConfig.vue<TrackingConfig> (no <TrackingTrackingConfig>)
  • tracking/CreateTrackingForm.vue<TrackingCreateTrackingForm> (no empieza con "Tracking", se prefija)

Nuxt UI v4

  • UToggle no existe — usar <USwitch>
  • URange no existe — no usar slider de Nuxt UI

Timestamps de vuelos

Los campos departureTimestamp/arrivalTimestamp de Flightics estan en hora local de cada aeropuerto. Para calcular duraciones entre aeropuertos de distintas zonas horarias, usar siempre departureUtcTimestamp/arrivalUtcTimestamp.

Preferencias de usuario

useUserPreferences usa useState de Nuxt para estado compartido y $fetch('/api/profile') para persistencia. La preferencia "hora en origen" (useOriginTime) lee de la cuenta del usuario si esta logueado, con fallback a useCookie para visitantes anonimos.

API Flightics

  • La busqueda requiere polling: primera respuesta tiene notComplete: true. El composable hace hasta 3 rondas automaticamente.
  • company.name viene vacio ("") en la mayoria de respuestas. Se resuelve con diccionario integrado en useAirlineNames (50+ aerolineas).
  • Las fechas vacias causan 400. Se generan fechas por defecto (hoy + 30 dias).
  • getInspirations devuelve vacio para aeropuertos pequenos — es normal.

Supabase Docker

  • La imagen trae todos los roles internos pre-creados. Los SQL de init solo ajustan passwords.
  • Si GoTrue falla: docker compose down -v && docker compose up -d.
  • Studio: puerto 3100. Meta: puerto 8085 (remapeado de 8080).

Variables de entorno

SUPABASE_URL=http://localhost:8000          # Kong gateway
SUPABASE_KEY=eyJ...                         # anon key (JWT demo)
SUPABASE_SERVICE_ROLE_KEY=eyJ...            # service_role key (server-side)

Las keys demo estan en .env.example. Para produccion, generar nuevas con un JWT_SECRET propio.