Full Vuelos

Documentación técnica · generado el 18/10/2026

Documentación técnica — Full Vuelos

Full Vuelos es una aplicación de práctica del campus Full Advanced: una aerolínea de bajo costo (identidad visual inspirada en Wingo) que sirve como objetivo realista para practicar testing manual y automatizado.

Esta sección documenta las reglas de negocio exactas que implementa el código — es la referencia para escribir casos de prueba contra la app.

Contenido

  1. Autenticación y sesiones — usuarios propios, sesión aparte, registro público con reservas de ejemplo.
  2. Tarifas y precios — multiplicadores por tarifa, tipos de pasajero, extras, monedas de visualización.
  3. Reservas e inventario — PNR, validaciones, asientos y atomicidad.
  4. Cancelación y check-in — ventanas de tiempo, selección de asiento y restauración de inventario.
  5. Pagos simulados — validación de tarjeta (Luhn), qué se almacena.

Datos de demostración

Convenciones

Autenticación y sesiones

Modelo

Full Vuelos tiene su propia tabla de usuarios (vuelos_users) y su propia cookie de sesión (fv_sesion, firmada, válida 14 días y limitada a /practica-vuelos). No hay relación con las cuentas del campus Full Advanced:

Registro público

POST /practica-vuelos/registro crea una cuenta y abre sesión de inmediato, redirigiendo a la página principal con el aviso de bienvenida. Si el inventario de vuelos existe, la cuenta recibe las mismas dos reservas de ejemplo que viajero.demo (seed_example_bookings): una ida y vuelta BOG ↔ BAQ cancelable (tarifa Plus + maleta documentada + selección de asiento, ~5 días) y un solo-trayecto BOG → MDE dentro de la ventana de check-in. Vuelos agotados o inventario ausente simplemente omiten la reserva correspondiente — el registro nunca falla por esto.

Regla Mensaje
Todos los campos obligatorios Todos los campos son obligatorios.
Contraseña de mínimo 8 caracteres La contraseña debe tener al menos 8 caracteres.
Usuario único El nombre de usuario ya está registrado.
Correo único El correo electrónico ya está registrado.

Las contraseñas se almacenan con hash Argon2id.

Login

POST /practica-vuelos/login. Cualquier fallo (usuario inexistente, contraseña errada, cuenta desactivada) responde 401 con el mismo mensaje genérico Usuario o contraseña inválidos. — nunca se revela cuál parte falló.

El parámetro next redirige tras el login, pero solo a rutas locales de /practica-vuelos; cualquier otro valor cae a la página principal (anti open-redirect).

Páginas protegidas

Requieren sesión de Full Vuelos: el flujo de reserva (/reservar*), Mis reservas, el detalle de reserva, cancelación y check-in. Un visitante anónimo es redirigido (303) al login con ?next= apuntando a su destino original, query string incluida — la búsqueda y el manual son públicos.

Cancelación y check-in

Cancelación

POST /practica-vuelos/reservas/{codigo}/cancelar.

Reglas:

Efectos de una cancelación exitosa:

Selección de asiento

GET|POST /practica-vuelos/reservas/{codigo}/asientos.

Check-in

POST /practica-vuelos/reservas/{codigo}/checkin (también listado en /checkin con las reservas elegibles).

Reglas:

Efectos del check-in:

Matriz de estados visible en la UI

Estado Etiqueta Acciones
Confirmada, > 24 h, con derecho a asientos Confirmada Elegir asientos, Cancelar
Confirmada, > 24 h, sin derecho a asientos Confirmada Cancelar
Confirmada, dentro de 24 h Confirmada Elegir asientos (gratis), Hacer check-in
Check-in hecho Check-in hecho + fecha Ninguna
Cancelada Cancelada Ninguna

Pagos simulados

El paso de pago no procesa cargos reales: no hay pasarela, no hay red bancaria. Aun así valida como un formulario real, porque el propósito de la aplicación es practicar pruebas contra reglas verídicas.

Validaciones de la tarjeta

Campo Regla Mensaje
Número Solo dígitos, 13–19 caracteres, algoritmo de Luhn El número de tarjeta no es válido.
Titular Obligatorio Indica el nombre del titular de la tarjeta.
Vencimiento Formato MM/AA, mes 01–12, fecha futura La fecha de vencimiento debe ser MM/AA. / La tarjeta está vencida.
CVV 3 o 4 dígitos El CVV debe tener 3 o 4 dígitos.

Tarjeta de prueba canónica de la demo: 4111 1111 1111 1111 con cualquier vencimiento futuro y cualquier CVV válido.

Qué se almacena

Propiedades del pago

Reservas e inventario

La reserva (PNR)

Una reserva es un registro con código PNR de 6 caracteres del alfabeto sin ambigüedades ABCDEFGHJKLMNPQRSTUVWXYZ23456789 (sin 0/O ni 1/I), generado al azar hasta ser único. Un viaje de ida y vuelta es una sola reserva con dos tramos (vuelos_booking_legs, posición 0 = ida, 1 = regreso).

Validaciones al reservar

Todas se verifican dos veces: al cotizar (paso de pago) y dentro de la transacción (paso de confirmación). Cualquier violación responde 400 con el mensaje correspondiente:

