Skip to main content

Konfigurasi Environment

Panduan lengkap untuk konfigurasi environment MStore Mobile.

๐ŸŒ Multiple Environments

MStore mendukung 3 environment berbeda:
  • Development - Untuk development lokal
  • Staging - Untuk testing sebelum production
  • Production - Untuk release ke users

๐Ÿ“ Environment Files

Struktur File

deploy/
โ”œโ”€โ”€ .env.dev          # Development environment
โ”œโ”€โ”€ .env.staging      # Staging environment
โ””โ”€โ”€ .env.prod         # Production environment

.env.dev (Development)

# API Configuration
API_BASE_URL=https://dev-api.mstore.com
API_TIMEOUT=30000

# MQTT Configuration
MQTT_BROKER=dev-mqtt.mstore.com
MQTT_PORT=1883
MQTT_USERNAME=dev_user
MQTT_PASSWORD=dev_password_123
MQTT_CLIENT_ID=mstore_mobile_dev

# Feature Flags
ENABLE_ANALYTICS=false
ENABLE_CRASHLYTICS=false
ENABLE_DEBUG_LOGGING=true

# MinIO/S3 Configuration
MINIO_ENDPOINT=https://dev-storage.mstore.com
MINIO_ACCESS_KEY=dev_access_key
MINIO_SECRET_KEY=dev_secret_key
MINIO_BUCKET=mstore-dev

.env.staging (Staging)

# API Configuration
API_BASE_URL=https://staging-api.mstore.com
API_TIMEOUT=20000

# MQTT Configuration
MQTT_BROKER=staging-mqtt.mstore.com
MQTT_PORT=1883
MQTT_USERNAME=staging_user
MQTT_PASSWORD=staging_password_456
MQTT_CLIENT_ID=mstore_mobile_staging

# Feature Flags
ENABLE_ANALYTICS=true
ENABLE_CRASHLYTICS=true
ENABLE_DEBUG_LOGGING=true

# MinIO/S3 Configuration
MINIO_ENDPOINT=https://staging-storage.mstore.com
MINIO_ACCESS_KEY=staging_access_key
MINIO_SECRET_KEY=staging_secret_key
MINIO_BUCKET=mstore-staging

.env.prod (Production)

# API Configuration
API_BASE_URL=https://api.mstore.com
API_TIMEOUT=15000

# MQTT Configuration
MQTT_BROKER=mqtt.mstore.com
MQTT_PORT=1883
MQTT_USERNAME=prod_user
MQTT_PASSWORD=prod_secure_password_789
MQTT_CLIENT_ID=mstore_mobile_prod

# Feature Flags
ENABLE_ANALYTICS=true
ENABLE_CRASHLYTICS=true
ENABLE_DEBUG_LOGGING=false

# MinIO/S3 Configuration
MINIO_ENDPOINT=https://storage.mstore.com
MINIO_ACCESS_KEY=prod_access_key
MINIO_SECRET_KEY=prod_secret_key
MINIO_BUCKET=mstore-production

๐Ÿ”ง App Constants

File: lib/pkg/common/app_constants.dart
import 'package:flutter_dotenv/flutter_dotenv.dart';

// API Configuration
final String API_BASE_URL = dotenv.env['API_BASE_URL'] ?? '';
final int API_TIMEOUT = int.tryParse(dotenv.env['API_TIMEOUT'] ?? '15000') ?? 15000;

// MQTT Configuration
final String MQTT_BROKER = dotenv.env['MQTT_BROKER'] ?? '';
final String MQTT_PORT = dotenv.env['MQTT_PORT'] ?? '1883';
final String MQTT_USERNAME = dotenv.env['MQTT_USERNAME'] ?? '';
final String MQTT_PASSWORD = dotenv.env['MQTT_PASSWORD'] ?? '';
final String MQTT_CLIENT_ID = dotenv.env['MQTT_CLIENT_ID'] ?? '';

// Feature Flags
final bool ENABLE_ANALYTICS = dotenv.env['ENABLE_ANALYTICS'] == 'true';
final bool ENABLE_CRASHLYTICS = dotenv.env['ENABLE_CRASHLYTICS'] == 'true';
final bool ENABLE_DEBUG_LOGGING = dotenv.env['ENABLE_DEBUG_LOGGING'] == 'true';

// Storage Configuration
final String MINIO_ENDPOINT = dotenv.env['MINIO_ENDPOINT'] ?? '';
final String MINIO_ACCESS_KEY = dotenv.env['MINIO_ACCESS_KEY'] ?? '';
final String MINIO_SECRET_KEY = dotenv.env['MINIO_SECRET_KEY'] ?? '';
final String MINIO_BUCKET = dotenv.env['MINIO_BUCKET'] ?? '';

๐Ÿ”ฅ Firebase Configuration

Multiple Firebase Projects

MStore menggunakan Firebase project berbeda untuk setiap environment.

