09 - Config & Environments

How the app reads its base URL, routes, theme, and asset paths. All four config files are static, compile-time constants.

api_config.dart

The single source of truth for backend URLs, route paths, and timeouts. Reads environment from a compile-time flag.

flutter_app/lib/config/api_config.dartDart
/// Backend API configuration and endpoint constants.
///
/// Environment is set via build-time flag:
///   flutter run --dart-define=ENV=dev    (default, localhost)
///   flutter run --dart-define=ENV=uat    (UAT server)
///   flutter run --dart-define=ENV=prod   (Production)
class ApiConfig {
  static const _env = String.fromEnvironment('ENV', defaultValue: 'dev');

  static String get baseUrl {
    switch (_env) {
      case 'prod': return 'https://ekyc.motilaloswal.com';
      case 'uat':  return 'https://ekycuat.motilaloswaluat.com';
      default:    return 'http://localhost:5000';
    }
  }

  static bool get isDev => _env == 'dev';
  static bool get isProd => _env == 'prod';

  static const String apiVersion = 'api/v1';
  static String get _base => '$baseUrl/$apiVersion';

  // Stage endpoints (abbreviated)
  static String get journeyInit => '$_base/journey/init';
  static String get registrationSignup => '$_base/registration/signup';
  static String get registrationOtpVerify => '$_base/registration/otp/verify';
  // ... ~60 endpoints total

  // Timeouts
  static const Duration apiTimeout = Duration(seconds: 30);
  static const Duration sessionTimeout = Duration(minutes: 15);
  static const Duration sessionWarningAt = Duration(minutes: 13);
}

Environment Flag

ENV valueBase URLisDevisProd
dev (default)http://localhost:5000truefalse
uathttps://ekycuat.motilaloswaluat.comfalsefalse
prodhttps://ekyc.motilaloswal.comfalsetrue

Build Commands per Env and Platform

BashWeb (Chrome)
# Dev (default)
C:\flutter\bin\flutter run -d chrome --web-port 8080

# UAT
C:\flutter\bin\flutter run -d chrome --web-port 8080 --dart-define=ENV=uat

# Prod
C:\flutter\bin\flutter run -d chrome --web-port 8080 --dart-define=ENV=prod

# Production web build
C:\flutter\bin\flutter build web --release --dart-define=ENV=prod
BashAndroid
# Run on connected device/emulator (debug, dev)
C:\flutter\bin\flutter run

# Release APK for prod
C:\flutter\bin\flutter build apk --release --dart-define=ENV=prod

# App Bundle for Play Store
C:\flutter\bin\flutter build appbundle --release --dart-define=ENV=prod

# UAT build
C:\flutter\bin\flutter build apk --release --dart-define=ENV=uat
BashiOS (macOS only)
cd ios && pod install && cd ..

# Debug on simulator (dev)
flutter run -d ios

# Release IPA for TestFlight
flutter build ipa --release --dart-define=ENV=prod
Tree-shaking guarantee

Because _env is a compile-time constant, the Dart compiler resolves the switch statement at build time. In a prod build, the dev and uat cases become dead code and are removed from the binary. The resulting APK/IPA has exactly one base URL hardcoded.

isDev Guards (Mock URL Detection)

The isDev getter is used only in two places - Stage 5 (DigiLocker) and Stage 6 (Bank) - to bypass mock redirect URLs in development.

flutter_app/lib/screens/stage5_digilocker.dartDart
if (ApiConfig.isDev &&
    (_redirectUrl!.contains('mock-digilocker') ||
     _redirectUrl!.contains('example.com'))) {
  await _handleMockDigilocker();
  return;
}

In a prod build, ApiConfig.isDev is always false, so the entire if block is dead code and gets removed. See 02 - Mock Mode for more.

routes.dart

Static route name constants and a stage-index → route map used for journey resume.

flutter_app/lib/config/routes.dartDart
class AppRoutes {
  static const stage0Arrival      = '/';
  static const stage1Registration  = '/registration';
  static const stage2Otp           = '/otp';
  static const stage3Email         = '/email';
  static const stage4Pan           = '/pan';
  static const stage5Digilocker    = '/digilocker';
  static const stage6Bank          = '/bank';
  static const stage7Liveness      = '/liveness';
  static const stage8Signature     = '/signature';
  static const stage9Personal      = '/personal';
  static const stage10Income       = '/income';
  static const stage11Validation   = '/validation';
  static const stage12Document     = '/document';
  static const stage13Esign        = '/esign';
  static const stage14Account      = '/account';
  static const stage15Congrats     = '/congrats';

  static Map<int, String> stageRoutes = {
    0: stage0Arrival,
    1: stage1Registration,
    2: stage2Otp,
    // ...
  };
}

Stage 0 (stage0Arrival) uses this map to auto-resume the user to their saved stage after an app restart.

theme.dart

MaterialApp ThemeData. Defines RISE brand colors, Inter font, button radius, AppBar style.

flutter_app/lib/config/theme.dartDart
class AppTheme {
  // Brand colors
  static const primary     = Color(0xFF2B2E8C);
  static const navy        = Color(0xFF2B2E8C);
  static const success     = Color(0xFF008743);
  static const error       = Color(0xFFCC101C);
  static const progress    = Color(0xFF47A5E3);
  static const progressBg  = Color(0xFFEDEEFC);
  static const textPrimary = Color(0xFF0F0F10);
  static const background  = Color(0xFFFFFFFF);

  static ThemeData get lightTheme {
    return ThemeData(
      primaryColor: primary,
      scaffoldBackgroundColor: background,
      fontFamily: GoogleFonts.inter().fontFamily,
      elevatedButtonTheme: ElevatedButtonThemeData(
        style: ElevatedButton.styleFrom(
          backgroundColor: primary,
          foregroundColor: Colors.white,
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(8),
          ),
        ),
      ),
      // ... more theme options
    );
  }
}

To change the primary brand color, edit AppTheme.primary. It propagates to all buttons, AppBars, and accents automatically.

assets.dart

Static path constants for Lottie, SVG, PNG, WebP assets. Never hardcode asset paths in screen files - always use these constants.

flutter_app/lib/config/assets.dartDart
class AppAssets {
  static const _base = 'assets/images';

  // Lottie animations
  static const loader                  = '$_base/ic_loader.json';
  static const tickAnimation           = '$_base/ic_tick_animation.json';
  static const congratulationAnimation = '$_base/congratulation_animation.json';
  static const noConnection            = '$_base/no_connection.json';
  static const riseLogoAnimation       = '$_base/riselogo.json';

  // SVG illustrations
  static const riseLogo             = '$_base/ic_rise_logo.svg';
  static const registerIllustration = '$_base/ic_register_illustration.svg';
  static const panIllustration      = '$_base/ic_pan_illustrator.svg';
  // ... more SVGs and PNGs
}

pubspec.yaml Asset Registration

The assets/images/ folder must be registered in pubspec.yaml for Flutter to bundle the files.

flutter_app/pubspec.yamlYAML
flutter:
  uses-material-design: true
  assets:
    - assets/images/

The trailing slash registers the entire folder - you don't need to list individual files.

Backend configuration counterpart
  • backend/src/MO.Ekyc.Api/appsettings.json - production defaults
  • backend/src/MO.Ekyc.Api/appsettings.Development.json - dev overrides (mock mode, fixed OTP)
  • Backend config docs (pending) - placeholder