> ## 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.

# Clean Architecture Implementation

> Deep dive into how Viax implements Clean Architecture principles for maintainable and scalable code

# Clean Architecture in Viax

Viax implements **Clean Architecture** as proposed by Robert C. Martin (Uncle Bob), separating code into distinct layers with well-defined responsibilities.

## What is Clean Architecture?

Clean Architecture is a software design philosophy that enforces separation of concerns through layered architecture, making code:

<CardGroup cols={2}>
  <Card title="Maintainable" icon="wrench">
    Organized code that's easy to understand and modify
  </Card>

  <Card title="Testable" icon="vial">
    Each layer can be tested independently
  </Card>

  <Card title="Scalable" icon="arrow-up-right-dots">
    Easy to add features without breaking existing code
  </Card>

  <Card title="Framework Independent" icon="cube">
    Business logic doesn't depend on Flutter or any framework
  </Card>
</CardGroup>

## The Dependency Rule

<Warning>
  **Critical Principle**: Source code dependencies must point INWARD. Inner layers know nothing about outer layers.
</Warning>

```mermaid theme={null}
graph TB
    subgraph "Outer Layer"
        A[Presentation]
    end
    subgraph "Middle Layer"
        B[Data]
    end
    subgraph "Inner Layer"
        C[Domain]
    end
    
    A -->|depends on| B
    B -->|depends on| C
    C -->|pure business logic| C
```

## Layer Architecture

Viax organizes each feature into three distinct layers:

### Domain Layer (Core Business Logic)

**Location**: `lib/src/features/{feature}/domain/`

<Info>
  The domain layer contains **pure business logic** with ZERO external dependencies.
</Info>

#### Components

<Tabs>
  <Tab title="Entities">
    **Entities** are business objects that encapsulate enterprise business rules.

    ```dart theme={null}
    // lib/src/features/conductor/domain/entities/conductor_profile.dart
    class ConductorProfile {
      final int id;
      final int conductorId;
      final String nombreCompleto;
      final String telefono;
      final String? direccion;
      final DriverLicense? license;
      final Vehicle? vehicle;
      final String estadoVerificacion;
      
      const ConductorProfile({
        required this.id,
        required this.conductorId,
        required this.nombreCompleto,
        required this.telefono,
        this.direccion,
        this.license,
        this.vehicle,
        required this.estadoVerificacion,
      });
      
      // Business logic: Calculate profile completion
      int get completionPercentage {
        int completed = 0;
        int total = 5;
        
        if (nombreCompleto.isNotEmpty) completed++;
        if (telefono.isNotEmpty) completed++;
        if (direccion != null && direccion!.isNotEmpty) completed++;
        if (license != null) completed++;
        if (vehicle != null) completed++;
        
        return ((completed / total) * 100).round();
      }
      
      // Business logic: Check if ready for approval
      bool get canSubmitForApproval {
        return completionPercentage == 100 && 
               estadoVerificacion == 'pendiente';
      }
      
      // Immutability: Create modified copies
      ConductorProfile copyWith({
        String? nombreCompleto,
        String? telefono,
        String? direccion,
        DriverLicense? license,
        Vehicle? vehicle,
      }) {
        return ConductorProfile(
          id: id,
          conductorId: conductorId,
          nombreCompleto: nombreCompleto ?? this.nombreCompleto,
          telefono: telefono ?? this.telefono,
          direccion: direccion ?? this.direccion,
          license: license ?? this.license,
          vehicle: vehicle ?? this.vehicle,
          estadoVerificacion: estadoVerificacion,
        );
      }
    }
    ```

    **Key Points:**

    * Immutable objects (all fields final)
    * Business logic methods (completionPercentage, canSubmitForApproval)
    * No dependencies on UI or data layers
    * Pure Dart code
  </Tab>

  <Tab title="Repositories (Contracts)">
    **Repository Interfaces** define contracts for data access without implementation.

    ```dart theme={null}
    // lib/src/features/conductor/domain/repositories/conductor_repository.dart
    import 'package:dartz/dartz.dart';
    import '../entities/conductor_profile.dart';
    import '../../../../core/error/failures.dart';

    abstract class ConductorRepository {
      // Get driver profile
      Future<Either<Failure, ConductorProfile>> getProfile(int conductorId);
      
      // Update profile information
      Future<Either<Failure, ConductorProfile>> updateProfile({
        required int conductorId,
        required String nombreCompleto,
        required String telefono,
        String? direccion,
      });
      
      // Update driver license
      Future<Either<Failure, Unit>> updateDriverLicense({
        required int conductorId,
        required String numeroLicencia,
        required DateTime fechaExpedicion,
        required DateTime fechaVencimiento,
        required String categoria,
      });
      
      // Submit for approval
      Future<Either<Failure, Unit>> submitForApproval(int conductorId);
    }
    ```

    **Key Points:**

    * Abstract class (interface)
    * Returns `Either<Failure, T>` for error handling
    * No implementation details
    * Defines what, not how
  </Tab>

  <Tab title="Use Cases">
    **Use Cases** encapsulate application business rules - one use case per action.

    ```dart theme={null}
    // lib/src/features/conductor/domain/usecases/get_conductor_profile.dart
    import 'package:dartz/dartz.dart';
    import '../entities/conductor_profile.dart';
    import '../repositories/conductor_repository.dart';
    import '../../../../core/error/failures.dart';

    class GetConductorProfile {
      final ConductorRepository repository;
      
      GetConductorProfile(this.repository);
      
      Future<Either<Failure, ConductorProfile>> call(int conductorId) async {
        // Validation logic
        if (conductorId <= 0) {
          return Left(ValidationFailure('Invalid conductor ID'));
        }
        
        // Delegate to repository
        return await repository.getProfile(conductorId);
      }
    }
    ```

    **More Use Cases:**

    ```dart theme={null}
    // Update profile
    class UpdateConductorProfile {
      final ConductorRepository repository;
      UpdateConductorProfile(this.repository);
      
      Future<Either<Failure, ConductorProfile>> call({
        required int conductorId,
        required String nombreCompleto,
        required String telefono,
        String? direccion,
      }) async {
        // Validation
        if (nombreCompleto.trim().isEmpty) {
          return Left(ValidationFailure('Name cannot be empty'));
        }
        if (telefono.trim().isEmpty) {
          return Left(ValidationFailure('Phone cannot be empty'));
        }
        
        // Execute
        return await repository.updateProfile(
          conductorId: conductorId,
          nombreCompleto: nombreCompleto,
          telefono: telefono,
          direccion: direccion,
        );
      }
    }
    ```

    **Key Points:**

    * Single responsibility (one action)
    * Contains validation logic
    * Orchestrates repository calls
    * Returns domain entities
  </Tab>
