The Ultimate Flutter Enterprise Architecture Guide for Complex Mobile Applications

 



 



1. Background of This Task

In today's mobile-first world, enterprise applications are becoming increasingly complex. They need to handle:

  • Massive Scale: Supporting 100+ screens with intricate navigation flows

  • Multiple Authentication Methods: JWT, Bearer tokens, API keys, social logins

  • External Integrations: Firebase, OneSignal, Google Auth, payment gateways

  • Offline Capabilities: Data synchronization, background jobs, local storage

  • Performance Optimization: Efficient API calls, caching, lazy loading

  • Maintainability: Clean code structure for large development teams

  • Monitoring & Analytics: Error tracking, user behavior analysis, crash reporting

Traditional Flutter architectures often break down when faced with such complexity. Developers find themselves wrestling with:

  • Spaghetti code where UI, business logic, and data access are tightly coupled

  • Authentication headaches with token management and refresh logic

  • Poor error handling that crashes the entire app

  • Unmaintainable codebases that new team members struggle to understand

  • Inconsistent API integration patterns across different features

  • No standardized approach for handling background tasks and notifications

This comprehensive guide addresses these challenges by presenting a production-ready enterprise architecture that has been battle-tested in large-scale applications serving millions of users.


2. What You Will Learn

By following this guide, you'll master:

📚 Architecture Patterns

  • Clean Architecture principles with clear separation of concerns

  • Repository Pattern implementation for data abstraction

  • Dependency Injection setup using GetIt service locator

  • MVVM with State Management using Riverpod/Provider

  • Multi-layered architecture (Domain, Data, Presentation)

🔐 Authentication & Security

  • JWT Token Management with auto-refresh logic

  • Multiple Auth Strategies: Bearer tokens, API keys, no-auth endpoints

  • Social Authentication: Google, Apple, Facebook integration

  • Secure Storage using Flutter Secure Storage

  • Token expiration handling and session management

🔄 API Communication

  • Dio with Interceptors for centralized API handling

  • Retry Logic with exponential backoff for failed requests

  • Request/Response Caching to reduce network calls

  • Multipart Uploads with progress tracking

  • WebSocket-like polling for real-time updates

📱 Advanced Flutter Features

  • Auto-Route Navigation with route guards

  • Background Job Processing using WorkManager

  • Push Notification Integration with Firebase and OneSignal

  • Analytics & Monitoring with Sentry and Firebase Analytics

  • Offline-first Approach with local database synchronization

⚡ Performance Optimization

  • Image Caching strategies for better UX

  • Lazy Loading implementation

  • Connection Pooling for efficient networking

  • State Persistence across app restarts

  • Memory Management best practices

🧪 Testing & Quality

  • Unit Testing strategies for business logic

  • Widget Testing approaches for UI components

  • Integration Testing for complete user flows

  • Mock Services for API testing

  • Code Generation for routes and API clients

🔧 DevOps & Tooling

  • Environment Configuration (Dev, Staging, Prod)

  • Build Flavors setup

  • CI/CD Pipeline considerations

  • Monitoring & Alerting implementation

  • Performance Profiling techniques


3. Appendix

A. Installation & Setup Commands

bash
# Create new Flutter project
flutter create enterprise_app --org com.yourapp

# Add dependencies to pubspec.yaml
# (Refer to the complete pubspec.yaml in main content)

# Generate route files
flutter packages pub run build_runner build --delete-conflicting-outputs

# Generate API client files (if using Retrofit)
flutter pub run build_runner build

# Run in specific flavor
flutter run --flavor dev --target lib/main_dev.dart

B. Environment Configuration Files

.env.development:

text
BASE_URL=https://dev-api.example.com
API_KEY=dev_key_123
ENABLE_LOGGING=true
SENTRY_DSN=your_dev_sentry_dsn
ONESIGNAL_APP_ID=dev_app_id

.env.production:

text
BASE_URL=https://api.example.com
API_KEY=prod_key_456
ENABLE_LOGGING=false
SENTRY_DSN=your_prod_sentry_dsn
ONESIGNAL_APP_ID=prod_app_id

C. Code Generation Commands

bash
# Generate all code
flutter pub run build_runner build --delete-conflicting-outputs

# Watch mode for development
flutter pub run build_runner watch

# Clean generated files
flutter pub run build_runner clean

D. Useful Flutter Commands

bash
# Analyze code
flutter analyze

# Run tests
flutter test
flutter test --coverage

# Build for production
flutter build apk --release --flavor prod
flutter build ios --release --flavor prod

# Check dependencies
flutter pub outdated
flutter pub upgrade

# Generate icons
flutter pub run flutter_launcher_icons

# Generate splash screen
flutter pub run flutter_native_splash:create

E. Firebase Setup Commands

bash
# Add Firebase to your project
flutterfire configure

# Generate configuration
dart pub global activate flutterfire_cli
flutterfire configure

# For specific platforms
flutterfire configure --platforms=android,ios,macos,web

F. Common Issues & Solutions

IssueSolution
Build Runner ConflictsRun with --delete-conflicting-outputs flag
iOS Build FailsCheck Podfile, run pod install in ios directory
Android Build FailsCheck gradle.properties, update build tools
Dio Timeout ErrorsIncrease timeout duration, check network connectivity
Token Refresh LoopImplement proper error handling in auth interceptor
Memory LeaksUse dispose() methods, avoid circular references

G. Performance Metrics Benchmark

MetricTargetMeasurement Tool
App Size< 50MBAPK Analyzer
Startup Time< 2 secondsFlutter DevTools
FPS≥ 60 FPSPerformance Overlay
Memory Usage< 200MBMemory Profiler
API Response Time< 2 secondsNetwork Profiler

H. Testing Coverage Report

yaml
# .github/workflows/test.yml
name: Flutter Tests

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: subosito/flutter-action@v2
      - run: flutter pub get
      - run: flutter test --coverage
      - run: genhtml coverage/lcov.info -o coverage/html

📁 Complete Project Structure

text
lib/
├── core/                          # Core functionality
│   ├── app/
│   │   ├── app.dart
│   │   ├── app_config.dart
│   │   └── app_theme.dart
│   ├── constants/
│   ├── enums/
│   ├── extensions/
│   ├── utils/
│   └── widgets/
│
├── data/                          # Data Layer
│   ├── datasources/
│   │   ├── local/
│   │   │   ├── app_database.dart
│   │   │   ├── local_datasource.dart
│   │   │   └── models/
│   │   └── remote/
│   │       ├── api_client.dart
│   │       ├── api_endpoints.dart
│   │       ├── api_interceptors.dart
│   │       ├── api_service.dart
│   │       ├── auth_api_service.dart
│   │       ├── base_api_service.dart
│   │       └── models/
│   ├── models/
│   ├── repositories/
│   └── repositories_impl/
│
├── domain/                        # Domain Layer (Business Logic)
│   ├── entities/
│   ├── repositories/
│   ├── usecases/
│   └── values/
│
├── presentation/                  # Presentation Layer
│   ├── views/
│   │   ├── auth/
│   │   ├── home/
│   │   └── ...
│   ├── viewmodels/
│   ├── widgets/
│   └── routers/
│
├── di/                            # Dependency Injection
│   ├── injector.dart
│   └── service_locator.dart
│
├── services/                      # External Services
│   ├── auth/
│   │   ├── auth_service.dart
│   │   └── session_manager.dart
│   ├── notification/
│   │   ├── firebase_messaging_service.dart
│   │   └── onesignal_service.dart
│   ├── background/
│   │   └── background_job_service.dart
│   ├── storage/
│   │   └── secure_storage_service.dart
│   └── analytics/
│       └── analytics_service.dart
│
└── main.dart

