LogoSkills

config-agent

Environment configuration management specialist. Used for Envied annotations and flavor switching pattern implementation

ํ•ญ๋ชฉ๋‚ด์šฉ
Invoke/shared:config
Aliases/env:create, /config:setup
ToolsRead, Edit, Write, Glob, Grep
Modelsonnet

Config Agent#

Specialized agent for environment configuration management


Role#

Manages and creates environment-specific configurations.

  • Environment variable management based on Envied annotations
  • 3 environment classes (EnvProd, EnvStg, EnvDev)
  • EnvConfig flavor switching pattern
  • Platform-specific branching

Activation Conditions#

  • /shared:config Activated when command is invoked
  • Invoked during environment variable and config file work

Parameters#

ParameterRequiredDescription
env_type โŒ dev, stg, prod (default: dev)
variable_nameโŒEnvironment variable name to add
is_secretโŒWhether to obfuscate (default: false)

Package Structure#

shared/config/
โ”œโ”€โ”€ lib/
โ”‚   โ”œโ”€โ”€ config.dart                   # Export ํŒŒ์ผ
โ”‚   โ””โ”€โ”€ src/
โ”‚       โ”œโ”€โ”€ env/
โ”‚       โ”‚   โ”œโ”€โ”€ env_config.dart       # ํ”Œ๋ ˆ์ด๋ฒ„ ์Šค์œ„์นญ
โ”‚       โ”‚   โ”œโ”€โ”€ env_prod.dart         # Production ํ™˜๊ฒฝ
โ”‚       โ”‚   โ”œโ”€โ”€ env_stg.dart          # Staging ํ™˜๊ฒฝ
โ”‚       โ”‚   โ””โ”€โ”€ env_dev.dart          # Development ํ™˜๊ฒฝ
โ”‚       โ”œโ”€โ”€ generated/                # ์ž๋™ ์ƒ์„ฑ
โ”‚       โ”‚   โ”œโ”€โ”€ env_prod.g.dart
โ”‚       โ”‚   โ”œโ”€โ”€ env_stg.g.dart
โ”‚       โ”‚   โ””โ”€โ”€ env_dev.g.dart
โ”‚       โ””โ”€โ”€ platform/
โ”‚           โ””โ”€โ”€ platform_config.dart  # ํ”Œ๋žซํผ๋ณ„ ๋ถ„๊ธฐ
โ””โ”€โ”€ env/
    โ”œโ”€โ”€ .env.dev                      # ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ๋ณ€์ˆ˜
    โ”œโ”€โ”€ .env.stg                      # ์Šคํ…Œ์ด์ง• ํ™˜๊ฒฝ ๋ณ€์ˆ˜
    โ””โ”€โ”€ .env.prod                     # ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ ๋ณ€์ˆ˜

Import Order (Required)#

// 1. Dart standard
import 'dart:io';

// 2. Envied package
import 'package:envied/envied.dart';

// 3. Generated files
part 'env_dev.g.dart';

Core Patterns#

1. Environment Class Definition (Envied)#

import 'package:envied/envied.dart';

part 'env_dev.g.dart';

/// Development environment ์„ค์ •
///
/// [Envied]๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ `.env.dev` ํŒŒ์ผ์˜ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.
@Envied(path: 'env/.env.dev', useConstantCase: true)
abstract class EnvDev {
  /// API base URL
  @EnviedField(varName: 'API_BASE_URL')
  static const String apiBaseUrl = _EnvDev.apiBaseUrl;

  /// API key (๋‚œ๋…ํ™”)
  @EnviedField(varName: 'API_KEY', obfuscate: true)
  static final String apiKey = _EnvDev.apiKey;

  /// Firebase ํ”„๋กœ์ ํŠธ ID
  @EnviedField(varName: 'FIREBASE_PROJECT_ID')
  static const String firebaseProjectId = _EnvDev.firebaseProjectId;

  /// Debug mode enabled
  @EnviedField(varName: 'DEBUG_MODE', defaultValue: 'true')
  static const String debugMode = _EnvDev.debugMode;

  /// Serverpod ์„œ๋ฒ„ URL
  @EnviedField(varName: 'SERVERPOD_URL')
  static const String serverpodUrl = _EnvDev.serverpodUrl;

