> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/Braian551/viax/llms.txt
> Use this file to discover all available pages before exploring further.

# Service Areas

> Define geographic service boundaries and operational zones

## Overview

Service Areas define the geographic boundaries where Viax operates, ensuring drivers and clients can only request or accept trips within designated zones.

<Info>
  Service area configuration prevents trips outside operational zones and helps manage driver coverage.
</Info>

## Geographic Boundaries

Service areas are defined using geographic coordinates:

```dart theme={null}
class ServiceArea {
  final int id;
  final String nombre;
  final String descripcion;
  final List<LatLng> boundaries; // Polygon coordinates
  final bool activo;
  final DateTime creadoEn;
  final DateTime? actualizadoEn;
}
```

## Defining Service Areas

<Steps>
  <Step title="Create Area">
    Define a new service area with a descriptive name
  </Step>

  <Step title="Draw Boundaries">
    Use map interface to draw polygon boundaries
  </Step>

  <Step title="Set Properties">
    Configure area-specific settings:

    * Minimum drivers required
    * Vehicle types allowed
    * Operating hours
  </Step>

  <Step title="Activate Area">
    Enable the service area for operations
  </Step>
</Steps>

## Colombia Service Areas

### Major Cities

<Tabs>
  <Tab title="Bogotá">
    **Department:** Cundinamarca

    **Population:** \~8 million

    **Coverage:** All 20 localities

    **Vehicle Types:** All (moto, carro, moto\_carga, carro\_carga)
  </Tab>

  <Tab title="Medellín">
    **Department:** Antioquia

    **Population:** \~2.5 million

    **Coverage:** Metropolitan area

    **Vehicle Types:** All
  </Tab>

  <Tab title="Cali">
    **Department:** Valle del Cauca

    **Population:** \~2.2 million

    **Coverage:** Urban area

    **Vehicle Types:** All
  </Tab>

  <Tab title="Barranquilla">
    **Department:** Atlántico

    **Population:** \~1.2 million

    **Coverage:** Urban area

    **Vehicle Types:** Moto, Carro
  </Tab>
</Tabs>

## Point-in-Polygon Check

Determine if a location is within a service area:

```dart theme={null}
bool isLocationInServiceArea(LatLng location, ServiceArea area) {
  // Ray casting algorithm
  int intersectCount = 0;
  final polygon = area.boundaries;
  
  for (int i = 0; i < polygon.length; i++) {
    final vertex1 = polygon[i];
    final vertex2 = polygon[(i + 1) % polygon.length];
    
    if (rayIntersectsSegment(location, vertex1, vertex2)) {
      intersectCount++;
    }
  }
  
  // Odd number of intersections = inside polygon
  return intersectCount % 2 == 1;
}

bool rayIntersectsSegment(LatLng point, LatLng vertex1, LatLng vertex2) {
  if (vertex1.latitude > vertex2.latitude) {
    final temp = vertex1;
    vertex1 = vertex2;
    vertex2 = temp;
  }
  
  if (point.latitude < vertex1.latitude || point.latitude > vertex2.latitude) {
    return false;
  }
  
  if (point.longitude >= max(vertex1.longitude, vertex2.longitude)) {
    return false;
  }
  
  if (point.longitude < min(vertex1.longitude, vertex2.longitude)) {
    return true;
  }
  
  final slope = (vertex2.longitude - vertex1.longitude) / 
                (vertex2.latitude - vertex1.latitude);
  final xIntersection = vertex1.longitude + 
                        (point.latitude - vertex1.latitude) * slope;
  
  return point.longitude < xIntersection;
}
```

## Validation on Trip Request

Check both origin and destination:

```dart theme={null}
Future<Result<bool>> validateTripLocations({
  required LatLng origin,
  required LatLng destination,
}) async {
  final serviceAreas = await getActiveServiceAreas();
  
  bool originValid = false;
  bool destinationValid = false;
  
  for (final area in serviceAreas) {
    if (isLocationInServiceArea(origin, area)) {
      originValid = true;
    }
    if (isLocationInServiceArea(destination, area)) {
      destinationValid = true;
    }
  }
  
  if (!originValid) {
    return Error(ValidationFailure(
      'El origen está fuera del área de servicio'
    ));
  }
  
  if (!destinationValid) {
    return Error(ValidationFailure(
      'El destino está fuera del área de servicio'
    ));
  }
  
  return Success(true);
}
```

## Map Visualization

Display service areas on the map:

```dart theme={null}
MapboxMap(
  initialCameraPosition: CameraPosition(
    target: LatLng(4.6097, -74.0817), // Bogotá
    zoom: 11,
  ),
  polygons: serviceAreas.map((area) => Polygon(
    polygonId: PolygonId(area.id.toString()),
    points: area.boundaries,
    strokeColor: AppColors.primary,
    strokeWidth: 2,
    fillColor: AppColors.primary.withOpacity(0.2),
  )).toSet(),
)
```

## Database Schema