1. Core Layer

App Configuration

dart
// core/app/app_config.dart
enum AppEnvironment { dev, staging, prod }

class AppConfig {
  final AppEnvironment environment;
  final String appName;
  final String baseUrl;
  final String apiKey;
  final bool enableLogging;
  final int sessionTimeout;
  
  static AppConfig? _instance;
  
  AppConfig._({
    required this.environment,
    required this.appName,
    required this.baseUrl,
    required this.apiKey,
    required this.enableLogging,
    required this.sessionTimeout,
  });
  
  factory AppConfig({
    required AppEnvironment environment,
    required String appName,
    required String baseUrl,
    required String apiKey,
    bool enableLogging = false,
    int sessionTimeout = 15,
  }) {
    return _instance ??= AppConfig._(
      environment: environment,
      appName: appName,
      baseUrl: baseUrl,
      apiKey: apiKey,
      enableLogging: enableLogging,
      sessionTimeout: sessionTimeout,
    );
  }
  
  static AppConfig get instance => _instance!;
  
  bool get isDevelopment => environment == AppEnvironment.dev;
  bool get isProduction => environment == AppEnvironment.prod;
}

App Initialization

dart
// core/app/app.dart
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:onesignal_flutter/onesignal_flutter.dart';
import 'di/service_locator.dart';

class App {
  static Future<void> initialize({
    required AppEnvironment environment,
    required String appName,
    required String baseUrl,
    required String apiKey,
  }) async {
    // Initialize Firebase
    await Firebase.initializeApp();
    
    // Configure app
    AppConfig(
      environment: environment,
      appName: appName,
      baseUrl: baseUrl,
      apiKey: apiKey,
      enableLogging: environment != AppEnvironment.prod,
    );
    
    // Initialize services
    await setupLocator();
    
    // Initialize OneSignal
    await OneSignal.shared.setAppId("your-onesignal-app-id");
    
    // Set notification handlers
    await _setupNotifications();
    
    // Initialize background services
    await _setupBackgroundServices();
  }
  
  static Future<void> _setupNotifications() async {
    OneSignal.shared.setNotificationWillShowInForegroundHandler(
      (OSNotificationReceivedEvent event) {
        event.complete(event.notification);
      },
    );
    
    OneSignal.shared.setNotificationOpenedHandler(
      (OSNotificationOpenedResult result) {
        // Handle notification click
        sl<NotificationService>().handleNotificationClick(result);
      },
    );
  }
  
  static Future<void> _setupBackgroundServices() async {
    // Setup background job scheduler
    await BackgroundJobScheduler.initialize();
    
    // Register periodic jobs
    BackgroundJobScheduler.registerPeriodicJob(
      jobId: 'sync_data',
      frequency: Duration(minutes: 15),
      task: () => sl<DataSyncService>().syncPendingData(),
    );
  }
}

2. Data Layer - API Infrastructure

Base API Service with Multiple Authentication Strategies

dart
// data/datasources/remote/base_api_service.dart
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:logger/logger.dart';
import '../../../core/app/app_config.dart';
import '../../../services/auth/auth_service.dart';
import 'api_exceptions.dart';

abstract class BaseApiService {
  final Dio _dio;
  final AuthService _authService;
  final Logger _logger;
  
  BaseApiService({
    required Dio dio,
    required AuthService authService,
    required Logger logger,
  }) : _dio = dio, _authService = authService, _logger = logger;
  
  Future<Response<T>> request<T>(
    String path, {
    HttpMethod method = HttpMethod.get,
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Map<String, dynamic>? headers,
    CancelToken? cancelToken,
    Options? options,
    String? contentType,
    AuthType authType = AuthType.bearer,
    bool retryOnAuthFailure = true,
    int? retryCount,
  }) async {
    // Check connectivity
    await _checkConnectivity();
    
    // Prepare request
    final requestOptions = _buildRequestOptions(
      path,
      method,
      headers,
      contentType,
      authType,
      options,
    );
    
    // Execute with retry logic
    return _executeWithRetry<T>(
      () => _executeRequest<T>(
        method,
        path,
        data: data,
        queryParameters: queryParameters,
        options: requestOptions,
        cancelToken: cancelToken,
      ),
      retryCount: retryCount ?? (retryOnAuthFailure ? 2 : 0),
      retryOnAuthFailure: retryOnAuthFailure,
      authType: authType,
    );
  }
  
  Options _buildRequestOptions(
    String path,
    HttpMethod method,
    Map<String, dynamic>? headers,
    String? contentType,
    AuthType authType,
    Options? options,
  ) {
    final baseHeaders = <String, dynamic>{
      'Content-Type': contentType ?? 'application/json',
      'Accept': 'application/json',
      'X-App-Version': '1.0.0',
      'X-Platform': 'flutter',
      'X-Device-ID': 'device_id_here', // Get from device info
    };
    
    // Add auth header based on type
    switch (authType) {
      case AuthType.bearer:
        final token = _authService.getAccessToken();
        if (token != null) {
          baseHeaders['Authorization'] = 'Bearer $token';
        }
        break;
      case AuthType.basic:
        // Implement basic auth if needed
        break;
      case AuthType.apiKey:
        baseHeaders['X-API-Key'] = AppConfig.instance.apiKey;
        break;
      case AuthType.none:
        break;
    }
    
    // Merge headers
    if (headers != null) {
      baseHeaders.addAll(headers);
    }
    
    return (options ?? Options()).copyWith(
      method: method.name.toUpperCase(),
      headers: baseHeaders,
    );
  }
  
  Future<Response<T>> _executeWithRetry<T>(
    Future<Response<T>> Function() request,
    int retryCount,
    bool retryOnAuthFailure,
    AuthType authType,
  ) async {
    int attempts = 0;
    
    while (true) {
      try {
        return await request();
      } on DioException catch (e) {
        attempts++;
        
        // Check if should retry on auth failure
        if (retryOnAuthFailure && 
            _isAuthError(e) && 
            authType == AuthType.bearer) {
          if (attempts <= retryCount) {
            try {
              await _authService.refreshToken();
              continue; // Retry with new token
            } catch (refreshError) {
              _logger.e('Token refresh failed', refreshError);
              _authService.logout();
              throw UnauthorizedException('Session expired');
            }
          }
        }
        
        // Check if should retry on network error
        if (attempts <= retryCount && _isNetworkError(e)) {
          await Future.delayed(Duration(seconds: 1 * attempts));
          continue;
        }
        
        throw _handleDioError(e);
      } catch (e) {
        rethrow;
      }
    }
  }
  