iOS Configuration

ios/Runner/
โ”œโ”€โ”€ GoogleService-Info.plist              # Development (default)
โ”œโ”€โ”€ GoogleService-Info-Staging.plist      # Staging
โ””โ”€โ”€ GoogleService-Info-Production.plist   # Production
Script untuk switch Firebase config (iOS):
# ios/scripts/copy-firebase-config.sh
#!/bin/bash

FLAVOR=$1

if [ "$FLAVOR" == "production" ]; then
    cp ios/Runner/GoogleService-Info-Production.plist ios/Runner/GoogleService-Info.plist
elif [ "$FLAVOR" == "staging" ]; then
    cp ios/Runner/GoogleService-Info-Staging.plist ios/Runner/GoogleService-Info.plist
else
    cp ios/Runner/GoogleService-Info.plist ios/Runner/GoogleService-Info.plist
fi

Android Configuration

android/app/src/
โ”œโ”€โ”€ development/
โ”‚   โ””โ”€โ”€ google-services.json
โ”œโ”€โ”€ staging/
โ”‚   โ””โ”€โ”€ google-services.json
โ””โ”€โ”€ production/
    โ””โ”€โ”€ google-services.json
Android Gradle otomatis memilih config berdasarkan flavor.

Firebase Options

File: lib/core/firebase/firebase_options_*.dart
// firebase_options_dev.dart
class DefaultFirebaseOptions {
  static FirebaseOptions get currentPlatform {
    if (Platform.isIOS) {
      return ios;
    } else if (Platform.isAndroid) {
      return android;
    } else if (Platform.isMacOS) {
      return macos;
    } else {
      return web;
    }
  }

  static const FirebaseOptions ios = FirebaseOptions(
    apiKey: 'AIza...',
    appId: '1:123:ios:abc',
    messagingSenderId: '123',
    projectId: 'mstore-dev',
    storageBucket: 'mstore-dev.appspot.com',
    iosBundleId: 'com.mstore.mobile.dev',
  );

  static const FirebaseOptions android = FirebaseOptions(
    apiKey: 'AIza...',
    appId: '1:123:android:def',
    messagingSenderId: '123',
    projectId: 'mstore-dev',
    storageBucket: 'mstore-dev.appspot.com',
  );
  
  // ... web, macos
}

๐ŸŽจ Flavor Configuration

iOS (Xcode Schemes)

  1. Open Xcode
  2. Product โ†’ Scheme โ†’ Manage Schemes
  3. Create schemes:
    • Runner-Development
    • Runner-Staging
    • Runner-Production

Android (build.gradle)

// android/app/build.gradle
android {
    flavorDimensions "environment"
    
    productFlavors {
        development {
            dimension "environment"
            applicationIdSuffix ".dev"
            versionNameSuffix "-dev"
            resValue "string", "app_name", "MStore Dev"
        }
        
        staging {
            dimension "environment"
            applicationIdSuffix ".staging"
            versionNameSuffix "-staging"
            resValue "string", "app_name", "MStore Staging"
        }
        
        production {
            dimension "environment"
            resValue "string", "app_name", "MStore"
        }
    }
}

๐Ÿš€ Running with Flavors

Development

# iOS
flutter run --flavor development -t lib/main_development.dart

# Android
flutter run --flavor development -t lib/main_development.dart

# Web
flutter run -d chrome --flavor development -t lib/main_development.dart

Staging

flutter run --flavor staging -t lib/main_staging.dart

Production

flutter run --flavor production -t lib/main_production.dart

๐Ÿ—๏ธ Build Commands

Development Build

# iOS
flutter build ios --flavor development -t lib/main_development.dart

# Android APK
flutter build apk --flavor development -t lib/main_development.dart

# Android App Bundle
flutter build appbundle --flavor development -t lib/main_development.dart

Production Build

# iOS
flutter build ios --release --flavor production -t lib/main_production.dart

# Android
flutter build appbundle --release --flavor production -t lib/main_production.dart

๐Ÿ” Secure Configuration

Sensitive Data