</Tabs>

**Benefits of Domain Layer:**

* ✅ 100% testable without mocks
* ✅ Reusable across platforms (web, mobile, desktop)
* ✅ Independent of frameworks
* ✅ Pure business logic

***

### Data Layer (Implementation)

**Location**: `lib/src/features/{feature}/data/`

<Info>
  The data layer implements repository contracts and handles all external data sources.
</Info>

#### Components

<Tabs>
  <Tab title="Data Sources">
    **Data Sources** handle actual communication with external services.

    ```dart theme={null}
    // Interface
    // lib/src/features/conductor/data/datasources/conductor_remote_datasource.dart
    abstract class ConductorRemoteDataSource {
      Future<Map<String, dynamic>> getProfile(int conductorId);
      Future<Map<String, dynamic>> updateProfile(Map<String, dynamic> data);
    }

    // Implementation
    // lib/src/features/conductor/data/datasources/conductor_remote_datasource_impl.dart
    import 'package:http/http.dart' as http;
    import 'dart:convert';

    class ConductorRemoteDataSourceImpl implements ConductorRemoteDataSource {
      final http.Client client;
      final String baseUrl;
      
      ConductorRemoteDataSourceImpl({
        required this.client,
        required this.baseUrl,
      });
      
      @override
      Future<Map<String, dynamic>> getProfile(int conductorId) async {
        final response = await client.get(
          Uri.parse('$baseUrl/conductor/get_profile.php?conductor_id=$conductorId'),
          headers: {'Content-Type': 'application/json'},
        ).timeout(Duration(seconds: 30));
        
        if (response.statusCode == 200) {
          final json = jsonDecode(response.body);
          if (json['success'] == true) {
            return json['profile'];
          } else {
            throw ServerException(json['message'] ?? 'Unknown error');
          }
        } else {
          throw ServerException('HTTP ${response.statusCode}');
        }
      }
      
      @override
      Future<Map<String, dynamic>> updateProfile(Map<String, dynamic> data) async {
        final response = await client.post(
          Uri.parse('$baseUrl/conductor/update_profile.php'),
          headers: {'Content-Type': 'application/json'},
          body: jsonEncode(data),
        );
        
        if (response.statusCode == 200) {
          final json = jsonDecode(response.body);
          if (json['success'] == true) {
            return json['profile'];
          } else {
            throw ServerException(json['message'] ?? 'Update failed');
          }
        } else {
          throw ServerException('HTTP ${response.statusCode}');
        }
      }
    }
    ```

    **Key Points:**

    * Concrete implementations
    * HTTP calls, database queries, etc.
    * Throws technical exceptions
    * Returns raw data (Maps, Lists)
  </Tab>

  <Tab title="Models">
    **Models** extend entities with serialization capabilities.

    ```dart theme={null}
    // lib/src/features/conductor/data/models/conductor_profile_model.dart
    import '../../domain/entities/conductor_profile.dart';
    import 'driver_license_model.dart';
    import 'vehicle_model.dart';

    class ConductorProfileModel extends ConductorProfile {
      const ConductorProfileModel({
        required int id,
        required int conductorId,
        required String nombreCompleto,
        required String telefono,
        String? direccion,
        DriverLicense? license,
        Vehicle? vehicle,
        required String estadoVerificacion,
      }) : super(
        id: id,
        conductorId: conductorId,
        nombreCompleto: nombreCompleto,
        telefono: telefono,
        direccion: direccion,
        license: license,
        vehicle: vehicle,
        estadoVerificacion: estadoVerificacion,
      );
      
      // From JSON (API response to Model)
      factory ConductorProfileModel.fromJson(Map<String, dynamic> json) {
        return ConductorProfileModel(
          id: json['id'] ?? 0,
          conductorId: json['conductor_id'] ?? 0,
          nombreCompleto: json['nombre_completo'] ?? '',
          telefono: json['telefono'] ?? '',
          direccion: json['direccion'],
          license: json['license'] != null 
              ? DriverLicenseModel.fromJson(json['license']) 
              : null,
          vehicle: json['vehicle'] != null 
              ? VehicleModel.fromJson(json['vehicle']) 
              : null,
          estadoVerificacion: json['estado_verificacion'] ?? 'pendiente',
        );
      }
      
      // To JSON (Model to API request)
      Map<String, dynamic> toJson() {
        return {
          'id': id,
          'conductor_id': conductorId,
          'nombre_completo': nombreCompleto,
          'telefono': telefono,
          'direccion': direccion,
          'estado_verificacion': estadoVerificacion,
        };
      }
      
      // Convert Model to Entity
      ConductorProfile toEntity() {
        return ConductorProfile(
          id: id,
          conductorId: conductorId,
          nombreCompleto: nombreCompleto,
          telefono: telefono,
          direccion: direccion,
          license: license,
          vehicle: vehicle,
          estadoVerificacion: estadoVerificacion,
        );
      }
    }
    ```

    **Key Points:**

    * Extends domain entities
    * Handles JSON serialization
    * Knows about API structure
    * Converts between Model and Entity
  </Tab>

  <Tab title="Repository Impl">
    **Repository Implementation** connects data sources to domain contracts.

    ```dart theme={null}
    // lib/src/features/conductor/data/repositories/conductor_repository_impl.dart
    import 'package:dartz/dartz.dart';
    import '../../domain/entities/conductor_profile.dart';
    import '../../domain/repositories/conductor_repository.dart';
    import '../../../../core/error/failures.dart';
    import '../../../../core/error/exceptions.dart';
    import '../datasources/conductor_remote_datasource.dart';
    import '../models/conductor_profile_model.dart';

    class ConductorRepositoryImpl implements ConductorRepository {
      final ConductorRemoteDataSource remoteDataSource;
      
      ConductorRepositoryImpl({required this.remoteDataSource});
      
      @override
      Future<Either<Failure, ConductorProfile>> getProfile(int conductorId) async {
        try {
          // Call data source
          final profileData = await remoteDataSource.getProfile(conductorId);
          
          // Convert to model, then to entity
          final model = ConductorProfileModel.fromJson(profileData);
          final entity = model.toEntity();
          
          return Right(entity);
        } on ServerException catch (e) {
          return Left(ServerFailure(e.message));
        } on NetworkException catch (e) {
          return Left(NetworkFailure(e.message));
        } catch (e) {
          return Left(UnexpectedFailure(e.toString()));
        }
      }
      
      @override
      Future<Either<Failure, ConductorProfile>> updateProfile({
        required int conductorId,
        required String nombreCompleto,
        required String telefono,
        String? direccion,
      }) async {
        try {
          final data = {
            'conductor_id': conductorId,
            'nombre_completo': nombreCompleto,
            'telefono': telefono,
            if (direccion != null) 'direccion': direccion,
          };
          
          final profileData = await remoteDataSource.updateProfile(data);
          final model = ConductorProfileModel.fromJson(profileData);
          
          return Right(model.toEntity());
        } on ServerException catch (e) {
          return Left(ServerFailure(e.message));
        } catch (e) {
          return Left(UnexpectedFailure(e.toString()));
        }
      }
      
      // Other methods...
    }
    ```

    **Key Points:**

    * Implements domain repository interface
    * Coordinates data sources
    * Converts exceptions to failures
    * Returns domain entities (not models)
  </Tab>
</Tabs>

**Benefits of Data Layer:**

* ✅ Swappable data sources (API → Local DB)
* ✅ Centralized error handling
* ✅ Easy to mock for testing
* ✅ Isolates technical details

***

### Presentation Layer (UI & State)

**Location**: `lib/src/features/{feature}/presentation/`

<Info>
  The presentation layer handles UI rendering and state management.
</Info>

#### Components

<Tabs>
  <Tab title="Providers">
    **Providers** manage UI state and invoke use cases.

    ```dart theme={null}
    // lib/src/features/conductor/presentation/providers/conductor_profile_provider.dart
    import 'package:flutter/foundation.dart';
    import '../../domain/entities/conductor_profile.dart';
    import '../../domain/usecases/get_conductor_profile.dart';
    import '../../domain/usecases/update_conductor_profile.dart';

    class ConductorProfileProvider with ChangeNotifier {
      // Use cases (injected)
      final GetConductorProfile getConductorProfileUseCase;
      final UpdateConductorProfile updateConductorProfileUseCase;
      
      ConductorProfileProvider({
        required this.getConductorProfileUseCase,
        required this.updateConductorProfileUseCase,
      });
      
      // State
      ConductorProfile? _profile;
      bool _isLoading = false;
      String? _errorMessage;
      
      // Getters
      ConductorProfile? get profile => _profile;
      bool get isLoading => _isLoading;
      String? get errorMessage => _errorMessage;
      bool get hasError => _errorMessage != null;
      
      // Load profile
      Future<void> loadProfile(int conductorId) async {
        _isLoading = true;
        _errorMessage = null;
        notifyListeners();
        
        final result = await getConductorProfileUseCase(conductorId);
        
        result.fold(
          (failure) {
            _errorMessage = _mapFailureToMessage(failure);
            _profile = null;
          },
          (profile) {
            _profile = profile;
            _errorMessage = null;
          },
        );
        
        _isLoading = false;
        notifyListeners();
      }
      
      // Update profile
      Future<bool> updateProfile({
        required int conductorId,
        required String nombreCompleto,
        required String telefono,
        String? direccion,
      }) async {
        _isLoading = true;
        _errorMessage = null;
        notifyListeners();
        
        final result = await updateConductorProfileUseCase(
          conductorId: conductorId,
          nombreCompleto: nombreCompleto,
          telefono: telefono,
          direccion: direccion,
        );
        
        bool success = false;
        result.fold(
          (failure) {
            _errorMessage = _mapFailureToMessage(failure);
            success = false;
          },
          (profile) {
            _profile = profile;
            _errorMessage = null;
            success = true;
          },
        );
        
        _isLoading = false;
        notifyListeners();
        return success;
      }
      
      String _mapFailureToMessage(Failure failure) {
        if (failure is ServerFailure) {
          return 'Error del servidor: ${failure.message}';
        } else if (failure is NetworkFailure) {
          return 'Sin conexión a internet';
        } else if (failure is ValidationFailure) {
          return 'Error de validación: ${failure.message}';
        } else {
          return 'Error inesperado';
        }
      }
    }
    ```

    **Key Points:**

    * Extends ChangeNotifier (Provider pattern)
    * NO business logic (only state management)
    * Calls use cases
    * Converts failures to user messages
  </Tab>

  <Tab title="Screens">
    **Screens** are pure UI components.

    ```dart theme={null}
    // lib/src/features/conductor/presentation/screens/conductor_profile_screen.dart
    import 'package:flutter/material.dart';
    import 'package:provider/provider.dart';
    import '../providers/conductor_profile_provider.dart';

    class ConductorProfileScreen extends StatefulWidget {
      final int conductorId;
      
      const ConductorProfileScreen({required this.conductorId});
      
      @override
      State<ConductorProfileScreen> createState() => _ConductorProfileScreenState();
    }

    class _ConductorProfileScreenState extends State<ConductorProfileScreen> {
      @override
      void initState() {
        super.initState();
        // Load data on init
        WidgetsBinding.instance.addPostFrameCallback((_) {
          context.read<ConductorProfileProvider>().loadProfile(widget.conductorId);
        });
      }
      
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: Text('Perfil del Conductor')),
          body: Consumer<ConductorProfileProvider>(
            builder: (context, provider, child) {
              // Loading state
              if (provider.isLoading) {
                return Center(child: CircularProgressIndicator());
              }
              
              // Error state
              if (provider.hasError) {
                return Center(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Icon(Icons.error, size: 64, color: Colors.red),
                      SizedBox(height: 16),
                      Text(provider.errorMessage!),
                      ElevatedButton(
                        onPressed: () => provider.loadProfile(widget.conductorId),
                        child: Text('Reintentar'),
                      ),
                    ],
                  ),
                );
              }
              
              // Success state
              final profile = provider.profile;
              if (profile == null) {
                return Center(child: Text('No hay datos'));
              }
              
              return SingleChildScrollView(
                padding: EdgeInsets.all(16),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    // Profile completion card
                    Card(
                      child: Padding(
                        padding: EdgeInsets.all(16),
                        child: Column(
                          children: [
                            Text(
                              'Completitud del Perfil',
                              style: Theme.of(context).textTheme.titleLarge,
                            ),
                            SizedBox(height: 8),
                            LinearProgressIndicator(
                              value: profile.completionPercentage / 100,
                            ),
                            SizedBox(height: 4),
                            Text('${profile.completionPercentage}%'),
                          ],
                        ),
                      ),
                    ),
                    
                    SizedBox(height: 16),
                    
                    // Profile details
                    _buildInfoCard('Nombre', profile.nombreCompleto),
                    _buildInfoCard('Teléfono', profile.telefono),
                    if (profile.direccion != null)
                      _buildInfoCard('Dirección', profile.direccion!),
                    
                    // License info
                    if (profile.license != null) ..[
                      SizedBox(height: 16),
                      Text('Licencia de Conducción'),
                      _buildInfoCard('Número', profile.license!.numeroLicencia),
                    ],
                    
                    // Submit button
                    if (profile.canSubmitForApproval) ..[
                      SizedBox(height: 24),
                      SizedBox(
                        width: double.infinity,
                        child: ElevatedButton(
                          onPressed: () {
                            // Submit for approval
                          },
                          child: Text('Enviar para Aprobación'),
                        ),
                      ),
                    ],
                  ],
                ),
              );
            },
          ),
        );
      }
      
      Widget _buildInfoCard(String label, String value) {
        return Card(
          child: ListTile(
            title: Text(label),
            subtitle: Text(value),
          ),
        );
      }
    }
    ```

    **Key Points:**

    * Pure UI code
    * Consumes provider state
    * Handles loading/error/success states
    * No business logic
  </Tab>