  Future<Response<T>> _executeRequest<T>(
    HttpMethod method,
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
  }) async {
    switch (method) {
      case HttpMethod.get:
        return await _dio.get<T>(
          path,
          queryParameters: queryParameters,
          options: options,
          cancelToken: cancelToken,
        );
      case HttpMethod.post:
        return await _dio.post<T>(
          path,
          data: data,
          queryParameters: queryParameters,
          options: options,
          cancelToken: cancelToken,
        );
      case HttpMethod.put:
        return await _dio.put<T>(
          path,
          data: data,
          queryParameters: queryParameters,
          options: options,
          cancelToken: cancelToken,
        );
      case HttpMethod.patch:
        return await _dio.patch<T>(
          path,
          data: data,
          queryParameters: queryParameters,
          options: options,
          cancelToken: cancelToken,
        );
      case HttpMethod.delete:
        return await _dio.delete<T>(
          path,
          data: data,
          queryParameters: queryParameters,
          options: options,
          cancelToken: cancelToken,
        );
    }
  }
  
  bool _isAuthError(DioException error) {
    return error.response?.statusCode == 401 ||
           error.response?.statusCode == 403;
  }
  
  bool _isNetworkError(DioException error) {
    return error.type == DioExceptionType.connectionError ||
           error.type == DioExceptionType.connectionTimeout ||
           error.type == DioExceptionType.sendTimeout ||
           error.type == DioExceptionType.receiveTimeout;
  }
  
  Future<void> _checkConnectivity() async {
    final connectivityResult = await Connectivity().checkConnectivity();
    if (connectivityResult == ConnectivityResult.none) {
      throw NetworkException('No internet connection');
    }
  }
  
  ApiException _handleDioError(DioException error) {
    _logger.e('API Error: ${error.message}', error);
    
    if (error.response != null) {
      final statusCode = error.response!.statusCode;
      final data = error.response!.data;
      
      try {
        final errorData = data is String ? jsonDecode(data) : data;
        final message = errorData['message'] ?? error.message ?? 'Unknown error';
        final errorCode = errorData['error_code']?.toString();
        
        return ApiException(
          message: message,
          statusCode: statusCode,
          errorCode: errorCode,
        );
      } catch (e) {
        return ApiException(
          message: error.message ?? 'Unknown error',
          statusCode: statusCode,
        );
      }
    }
    
    return ApiException(message: error.message ?? 'Unknown error');
  }
}

enum HttpMethod { get, post, put, patch, delete }
enum AuthType { bearer, basic, apiKey, none }

API Client with Interceptors

dart
// data/datasources/remote/api_client.dart
import 'package:dio/dio.dart';
import 'package:dio/io.dart';
import 'package:logger/logger.dart';
import '../../../core/app/app_config.dart';
import 'api_interceptors.dart';

class ApiClient {
  late Dio _dio;
  final Logger _logger;
  final AuthInterceptor _authInterceptor;
  final LoggingInterceptor _loggingInterceptor;
  final ErrorInterceptor _errorInterceptor;
  final CacheInterceptor _cacheInterceptor;
  
  ApiClient({
    required Logger logger,
    required AuthInterceptor authInterceptor,
    required LoggingInterceptor loggingInterceptor,
    required ErrorInterceptor errorInterceptor,
    required CacheInterceptor cacheInterceptor,
  }) : _logger = logger,
       _authInterceptor = authInterceptor,
       _loggingInterceptor = loggingInterceptor,
       _errorInterceptor = errorInterceptor,
       _cacheInterceptor = cacheInterceptor {
    _init();
  }
  
  void _init() {
    _dio = Dio(BaseOptions(
      baseUrl: AppConfig.instance.baseUrl,
      connectTimeout: const Duration(seconds: 30),
      receiveTimeout: const Duration(seconds: 30),
      sendTimeout: const Duration(seconds: 30),
      headers: {
        'Content-Type': 'application/json',
      },
    ));
    
    // Add interceptors
    _dio.interceptors.addAll([
      _authInterceptor,
      _loggingInterceptor,
      _cacheInterceptor,
      _errorInterceptor,
    ]);
    
    // For self-signed certificates in dev
    if (AppConfig.instance.isDevelopment) {
      (_dio.httpClientAdapter as IOHttpClientAdapter).createHttpClient = () {
        final client = HttpClient();
        client.badCertificateCallback = 
            (X509Certificate cert, String host, int port) => true;
        return client;
      };
    }
  }
  
  Dio get dio => _dio;
  
  Future<void> updateBaseUrl(String baseUrl) {
    _dio.options.baseUrl = baseUrl;
    return Future.value();
  }
  
  void addInterceptor(Interceptor interceptor) {
    _dio.interceptors.add(interceptor);
  }
  
  void removeInterceptor(Interceptor interceptor) {
    _dio.interceptors.remove(interceptor);
  }
  
  void clearInterceptors() {
    _dio.interceptors.clear();
  }
}

JWT Authentication Interceptor

dart
// data/datasources/remote/api_interceptors.dart
import 'package:dio/dio.dart';
import '../../../services/auth/auth_service.dart';

class AuthInterceptor extends Interceptor {
  final AuthService _authService;
  final Set<String> _excludedPaths = {
    '/auth/login',
    '/auth/register',
    '/auth/refresh',
    '/public/',
  };
  
  AuthInterceptor(this._authService);
  
  
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    // Skip auth for excluded paths
    if (_shouldSkipAuth(options.path)) {
      return handler.next(options);
    }
    
    final token = _authService.getAccessToken();
    if (token != null) {
      options.headers['Authorization'] = 'Bearer $token';
    }
    
    handler.next(options);
  }
  
  
  void onError(DioException err, ErrorInterceptorHandler handler) async {
    if (err.response?.statusCode == 401 && !_shouldSkipAuth(err.requestOptions.path)) {
      try {
        // Try to refresh token
        await _authService.refreshToken();
        
        // Retry the original request
        final response = await _retryRequest(err.requestOptions);
        return handler.resolve(response);
      } catch (e) {
        // Refresh failed, logout user
        _authService.logout();
        return handler.next(err);
      }
    }
    
    handler.next(err);
  }
  
  bool _shouldSkipAuth(String path) {
    return _excludedPaths.any((excluded) => path.contains(excluded));
  }
  
  Future<Response<dynamic>> _retryRequest(RequestOptions options) async {
    final newOptions = options.copyWith(
      headers: {
        ...options.headers,
        'Authorization': 'Bearer ${_authService.getAccessToken()}',
      },
    );
    
    final dio = Dio();
    return await dio.fetch(newOptions);
  }
}

class LoggingInterceptor extends Interceptor {
  final Logger _logger;
  
  LoggingInterceptor(this._logger);
  
  
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    if (AppConfig.instance.enableLogging) {
      _logger.i('Request: ${options.method} ${options.path}');
      _logger.i('Headers: ${options.headers}');
      if (options.data != null) {
        _logger.i('Body: ${options.data}');
      }
    }
    handler.next(options);
  }
  
  
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    if (AppConfig.instance.enableLogging) {
      _logger.i('Response: ${response.statusCode} ${response.requestOptions.path}');
      _logger.i('Response Data: ${response.data}');
    }
    handler.next(response);
  }
}

class CacheInterceptor extends Interceptor {
  final CacheManager _cacheManager;
  
  CacheInterceptor(this._cacheManager);
  
  
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
    if (options.extra['cache'] == true) {
      final cachedResponse = await _cacheManager.get(options.path);
      if (cachedResponse != null) {
        return handler.resolve(Response(
          requestOptions: options,
          data: cachedResponse,
          statusCode: 200,
        ));
      }
    }
    handler.next(options);
  }
  
  
  void onResponse(Response response, ResponseInterceptorHandler handler) async {
    if (response.requestOptions.extra['cache'] == true) {
      await _cacheManager.set(
        response.requestOptions.path,
        response.data,
        duration: Duration(minutes: 5),
      );
    }
    handler.next(response);
  }
}

class ErrorInterceptor extends Interceptor {
  
  void onError(DioException err, ErrorInterceptorHandler handler) {
    // Handle specific error cases
    if (err.type == DioExceptionType.connectionTimeout) {
      err = err.copyWith(
        error: 'Connection timeout. Please check your internet.',
      );
    } else if (err.type == DioExceptionType.receiveTimeout) {
      err = err.copyWith(
        error: 'Server response timeout. Please try again.',
      );
    }
    
    handler.next(err);
  }
}

API Service Implementation

dart
// data/datasources/remote/api_service.dart
import 'package:dio/dio.dart';
import 'base_api_service.dart';
import '../../../core/app/app_config.dart';

