Some checks failed
ci / ci (22, ubuntu-latest) (push) Has been cancelled
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>
258 lines
12 KiB
Markdown
258 lines
12 KiB
Markdown
# 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](https://nuxt.com) (Vue 3, file-based routing) |
|
|
| UI | [@nuxt/ui v4](https://ui.nuxt.com) + Tailwind CSS v4 |
|
|
| Iconos | [Lucide](https://lucide.dev) via `@iconify-json/lucide` (`i-lucide-*`) |
|
|
| Auth + DB | [Supabase](https://supabase.com) (PostgreSQL, GoTrue, RLS) en Docker |
|
|
| Mapas | [Leaflet](https://leafletjs.com) via `@vue-leaflet/vue-leaflet` |
|
|
| Graficos | [Chart.js](https://www.chartjs.org) via `vue-chartjs` |
|
|
| API de vuelos | [Flightics](https://flightics.com) (proxy via server routes) |
|
|
| Vuelos en vivo | [Flightradar24](https://flightradar24.com) (endpoint no oficial, cache 5 min) |
|
|
| Runtime | [Nitro](https://nitro.build) (server routes, cached handlers) |
|
|
|
|
## Arrancar
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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.
|