Skip to main content

Production Deployment

Building for Production

Preparing a Hypermodern application for production involves optimization, security hardening, and creating deployable artifacts that can run efficiently in production environments.

Production Build Process

# Basic production build
hypermodern build

# Advanced build with custom options
hypermodern build \
  --output dist \
  --minify \
  --tree-shake \
  --no-source-maps \
  --docker \
  --env production

The build process performs several optimizations:

class ProductionBuilder {
  final BuildConfig _config;
  final CodeOptimizer _optimizer;
  final AssetProcessor _assetProcessor;
  final SecurityHardener _securityHardener;
  
  ProductionBuilder({
    required BuildConfig config,
    required CodeOptimizer optimizer,
    required AssetProcessor assetProcessor,
    required SecurityHardener securityHardener,
  }) : _config = config,
       _optimizer = optimizer,
       _assetProcessor = assetProcessor,
       _securityHardener = securityHardener;
  
  Future<BuildResult> build() async {
    print('🏗️ Building for production...');
    final stopwatch = Stopwatch()..start();
    
    try {
      // Clean output directory
      await _cleanOutputDirectory();
      
      // Compile Dart code
      final compiledCode = await _compileCode();
      
      // Optimize code
      final optimizedCode = await _optimizer.optimize(compiledCode);
      
      // Process assets
      final processedAssets = await _assetProcessor.process();
      
      // Apply security hardening
      await _securityHardener.harden(optimizedCode);
      
      // Generate deployment artifacts
      final artifacts = await _generateArtifacts(optimizedCode, processedAssets);
      
      // Create Docker image if requested
      if (_config.generateDocker) {
        await _generateDockerFiles(artifacts);
      }
      
      // Generate deployment scripts
      await _generateDeploymentScripts(artifacts);
      
      stopwatch.stop();
      
      return BuildResult(
        success: true,
        artifacts: artifacts,
        buildTime: stopwatch.elapsed,
        outputSize: await _calculateOutputSize(artifacts),
      );
      
    } catch (e) {
      return BuildResult(
        success: false,
        error: e.toString(),
        buildTime: stopwatch.elapsed,
      );
    }
  }
  
  Future<void> _cleanOutputDirectory() async {
    final outputDir = Directory(_config.outputDirectory);
    if (await outputDir.exists()) {
      await outputDir.delete(recursive: true);
    }
    await outputDir.create(recursive: true);
  }
  
  Future<CompiledCode> _compileCode() async {
    print('📦 Compiling Dart code...');
    
    // Compile to native executable
    final result = await Process.run('dart', [
      'compile',
      'exe',
      'lib/main.dart',
      '-o',
      '${_config.outputDirectory}/app',
      if (_config.optimize) '--optimization-level=2',
      if (!_config.includeSourceMaps) '--no-source-maps',
    ]);
    
    if (result.exitCode != 0) {
      throw BuildException('Compilation failed: ${result.stderr}');
    }
    
    return CompiledCode(
      executablePath: '${_config.outputDirectory}/app',
      size: await File('${_config.outputDirectory}/app').length(),
    );
  }
  
  Future<List<BuildArtifact>> _generateArtifacts(
    CompiledCode code,
    List<ProcessedAsset> assets,
  ) async {
    final artifacts = <BuildArtifact>[];
    
    // Main executable
    artifacts.add(BuildArtifact(
      name: 'app',
      type: ArtifactType.executable,
      path: code.executablePath,
      size: code.size,
    ));
    
    // Configuration files
    artifacts.add(await _generateProductionConfig());
    
    // Database migrations
    artifacts.addAll(await _packageMigrations());
    
    // Static assets
    for (final asset in assets) {
      artifacts.add(BuildArtifact(
        name: asset.name,
        type: ArtifactType.asset,
        path: asset.outputPath,
        size: asset.size,
      ));
    }
    
    return artifacts;
  }
  