class ApiService extends BaseApiService {
  ApiService({
    required super.dio,
    required super.authService,
    required super.logger,
  });
  
  // Example: Public API (no auth required)
  Future<Map<String, dynamic>> getPublicData() async {
    final response = await request<Map<String, dynamic>>(
      '/public/data',
      authType: AuthType.none,
    );
    return response.data!;
  }
  
  // Example: JWT Protected API
  Future<List<dynamic>> getProtectedData({
    int page = 1,
    int limit = 20,
    String? search,
  }) async {
    final response = await request<List<dynamic>>(
      '/protected/data',
      queryParameters: {
        'page': page,
        'limit': limit,
        if (search != null) 'search': search,
      },
      authType: AuthType.bearer,
    );
    return response.data!;
  }
  
  // Example: API Key Authentication
  Future<Map<String, dynamic>> getThirdPartyData() async {
    final response = await request<Map<String, dynamic>>(
      '/third-party/data',
      authType: AuthType.apiKey,
    );
    return response.data!;
  }
  
  // Example: File Upload with Progress
  Future<void> uploadFile(
    String filePath, {
    ProgressCallback? onProgress,
    CancelToken? cancelToken,
  }) async {
    final formData = FormData.fromMap({
      'file': await MultipartFile.fromFile(filePath),
    });
    
    await request<void>(
      '/upload',
      method: HttpMethod.post,
      data: formData,
      contentType: 'multipart/form-data',
      authType: AuthType.bearer,
      cancelToken: cancelToken,
      options: Options(
        extra: {
          'onProgress': onProgress,
        },
      ),
    );
  }
  
  // Example: WebSocket-like polling
  Stream<Map<String, dynamic>> pollUpdates(int intervalSeconds) {
    final streamController = StreamController<Map<String, dynamic>>();
    
    Timer.periodic(Duration(seconds: intervalSeconds), (timer) async {
      try {
        final response = await request<Map<String, dynamic>>(
          '/updates',
          authType: AuthType.bearer,
        );
        streamController.add(response.data!);
      } catch (e) {
        streamController.addError(e);
      }
    });
    
    return streamController.stream;
  }
}

Authentication API Service

dart
// data/datasources/remote/auth_api_service.dart
import 'package:dio/dio.dart';
import 'base_api_service.dart';
import '../../../domain/entities/auth_entity.dart';

class AuthApiService extends BaseApiService {
  AuthApiService({
    required super.dio,
    required super.authService,
    required super.logger,
  });
  
  Future<AuthResponse> login({
    required String email,
    required String password,
    String? deviceToken,
  }) async {
    final response = await request<Map<String, dynamic>>(
      '/auth/login',
      method: HttpMethod.post,
      data: {
        'email': email,
        'password': password,
        'device_token': deviceToken,
        'device_type': 'mobile',
      },
      authType: AuthType.none,
    );
    
    return AuthResponse.fromJson(response.data!);
  }
  
  Future<AuthResponse> register({
    required String name,
    required String email,
    required String password,
    String? phone,
  }) async {
    final response = await request<Map<String, dynamic>>(
      '/auth/register',
      method: HttpMethod.post,
      data: {
        'name': name,
        'email': email,
        'password': password,
        'phone': phone,
      },
      authType: AuthType.none,
    );
    
    return AuthResponse.fromJson(response.data!);
  }
  
  Future<AuthResponse> refreshToken(String refreshToken) async {
    final response = await request<Map<String, dynamic>>(
      '/auth/refresh',
      method: HttpMethod.post,
      data: {
        'refresh_token': refreshToken,
      },
      authType: AuthType.none,
    );
    
    return AuthResponse.fromJson(response.data!);
  }
  
  Future<void> logout() async {
    try {
      await request<void>(
        '/auth/logout',
        method: HttpMethod.post,
        authType: AuthType.bearer,
      );
    } catch (e) {
      // Even if API fails, we should logout locally
      _logger.w('Logout API failed, but proceeding with local logout');
    }
  }
  
  Future<void> forgotPassword(String email) async {
    await request<void>(
      '/auth/forgot-password',
      method: HttpMethod.post,
      data: {'email': email},
      authType: AuthType.none,
    );
  }
  
  Future<void> resetPassword({
    required String token,
    required String newPassword,
  }) async {
    await request<void>(
      '/auth/reset-password',
      method: HttpMethod.post,
      data: {
        'token': token,
        'new_password': newPassword,
      },
      authType: AuthType.none,
    );
  }
  
  // Social login
  Future<AuthResponse> socialLogin({
    required SocialProvider provider,
    required String token,
    String? deviceToken,
  }) async {
    final response = await request<Map<String, dynamic>>(
      '/auth/social/login',
      method: HttpMethod.post,
      data: {
        'provider': provider.name,
        'token': token,
        'device_token': deviceToken,
      },
      authType: AuthType.none,
    );
    
    return AuthResponse.fromJson(response.data!);
  }
}

3. Authentication Service

dart
// services/auth/auth_service.dart
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:jwt_decoder/jwt_decoder.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:sign_in_with_apple/sign_in_with_apple.dart';
import '../../data/datasources/remote/auth_api_service.dart';
import '../../domain/entities/auth_entity.dart';

class AuthService {
  final AuthApiService _authApiService;
  final SecureStorageService _secureStorage;
  final GoogleSignIn _googleSignIn;
  final FirebaseAuth _firebaseAuth;
  
  AuthService({
    required AuthApiService authApiService,
    required SecureStorageService secureStorage,
  }) : _authApiService = authApiService,
       _secureStorage = secureStorage,
       _googleSignIn = GoogleSignIn(
         scopes: ['email', 'profile'],
       ),
       _firebaseAuth = FirebaseAuth.instance;
  
  // Authentication state stream
  Stream<AuthState> get authStateChanges => _authStateController.stream;
  final StreamController<AuthState> _authStateController = 
      StreamController<AuthState>.broadcast();
  
  // Current user
  UserEntity? _currentUser;
  UserEntity? get currentUser => _currentUser;
  
  // Tokens
  String? _accessToken;
  String? _refreshToken;
  
  Future<void> initialize() async {
    // Try to load saved session
    await _loadSavedSession();
  }
  
  Future<void> _loadSavedSession() async {
    try {
      _accessToken = await _secureStorage.getAccessToken();
      _refreshToken = await _secureStorage.getRefreshToken();
      
      if (_accessToken != null && !_isTokenExpired(_accessToken!)) {
        final userData = await _secureStorage.getUserData();
        if (userData != null) {
          _currentUser = UserEntity.fromJson(userData);
          _authStateController.add(AuthState.authenticated);
        }
      } else if (_refreshToken != null) {
        // Try to refresh token
        await refreshToken();
      } else {
        _authStateController.add(AuthState.unauthenticated);
      }
    } catch (e) {
      await logout();
    }
  }
  
  Future<AuthResponse> login({
    required String email,
    required String password,
  }) async {
    try {
      final response = await _authApiService.login(
        email: email,
        password: password,
        deviceToken: await _getDeviceToken(),
      );
      
      await _saveAuthData(response);
      _currentUser = response.user;
      _authStateController.add(AuthState.authenticated);
      
      return response;
    } catch (e) {
      _authStateController.add(AuthState.unauthenticated);
      rethrow;
    }
  }
  
  Future<AuthResponse> googleSignIn() async {
    try {
      final googleAccount = await _googleSignIn.signIn();
      if (googleAccount == null) {
        throw Exception('Google sign in cancelled');
      }
      
      final googleAuth = await googleAccount.authentication;
      
      // Option 1: Use Google token directly with your backend
      final response = await _authApiService.socialLogin(
        provider: SocialProvider.google,
        token: googleAuth.idToken!,
        deviceToken: await _getDeviceToken(),
      );
      
      // Option 2: Use Firebase Auth (if using Firebase)
      // final credential = GoogleAuthProvider.credential(
      //   accessToken: googleAuth.accessToken,
      //   idToken: googleAuth.idToken,
      // );
      // final firebaseUser = await _firebaseAuth.signInWithCredential(credential);
      
      await _saveAuthData(response);
      _currentUser = response.user;
      _authStateController.add(AuthState.authenticated);
      
      return response;
    } catch (e) {
      _authStateController.add(AuthState.unauthenticated);
      rethrow;
    }
  }
  
  Future<AuthResponse> appleSignIn() async {
    try {
      final credential = await SignInWithApple.getAppleIDCredential(
        scopes: [
          AppleIDAuthorizationScopes.email,
          AppleIDAuthorizationScopes.fullName,
        ],
      );
      
      final response = await _authApiService.socialLogin(
        provider: SocialProvider.apple,
        token: credential.identityToken!,
        deviceToken: await _getDeviceToken(),
      );
      
      await _saveAuthData(response);
      _currentUser = response.user;
      _authStateController.add(AuthState.authenticated);
      
      return response;
    } catch (e) {
      _authStateController.add(AuthState.unauthenticated);
      rethrow;
    }
  }
  
  Future<void> refreshToken() async {
    if (_refreshToken == null) {
      throw Exception('No refresh token available');
    }
    
    try {
      final response = await _authApiService.refreshToken(_refreshToken!);
      await _saveAuthData(response);
      _currentUser = response.user;
    } catch (e) {
      await logout();
      rethrow;
    }
  }
  
  Future<void> logout() async {
    try {
      await _authApiService.logout();
    } catch (e) {
      // Continue with local logout even if API fails
    }
    
    // Clear local data
    await _secureStorage.clearAll();
    await _googleSignIn.signOut();
    await _firebaseAuth.signOut();
    
    // Reset state
    _accessToken = null;
    _refreshToken = null;
    _currentUser = null;
    
    // Notify listeners
    _authStateController.add(AuthState.unauthenticated);
  }
  
  Future<void> _saveAuthData(AuthResponse response) async {
    _accessToken = response.accessToken;
    _refreshToken = response.refreshToken;
    
    await Future.wait([
      _secureStorage.setAccessToken(response.accessToken),
      _secureStorage.setRefreshToken(response.refreshToken),
      _secureStorage.setUserData(response.user.toJson()),
    ]);
    
    if (response.expiresIn != null) {
      final expiryTime = DateTime.now().add(
        Duration(seconds: response.expiresIn!),
      );
      await _secureStorage.setTokenExpiry(expiryTime.toIso8601String());
    }
  }
  
  bool _isTokenExpired(String token) {
    try {
      return JwtDecoder.isExpired(token);
    } catch (e) {
      return true;
    }
  }
  
  Future<String?> _getDeviceToken() async {
    // Get FCM token for push notifications
    try {
      return await FirebaseMessaging.instance.getToken();
    } catch (e) {
      return null;
    }
  }
  
  String? getAccessToken() => _accessToken;
  String? getRefreshToken() => _refreshToken;
  
  bool get isAuthenticated => _accessToken != null && 
                             !_isTokenExpired(_accessToken!);
  
  Future<void> dispose() async {
    await _authStateController.close();
  }
}

enum AuthState {
  unauthenticated,
  authenticated,
  loading,
  error,
}

enum SocialProvider {
  google,
  apple,
  facebook,
}

Secure Storage Service

dart
// services/storage/secure_storage_service.dart
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

class SecureStorageService {
  static const _storage = FlutterSecureStorage();
  
  // Keys
  static const _keyAccessToken = 'access_token';
  static const _keyRefreshToken = 'refresh_token';
  static const _keyUserData = 'user_data';
  static const _keyTokenExpiry = 'token_expiry';
  static const _keyAppSettings = 'app_settings';
  
  Future<void> setAccessToken(String token) async {
    await _storage.write(key: _keyAccessToken, value: token);
  }
  
  Future<String?> getAccessToken() async {
    return await _storage.read(key: _keyAccessToken);
  }
  
  Future<void> setRefreshToken(String token) async {
    await _storage.write(key: _keyRefreshToken, value: token);
  }
  
  Future<String?> getRefreshToken() async {
    return await _storage.read(key: _keyRefreshToken);
  }
  
  Future<void> setUserData(String userData) async {
    await _storage.write(key: _keyUserData, value: userData);
  }
  
  Future<String?> getUserData() async {
    return await _storage.read(key: _keyUserData);
  }
  
  Future<void> setTokenExpiry(String expiry) async {
    await _storage.write(key: _keyTokenExpiry, value: expiry);
  }
  
  Future<String?> getTokenExpiry() async {
    return await _storage.read(key: _keyTokenExpiry);
  }
  
  Future<void> clearAll() async {
    await _storage.deleteAll();
  }
  
  Future<void> clearAuthData() async {
    await Future.wait([
      _storage.delete(key: _keyAccessToken),
      _storage.delete(key: _keyRefreshToken),
      _storage.delete(key: _keyUserData),
      _storage.delete(key: _keyTokenExpiry),
    ]);
  }
}

4. Dependency Injection

dart
// di/service_locator.dart
import 'package:get_it/get_it.dart';
import 'package:logger/logger.dart';
import '../services/auth/auth_service.dart';
import '../services/storage/secure_storage_service.dart';
import '../data/datasources/remote/api_client.dart';
import '../data/datasources/remote/api_service.dart';
import '../data/datasources/remote/auth_api_service.dart';
import '../data/datasources/remote/api_interceptors.dart';

final GetIt sl = GetIt.instance;

Future<void> setupLocator() async {
  // Logger
  sl.registerLazySingleton<Logger>(() => Logger(
    printer: PrettyPrinter(
      methodCount: 0,
      errorMethodCount: 5,
      colors: true,
      printEmojis: true,
    ),
  ));
  
  // Storage
  sl.registerLazySingleton<SecureStorageService>(
    () => SecureStorageService(),
  );
  
  // Interceptors
  sl.registerLazySingleton<AuthInterceptor>(
    () => AuthInterceptor(sl<AuthService>()),
  );
  
  sl.registerLazySingleton<LoggingInterceptor>(
    () => LoggingInterceptor(sl<Logger>()),
  );
  
  sl.registerLazySingleton<ErrorInterceptor>(
    () => ErrorInterceptor(),
  );
  
  sl.registerLazySingleton<CacheInterceptor>(
    () => CacheInterceptor(sl<CacheManager>()),
  );
  
  // API Client
  sl.registerLazySingleton<ApiClient>(() => ApiClient(
    logger: sl<Logger>(),
    authInterceptor: sl<AuthInterceptor>(),
    loggingInterceptor: sl<LoggingInterceptor>(),
    errorInterceptor: sl<ErrorInterceptor>(),
    cacheInterceptor: sl<CacheInterceptor>(),
  ));
  
  // API Services
  sl.registerLazySingleton<ApiService>(() => ApiService(
    dio: sl<ApiClient>().dio,
    authService: sl<AuthService>(),
    logger: sl<Logger>(),
  ));
  
  sl.registerLazySingleton<AuthApiService>(() => AuthApiService(
    dio: sl<ApiClient>().dio,
    authService: sl<AuthService>(),
    logger: sl<Logger>(),
  ));
  
  // Authentication Service
  sl.registerLazySingleton<AuthService>(() => AuthService(
    authApiService: sl<AuthApiService>(),
    secureStorage: sl<SecureStorageService>(),
  ));
  
  // Initialize services
  await sl<AuthService>().initialize();
}

