Skip to main content

Trip Lifecycle

Understand the complete journey of a trip request in Viax, from the moment a user requests a ride to trip completion and payment.

Lifecycle Overview


Phase 1: Trip Request

User Actions

1

Select Pickup Location

User taps on map or uses current GPS location to set pickup point.Data Captured:
{
  "latitud_origen": -34.603722,
  "longitud_origen": -58.381592,
  "direccion_origen": "Av. Corrientes 1234, Buenos Aires"
}
2

Select Destination

User taps on map or searches for address to set dropoff point.Data Captured:
{
  "latitud_destino": -34.613722,
  "longitud_destino": -58.391592,
  "direccion_destino": "Av. Santa Fe 5678, Buenos Aires"
}
3

Choose Service Type

User selects between:
  • Viaje (Ride): Personal transportation
  • Paquete (Package): Delivery service
4

Select Vehicle Type

User chooses from available options:
  • 🏍️ Moto (Motorcycle)
  • 🚗 Carro (Car)
  • 🏍️ Moto Carga (Cargo Motorcycle)
  • 🚙 Carro Carga (Cargo Car)
5

View Estimate

System calculates and displays:
  • Route distance (km)
  • Estimated duration (minutes)
  • Price estimate (COP)
Calculation:
final baseFare = vehicleType.baseFare; // e.g., 5000 COP
final distanceCost = distance * pricePerKm; // e.g., 12.5 km * 1000
final timeCost = duration * pricePerMin; // e.g., 25 min * 100
final total = baseFare + distanceCost + timeCost;
6

Confirm Request

User taps “Solicitar viaje” button to submit request.

Backend Processing

