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>
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, paiscountries— 223 paises con codigo, nombre, idiomasairlines— aerolineas con IATA, ICAO y nombre
Tablas de usuario (RLS: auth.uid() = user_id)
profiles— aeropuertos habituales, pasajeros por defecto, locale, show_origin_timewatchlist— vuelos guardados con precio original/actual y estadorecent_searches— busquedas recientes con params y route_summarytracked_searches— seguimientos con frecuencia, estado, parametros de busquedasearch_runs— ejecuciones de seguimientosprice_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
UToggleno existe — usar<USwitch>URangeno 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.nameviene vacio ("") en la mayoria de respuestas. Se resuelve con diccionario integrado enuseAirlineNames(50+ aerolineas).- Las fechas vacias causan 400. Se generan fechas por defecto (hoy + 30 dias).
getInspirationsdevuelve 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.