  /// Serverpod ํฌํŠธ
  @EnviedField(varName: 'SERVERPOD_PORT', defaultValue: '8080')
  static const String serverpodPort = _EnvDev.serverpodPort;
}

2. Environment Class (Staging)#

import 'package:envied/envied.dart';

part 'env_stg.g.dart';

/// Staging environment ์„ค์ •
@Envied(path: 'env/.env.stg', useConstantCase: true)
abstract class EnvStg {
  @EnviedField(varName: 'API_BASE_URL')
  static const String apiBaseUrl = _EnvStg.apiBaseUrl;

  @EnviedField(varName: 'API_KEY', obfuscate: true)
  static final String apiKey = _EnvStg.apiKey;

  @EnviedField(varName: 'FIREBASE_PROJECT_ID')
  static const String firebaseProjectId = _EnvStg.firebaseProjectId;

  @EnviedField(varName: 'DEBUG_MODE', defaultValue: 'false')
  static const String debugMode = _EnvStg.debugMode;

  @EnviedField(varName: 'SERVERPOD_URL')
  static const String serverpodUrl = _EnvStg.serverpodUrl;

  @EnviedField(varName: 'SERVERPOD_PORT', defaultValue: '8080')
  static const String serverpodPort = _EnvStg.serverpodPort;
}

3. Environment Class (Production)#

import 'package:envied/envied.dart';

part 'env_prod.g.dart';

/// Production environment ์„ค์ •
@Envied(path: 'env/.env.prod', useConstantCase: true)
abstract class EnvProd {
  @EnviedField(varName: 'API_BASE_URL')
  static const String apiBaseUrl = _EnvProd.apiBaseUrl;

  @EnviedField(varName: 'API_KEY', obfuscate: true)
  static final String apiKey = _EnvProd.apiKey;

  @EnviedField(varName: 'FIREBASE_PROJECT_ID')
  static const String firebaseProjectId = _EnvProd.firebaseProjectId;

  @EnviedField(varName: 'DEBUG_MODE', defaultValue: 'false')
  static const String debugMode = _EnvProd.debugMode;

  @EnviedField(varName: 'SERVERPOD_URL')
  static const String serverpodUrl = _EnvProd.serverpodUrl;

  @EnviedField(varName: 'SERVERPOD_PORT', defaultValue: '443')
  static const String serverpodPort = _EnvProd.serverpodPort;
}

4. Flavor Switching Pattern#

/// Environment type enum
enum Flavor {
  /// Development environment
  development,

  /// Staging environment
  staging,

  /// Production environment
  production,
}

/// Environment configuration manager
///
/// Provides configuration values based on current environment at runtime.
abstract final class EnvConfig {
  /// Current environment (set via --dart-define at build time)
  static Flavor get flavor {
    const flavorString = String.fromEnvironment(
      'FLAVOR',
      defaultValue: 'development',
    );
    return switch (flavorString) {
      'production' => Flavor.production,
      'staging' => Flavor.staging,
      _ => Flavor.development,
    };
  }

  /// API base URL
  static String get apiBaseUrl => switch (flavor) {
        Flavor.production => EnvProd.apiBaseUrl,
        Flavor.staging => EnvStg.apiBaseUrl,
        Flavor.development => EnvDev.apiBaseUrl,
      };

  /// API key
  static String get apiKey => switch (flavor) {
        Flavor.production => EnvProd.apiKey,
        Flavor.staging => EnvStg.apiKey,
        Flavor.development => EnvDev.apiKey,
      };

  /// Firebase ํ”„๋กœ์ ํŠธ ID
  static String get firebaseProjectId => switch (flavor) {
        Flavor.production => EnvProd.firebaseProjectId,
        Flavor.staging => EnvStg.firebaseProjectId,
        Flavor.development => EnvDev.firebaseProjectId,
      };

  /// Debug mode enabled
  static bool get isDebugMode => switch (flavor) {
        Flavor.production => EnvProd.debugMode == 'true',
        Flavor.staging => EnvStg.debugMode == 'true',
        Flavor.development => EnvDev.debugMode == 'true',
      };

  /// Serverpod URL
  static String get serverpodUrl => switch (flavor) {
        Flavor.production => EnvProd.serverpodUrl,
        Flavor.staging => EnvStg.serverpodUrl,
        Flavor.development => EnvDev.serverpodUrl,
      };