5. Repository Pattern Implementation

dart
// domain/repositories/auth_repository.dart
import '../entities/auth_entity.dart';
import '../entities/user_entity.dart';

abstract class AuthRepository {
  Future<AuthResponse> login(String email, String password);
  Future<AuthResponse> register(UserEntity user, String password);
  Future<AuthResponse> refreshToken(String refreshToken);
  Future<void> logout();
  Future<void> forgotPassword(String email);
  Future<void> resetPassword(String token, String newPassword);
  Future<AuthResponse> socialLogin(SocialProvider provider, String token);
  Stream<AuthState> get authStateChanges;
  UserEntity? get currentUser;
}

// data/repositories_impl/auth_repository_impl.dart
class AuthRepositoryImpl implements AuthRepository {
  final AuthApiService _authApiService;
  final AuthService _authService;
  
  AuthRepositoryImpl({
    required AuthApiService authApiService,
    required AuthService authService,
  }) : _authApiService = authApiService,
       _authService = authService;
  
  
  Future<AuthResponse> login(String email, String password) async {
    return await _authApiService.login(
      email: email,
      password: password,
    );
  }
  
  
  Future<AuthResponse> register(UserEntity user, String password) async {
    return await _authApiService.register(
      name: user.name,
      email: user.email,
      password: password,
      phone: user.phone,
    );
  }
  
  
  Future<AuthResponse> refreshToken(String refreshToken) async {
    return await _authApiService.refreshToken(refreshToken);
  }
  
  
  Future<void> logout() async {
    await _authService.logout();
  }
  
  
  Future<void> forgotPassword(String email) async {
    await _authApiService.forgotPassword(email);
  }
  
  
  Future<void> resetPassword(String token, String newPassword) async {
    await _authApiService.resetPassword(
      token: token,
      newPassword: newPassword,
    );
  }
  
  
  Future<AuthResponse> socialLogin(SocialProvider provider, String token) async {
    return await _authApiService.socialLogin(
      provider: provider,
      token: token,
    );
  }
  
  
  Stream<AuthState> get authStateChanges => _authService.authStateChanges;
  
  
  UserEntity? get currentUser => _authService.currentUser;
}

6. Use Cases (Business Logic)

dart
// domain/usecases/auth_usecases.dart
import '../repositories/auth_repository.dart';

class LoginUseCase {
  final AuthRepository _repository;
  
  LoginUseCase(this._repository);
  
  Future<AuthResponse> execute({
    required String email,
    required String password,
  }) async {
    // Add business logic here
    if (email.isEmpty || password.isEmpty) {
      throw Exception('Email and password are required');
    }
    
    if (!_isValidEmail(email)) {
      throw Exception('Invalid email format');
    }
    
    return await _repository.login(email, password);
  }
  
  bool _isValidEmail(String email) {
    return RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(email);
  }
}

class LogoutUseCase {
  final AuthRepository _repository;
  
  LogoutUseCase(this._repository);
  
  Future<void> execute() async {
    // Add business logic here (cleanup, analytics, etc.)
    await _repository.logout();
    
    // Additional cleanup if needed
    // await _analyticsService.logEvent('user_logout');
  }
}

7. State Management with Provider/Riverpod

Using Riverpod (Recommended for large apps)

dart
// presentation/providers/auth_provider.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../../../domain/usecases/auth_usecases.dart';

part 'auth_provider.g.dart';


class AuthNotifier extends _$AuthNotifier {
  late LoginUseCase _loginUseCase;
  late LogoutUseCase _logoutUseCase;
  
  
  AuthState build() {
    // Initialize use cases
    _loginUseCase = ref.read(loginUseCaseProvider);
    _logoutUseCase = ref.read(logoutUseCaseProvider);
    
    // Initial state
    return AuthState.initial;
  }
  
  Future<void> login(String email, String password) async {
    state = AuthState.loading;
    
    try {
      final response = await _loginUseCase.execute(
        email: email,
        password: password,
      );
      state = AuthState.authenticated(response.user);
    } catch (e) {
      state = AuthState.error(e.toString());
      rethrow;
    }
  }
  
  Future<void> logout() async {
    try {
      await _logoutUseCase.execute();
      state = AuthState.unauthenticated;
    } catch (e) {
      state = AuthState.error(e.toString());
      rethrow;
    }
  }
}

// Provider definitions
final loginUseCaseProvider = Provider<LoginUseCase>((ref) {
  final repository = ref.read(authRepositoryProvider);
  return LoginUseCase(repository);
});

final logoutUseCaseProvider = Provider<LogoutUseCase>((ref) {
  final repository = ref.read(authRepositoryProvider);
  return LogoutUseCase(repository);
});

final authRepositoryProvider = Provider<AuthRepository>((ref) {
  return AuthRepositoryImpl(
    authApiService: ref.read(authApiServiceProvider),
    authService: ref.read(authServiceProvider),
  );
});

8. Navigation & Routing

dart
// presentation/routers/app_router.dart
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import '../views/auth/login_screen.dart';
import '../views/home/home_screen.dart';
import '../views/splash/splash_screen.dart';

part 'app_router.gr.dart';

()
class AppRouter extends _$AppRouter {
  
  List<AutoRoute> get routes => [
    AutoRoute(
      page: SplashRoute.page,
      initial: true,
    ),
    AutoRoute(
      page: LoginRoute.page,
    ),
    AutoRoute(
      page: HomeRoute.page,
    ),
    // Add more routes...
  ];
}

// Route guards
class AuthGuard extends AutoRouteGuard {
  final AuthService _authService;
  
  AuthGuard(this._authService);
  
  
  void onNavigation(NavigationResolver resolver, StackRouter router) async {
    if (_authService.isAuthenticated) {
      resolver.next(true);
    } else {
      router.push(LoginRoute(onResult: (success) {
        if (success) {
          resolver.next(true);
        } else {
          resolver.next(false);
        }
      }));
    }
  }
}

9. Background Job Scheduler

dart
// services/background/background_job_service.dart
import 'package:workmanager/workmanager.dart';
import 'package:connectivity_plus/connectivity_plus.dart';

class BackgroundJobScheduler {
  static const String _syncDataTask = 'syncDataTask';
  static const String _uploadPendingTask = 'uploadPendingTask';
  static const String _cleanupTask = 'cleanupTask';
  
  static Future<void> initialize() async {
    await Workmanager().initialize(
      callbackDispatcher,
      isInDebugMode: AppConfig.instance.isDevelopment,
    );
  }
  
  static void callbackDispatcher() {
    Workmanager().executeTask((task, inputData) async {
      switch (task) {
        case _syncDataTask:
          return await _syncData();
        case _uploadPendingTask:
          return await _uploadPending();
        case _cleanupTask:
          return await _cleanup();
        default:
          return false;
      }
    });
  }
  
  static Future<void> registerPeriodicJob({
    required String jobId,
    required Duration frequency,
    required Future<void> Function() task,
    Duration initialDelay = Duration.zero,
    bool requiresCharging = false,
    bool requiresDeviceIdle = false,
    NetworkType networkType = NetworkType.connected,
  }) async {
    await Workmanager().registerPeriodicTask(
      jobId,
      jobId,
      frequency: frequency,
      initialDelay: initialDelay,
      constraints: Constraints(
        networkType: networkType,
        requiresCharging: requiresCharging,
        requiresDeviceIdle: requiresDeviceIdle,
      ),
    );
  }
  
  static Future<bool> _syncData() async {
    try {
      final connectivity = await Connectivity().checkConnectivity();
      if (connectivity == ConnectivityResult.none) {
        return false;
      }
      
      // Your sync logic here
      await sl<DataSyncService>().syncPendingData();
      return true;
    } catch (e) {
      return false;
    }
  }
  