Regla Mensaje
1–9 personas por reservación El grupo máximo permitido son 9 personas por reservación.
Al menos un adulto Debe viajar al menos un adulto.
Máximo 1 bebé por adulto Cada bebé debe viajar en el regazo de un adulto: máximo 1 bebé por adulto.
Tipo de pasajero válido (adulto / menor / bebe) El tipo del pasajero N no es válido (adulto, menor o bebe).
Nombre, apellido y documento obligatorios por pasajero Completa nombre, apellido y documento del pasajero N.
Documento único dentro de la reserva El documento X está repetido en la reserva.
El vuelo de regreso debe ser la ruta inversa al de ida El vuelo de regreso debe ser la ruta inversa al de ida.
Tarifa válida (basica / plus / full) Tarifa desconocida: X
El vuelo debe estar programado El vuelo X ya no está disponible.
El vuelo no debe haber partido El vuelo X ya partió.
Asientos suficientes para los pasajeros con silla El vuelo X no tiene suficientes asientos disponibles.

Inventario de asientos

Búsqueda

validate_search impone: origen dentro del mapa direccional de venta (ROUTE_DESTINATIONS: BAQ, CCS, CLO, GUA, HAV), destino servido por ese origen, ida no en el pasado, regreso ≥ ida (si aplica), al menos 1 adulto, ≤ 1 bebé por adulto y ≤ 9 personas en total. Los resultados se ordenan por hora de salida y solo incluyen vuelos del día consultado con estado scheduled.

Los selectores de ciudad se ordenan alfabéticamente por nombre de ciudad (ignorando acentos), no por código IATA.

Tira de fechas (resultados)

date_strip calcula, para la ruta y el día consultados, la disponibilidad de los 3 días anteriores y 3 posteriores (nunca en el pasado): cada día sabe si hay vuelos con asientos suficientes y el precio base más barato. La UI pinta de gris y deshabilita los días sin vuelos (title="No hay vuelos disponibles") y enlaza los disponibles a /buscar conservando ruta, tipo de viaje y composición de pasajeros. Cuando no hay selección posible, el botón Continuar se deshabilita y GET /reservar con selección inválida redirige a la página principal con ?aviso=seleccion.

Mis reservas (gestión)

filter_bookings aplica búsqueda por código (substring, sin mayúsculas) y filtro de estado (todas / confirmada / checkin / cancelada); split_bookings separa el resultado en próximas (confirmadas con primer vuelo futuro, más cercanas primero) e historial (voladas o canceladas, más recientes primero, plegadas en la UI).

Tarifas y precios

Tarifas

Cada vuelo tiene un precio base (USD, tarifa Básica, por pasajero). Las tarifas superiores multiplican el precio base y agregan inclusiones:

Tarifa Multiplicador Incluye
Básica (basica) ×1.00 Artículo personal
Plus (plus) ×1.25 + Equipaje de mano 10 kg
Full (full) ×1.50 + Equipaje de mano, maleta documentada 20 kg y selección de asiento

La tarifa se elige una vez por reserva y aplica a todos los tramos (ida y regreso).

Tipos de pasajero

Cada pasajero tiene un tipo (pax_type):

Tipo Edad Precio Asiento
adulto 12+ años Tarifa plena Sí
menor 2-11 años Tarifa plena Sí
bebe 0-23 meses Gratis (en regazo) No

Reglas del grupo (validadas en búsqueda y en la reserva):

Los cálculos de precio e inventario usan el conteo con asiento (seated = adultos + menores): los bebés no pagan ni descuentan inventario.

Extras

Los extras se compran por separado y aplican a todos los pasajeros con asiento de la reserva (regla deliberada de simplificación del demo):

Extra Clave Precio por pasajero
Equipaje de mano 10 kg carry_on $18.00
Maleta documentada 20 kg checked_bag $35.00
Selección de asiento seat_selection $9.00

Regla de inclusión: un extra que la tarifa ya incluye no se puede comprar — la UI no lo muestra y el servicio rechaza la compra con La tarifa <tarifa> ya incluye este extra. Con tarifa Full no hay extras disponibles.

Monedas de visualización

Los precios se almacenan en USD; el selector 💱 de la barra superior (cookie fv_currency, 180 días) solo cambia cómo se muestran — incluidos búsqueda, tarifas, extras, resumen de pago y detalle de reserva. Las tasas son fijas y ficticias (entorno de demostración, sin feed de mercado):

Moneda Código Símbolo Tasa por USD Decimales
Pesos argentinos ARS $ 950 0
Pesos chilenos CLP $ 920 0
Pesos dominicanos DOP RD$ 59 2
Pesos mexicanos MXN $ 18.5 2
Pesos colombianos COP $ 4.200 0
Soles peruanos PEN S/ 3.75 2
Reales brasileños BRL R$ 5.4 2
Florines de Aruba AWG Afl. 1.79 2
Dólares estadounidenses USD US$ 1 2

Un código desconocido en la cookie o en el parámetro cae a USD. Formato: US$ 49.99 para USD; $ 209.958 COP para el resto (código como sufijo).

Fórmula del total

total = (Σ precio_tarifa(tramo) + Σ extras) × pasajeros_con_asiento

Ejemplo

BOG→BAQ (base $58.99) ida y vuelta, tarifa Plus, 2 adultos + 1 bebé, maleta documentada como extra: