# Warehouse Feature - Architecture Diagram ## Clean Architecture Layers ``` ┌─────────────────────────────────────────────────────────────────┐ │ PRESENTATION LAYER │ │ (UI, State Management, User Interactions) │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────┐ ┌──────────────────────────────────┐ │ │ │ WarehouseCard │ │ WarehouseSelectionPage │ │ │ │ - Shows warehouse │ │ - Displays warehouse list │ │ │ │ information │ │ - Handles user selection │ │ │ └─────────────────────┘ │ - Pull to refresh │ │ │ │ - Loading/Error/Empty states │ │ │ └──────────────────────────────────┘ │ │ ↓ │ │ ┌──────────────────────────────────┐ │ │ │ WarehouseNotifier │ │ │ │ (StateNotifier) │ │ │ │ - loadWarehouses() │ │ │ │ - selectWarehouse() │ │ │ │ - refresh() │ │ │ └──────────────────────────────────┘ │ │ ↓ │ │ ┌──────────────────────────────────┐ │ │ │ WarehouseState │ │ │ │ - warehouses: List │ │ │ │ - selectedWarehouse: Warehouse? │ │ │ │ - isLoading: bool │ │ │ │ - error: String? │ │ │ └──────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ↓ uses ┌─────────────────────────────────────────────────────────────────┐ │ DOMAIN LAYER │ │ (Business Logic, Entities, Use Cases) │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ GetWarehousesUseCase │ │ │ │ - Encapsulates business logic for fetching warehouses │ │ │ │ - Single responsibility │ │ │ │ - Returns Either> │ │ │ └──────────────────────────────────────────────────────────┘ │ │ ↓ uses │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ WarehouseRepository (Interface) │ │ │ │ + getWarehouses(): Either> │ │ │ └──────────────────────────────────────────────────────────┘ │ │ │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ WarehouseEntity │ │ │ │ - id: int │ │ │ │ - name: String │ │ │ │ - code: String │ │ │ │ - description: String? │ │ │ │ - isNGWareHouse: bool │ │ │ │ - totalCount: int │ │ │ │ + hasItems: bool │ │ │ │ + isNGType: bool │ │ │ └──────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ↓ implements ┌─────────────────────────────────────────────────────────────────┐ │ DATA LAYER │ │ (API Calls, Data Sources, Models) │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ WarehouseRepositoryImpl │ │ │ │ - Implements WarehouseRepository interface │ │ │ │ - Coordinates data sources │ │ │ │ - Converts exceptions to failures │ │ │ │ - Maps models to entities │ │ │ └──────────────────────────────────────────────────────────┘ │ │ ↓ uses │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ WarehouseRemoteDataSource (Interface) │ │ │ │ + getWarehouses(): Future> │ │ │ └──────────────────────────────────────────────────────────┘ │ │ ↓ │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ WarehouseRemoteDataSourceImpl │ │ │ │ - Makes API calls using ApiClient │ │ │ │ - Parses ApiResponse wrapper │ │ │ │ - Throws ServerException or NetworkException │ │ │ └──────────────────────────────────────────────────────────┘ │ │ ↓ uses │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ WarehouseModel │ │ │ │ - Extends WarehouseEntity │ │ │ │ - Adds JSON serialization (fromJson, toJson) │ │ │ │ - Maps API fields to entity fields │ │ │ └──────────────────────────────────────────────────────────┘ │ │ ↓ uses │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ ApiClient (Core) │ │ │ │ - Dio HTTP client wrapper │ │ │ │ - Adds authentication headers │ │ │ │ - Handles 401 errors │ │ │ │ - Logging and error handling │ │ │ └──────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ``` ## Data Flow ### 1. Loading Warehouses Flow ``` User Action (Pull to Refresh / Page Load) ↓ WarehouseSelectionPage ↓ calls ref.read(warehouseProvider.notifier).loadWarehouses() ↓ WarehouseNotifier.loadWarehouses() ↓ sets state state = state.setLoading() → UI shows loading indicator ↓ calls GetWarehousesUseCase.call() ↓ calls WarehouseRepository.getWarehouses() ↓ calls WarehouseRemoteDataSource.getWarehouses() ↓ makes HTTP request ApiClient.get('/warehouses') ↓ API Response { "Value": [...], "IsSuccess": true, "IsFailure": false, "Errors": [], "ErrorCodes": [] } ↓ parse List from JSON ↓ convert List ↓ wrap Right(warehouses) or Left(failure) ↓ update state state = state.setSuccess(warehouses) ↓ UI rebuilds with warehouse list ``` ### 2. Error Handling Flow ``` API Error / Network Error ↓ ApiClient throws DioException ↓ _handleDioError() converts to custom exception ↓ ServerException or NetworkException ↓ WarehouseRemoteDataSource catches and rethrows ↓ WarehouseRepositoryImpl catches exception ↓ Converts to Failure: - ServerException → ServerFailure - NetworkException → NetworkFailure ↓ Returns Left(failure) ↓ GetWarehousesUseCase returns Left(failure) ↓ WarehouseNotifier receives Left(failure) ↓ state = state.setError(failure.message) ↓ UI shows error state with retry button ``` ### 3. Warehouse Selection Flow ``` User taps on WarehouseCard ↓ onTap callback triggered ↓ _onWarehouseSelected(warehouse) ↓ ref.read(warehouseProvider.notifier).selectWarehouse(warehouse) ↓ state = state.setSelectedWarehouse(warehouse) ↓ Navigation: context.push('/operations', extra: warehouse) ↓ OperationSelectionPage receives warehouse ``` ## Dependency Graph ``` ┌─────────────────────────────────────────────────┐ │ Riverpod Providers │ ├─────────────────────────────────────────────────┤ │ │ │ secureStorageProvider │ │ ↓ │ │ apiClientProvider │ │ ↓ │ │ warehouseRemoteDataSourceProvider │ │ ↓ │ │ warehouseRepositoryProvider │ │ ↓ │ │ getWarehousesUseCaseProvider │ │ ↓ │ │ warehouseProvider (StateNotifierProvider) │ │ ↓ │ │ WarehouseSelectionPage watches this provider │ │ │ └─────────────────────────────────────────────────┘ ``` ## File Dependencies ``` warehouse_selection_page.dart ↓ imports - warehouse_entity.dart - warehouse_card.dart - warehouse_provider.dart (via DI setup) warehouse_card.dart ↓ imports - warehouse_entity.dart warehouse_provider.dart ↓ imports - warehouse_entity.dart - get_warehouses_usecase.dart get_warehouses_usecase.dart ↓ imports - warehouse_entity.dart - warehouse_repository.dart (interface) warehouse_repository_impl.dart ↓ imports - warehouse_entity.dart - warehouse_repository.dart (interface) - warehouse_remote_datasource.dart warehouse_remote_datasource.dart ↓ imports - warehouse_model.dart - api_client.dart - api_response.dart warehouse_model.dart ↓ imports - warehouse_entity.dart ``` ## State Transitions ``` ┌──────────────┐ │ Initial │ │ isLoading: F │ │ error: null │ │ warehouses:[]│ └──────────────┘ ↓ loadWarehouses() ↓ ┌──────────────┐ │ Loading │ │ isLoading: T │────────────────┐ │ error: null │ │ │ warehouses:[]│ │ └──────────────┘ │ ↓ │ Success Failure ↓ ↓ ┌──────────────┐ ┌──────────────┐ │ Success │ │ Error │ │ isLoading: F │ │ isLoading: F │ │ error: null │ │ error: "..." │ │ warehouses:[…]│ │ warehouses:[]│ └──────────────┘ └──────────────┘ ↓ ↓ Selection Retry ↓ ↓ ┌──────────────┐ (back to Loading) │ Selected │ │ selected: W │ └──────────────┘ ``` ## API Response Parsing ``` Raw API Response (JSON) ↓ { "Value": [ { "Id": 1, "Name": "Warehouse A", "Code": "001", ... } ], "IsSuccess": true, ... } ↓ ApiResponse.fromJson() parses wrapper ↓ ApiResponse> { value: [WarehouseModel, WarehouseModel, ...], isSuccess: true, isFailure: false, errors: [], errorCodes: [] } ↓ Check isSuccess ↓ if (isSuccess && value != null) return value! else throw ServerException(errors.first) ↓ List ↓ map((model) => model.toEntity()) ↓ List ``` ## Separation of Concerns ### Domain Layer - **No dependencies** on Flutter, Dio, or other frameworks - Contains **pure business logic** - Defines **contracts** (repository interfaces) - **Independent** and **testable** ### Data Layer - **Implements** domain contracts - Handles **external dependencies** (API, database) - **Converts** between models and entities - **Transforms** exceptions to failures ### Presentation Layer - **Depends** only on domain layer - Handles **UI rendering** and **user interactions** - Manages **local state** with Riverpod - **Observes** changes and **reacts** to state updates ## Testing Strategy ``` Unit Tests ├── Domain Layer │ ├── Test entities (equality, methods) │ ├── Test use cases (mock repository) │ └── Verify business logic ├── Data Layer │ ├── Test models (JSON serialization) │ ├── Test data sources (mock ApiClient) │ └── Test repository (mock data source) └── Presentation Layer ├── Test notifier (mock use case) └── Test state transitions Widget Tests ├── Test UI rendering ├── Test user interactions └── Test state-based UI changes Integration Tests ├── Test complete flow └── Test with real dependencies ``` ## Benefits of This Architecture 1. **Testability**: Each layer can be tested independently with mocks 2. **Maintainability**: Changes in one layer don't affect others 3. **Scalability**: Easy to add new features following the same pattern 4. **Reusability**: Domain entities and use cases can be reused 5. **Separation**: Clear boundaries between UI, business logic, and data 6. **Flexibility**: Easy to swap implementations (e.g., change API client) --- **Last Updated:** 2025-10-27 **Version:** 1.0.0