  static Future<bool> _uploadPending() async {
    try {
      // Upload pending files, logs, etc.
      return true;
    } catch (e) {
      return false;
    }
  }
  
  static Future<bool> _cleanup() async {
    try {
      // Cleanup old data
      return true;
    } catch (e) {
      return false;
    }
  }
}

10. Notification Service

dart
// services/notification/firebase_messaging_service.dart
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

class FirebaseMessagingService {
  final FirebaseMessaging _firebaseMessaging;
  final FlutterLocalNotificationsPlugin _localNotifications;
  
  FirebaseMessagingService({
    required FirebaseMessaging firebaseMessaging,
    required FlutterLocalNotificationsPlugin localNotifications,
  }) : _firebaseMessaging = firebaseMessaging,
       _localNotifications = localNotifications;
  
  Future<void> initialize() async {
    // Request permissions
    final settings = await _firebaseMessaging.requestPermission(
      alert: true,
      badge: true,
      sound: true,
    );
    
    if (settings.authorizationStatus == AuthorizationStatus.authorized) {
      // Configure message handlers
      FirebaseMessaging.onMessage.listen(_handleForegroundMessage);
      FirebaseMessaging.onMessageOpenedApp.listen(_handleMessageOpened);
      FirebaseMessaging.onBackgroundMessage(_handleBackgroundMessage);
      
      // Get token
      final token = await _firebaseMessaging.getToken();
      await _sendTokenToServer(token);
      
      // Setup local notifications
      await _setupLocalNotifications();
    }
  }
  
  Future<void> _setupLocalNotifications() async {
    const androidSettings = AndroidInitializationSettings('@mipmap/ic_launcher');
    const iosSettings = DarwinInitializationSettings();
    const initSettings = InitializationSettings(
      android: androidSettings,
      iOS: iosSettings,
    );
    
    await _localNotifications.initialize(
      initSettings,
      onDidReceiveNotificationResponse: _onNotificationTap,
    );
  }
  
  Future<void> _handleForegroundMessage(RemoteMessage message) async {
    // Show local notification
    await _showLocalNotification(message);
    
    // Update app state if needed
    _updateAppState(message);
  }
  
  Future<void> _handleBackgroundMessage(RemoteMessage message) async {
    // Handle background message
    await _processBackgroundMessage(message);
  }
  
  Future<void> _handleMessageOpened(RemoteMessage message) async {
    // Handle when user taps notification
    await _navigateToScreen(message);
  }
  
  Future<void> _showLocalNotification(RemoteMessage message) async {
    final androidDetails = const AndroidNotificationDetails(
      'channel_id',
      'Channel Name',
      channelDescription: 'Channel Description',
      importance: Importance.high,
      priority: Priority.high,
    );
    
    final iosDetails = const DarwinNotificationDetails();
    
    final notificationDetails = NotificationDetails(
      android: androidDetails,
      iOS: iosDetails,
    );
    
    await _localNotifications.show(
      message.hashCode,
      message.notification?.title ?? 'Notification',
      message.notification?.body ?? '',
      notificationDetails,
    );
  }
  
  void _updateAppState(RemoteMessage message) {
    // Update your app state based on notification
    // e.g., refresh data, show badge, etc.
  }
  
  Future<void> _processBackgroundMessage(RemoteMessage message) async {
    // Process data-only messages in background
  }
  
  Future<void> _navigateToScreen(RemoteMessage message) async {
    // Navigate to appropriate screen based on notification data
    final data = message.data;
    final route = data['route'];
    
    // Use your navigation service to navigate
    // navigator.pushNamed(route);
  }
  
  Future<void> _sendTokenToServer(String? token) async {
    if (token != null) {
      // Send token to your backend
      await sl<ApiService>().updateDeviceToken(token);
    }
  }
  
  void _onNotificationTap(NotificationResponse response) {
    // Handle notification tap
  }
}

11. Analytics & Monitoring

dart
// services/analytics/analytics_service.dart
import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:sentry_flutter/sentry_flutter.dart';

class AnalyticsService {
  final FirebaseAnalytics _firebaseAnalytics;
  final bool _enableAnalytics;
  
  AnalyticsService({
    required FirebaseAnalytics firebaseAnalytics,
    bool enableAnalytics = true,
  }) : _firebaseAnalytics = firebaseAnalytics,
       _enableAnalytics = enableAnalytics;
  
  Future<void> logEvent({
    required String name,
    Map<String, dynamic>? parameters,
  }) async {
    if (!_enableAnalytics) return;
    
    try {
      await _firebaseAnalytics.logEvent(
        name: name,
        parameters: parameters,
      );
    } catch (e) {
      // Log error but don't crash
      Sentry.captureException(e);
    }
  }
  
  Future<void> setUserProperties({
    String? userId,
    String? email,
    String? name,
  }) async {
    if (!_enableAnalytics) return;
    
    try {
      if (userId != null) {
        await _firebaseAnalytics.setUserId(id: userId);
      }
      
      await _firebaseAnalytics.setUserProperty(
        name: 'email',
        value: email,
      );
      
      await _firebaseAnalytics.setUserProperty(
        name: 'name',
        value: name,
      );
    } catch (e) {
      Sentry.captureException(e);
    }
  }
  
  Future<void> logScreenView({
    required String screenName,
    String? screenClass,
  }) async {
    if (!_enableAnalytics) return;
    
    try {
      await _firebaseAnalytics.logScreenView(
        screenName: screenName,
        screenClass: screenClass,
      );
    } catch (e) {
      Sentry.captureException(e);
    }
  }
  
  Future<void> logError({
    required dynamic error,
    StackTrace? stackTrace,
    String? context,
  }) async {
    await Sentry.captureException(
      error,
      stackTrace: stackTrace,
    );
    
    // Also log to analytics
    await logEvent(
      name: 'error_occurred',
      parameters: {
        'error': error.toString(),
        'context': context,
        'timestamp': DateTime.now().toIso8601String(),
      },
    );
  }
}

12. Main Application Entry

dart
// main.dart
import 'package:flutter/material.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'core/app/app.dart';
import 'presentation/routers/app_router.dart';
import 'di/service_locator.dart';

Future<void> main() async {
  // Ensure Flutter is initialized
  WidgetsFlutterBinding.ensureInitialized();
  
  await SentryFlutter.init(
    (options) {
      options.dsn = 'your-sentry-dsn';
      options.tracesSampleRate = 1.0;
      options.enableAutoPerformanceTracing = true;
    },
    appRunner: () => _runApp(),
  );
}

Future<void> _runApp() async {
  // Initialize app with proper environment
  await App.initialize(
    environment: AppEnvironment.dev, // Change for production
    appName: 'My Enterprise App',
    baseUrl: 'https://api.example.com',
    apiKey: 'your-api-key',
  );
  
  // Set up error reporting
  FlutterError.onError = (errorDetails) {
    FirebaseCrashlytics.instance.recordFlutterError(errorDetails);
    Sentry.captureException(
      errorDetails.exception,
      stackTrace: errorDetails.stack,
    );
  };
  
  // Set up uncaught errors
  PlatformDispatcher.instance.onError = (error, stack) {
    FirebaseCrashlytics.instance.recordError(error, stack);
    Sentry.captureException(error, stackTrace: stack);
    return true;
  };
  
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final _appRouter = AppRouter();
  
  MyApp({super.key});
  
  
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: _appRouter.config(),
      title: 'Enterprise App',
      theme: AppTheme.lightTheme,
      darkTheme: AppTheme.darkTheme,
      themeMode: ThemeMode.system,
      debugShowCheckedModeBanner: false,
      builder: (context, child) {
        return GestureDetector(
          onTap: () => _hideKeyboard(context),
          child: child,
        );
      },
    );
  }
  
  void _hideKeyboard(BuildContext context) {
    final currentFocus = FocusScope.of(context);
    if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
      FocusManager.instance.primaryFocus?.unfocus();
    }
  }
}