```sql theme={null}
CREATE TABLE service_areas (
  id INT AUTO_INCREMENT PRIMARY KEY,
  nombre VARCHAR(100) NOT NULL,
  descripcion TEXT,
  activo BOOLEAN DEFAULT TRUE,
  creado_en TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  actualizado_en TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

CREATE TABLE service_area_boundaries (
  id INT AUTO_INCREMENT PRIMARY KEY,
  service_area_id INT NOT NULL,
  latitud DECIMAL(10, 8) NOT NULL,
  longitud DECIMAL(11, 8) NOT NULL,
  orden INT NOT NULL, -- Order of point in polygon
  FOREIGN KEY (service_area_id) REFERENCES service_areas(id) ON DELETE CASCADE
);

CREATE TABLE service_area_restrictions (
  id INT AUTO_INCREMENT PRIMARY KEY,
  service_area_id INT NOT NULL,
  tipo_vehiculo ENUM('moto', 'carro', 'moto_carga', 'carro_carga'),
  hora_inicio TIME,
  hora_fin TIME,
  activo BOOLEAN DEFAULT TRUE,
  FOREIGN KEY (service_area_id) REFERENCES service_areas(id) ON DELETE CASCADE
);
```

## Operating Hours

Restrict service availability by time:

```dart theme={null}
class OperatingHours {
  final TimeOfDay start;
  final TimeOfDay end;
  final List<int> daysOfWeek; // 1-7 (Monday-Sunday)
  
  bool isCurrentlyOperating() {
    final now = DateTime.now();
    final currentTime = TimeOfDay.fromDateTime(now);
    final currentDay = now.weekday;
    
    if (!daysOfWeek.contains(currentDay)) {
      return false;
    }
    
    final currentMinutes = currentTime.hour * 60 + currentTime.minute;
    final startMinutes = start.hour * 60 + start.minute;
    final endMinutes = end.hour * 60 + end.minute;
    
    return currentMinutes >= startMinutes && currentMinutes <= endMinutes;
  }
}
```

## Geocoding Integration

Use Nominatim (OpenStreetMap) for address validation:

```dart theme={null}
Future<LatLng?> geocodeAddress(String address) async {
  final url = 'https://nominatim.openstreetmap.org/search';
  final params = {
    'q': address,
    'format': 'json',
    'countrycodes': 'co', // Colombia only
    'limit': '1',
  };
  
  final response = await http.get(Uri.parse(url).replace(
    queryParameters: params,
  ));
  
  if (response.statusCode == 200) {
    final data = jsonDecode(response.body);
    if (data.isNotEmpty) {
      return LatLng(
        double.parse(data[0]['lat']),
        double.parse(data[0]['lon']),
      );
    }
  }
  
  return null;
}
```

## Driver Coverage Zones

Track which service areas have adequate driver coverage:

```dart theme={null}
class CoverageMetrics {
  final ServiceArea area;
  final int activeDrivers;
  final int minimumRequired;
  final double averageResponseTime; // seconds
  
  bool get hasAdequateCoverage => activeDrivers >= minimumRequired;
  
  CoverageStatus get status {
    if (activeDrivers == 0) return CoverageStatus.noCoverage;
    if (activeDrivers < minimumRequired * 0.5) return CoverageStatus.low;
    if (activeDrivers < minimumRequired) return CoverageStatus.medium;
    return CoverageStatus.high;
  }
}

enum CoverageStatus {
  noCoverage,
  low,
  medium,
  high,
}
```

## Expansion Planning

Analyze demand for new service areas:

<CardGroup cols={3}>
  <Card title="Request Density" icon="heat">
    Track trip requests outside current areas
  </Card>

  <Card title="Driver Interest" icon="users">
    Survey drivers on expansion preferences
  </Card>

  <Card title="Competition Analysis" icon="chart-line">
    Research competitor coverage
  </Card>
</CardGroup>

## Multi-Area Trips

Handle trips that cross service area boundaries:

```dart theme={null}
enum TripAreaPolicy {
  // Both origin and destination must be in same area
  sameAreaOnly,
  
  // Origin must be in an area, destination can be anywhere
  originAreaOnly,
  
  // Either origin or destination must be in an area
  eitherInArea,
  
  // Both origin and destination must be in areas (can be different)
  bothInAreas,
}

bool validateMultiAreaTrip({
  required LatLng origin,
  required LatLng destination,
  required TripAreaPolicy policy,
}) {
  final originArea = findServiceAreaForLocation(origin);
  final destArea = findServiceAreaForLocation(destination);
  
  switch (policy) {
    case TripAreaPolicy.sameAreaOnly:
      return originArea != null && 
             destArea != null && 
             originArea.id == destArea.id;
    
    case TripAreaPolicy.originAreaOnly:
      return originArea != null;
    
    case TripAreaPolicy.eitherInArea:
      return originArea != null || destArea != null;
    
    case TripAreaPolicy.bothInAreas:
      return originArea != null && destArea != null;
  }
}
```

## Best Practices

<Accordion title="Start Conservative">
  Begin with smaller, well-defined service areas and expand based on demand and driver availability.
</Accordion>

<Accordion title="Monitor Coverage">
  Regularly check driver coverage in all service areas to ensure adequate response times.
</Accordion>

<Accordion title="Use Natural Boundaries">
  Align service areas with natural or administrative boundaries (municipalities, neighborhoods).
</Accordion>

<Accordion title="Consider Traffic Patterns">
  Expand service areas based on commute patterns and high-demand routes.
</Accordion>

<Accordion title="Communicate Clearly">
  Clearly display service area boundaries to users so they know where service is available.
</Accordion>

## Related Features

<CardGroup cols={3}>
  <Card title="Pricing Configuration" icon="dollar-sign" href="/admin/pricing-configuration">
    Zone-based pricing (future)
  </Card>

  <Card title="Driver Management" icon="id-card" href="/admin/driver-management">
    Assign drivers to zones
  </Card>

  <Card title="Trip Monitoring" icon="route" href="/admin/trip-monitoring">
    Monitor trips by area
  </Card>
</CardGroup>