  Future<BuildArtifact> _generateProductionConfig() async {
    final config = ProductionConfig(
      server: ServerConfig(
        httpPort: int.fromEnvironment('HTTP_PORT', defaultValue: 8080),
        wsPort: int.fromEnvironment('WS_PORT', defaultValue: 8082),
        tcpPort: int.fromEnvironment('TCP_PORT', defaultValue: 8081),
        bindAddress: const String.fromEnvironment('BIND_ADDRESS', defaultValue: '0.0.0.0'),
        maxConnections: int.fromEnvironment('MAX_CONNECTIONS', defaultValue: 1000),
        requestTimeout: Duration(
          seconds: int.fromEnvironment('REQUEST_TIMEOUT', defaultValue: 30),
        ),
      ),
      database: DatabaseConfig(
        url: const String.fromEnvironment('DATABASE_URL'),
        maxConnections: int.fromEnvironment('DB_MAX_CONNECTIONS', defaultValue: 20),
        connectionTimeout: Duration(
          seconds: int.fromEnvironment('DB_CONNECTION_TIMEOUT', defaultValue: 10),
        ),
      ),
      security: SecurityConfig(
        jwtSecret: const String.fromEnvironment('JWT_SECRET'),
        corsOrigins: const String.fromEnvironment('CORS_ORIGINS', defaultValue: '*')
            .split(','),
        rateLimitEnabled: const bool.fromEnvironment('RATE_LIMIT_ENABLED', defaultValue: true),
        rateLimitRequests: int.fromEnvironment('RATE_LIMIT_REQUESTS', defaultValue: 100),
      ),
      logging: LoggingConfig(
        level: const String.fromEnvironment('LOG_LEVEL', defaultValue: 'info'),
        format: const String.fromEnvironment('LOG_FORMAT', defaultValue: 'json'),
        output: const String.fromEnvironment('LOG_OUTPUT', defaultValue: 'stdout'),
      ),
    );
    
    final configPath = '${_config.outputDirectory}/config.yaml';
    await File(configPath).writeAsString(yaml.encode(config.toJson()));
    
    return BuildArtifact(
      name: 'config.yaml',
      type: ArtifactType.config,
      path: configPath,
      size: await File(configPath).length(),
    );
  }
}

class BuildConfig {
  final String outputDirectory;
  final bool optimize;
  final bool minify;
  final bool treeShake;
  final bool includeSourceMaps;
  final bool generateDocker;
  final String environment;
  
  BuildConfig({
    this.outputDirectory = 'dist',
    this.optimize = true,
    this.minify = true,
    this.treeShake = true,
    this.includeSourceMaps = false,
    this.generateDocker = false,
    this.environment = 'production',
  });
}

Code Optimization

class CodeOptimizer {
  final OptimizationConfig _config;
  
  CodeOptimizer(this._config);
  
  Future<CompiledCode> optimize(CompiledCode code) async {
    print('⚡ Optimizing code...');
    
    var optimizedCode = code;
    
    // Dead code elimination
    if (_config.eliminateDeadCode) {
      optimizedCode = await _eliminateDeadCode(optimizedCode);
    }
    
    // Tree shaking
    if (_config.treeShake) {
      optimizedCode = await _performTreeShaking(optimizedCode);
    }
    
    // Binary optimization
    if (_config.optimizeBinary) {
      optimizedCode = await _optimizeBinary(optimizedCode);
    }
    
    // Compression
    if (_config.compress) {
      optimizedCode = await _compressExecutable(optimizedCode);
    }
    
    return optimizedCode;
  }
  
  Future<CompiledCode> _eliminateDeadCode(CompiledCode code) async {
    // Analyze code to find unused functions and classes
    final analyzer = DeadCodeAnalyzer();
    final unusedSymbols = await analyzer.findUnusedSymbols(code);
    
    print('🗑️ Eliminating ${unusedSymbols.length} unused symbols');
    
    // Remove unused code (this would be more complex in practice)
    return code.copyWith(
      size: (code.size * 0.95).round(), // Estimated size reduction
    );
  }
  
  Future<CompiledCode> _performTreeShaking(CompiledCode code) async {
    print('🌳 Performing tree shaking...');
    
    // Tree shaking removes unused imports and dependencies
    // This would integrate with Dart's tree shaking capabilities
    return code.copyWith(
      size: (code.size * 0.9).round(), // Estimated size reduction
    );
  }
  
  Future<CompiledCode> _optimizeBinary(CompiledCode code) async {
    print('🔧 Optimizing binary...');
    
    // Apply binary-level optimizations
    final result = await Process.run('strip', [code.executablePath]);
    
    if (result.exitCode == 0) {
      final newSize = await File(code.executablePath).length();
      return code.copyWith(size: newSize);
    }
    
    return code;
  }
  
  Future<CompiledCode> _compressExecutable(CompiledCode code) async {
    print('📦 Compressing executable...');
    
    // Use UPX or similar tool to compress the executable
    final result = await Process.run('upx', [
      '--best',
      '--lzma',
      code.executablePath,
    ]);
    
    if (result.exitCode == 0) {
      final newSize = await File(code.executablePath).length();
      print('📉 Compressed from ${_formatBytes(code.size)} to ${_formatBytes(newSize)}');
      return code.copyWith(size: newSize);
    }
    
    return code;
  }
  