</Tabs>

## Data Flow Example

Let's trace a complete flow: **Loading driver profile**

<Steps>
  <Step title="User Interaction">
    User taps "Ver Perfil" button in the app
  </Step>

  <Step title="Screen Triggers Load">
    ```dart theme={null}
    // ConductorProfileScreen
    context.read<ConductorProfileProvider>().loadProfile(42);
    ```
  </Step>

  <Step title="Provider Invokes Use Case">
    ```dart theme={null}
    // ConductorProfileProvider
    final result = await getConductorProfileUseCase(42);
    ```
  </Step>

  <Step title="Use Case Calls Repository">
    ```dart theme={null}
    // GetConductorProfile
    return await repository.getProfile(conductorId);
    ```
  </Step>

  <Step title="Repository Calls Data Source">
    ```dart theme={null}
    // ConductorRepositoryImpl
    final data = await remoteDataSource.getProfile(42);
    ```
  </Step>

  <Step title="Data Source Makes HTTP Call">
    ```dart theme={null}
    // ConductorRemoteDataSourceImpl
    final response = await client.get(
      Uri.parse('$baseUrl/conductor/get_profile.php?conductor_id=42')
    );
    ```
  </Step>

  <Step title="Backend Processes Request">
    ```php theme={null}
    // backend/conductor/get_profile.php
    $conductor_id = $_GET['conductor_id'];
    $stmt = $pdo->prepare("SELECT * FROM conductores WHERE id = ?");
    $stmt->execute([$conductor_id]);
    ```
  </Step>

  <Step title="Response Flows Back">
    ```
    Backend → Data Source (JSON)
    Data Source → Repository (Map)
    Repository → Use Case (Entity)
    Use Case → Provider (Entity)
    Provider → Screen (notifyListeners)
    Screen rebuilds with data
    ```
  </Step>
</Steps>

## Dependency Injection

Viax uses a **Service Locator** pattern for dependency injection:

```dart theme={null}
// lib/src/core/di/service_locator.dart
import 'package:get_it/get_it.dart';
import 'package:http/http.dart' as http;

final sl = GetIt.instance;

void setupServiceLocator() {
  // External dependencies
  sl.registerLazySingleton(() => http.Client());
  
  // Data sources
  sl.registerLazySingleton<ConductorRemoteDataSource>(
    () => ConductorRemoteDataSourceImpl(
      client: sl(),
      baseUrl: AppConfig.conductorServiceUrl,
    ),
  );
  
  // Repositories
  sl.registerLazySingleton<ConductorRepository>(
    () => ConductorRepositoryImpl(
      remoteDataSource: sl(),
    ),
  );
  
  // Use cases
  sl.registerLazySingleton(() => GetConductorProfile(sl()));
  sl.registerLazySingleton(() => UpdateConductorProfile(sl()));
  
  // Providers
  sl.registerFactory(
    () => ConductorProfileProvider(
      getConductorProfileUseCase: sl(),
      updateConductorProfileUseCase: sl(),
    ),
  );
}
```

**Usage:**

```dart theme={null}
// In main.dart
void main() {
  setupServiceLocator();
  runApp(MyApp());
}

// In widget
ChangeNotifierProvider(
  create: (_) => sl<ConductorProfileProvider>(),
  child: ConductorProfileScreen(conductorId: 42),
)
```