JANGAN commit sensitive data ke Git!
# .gitignore
deploy/.env.*
ios/Runner/GoogleService-Info*.plist
android/app/google-services.json
android/app/src/*/google-services.json

Environment Variables di CI/CD

Gunakan secrets management:

GitHub Actions

# .github/workflows/build.yml
env:
  API_BASE_URL: ${{ secrets.API_BASE_URL }}
  MQTT_PASSWORD: ${{ secrets.MQTT_PASSWORD }}

GitLab CI

# .gitlab-ci.yml
variables:
  API_BASE_URL: $API_BASE_URL
  MQTT_PASSWORD: $MQTT_PASSWORD

๐Ÿ“ฑ App Configuration

App Info

// lib/pkg/common/app_info.dart
class AppInfo {
  static const String appName = 'MStore';
  static const String packageName = 'com.mstore.mobile';
  static const String version = '1.0.0';
  static const int buildNumber = 202510052314;
  
  static String get fullVersion => '$version+$buildNumber';
}

Platform-Specific Config

// lib/pkg/common/platform_config.dart
class PlatformConfig {
  static bool get isIOS => Platform.isIOS;
  static bool get isAndroid => Platform.isAndroid;
  static bool get isWeb => kIsWeb;
  static bool get isMobile => isIOS || isAndroid;
  static bool get isDesktop => Platform.isMacOS || Platform.isWindows;
  
  // Platform-specific features
  static bool get supportsBiometric => isMobile;
  static bool get supportsBluetoothPrinter => isMobile;
  static bool get supportsNFC => isAndroid;
}

๐ŸŽฏ Feature Flags

Remote Config (Firebase)

class FeatureFlagService {
  final FirebaseRemoteConfig _remoteConfig;
  
  Future<void> init() async {
    await _remoteConfig.setConfigSettings(
      RemoteConfigSettings(
        fetchTimeout: const Duration(minutes: 1),
        minimumFetchInterval: const Duration(hours: 1),
      ),
    );
    
    await _remoteConfig.setDefaults({
      'enable_new_checkout': false,
      'enable_loyalty_program': false,
      'maintenance_mode': false,
    });
    
    await _remoteConfig.fetchAndActivate();
  }
  
  bool isFeatureEnabled(String feature) {
    return _remoteConfig.getBool(feature);
  }
}

Local Feature Flags

class LocalFeatureFlags {
  static const bool enableBetaFeatures = bool.fromEnvironment(
    'ENABLE_BETA_FEATURES',
    defaultValue: false,
  );
  
  static const bool enableDebugTools = bool.fromEnvironment(
    'ENABLE_DEBUG_TOOLS',
    defaultValue: false,
  );
}

๐Ÿ—„๏ธ Database Configuration

Isar Database

class DatabaseConfig {
  static String get databaseName {
    if (kDebugMode) {
      return 'mstore_dev.isar';
    } else {
      return 'mstore.isar';
    }
  }
  
  static Future<Isar> openDatabase() async {
    final dir = await getApplicationDocumentsDirectory();
    
    return await Isar.open(
      [
        ProductLocalSchema,
        TransactionLocalSchema,
        // ... other schemas
      ],
      directory: dir.path,
      name: databaseName,
      inspector: kDebugMode, // Enable inspector in debug mode
    );
  }
}

๐Ÿ” Debugging Configuration

Debug Tools

void main() {
  if (kDebugMode) {
    // Enable debug logging
    Logger.root.level = Level.ALL;
    
    // Enable network inspector
    HttpOverrides.global = DebugHttpOverrides();
    
    // Enable performance overlay
    debugPaintSizeEnabled = false;
    debugPaintBaselinesEnabled = false;
  }
  
  runApp(MyApp());
}

VS Code Launch Configuration

// .vscode/launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Development",
      "request": "launch",
      "type": "dart",
      "program": "lib/main_development.dart",
      "args": ["--flavor", "development"]
    },
    {
      "name": "Staging",
      "request": "launch",
      "type": "dart",
      "program": "lib/main_staging.dart",
      "args": ["--flavor", "staging"]
    },
    {
      "name": "Production",
      "request": "launch",
      "type": "dart",
      "program": "lib/main_production.dart",
      "args": ["--flavor", "production"]
    }
  ]
}

๐Ÿ“Š Monitoring Configuration

Firebase Crashlytics

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  if (ENABLE_CRASHLYTICS) {
    await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true);
    
    FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterFatalError;
    
    PlatformDispatcher.instance.onError = (error, stack) {
      FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
      return true;
    };
  }
  
  runApp(MyApp());
}

Firebase Analytics

class AnalyticsService {
  final FirebaseAnalytics _analytics = FirebaseAnalytics.instance;
  
  Future<void> logEvent(String name, Map<String, dynamic> parameters) async {
    if (!ENABLE_ANALYTICS) return;
    
    await _analytics.logEvent(
      name: name,
      parameters: parameters,
    );
  }
}

๐Ÿงช Testing Configuration

// test/test_config.dart
class TestConfig {
  static const String mockApiBaseUrl = 'https://mock-api.test';
  static const String testDatabaseName = 'test.isar';
  
  static Future<void> setupTestEnvironment() async {
    TestWidgetsFlutterBinding.ensureInitialized();
    
    // Load test environment
    await dotenv.load(fileName: 'deploy/.env.test');
    
    // Setup mock services
    setupMockDI();
  }
}

Next Steps


Best Practices:
  • โœ… Gunakan environment files untuk configuration
  • โœ… Jangan commit sensitive data
  • โœ… Gunakan feature flags untuk gradual rollout
  • โœ… Setup proper monitoring di production
  • โœ… Test di semua environments sebelum release