  String _formatBytes(int bytes) {
    if (bytes < 1024) return '${bytes}B';
    if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(1)}KB';
    return '${(bytes / (1024 * 1024)).toStringAsFixed(1)}MB';
  }
}

Docker and Containerization

Multi-Stage Docker Build

# Dockerfile
# Build stage
FROM dart:3.2-sdk AS build

# Set working directory
WORKDIR /app

# Copy pubspec files
COPY pubspec.yaml pubspec.lock ./

# Install dependencies
RUN dart pub get

# Copy source code
COPY . .

# Generate code
RUN dart run hypermodern_cli:main generate

# Build application
RUN dart compile exe lib/main.dart -o server

# Runtime stage
FROM debian:bookworm-slim AS runtime

# Install runtime dependencies
RUN apt-get update && apt-get install -y \
    ca-certificates \
    curl \
    && rm -rf /var/lib/apt/lists/*

# Create app user
RUN useradd -r -s /bin/false -m -d /app app

# Set working directory
WORKDIR /app

# Copy built application
COPY --from=build /app/server ./
COPY --from=build /app/config ./config/
COPY --from=build /app/migrations ./migrations/

# Copy startup script
COPY docker/entrypoint.sh ./
RUN chmod +x entrypoint.sh

# Change ownership
RUN chown -R app:app /app

# Switch to app user
USER app

# Expose ports
EXPOSE 8080 8082 8081

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:8080/health || exit 1

# Start application
ENTRYPOINT ["./entrypoint.sh"]

Docker Compose for Development

# docker-compose.yml
version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
      target: runtime
    ports:
      - "8080:8080"   # HTTP
      - "8082:8082"   # WebSocket
      - "8081:8081"   # TCP
    environment:
      - DATABASE_URL=postgresql://postgres:password@db:5432/hypermodern
      - REDIS_URL=redis://redis:6379
      - JWT_SECRET=your-secret-key-here
      - LOG_LEVEL=info
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    restart: unless-stopped
    networks:
      - hypermodern

  db:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=hypermodern
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=password
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./migrations:/docker-entrypoint-initdb.d
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - hypermodern

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - hypermodern

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/ssl:/etc/nginx/ssl
    depends_on:
      - app
    networks:
      - hypermodern

volumes:
  postgres_data:
  redis_data:

networks:
  hypermodern:
    driver: bridge

Kubernetes Deployment

# k8s/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: hypermodern

---
# k8s/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: hypermodern-config
  namespace: hypermodern
data:
  HTTP_PORT: "8080"
  WS_PORT: "8082"
  TCP_PORT: "8081"
  LOG_LEVEL: "info"
  LOG_FORMAT: "json"

---
# k8s/secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: hypermodern-secrets
  namespace: hypermodern
type: Opaque
data:
  DATABASE_URL: cG9zdGdyZXNxbDovL3VzZXI6cGFzc0BkYjozNDMyL2h5cGVybW9kZXJu
  JWT_SECRET: eW91ci1qd3Qtc2VjcmV0LWtleQ==
  REDIS_URL: cmVkaXM6Ly9yZWRpczozNjM3OQ==

---
# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hypermodern-app
  namespace: hypermodern
  labels:
    app: hypermodern
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hypermodern
  template:
    metadata:
      labels:
        app: hypermodern
    spec:
      containers:
      - name: hypermodern
        image: hypermodern:latest
        ports:
        - containerPort: 8080
          name: http
        - containerPort: 8082
          name: websocket
        - containerPort: 8081
          name: tcp
        envFrom:
        - configMapRef:
            name: hypermodern-config
        - secretRef:
            name: hypermodern-secrets
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
        securityContext:
          runAsNonRoot: true
          runAsUser: 1000
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true

---
# k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: hypermodern-service
  namespace: hypermodern
spec:
  selector:
    app: hypermodern
  ports:
  - name: http
    port: 80
    targetPort: 8080
  - name: websocket
    port: 8082
    targetPort: 8082
  - name: tcp
    port: 8081
    targetPort: 8081
  type: ClusterIP

---
# k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hypermodern-ingress
  namespace: hypermodern
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/websocket-services: "hypermodern-service"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  tls:
  - hosts:
    - api.yourdomain.com
    secretName: hypermodern-tls
  rules:
  - host: api.yourdomain.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: hypermodern-service
            port:
              number: 80

---
# k8s/hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: hypermodern-hpa
  namespace: hypermodern
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: hypermodern-app
  minReplicas: 3
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80

Deployment Strategies

Blue-Green Deployment

class BlueGreenDeployment {
  final KubernetesClient _k8sClient;
  final LoadBalancer _loadBalancer;
  final HealthChecker _healthChecker;
  
  BlueGreenDeployment({
    required KubernetesClient k8sClient,
    required LoadBalancer loadBalancer,
    required HealthChecker healthChecker,
  }) : _k8sClient = k8sClient,
       _loadBalancer = loadBalancer,
       _healthChecker = healthChecker;
  
  Future<DeploymentResult> deploy({
    required String newVersion,
    required Duration healthCheckTimeout,
    required Duration rollbackTimeout,
  }) async {
    print('🚀 Starting blue-green deployment to version $newVersion');
    
    try {
      // Determine current and new environments
      final currentEnv = await _getCurrentEnvironment();
      final newEnv = currentEnv == 'blue' ? 'green' : 'blue';
      
      print('📍 Current environment: $currentEnv');
      print('🎯 Deploying to: $newEnv');
      
      // Deploy to new environment
      await _deployToEnvironment(newEnv, newVersion);
      
      // Wait for deployment to be ready
      await _waitForDeploymentReady(newEnv);
      
      // Perform health checks
      final healthCheckResult = await _performHealthChecks(newEnv, healthCheckTimeout);
      
      if (!healthCheckResult.healthy) {
        throw DeploymentException('Health checks failed: ${healthCheckResult.errors}');
      }
      
      // Switch traffic to new environment
      await _switchTraffic(currentEnv, newEnv);
      
      // Verify traffic switch
      await _verifyTrafficSwitch(newEnv);
      
      // Keep old environment for rollback window
      await _scheduleOldEnvironmentCleanup(currentEnv, rollbackTimeout);
      
      return DeploymentResult(
        success: true,
        version: newVersion,
        environment: newEnv,
        previousEnvironment: currentEnv,
      );
      
    } catch (e) {
      print('❌ Deployment failed: $e');
      
      // Attempt rollback if traffic was switched
      await _attemptRollback();
      
      return DeploymentResult(
        success: false,
        error: e.toString(),
      );
    }
  }
  
  Future<void> _deployToEnvironment(String environment, String version) async {
    print('📦 Deploying version $version to $environment environment');
    
    // Update deployment with new image
    await _k8sClient.updateDeployment(
      name: 'hypermodern-app-$environment',
      image: 'hypermodern:$version',
    );
    
    // Scale up if needed
    await _k8sClient.scaleDeployment(
      name: 'hypermodern-app-$environment',
      replicas: 3,
    );
  }
  
  Future<void> _waitForDeploymentReady(String environment) async {
    print('⏳ Waiting for deployment to be ready...');
    
    const maxWaitTime = Duration(minutes: 10);
    const checkInterval = Duration(seconds: 10);
    final deadline = DateTime.now().add(maxWaitTime);
    
    while (DateTime.now().isBefore(deadline)) {
      final ready = await _k8sClient.isDeploymentReady('hypermodern-app-$environment');
      
      if (ready) {
        print('✅ Deployment is ready');
        return;
      }
      
      await Future.delayed(checkInterval);
    }
    
    throw DeploymentException('Deployment did not become ready within $maxWaitTime');
  }
  
  Future<HealthCheckResult> _performHealthChecks(
    String environment,
    Duration timeout,
  ) async {
    print('🏥 Performing health checks...');
    
    final endpoints = await _k8sClient.getServiceEndpoints('hypermodern-service-$environment');
    final results = <String, bool>{};
    final errors = <String>[];
    
    for (final endpoint in endpoints) {
      try {
        final healthy = await _healthChecker.checkEndpoint(
          endpoint,
          timeout: timeout,
        );
        
        results[endpoint] = healthy;
        
        if (!healthy) {
          errors.add('Health check failed for $endpoint');
        }
      } catch (e) {
        results[endpoint] = false;
        errors.add('Health check error for $endpoint: $e');
      }
    }
    
    final allHealthy = results.values.every((healthy) => healthy);
    
    return HealthCheckResult(
      healthy: allHealthy,
      results: results,
      errors: errors,
    );
  }
  
  Future<void> _switchTraffic(String fromEnv, String toEnv) async {
    print('🔄 Switching traffic from $fromEnv to $toEnv');
    
    // Update load balancer configuration
    await _loadBalancer.updateTargets(
      serviceName: 'hypermodern-service',
      newTargets: await _k8sClient.getServiceEndpoints('hypermodern-service-$toEnv'),
    );
    
    // Update ingress to point to new service
    await _k8sClient.updateIngress(
      name: 'hypermodern-ingress',
      serviceName: 'hypermodern-service-$toEnv',
    );
  }
  
  Future<void> _verifyTrafficSwitch(String environment) async {
    print('🔍 Verifying traffic switch...');
    
    // Make test requests to verify traffic is going to new environment
    final testClient = HttpClient();
    
    for (int i = 0; i < 10; i++) {
      final response = await testClient.get('https://api.yourdomain.com/health');
      final version = response.headers['x-app-version']?.first;
      
      if (version == null) {
        throw DeploymentException('Unable to determine app version from response');
      }
      
      // Verify we're hitting the new environment
      // This would check some environment-specific identifier
    }
    
    print('✅ Traffic switch verified');
  }
}

Canary Deployment

class CanaryDeployment {
  final KubernetesClient _k8sClient;
  final MetricsCollector _metricsCollector;
  final AlertManager _alertManager;
  
  CanaryDeployment({
    required KubernetesClient k8sClient,
    required MetricsCollector metricsCollector,
    required AlertManager alertManager,
  }) : _k8sClient = k8sClient,
       _metricsCollector = metricsCollector,
       _alertManager = alertManager;
  
  Future<DeploymentResult> deploy({
    required String newVersion,
    required List<CanaryStage> stages,
    required Duration stageInterval,
    required CanaryMetrics successCriteria,
  }) async {
    print('🐤 Starting canary deployment to version $newVersion');
    
    try {
      // Deploy canary version
      await _deployCanaryVersion(newVersion);
      
      // Execute canary stages
      for (final stage in stages) {
        await _executeCanaryStage(stage, stageInterval, successCriteria);
      }
      
      // Promote canary to production
      await _promoteCanaryToProduction(newVersion);
      
      return DeploymentResult(
        success: true,
        version: newVersion,
        deploymentType: 'canary',
      );
      
    } catch (e) {
      print('❌ Canary deployment failed: $e');
      
      // Rollback canary
      await _rollbackCanary();
      
      return DeploymentResult(
        success: false,
        error: e.toString(),
      );
    }
  }
  
  Future<void> _executeCanaryStage(
    CanaryStage stage,
    Duration interval,
    CanaryMetrics successCriteria,
  ) async {
    print('📊 Executing canary stage: ${stage.trafficPercentage}% traffic');
    
    // Update traffic split
    await _updateTrafficSplit(stage.trafficPercentage);
    
    // Wait for stage interval
    await Future.delayed(interval);
    
    // Collect metrics
    final metrics = await _collectCanaryMetrics(interval);
    
    // Evaluate success criteria
    final evaluation = _evaluateMetrics(metrics, successCriteria);
    
    if (!evaluation.success) {
      throw CanaryException('Stage failed: ${evaluation.reason}');
    }
    
    print('✅ Stage completed successfully');
  }
  
  Future<void> _updateTrafficSplit(int canaryPercentage) async {
    await _k8sClient.updateTrafficSplit(
      serviceName: 'hypermodern-service',
      canaryPercentage: canaryPercentage,
      stablePercentage: 100 - canaryPercentage,
    );
  }
  
  Future<CanaryMetricsResult> _collectCanaryMetrics(Duration period) async {
    final endTime = DateTime.now();
    final startTime = endTime.subtract(period);
    
    final [
      canaryMetrics,
      stableMetrics,
    ] = await Future.wait([
      _metricsCollector.getMetrics(
        service: 'hypermodern-canary',
        startTime: startTime,
        endTime: endTime,
      ),
      _metricsCollector.getMetrics(
        service: 'hypermodern-stable',
        startTime: startTime,
        endTime: endTime,
      ),
    ]);
    
    return CanaryMetricsResult(
      canary: canaryMetrics,
      stable: stableMetrics,
      period: period,
    );
  }
  
  MetricsEvaluation _evaluateMetrics(
    CanaryMetricsResult metrics,
    CanaryMetrics criteria,
  ) {
    // Error rate check
    if (metrics.canary.errorRate > criteria.maxErrorRate) {
      return MetricsEvaluation(
        success: false,
        reason: 'Error rate too high: ${metrics.canary.errorRate}% > ${criteria.maxErrorRate}%',
      );
    }
    
    // Response time check
    if (metrics.canary.averageResponseTime > criteria.maxResponseTime) {
      return MetricsEvaluation(
        success: false,
        reason: 'Response time too high: ${metrics.canary.averageResponseTime}ms > ${criteria.maxResponseTime}ms',
      );
    }
    
    // Comparison with stable version
    final errorRateIncrease = metrics.canary.errorRate - metrics.stable.errorRate;
    if (errorRateIncrease > criteria.maxErrorRateIncrease) {
      return MetricsEvaluation(
        success: false,
        reason: 'Error rate increase too high: ${errorRateIncrease}%',
      );
    }
    
    return MetricsEvaluation(success: true);
  }
}

class CanaryStage {
  final int trafficPercentage;
  final Duration duration;
  
  CanaryStage({
    required this.trafficPercentage,
    required this.duration,
  });
}

class CanaryMetrics {
  final double maxErrorRate;
  final int maxResponseTime;
  final double maxErrorRateIncrease;
  
  CanaryMetrics({
    required this.maxErrorRate,
    required this.maxResponseTime,
    required this.maxErrorRateIncrease,
  });
}

Monitoring and Logging

Production Monitoring Setup

class ProductionMonitoring {
  final PrometheusClient _prometheus;
  final GrafanaClient _grafana;
  final AlertManagerClient _alertManager;
  final LogAggregator _logAggregator;
  
  ProductionMonitoring({
    required PrometheusClient prometheus,
    required GrafanaClient grafana,
    required AlertManagerClient alertManager,
    required LogAggregator logAggregator,
  }) : _prometheus = prometheus,
       _grafana = grafana,
       _alertManager = alertManager,
       _logAggregator = logAggregator;
  
  Future<void> setupMonitoring() async {
    print('📊 Setting up production monitoring...');
    
    // Configure Prometheus metrics
    await _setupPrometheusMetrics();
    
    // Create Grafana dashboards
    await _setupGrafanaDashboards();
    
    // Configure alerts
    await _setupAlerts();
    
    // Configure log aggregation
    await _setupLogAggregation();
    
    print('✅ Monitoring setup complete');
  }
  
  Future<void> _setupPrometheusMetrics() async {
    // Application metrics
    await _prometheus.createMetric(MetricDefinition(
      name: 'hypermodern_requests_total',
      type: MetricType.counter,
      help: 'Total number of requests',
      labels: ['method', 'endpoint', 'status', 'protocol'],
    ));
    
    await _prometheus.createMetric(MetricDefinition(
      name: 'hypermodern_request_duration_seconds',
      type: MetricType.histogram,
      help: 'Request duration in seconds',
      labels: ['method', 'endpoint', 'protocol'],
      buckets: [0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0],
    ));
    
    await _prometheus.createMetric(MetricDefinition(
      name: 'hypermodern_active_connections',
      type: MetricType.gauge,
      help: 'Number of active connections',
      labels: ['protocol'],
    ));
    
    await _prometheus.createMetric(MetricDefinition(
      name: 'hypermodern_database_connections',
      type: MetricType.gauge,
      help: 'Number of database connections',
      labels: ['state'], // active, idle, waiting
    ));
    
    // Business metrics
    await _prometheus.createMetric(MetricDefinition(
      name: 'hypermodern_users_active',
      type: MetricType.gauge,
      help: 'Number of active users',
    ));
    
    await _prometheus.createMetric(MetricDefinition(
      name: 'hypermodern_operations_total',
      type: MetricType.counter,
      help: 'Total number of business operations',
      labels: ['operation', 'status'],
    ));
  }
  
  Future<void> _setupGrafanaDashboards() async {
    // Application overview dashboard
    await _grafana.createDashboard(DashboardDefinition(
      title: 'Hypermodern Application Overview',
      panels: [
        PanelDefinition(
          title: 'Request Rate',
          type: PanelType.graph,
          query: 'rate(hypermodern_requests_total[5m])',
        ),
        PanelDefinition(
          title: 'Response Time',
          type: PanelType.graph,
          query: 'histogram_quantile(0.95, rate(hypermodern_request_duration_seconds_bucket[5m]))',
        ),
        PanelDefinition(
          title: 'Error Rate',
          type: PanelType.singleStat,
          query: 'rate(hypermodern_requests_total{status=~"5.."}[5m]) / rate(hypermodern_requests_total[5m]) * 100',
        ),
        PanelDefinition(
          title: 'Active Connections by Protocol',
          type: PanelType.graph,
          query: 'hypermodern_active_connections',
        ),
      ],
    ));
    
    // Infrastructure dashboard
    await _grafana.createDashboard(DashboardDefinition(
      title: 'Hypermodern Infrastructure',
      panels: [
        PanelDefinition(
          title: 'CPU Usage',
          type: PanelType.graph,
          query: 'rate(container_cpu_usage_seconds_total{pod=~"hypermodern-.*"}[5m]) * 100',
        ),
        PanelDefinition(
          title: 'Memory Usage',
          type: PanelType.graph,
          query: 'container_memory_usage_bytes{pod=~"hypermodern-.*"}',
        ),
        PanelDefinition(
          title: 'Database Connections',
          type: PanelType.graph,
          query: 'hypermodern_database_connections',
        ),
      ],
    ));
  }
  
  Future<void> _setupAlerts() async {
    // High error rate alert
    await _alertManager.createAlert(AlertRule(
      name: 'HighErrorRate',
      expression: 'rate(hypermodern_requests_total{status=~"5.."}[5m]) / rate(hypermodern_requests_total[5m]) > 0.05',
      duration: Duration(minutes: 2),
      severity: AlertSeverity.critical,
      summary: 'High error rate detected',
      description: 'Error rate is above 5% for more than 2 minutes',
      actions: [
        AlertAction.email(['ops@company.com']),
        AlertAction.slack('#alerts'),
        AlertAction.pagerDuty('hypermodern-service'),
      ],
    ));
    
    // High response time alert
    await _alertManager.createAlert(AlertRule(
      name: 'HighResponseTime',
      expression: 'histogram_quantile(0.95, rate(hypermodern_request_duration_seconds_bucket[5m])) > 2',
      duration: Duration(minutes: 5),
      severity: AlertSeverity.warning,
      summary: 'High response time detected',
      description: '95th percentile response time is above 2 seconds',
      actions: [
        AlertAction.slack('#performance'),
      ],
    ));
    
    // Database connection pool exhaustion
    await _alertManager.createAlert(AlertRule(
      name: 'DatabaseConnectionPoolExhaustion',
      expression: 'hypermodern_database_connections{state="waiting"} > 0',
      duration: Duration(minutes: 1),
      severity: AlertSeverity.warning,
      summary: 'Database connection pool under pressure',
      description: 'Requests are waiting for database connections',
      actions: [
        AlertAction.slack('#database'),
      ],
    ));
  }
  
  Future<void> _setupLogAggregation() async {
    // Configure structured logging
    await _logAggregator.configureSource(LogSource(
      name: 'hypermodern-app',
      pattern: '/var/log/hypermodern/*.log',
      parser: LogParser.json,
      fields: {
        'timestamp': 'timestamp',
        'level': 'level',
        'message': 'message',
        'trace_id': 'trace_id',
        'user_id': 'user_id',
        'endpoint': 'endpoint',
        'protocol': 'protocol',
      },
    ));
    
    // Create log-based alerts
    await _logAggregator.createAlert(LogAlert(
      name: 'DatabaseConnectionErrors',
      query: 'level:ERROR AND message:"database connection"',
      threshold: 10,
      timeWindow: Duration(minutes: 5),
      actions: [
        AlertAction.slack('#database'),
      ],
    ));
  }
}

Application Metrics Integration

class MetricsMiddleware implements Middleware {
  final PrometheusClient _prometheus;
  final Counter _requestsTotal;
  final Histogram _requestDuration;
  final Gauge _activeConnections;
  
  MetricsMiddleware(this._prometheus)
      : _requestsTotal = _prometheus.getCounter('hypermodern_requests_total'),
        _requestDuration = _prometheus.getHistogram('hypermodern_request_duration_seconds'),
        _activeConnections = _prometheus.getGauge('hypermodern_active_connections');
  
  @override
  Future<dynamic> handle(
    dynamic request,
    Future<dynamic> Function(dynamic) next,
  ) async {
    final stopwatch = Stopwatch()..start();
    final protocol = request.protocol as String;
    final endpoint = request.endpoint as String;
    
    // Increment active connections
    _activeConnections.inc(labels: {'protocol': protocol});
    
    try {
      final response = await next(request);
      
      stopwatch.stop();
      
      // Record successful request
      _requestsTotal.inc(labels: {
        'method': request.method ?? 'UNKNOWN',
        'endpoint': endpoint,
        'status': '200',
        'protocol': protocol,
      });
      
      _requestDuration.observe(
        stopwatch.elapsedMilliseconds / 1000.0,
        labels: {
          'method': request.method ?? 'UNKNOWN',
          'endpoint': endpoint,
          'protocol': protocol,
        },
      );
      
      return response;
      
    } catch (e) {
      stopwatch.stop();
      
      // Record failed request
      final statusCode = _getStatusCodeFromException(e);
      
      _requestsTotal.inc(labels: {
        'method': request.method ?? 'UNKNOWN',
        'endpoint': endpoint,
        'status': statusCode.toString(),
        'protocol': protocol,
      });
      
      _requestDuration.observe(
        stopwatch.elapsedMilliseconds / 1000.0,
        labels: {
          'method': request.method ?? 'UNKNOWN',
          'endpoint': endpoint,
          'protocol': protocol,
        },
      );
      
      rethrow;
    } finally {
      // Decrement active connections
      _activeConnections.dec(labels: {'protocol': protocol});
    }
  }
  
  int _getStatusCodeFromException(dynamic exception) {
    if (exception is NotFoundException) return 404;
    if (exception is ValidationException) return 400;
    if (exception is UnauthorizedException) return 401;
    if (exception is ForbiddenException) return 403;
    if (exception is RateLimitExceededException) return 429;
    return 500;
  }
}

Scaling Considerations

Horizontal Pod Autoscaling

# k8s/hpa-advanced.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: hypermodern-hpa
  namespace: hypermodern
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: hypermodern-app
  minReplicas: 3
  maxReplicas: 50
  metrics:
  # CPU-based scaling
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  # Memory-based scaling
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80
  # Custom metrics scaling
  - type: Pods
    pods:
      metric:
        name: hypermodern_active_connections
      target:
        type: AverageValue
        averageValue: "100"
  - type: Object
    object:
      metric:
        name: hypermodern_queue_length
      target:
        type: Value
        value: "1000"
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
      - type: Percent
        value: 10
        periodSeconds: 60
    scaleUp:
      stabilizationWindowSeconds: 60
      policies:
      - type: Percent
        value: 50
        periodSeconds: 60
      - type: Pods
        value: 5
        periodSeconds: 60
      selectPolicy: Max

Load Balancing Configuration

# nginx/nginx.conf
upstream hypermodern_http {
    least_conn;
    server hypermodern-app-1:8080 max_fails=3 fail_timeout=30s;
    server hypermodern-app-2:8080 max_fails=3 fail_timeout=30s;
    server hypermodern-app-3:8080 max_fails=3 fail_timeout=30s;
    keepalive 32;
}

upstream hypermodern_websocket {
    ip_hash;  # Sticky sessions for WebSocket
    server hypermodern-app-1:8082 max_fails=3 fail_timeout=30s;
    server hypermodern-app-2:8082 max_fails=3 fail_timeout=30s;
    server hypermodern-app-3:8082 max_fails=3 fail_timeout=30s;
}

server {
    listen 80;
    listen 443 ssl http2;
    server_name api.yourdomain.com;
    
    # SSL configuration
    ssl_certificate /etc/nginx/ssl/cert.pem;
    ssl_certificate_key /etc/nginx/ssl/key.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
    ssl_prefer_server_ciphers off;
    
    # Security headers
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
    
    # HTTP API
    location / {
        proxy_pass http://hypermodern_http;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # Timeouts
        proxy_connect_timeout 5s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
        
        # Buffering
        proxy_buffering on;
        proxy_buffer_size 4k;
        proxy_buffers 8 4k;
    }
    
    # WebSocket upgrade
    location /ws {
        proxy_pass http://hypermodern_websocket;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # WebSocket timeouts
        proxy_connect_timeout 7d;
        proxy_send_timeout 7d;
        proxy_read_timeout 7d;
    }
    
    # Health check endpoint
    location /health {
        access_log off;
        proxy_pass http://hypermodern_http;
        proxy_set_header Host $host;
    }
}

# TCP load balancing (requires stream module)
stream {
    upstream hypermodern_tcp {
        least_conn;
        server hypermodern-app-1:8081 max_fails=3 fail_timeout=30s;
        server hypermodern-app-2:8081 max_fails=3 fail_timeout=30s;
        server hypermodern-app-3:8081 max_fails=3 fail_timeout=30s;
    }
    
    server {
        listen 8081;
        proxy_pass hypermodern_tcp;
        proxy_timeout 1s;
        proxy_responses 1;
        error_log /var/log/nginx/tcp.log;
    }
}

What's Next

You now have comprehensive knowledge of production deployment for Hypermodern applications, including build optimization, containerization, deployment strategies, monitoring, and scaling. The next chapter will provide real-world examples, showing you how to build complete applications like chat systems, API gateways, and IoT platforms using everything you've learned throughout this book.