13. pubspec.yaml Dependencies

yaml
name: enterprise_app
description: Enterprise Flutter Application
publish_to: 'none'
version: 1.0.0+1

environment:
  sdk: '>=3.0.0 <4.0.0'

dependencies:
  flutter:
    sdk: flutter
  
  # State Management
  flutter_riverpod: ^2.4.0
  riverpod_annotation: ^2.2.0
  
  # Networking
  dio: ^5.3.0
  retrofit: ^4.0.1
  logger: ^2.0.0
  
  # Authentication & Security
  flutter_secure_storage: ^9.0.0
  jwt_decoder: ^2.0.1
  google_sign_in: ^6.1.0
  sign_in_with_apple: ^5.0.0
  firebase_auth: ^4.11.0
  
  # Firebase
  firebase_core: ^2.24.0
  firebase_messaging: ^14.7.0
  firebase_analytics: ^10.7.0
  firebase_crashlytics: ^3.2.0
  firebase_remote_config: ^3.6.0
  
  # Notifications
  flutter_local_notifications: ^16.0.0
  onesignal_flutter: ^5.0.0
  
  # Database & Storage
  sqflite: ^2.3.0
  hive: ^2.2.3
  path_provider: ^2.1.0
  shared_preferences: ^2.2.0
  
  # Navigation
  auto_route: ^7.8.0
  go_router: ^11.0.0
  
  # Background Tasks
  workmanager: ^0.5.1
  
  # Connectivity
  connectivity_plus: ^4.0.2
  
  # Monitoring & Analytics
  sentry_flutter: ^7.16.0
  
  # Utilities
  intl: ^0.18.1
  uuid: ^4.3.0
  equatable: ^2.0.5
  cached_network_image: ^3.3.0
  image_picker: ^1.0.4
  url_launcher: ^6.2.0
  share_plus: ^7.0.1
  
  # UI Components
  flutter_svg: ^2.0.9
  lottie: ^2.7.0
  shimmer: ^3.0.0
  pull_to_refresh: ^2.0.0
  
  # Testing
  mockito: ^5.4.0
  build_runner: ^2.4.0

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^3.0.0
  riverpod_generator: ^2.3.0
  retrofit_generator: ^4.0.1
  auto_route_generator: ^7.3.0
  hive_generator: ^2.0.0
  mocktail: ^1.0.0

14. Key Features of This Architecture

✅ Scalability & Maintainability

  • Clean Architecture: Clear separation of concerns

  • Modular Structure: Easy to add/remove features

  • Dependency Injection: Loose coupling, easy testing

  • Repository Pattern: Single source of truth

✅ Authentication Strategies

  1. JWT Bearer Tokens: Auto-refresh, secure storage

  2. Social Logins: Google, Apple, Facebook

  3. API Key Authentication: For third-party services

  4. Basic Auth: For legacy systems

✅ Performance Optimizations

  • Request Caching: Reduces network calls

  • Connection Pooling: Dio for efficient networking

  • Image Caching: cached_network_image

  • Lazy Loading: On-demand feature loading

✅ Error Handling & Monitoring

  • Global Error Boundary: Catch all unhandled errors

  • Sentry Integration: Real-time error tracking

  • Firebase Crashlytics: Crash reporting

  • Analytics: User behavior tracking

✅ Offline Support

  • Local Database: Hive/SQFlite for offline data

  • Background Sync: Workmanager for periodic sync

  • Queue System: Retry failed operations

✅ Security

  • Secure Storage: Encrypted local storage

  • Certificate Pinning: For production APIs

  • Input Validation: At multiple levels

  • JWT Verification: Token validation and refresh

✅ Testing Strategy

  • Unit Tests: For business logic (Use Cases)

  • Widget Tests: For UI components

  • Integration Tests: For complete flows

  • Mock Services: For API testing

15. Best Practices Implemented

🎯 Code Organization

  • Feature-based folder structure

  • Single responsibility principle

  • Interface-based programming

🎯 State Management

  • Riverpod for complex state

  • Provider for simple state

  • Clear separation of UI and business logic

🎯 API Communication

  • Retry logic with exponential backoff

  • Request/Response logging

  • Connection timeout handling

  • Multipart file upload support

🎯 User Experience

  • Loading states with shimmer

  • Error boundaries with retry

  • Pull-to-refresh functionality

  • Offline mode with cached data

🎯 Development Experience

  • Auto-generated code (routes, API clients)

  • Hot reload friendly

  • Environment-specific configurations

  • Comprehensive logging

This architecture is production-ready and can scale to handle 100+ screens, complex business logic, multiple external integrations, and large teams. It follows industry best practices and provides a solid foundation for enterprise Flutter applications.

Considerations for Implementation:

🏢 Team Size & Collaboration

  • Small Teams (1-5 developers): This architecture might seem heavy but pays off in long-term maintenance

  • Medium Teams (5-15 developers): Perfect fit, enables parallel feature development

  • Large Teams (15+ developers): Essential for code consistency and reducing merge conflicts

📱 Target Platforms

  • Mobile Only: This architecture works perfectly

  • Cross-Platform (Web, Desktop): Additional considerations needed for:

    • Web-specific API limitations

    • Desktop file system access

    • Platform-specific dependencies

⏱️ Project Timeline

  • Short Projects (1-3 months): Consider simplifying some layers

  • Medium Projects (3-12 months): Full implementation recommended

  • Long Projects (1+ years): This architecture is essential

🔒 Security Requirements

  • High Security (Finance, Health): Add additional layers:

    • Certificate pinning

    • Biometric authentication

    • Additional encryption layers

  • Standard Security: Basic implementation suffices

📶 Network Conditions

  • Always Connected: Can simplify offline capabilities

  • Poor Connectivity: Offline-first approach is crucial

  • Variable Connectivity: Implement smart synchronization

💾 Data Volume

  • Small Datasets (< 10MB): Simple local storage suffices

  • Medium Datasets (10MB-100MB): Implement pagination and lazy loading

  • Large Datasets (100MB+): Need advanced caching and data partitioning

🎯 Key Takeaways:

Architectural Excellence

This enterprise Flutter architecture represents the culmination of best practices from numerous large-scale production applications. It's not just about writing code—it's about creating a scalable, maintainable, and robust foundation that can grow with your application and team.

Future-Proof Design

The architecture is designed to evolve with:

  • New Flutter versions and features

  • Changing business requirements

  • Team growth and restructuring

  • Emerging technologies and integrations

Investment with Returns

While the initial setup requires more effort, this investment pays dividends through:

  • Reduced bug rates due to clear patterns and separation

  • Faster feature development once the foundation is laid

  • Easier onboarding for new team members

  • Better app performance and user experience

Adaptability

Remember that this is a template, not a rigid framework. Adapt it to:

  • Your team's specific needs and expertise

  • Your project's unique requirements

  • Your organization's development processes

  • Your performance and security constraints

💡 Final Thoughts:

Building enterprise Flutter applications is both an art and a science. This architecture provides the scientific foundation—the proven patterns and structures. The art comes from how you apply it to create amazing user experiences that solve real problems.

Remember: The best architecture is the one that works for your team and your users. Use this guide as a starting point, adapt it to your needs, and create something remarkable!



Post a Comment

0 Comments