## Testing Benefits

<Tabs>
  <Tab title="Unit Tests (Domain)">
    ```dart theme={null}
    test('should calculate completion percentage correctly', () {
      // Arrange
      final profile = ConductorProfile(
        id: 1,
        conductorId: 1,
        nombreCompleto: 'Juan',
        telefono: '123',
        direccion: 'Calle 123',
        license: null, // Missing
        vehicle: null, // Missing
        estadoVerificacion: 'pendiente',
      );
      
      // Act
      final percentage = profile.completionPercentage;
      
      // Assert
      expect(percentage, 60); // 3/5 fields = 60%
    });
    ```
  </Tab>

  <Tab title="Integration Tests (Data)">
    ```dart theme={null}
    test('should return profile when API call succeeds', () async {
      // Arrange
      final mockClient = MockClient();
      when(mockClient.get(any)).thenAnswer((_) async => 
        http.Response('{"success": true, "profile": {...}}', 200)
      );
      final dataSource = ConductorRemoteDataSourceImpl(
        client: mockClient,
        baseUrl: 'http://test.com',
      );
      
      // Act
      final result = await dataSource.getProfile(1);
      
      // Assert
      expect(result, isA<Map<String, dynamic>>());
    });
    ```
  </Tab>

  <Tab title="Widget Tests (Presentation)">
    ```dart theme={null}
    testWidgets('should show loading indicator', (tester) async {
      // Arrange
      final provider = MockConductorProfileProvider();
      when(provider.isLoading).thenReturn(true);
      
      // Act
      await tester.pumpWidget(
        ChangeNotifierProvider.value(
          value: provider,
          child: MaterialApp(
            home: ConductorProfileScreen(conductorId: 1),
          ),
        ),
      );
      
      // Assert
      expect(find.byType(CircularProgressIndicator), findsOneWidget);
    });
    ```
  </Tab>
</Tabs>

## Migration Path to Microservices

<Info>
  Clean Architecture makes migrating to microservices straightforward - only the data layer needs changes!
</Info>

**Current (Monolith):**

```dart theme={null}
static const String conductorServiceUrl = 'http://76.13.114.194/conductor';
```

**Future (Microservices):**

```dart theme={null}
static const String conductorServiceUrl = 'https://conductor-service.viax.com/v1';
```

**No other code changes needed!** The domain and presentation layers remain unchanged.

<Check>
  Viax's Clean Architecture implementation ensures maintainable, testable, and scalable code that's ready for future growth.
</Check>