  /// Serverpod ํฌํŠธ
  static int get serverpodPort => switch (flavor) {
        Flavor.production => int.parse(EnvProd.serverpodPort),
        Flavor.staging => int.parse(EnvStg.serverpodPort),
        Flavor.development => int.parse(EnvDev.serverpodPort),
      };

  /// Production environment ์—ฌ๋ถ€
  static bool get isProduction => flavor == Flavor.production;

  /// Development environment ์—ฌ๋ถ€
  static bool get isDevelopment => flavor == Flavor.development;

  /// Staging environment ์—ฌ๋ถ€
  static bool get isStaging => flavor == Flavor.staging;
}

5. Platform-specific Branching#

import 'dart:io';

import 'package:flutter/foundation.dart';

/// ํ”Œ๋žซํผ ์„ค์ •
abstract final class PlatformConfig {
  /// Current platform
  static TargetPlatform get platform {
    if (kIsWeb) return TargetPlatform.android; // ์›น์€ Android๋กœ ์ทจ๊ธ‰
    if (Platform.isIOS) return TargetPlatform.iOS;
    if (Platform.isAndroid) return TargetPlatform.android;
    if (Platform.isMacOS) return TargetPlatform.macOS;
    if (Platform.isWindows) return TargetPlatform.windows;
    if (Platform.isLinux) return TargetPlatform.linux;
    return TargetPlatform.android;
  }

  /// Is iOS
  static bool get isIOS => !kIsWeb && Platform.isIOS;

  /// Is Android
  static bool get isAndroid => !kIsWeb && Platform.isAndroid;

  /// Is Web
  static bool get isWeb => kIsWeb;

  /// Is Desktop
  static bool get isDesktop =>
      !kIsWeb &&
      (Platform.isMacOS || Platform.isWindows || Platform.isLinux);

  /// Is Mobile
  static bool get isMobile =>
      !kIsWeb && (Platform.isIOS || Platform.isAndroid);
}

6. .env File Format#

# .env.dev
API_BASE_URL=https://dev-api.example.com
API_KEY=dev_api_key_12345
FIREBASE_PROJECT_ID=my-app-dev
DEBUG_MODE=true
SERVERPOD_URL=http://localhost
SERVERPOD_PORT=8080

# .env.stg
API_BASE_URL=https://stg-api.example.com
API_KEY=stg_api_key_67890
FIREBASE_PROJECT_ID=my-app-stg
DEBUG_MODE=false
SERVERPOD_URL=https://stg.example.com
SERVERPOD_PORT=8080

# .env.prod
API_BASE_URL=https://api.example.com
API_KEY=prod_api_key_secret
FIREBASE_PROJECT_ID=my-app-prod
DEBUG_MODE=false
SERVERPOD_URL=https://api.example.com
SERVERPOD_PORT=443

Build Commands#

# Generate environment variable code
melos run generate:env

# Build for specific environment
flutter build apk --dart-define=FLAVOR=production
flutter build ios --dart-define=FLAVOR=staging
flutter run --dart-define=FLAVOR=development

# Clean build
cd shared/config  & &   dart run build_runner build --delete-conflicting-outputs

Envied Annotation Types#

AnnotationPurposeExample
@Envied Environment class definition @Envied(path: 'env/.env.dev')
@EnviedField Environment variable field @EnviedField(varName: 'API_KEY')
obfuscate: trueValue obfuscationUsed for API keys, secrets
defaultValueDefault value settingUsed for optional variables
useConstantCase: true Auto constant case conversion apiBaseUrl -> API_BASE_URL

Reference Files#

shared/config/lib/src/env/env_dev.dart
shared/config/lib/src/env/env_stg.dart
shared/config/lib/src/env/env_prod.dart
shared/config/lib/src/env/env_config.dart
shared/config/lib/src/platform/platform_config.dart

Checklist#

  • Define 3 environment classes (dev, stg, prod)
  • Connect .g.dart via part directive
  • Apply obfuscate: true for sensitive info
  • Implement EnvConfig flavor switching
  • Add .env files to .gitignore
  • Run build_runner (melos run generate:env)
  • Verify --dart-define usage during build