// backend/user/create_trip_request.php
$stmt = $pdo->prepare("
    INSERT INTO solicitudes_servicio (
        usuario_id, 
        latitud_origen, longitud_origen, direccion_origen,
        latitud_destino, longitud_destino, direccion_destino,
        tipo_servicio, tipo_vehiculo,
        distancia_km, duracion_minutos, precio_estimado,
        estado, fecha_solicitud
    ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pendiente', NOW())
");

$stmt->execute([
    $usuario_id,
    $lat_origen, $lng_origen, $dir_origen,
    $lat_destino, $lng_destino, $dir_destino,
    $tipo_servicio, $tipo_vehiculo,
    $distancia, $duracion, $precio,
]);

$solicitud_id = $pdo->lastInsertId();

Automatic Driver Discovery

The system automatically searches for available drivers within a 5km radius of the pickup location.
Search Query:
SELECT 
    c.id,
    c.nombre_completo,
    c.telefono,
    c.tipo_vehiculo,
    c.calificacion_promedio,
    c.latitud_actual,
    c.longitud_actual,
    (
        6371 * acos(
            cos(radians(?)) * cos(radians(c.latitud_actual)) *
            cos(radians(c.longitud_actual) - radians(?)) +
            sin(radians(?)) * sin(radians(c.latitud_actual))
        )
    ) AS distancia_km
FROM conductores c
WHERE 
    c.disponibilidad = 1
    AND c.estado_verificacion = 'aprobado'
    AND c.tipo_vehiculo = ?
    AND c.latitud_actual IS NOT NULL
    AND c.longitud_actual IS NOT NULL
HAVING distancia_km <= 5
ORDER BY distancia_km ASC
LIMIT 10;
Parameters:
  • ? placeholders: latitud_origen, longitud_origen (3 times for Haversine formula)
  • tipo_vehiculo: Matches requested vehicle type
  • Radius: 5 kilometers
  • Limit: Top 10 closest drivers

Driver Matching Criteria

Location

  • Within 5km of pickup point
  • GPS coordinates updated < 5 min ago
  • Calculated using Haversine formula

Availability

  • disponibilidad = 1 (online)
  • Not currently on another trip
  • Active in the system

Verification

  • estado_verificacion = ‘aprobado’
  • Documents validated
  • Background check passed

Vehicle Match

  • tipo_vehiculo matches request
  • Vehicle registered and insured
  • Passed vehicle inspection

Notification to Drivers

Push Notification (Future):
{
  "title": "Nueva solicitud de viaje",
  "body": "Av. Corrientes 1234 → Av. Santa Fe 5678 (12.5 km)",
  "data": {
    "solicitud_id": 123,
    "tipo": "viaje",
    "distancia": 12.5,
    "precio": 17500
  }
}
Current Implementation:
  • Drivers poll server every 5 seconds for new requests
  • Requests appear in driver’s “Pending Requests” screen

Phase 3: Driver Acceptance

Driver Views Request

Driver sees:
TripRequestCard(
  origen: "Av. Corrientes 1234",
  destino: "Av. Santa Fe 5678",
  distancia: 12.5,
  duracion: 25,
  precio: 17500,
  usuarioNombre: "Juan Pérez",
  tipoServicio: "Viaje",
)

Driver Actions

1

Review Request

Driver evaluates:
  • Distance to pickup
  • Route complexity
  • Estimated earnings
  • Current traffic conditions
2

Accept or Decline

If Accept:
// backend/conductor/accept_trip_request.php

// 1. Update trip status
UPDATE solicitudes_servicio 
SET estado = 'aceptada'
WHERE id = ?

// 2. Create assignment
INSERT INTO asignaciones_conductor (
    solicitud_id, conductor_id, fecha_asignacion, estado
) VALUES (?, ?, NOW(), 'aceptado')

// 3. Set driver offline
UPDATE conductores
SET disponibilidad = 0
WHERE id = ?
If Decline:
  • Request remains in pending state
  • Shown to other nearby drivers
3

Navigate to Pickup

Driver receives:
  • Pickup address
  • GPS coordinates
  • Navigation link (Google Maps/Waze)
  • User contact number (for coordination)

User Notification

User sees:
DriverAssignedScreen(
  driverName: "Carlos Rodríguez",
  driverPhoto: "url",
  driverRating: 4.8,
  vehicleType: "Toyota Corolla",
  vehiclePlate: "ABC123",
  vehicleColor: "Gris",
  eta: "5 minutos",
)

Phase 4: En Route to Pickup

Driver Status Updates

Driver’s location updated every 10 seconds:
// backend/conductor/update_location.php
UPDATE conductores
SET 
    latitud_actual = ?,
    longitud_actual = ?,
    ultima_actualizacion = NOW()
WHERE id = ?
User sees driver approaching on map in real-time.

Communication

In-App Features (Future):
  • Chat between user and driver
  • Quick messages (“I’m here”, “5 minutes away”)
  • Voice call button
Current:
  • Phone call via displayed number

Phase 5: Trip in Progress

Pickup Confirmation

1

Driver Arrives

Driver taps “He llegado” button
updateTripStatus(solicitudId, 'llegado');
2

User Enters Vehicle

Driver confirms: “Pasajero a bordo”
updateTripStatus(solicitudId, 'recogido');
3

Start Trip

Driver taps “Iniciar viaje”
// Create actual trip record
INSERT INTO viajes (
    solicitud_id,
    conductor_id,
    usuario_id,
    hora_inicio,
    latitud_inicio,
    longitud_inicio,
    estado
) VALUES (?, ?, ?, NOW(), ?, ?, 'en_curso')

// Update request status
UPDATE solicitudes_servicio
SET estado = 'en_curso'
WHERE id = ?

During Trip

Driver View

  • Route to destination
  • Current traffic
  • Updated ETA
  • Trip timer
  • Distance counter

User View

  • Real-time driver location
  • Route visualization
  • ETA to destination
  • Trip details
  • Share trip with contacts
Location Tracking:
// Updated every 10 seconds while in progress
streamController.add(
  DriverLocation(
    latitude: currentLat,
    longitude: currentLng,
    heading: currentHeading,
    speed: currentSpeed,
    timestamp: DateTime.now(),
  )
);

Phase 6: Trip Completion

Arrival at Destination

1

Driver Marks Arrival

updateTripStatus(solicitudId, 'llegado_destino');
2

Calculate Final Fare

// Actual distance and duration
final actualDistance = calculateTripDistance(routePoints);
final actualDuration = endTime.difference(startTime).inMinutes;

// Recalculate fare
final baseFare = 5000;
final distanceCost = actualDistance * 1000;
final timeCost = actualDuration * 100;
final totalFare = baseFare + distanceCost + timeCost;

// Compare with estimate
if (totalFare > estimatedFare * 1.2) {
  // Fare increased > 20%, notify user
  showFareChangeDialog();
}
3

Complete Trip

// backend/conductor/complete_trip.php

// 1. Update trip record
UPDATE viajes
SET 
    hora_fin = NOW(),
    latitud_fin = ?,
    longitud_fin = ?,
    distancia_real = ?,
    duracion_real = ?,
    precio_final = ?,
    estado = 'completado'
WHERE id = ?

// 2. Update request
UPDATE solicitudes_servicio
SET estado = 'completada'
WHERE id = ?

// 3. Set driver back online
UPDATE conductores
SET disponibilidad = 1
WHERE id = ?

Payment Processing

  • Driver confirms cash payment received
  • Or payment marked as pending for later processing
  • Receipt generated

Trip Summary

User Receives:
{
  "trip_summary": {
    "viaje_id": 123,
    "fecha": "2024-11-01 10:30:00",
    "origen": "Av. Corrientes 1234",
    "destino": "Av. Santa Fe 5678",
    "conductor": "Carlos Rodríguez",
    "vehiculo": "Toyota Corolla - ABC123",
    "distancia_km": 12.8,
    "duracion_minutos": 27,
    "precio_final": 17800,
    "metodo_pago": "Efectivo",
    "recibo_url": "https://viax.com/receipts/123.pdf"
  }
}
Driver Receives:
{
  "trip_earnings": {
    "viaje_id": 123,
    "precio_total": 17800,
    "comision_plataforma": 3560,
    "ganancia_conductor": 14240,
    "metodo_pago": "Efectivo"
  }
}

Phase 7: Post-Trip

Rating & Review

RatingDialog(
  driverName: "Carlos Rodríguez",
  tripId: 123,
  fields: [
    RatingField('Puntualidad', 1-5 stars),
    RatingField('Conducción', 1-5 stars),
    RatingField('Amabilidad', 1-5 stars),
    RatingField('Vehículo limpio', 1-5 stars),
  ],
  commentField: true,
  tipOption: true,
)
Stored in database:
INSERT INTO calificaciones (
    viaje_id, usuario_id, conductor_id,
    calificacion, comentario, fecha
) VALUES (?, ?, ?, ?, ?, NOW())

Trip History

Stored for:
  • User’s trip history
  • Driver’s trip log
  • Platform analytics
  • Financial records
  • Dispute resolution
  • Tax reporting

Cancellation Flows

User Cancellation

UPDATE solicitudes_servicio
SET estado = 'cancelada',
    motivo_cancelacion = 'Usuario canceló antes de asignación'
WHERE id = ? AND estado = 'pendiente'
No penalty for user.
// Charge cancellation fee
$cancellationFee = 2000; // COP

UPDATE solicitudes_servicio
SET 
    estado = 'cancelada',
    motivo_cancelacion = ?,
    tarifa_cancelacion = ?
WHERE id = ?

// Compensate driver
INSERT INTO compensaciones_conductor (
    conductor_id, viaje_id, monto, razon
) VALUES (?, ?, ?, 'Cancelación de usuario')
User charged ₡2,000 cancellation fee.
User cannot cancel once trip has started. Must complete trip or contact support.

Driver Cancellation

UPDATE solicitudes_servicio
SET estado = 'pendiente' // Back to pending
WHERE id = ?

// Track driver cancellation
INSERT INTO cancelaciones_conductor (
    conductor_id, solicitud_id, razon, fecha
) VALUES (?, ?, ?, NOW())

// Check cancellation rate
$rate = getCancellationRate($conductorId);
if ($rate > 0.15) { // > 15%
    // Warn or suspend driver
    notifyDriverHighCancellationRate($conductorId);
}
Trip returned to pending state, shown to other drivers.
Driver must contact support. Emergency cancellation only for valid reasons (safety, emergency).

State Transitions Summary

Valid State Flow:
pendiente → aceptada → en_camino → llegado → recogido → 
  en_curso → llegado_destino → completada
Cancellation Paths:
pendiente → cancelada (user/system)
aceptada → cancelada (user with fee)
en_camino → cancelada (user with fee)
aceptada → pendiente (driver cancels, back to pool)
Database Enum:
CREATE TYPE estado_solicitud AS ENUM (
    'pendiente',
    'aceptada',
    'en_camino',
    'llegado',
    'recogido',
    'en_curso',
    'llegado_destino',
    'completada',
    'cancelada'
);
The trip lifecycle in Viax is designed for reliability, transparency, and user satisfaction with clear state transitions and comprehensive tracking.

Build docs developers (and LLMs) love