Skip to main content

Environment Configuration

This guide covers production-specific configuration, optimization, and best practices for your BOOP integration.

🌍 Environment Overview

Environment Comparison

Understanding the differences between dev and production environments is crucial for proper configuration.
FeatureDevelopmentProduction
Base URLhttps://dev.app.boop.ithttps://app.boop.it
WebSocketwss://dev.app.boop.it/ws/vendorwss://app.boop.it/ws/vendor
Rate LimitsRelaxed for testingEnforced for stability
Data PersistenceTemporary (reset weekly)Permanent
SSL/TLSDevelopment certificatesProduction-grade certificates
Uptime SLABest effort99.9% guaranteed
SupportBusiness hours24/7 monitoring

Production Environment Features

High Availability

Redundant infrastructure with automatic failover

Global CDN

Optimized performance worldwide

Real-time Monitoring

24/7 monitoring and alerting

⚙️ Configuration Management

Environment Variables

Set up environment-specific configuration:
# Production Environment
export BOOP_ENV=production
export BOOP_BASE_URL=https://app.boop.it
export BOOP_VENDOR_ID=ven_live_your_vendor_id
export BOOP_API_KEY=sk_live_your_secret_key
export BOOP_WS_ENDPOINT=wss://app.boop.it/ws/vendor

# Security Settings
export BOOP_ENFORCE_HTTPS=true
export BOOP_API_TIMEOUT=30000
export BOOP_WS_HEARTBEAT_INTERVAL=30000
export BOOP_MAX_RETRIES=3

# Performance Settings
export BOOP_CONNECTION_POOL_SIZE=10
export BOOP_CACHE_TTL=300
export BOOP_BATCH_SIZE=50

Configuration Validation

Implement configuration validation to catch issues early:
class ConfigValidator {
  static validate(config) {
    const required = ['baseUrl', 'vendorId', 'apiKey', 'wsEndpoint'];
    const missing = required.filter(key => !config[key]);

    if (missing.length > 0) {
      throw new Error(`Missing required BOOP configuration: ${missing.join(', ')}`);
    }

    // Validate URLs
    try {
      new URL(config.baseUrl);
      new URL(config.wsEndpoint);
    } catch (error) {
      throw new Error(`Invalid BOOP URL configuration: ${error.message}`);
    }

    // Validate credentials format
    if (!config.vendorId.startsWith('ven_live_')) {
      console.warn('⚠️  Vendor ID should start with "ven_live_" in production');
    }

    if (!config.apiKey.startsWith('sk_live_')) {
      console.warn('⚠️  API Key should start with "sk_live_" in production');
    }

    // Validate environment
    if (config.baseUrl.includes('dev.app.boop.it')) {
      throw new Error('🚨 Development URL detected in production configuration!');
    }

    console.log('✅ BOOP configuration validation passed');
    return true;
  }
}

// Usage
const config = require('./config/production');
ConfigValidator.validate(config.boop);

🚀 Performance Optimization

Connection Management

Optimize connections for production performance:
class BoopWebSocketManager {
  constructor(config) {
    this.config = config;
    this.connections = new Map();
    this.maxConnections = config.maxConnections || 5;
    this.heartbeatInterval = config.heartbeatInterval || 30000;
  }

  async getConnection(vendorId) {
    if (this.connections.has(vendorId)) {
      const connection = this.connections.get(vendorId);
      if (connection.readyState === WebSocket.OPEN) {
        return connection;
      }
    }

    // Create new connection
    const ws = await this.createConnection(vendorId);
    this.connections.set(vendorId, ws);
    this.setupHeartbeat(ws);

    return ws;
  }

  setupHeartbeat(ws) {
    const heartbeat = setInterval(() => {
      if (ws.readyState === WebSocket.OPEN) {
        ws.send(JSON.stringify({ type: 'ping' }));
      } else {
        clearInterval(heartbeat);
      }
    }, this.heartbeatInterval);
  }
}
class BoopBatchProcessor {
  constructor(batchSize = 50, batchTimeout = 5000) {
    this.batchSize = batchSize;
    this.batchTimeout = batchTimeout;
    this.queue = [];
    this.timeout = null;
  }

  async addRequest(request) {
    return new Promise((resolve, reject) => {
      this.queue.push({ request, resolve, reject });

      if (this.queue.length >= this.batchSize) {
        this.processBatch();
      } else if (!this.timeout) {
        this.timeout = setTimeout(() => this.processBatch(), this.batchTimeout);
      }
    });
  }

  async processBatch() {
    if (this.timeout) {
      clearTimeout(this.timeout);
      this.timeout = null;
    }

    const batch = this.queue.splice(0, this.batchSize);
    if (batch.length === 0) return;

    try {
      const results = await this.executeBatch(batch.map(item => item.request));

      batch.forEach((item, index) => {
        item.resolve(results[index]);
      });
    } catch (error) {
      batch.forEach(item => item.reject(error));
    }
  }
}
class BoopCache {
  constructor(ttl = 300000) { // 5 minutes default
    this.cache = new Map();
    this.ttl = ttl;
  }

  set(key, value) {
    this.cache.set(key, {
      value,
      timestamp: Date.now(),
      hits: 0
    });
  }

  get(key) {
    const item = this.cache.get(key);

    if (!item) return null;

    if (Date.now() - item.timestamp > this.ttl) {
      this.cache.delete(key);
      return null;
    }

    item.hits++;
    return item.value;
  }

  // Cache user attributes for quick access
  cacheUserAttributes(userId, attributes) {
    this.set(`user_attributes:${userId}`, attributes);
  }

  getUserAttributes(userId) {
    return this.get(`user_attributes:${userId}`);
  }
}

Performance Monitoring

Track key performance metrics:
class PerformanceMonitor {
  constructor() {
    this.metrics = {
      authenticationsPerMinute: 0,
      averageResponseTime: 0,
      errorRate: 0,
      activeConnections: 0
    };

    this.startMonitoring();
  }

  recordAuthentication(responseTime, success) {
    // Update metrics
    this.metrics.authenticationsPerMinute++;
    this.updateAverageResponseTime(responseTime);

    if (!success) {
      this.metrics.errorRate = (this.metrics.errorRate + 1) / this.metrics.authenticationsPerMinute;
    }

    // Log to monitoring system
    this.logToMonitoring('authentication', {
      responseTime,
      success,
      timestamp: Date.now()
    });
  }

  getHealthCheck() {
    return {
      status: this.metrics.errorRate < 0.01 ? 'healthy' : 'degraded',
      metrics: this.metrics,
      timestamp: new Date().toISOString()
    };
  }

  startMonitoring() {
    // Reset counters every minute
    setInterval(() => {
      this.metrics.authenticationsPerMinute = 0;
    }, 60000);
  }
}

🔒 Security Configuration

API Key Management

Never hardcode production API keys. Use secure environment variable management.
class ApiKeyManager {
  constructor() {
    this.primaryKey = process.env.BOOP_API_KEY;
    this.secondaryKey = process.env.BOOP_API_KEY_SECONDARY;
    this.rotationDate = process.env.BOOP_KEY_ROTATION_DATE;
  }

  getCurrentKey() {
    // Use secondary key if rotation is active
    if (this.isRotationActive()) {
      return this.secondaryKey;
    }
    return this.primaryKey;
  }

  isRotationActive() {
    if (!this.rotationDate) return false;
    return new Date() >= new Date(this.rotationDate);
  }

  async makeApiCall(endpoint, data) {
    let apiKey = this.getCurrentKey();

    try {
      return await this.request(endpoint, data, apiKey);
    } catch (error) {
      if (error.status === 401 && this.secondaryKey) {
        // Try with secondary key
        console.warn('Primary key failed, trying secondary key');
        return await this.request(endpoint, data, this.secondaryKey);
      }
      throw error;
    }
  }
}
class SecurityValidator {
  static validateRequest(request) {
    // Validate HTTPS
    if (!request.url.startsWith('https://')) {
      throw new Error('HTTPS required for production');
    }

    // Validate headers
    const requiredHeaders = ['X-API-Key', 'Content-Type', 'User-Agent'];
    for (const header of requiredHeaders) {
      if (!request.headers[header]) {
        throw new Error(`Missing required header: ${header}`);
      }
    }

    // Validate API key format
    const apiKey = request.headers['X-API-Key'];
    if (!apiKey.startsWith('sk_live_')) {
      throw new Error('Invalid production API key format');
    }

    return true;
  }

  static sanitizeLog(data) {
    const sensitive = ['api_key', 'apiKey', 'secret', 'password', 'token'];
    const sanitized = { ...data };

    for (const key of sensitive) {
      if (sanitized[key]) {
        sanitized[key] = '***REDACTED***';
      }
    }

    return sanitized;
  }
}

Network Security

Configure production network security:
// HTTPS enforcement
app.use((req, res, next) => {
  if (req.header('x-forwarded-proto') !== 'https') {
    res.redirect(`https://${req.header('host')}${req.url}`);
  } else {
    next();
  }
});

// Security headers
app.use((req, res, next) => {
  res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
  res.setHeader('X-Content-Type-Options', 'nosniff');
  res.setHeader('X-Frame-Options', 'DENY');
  res.setHeader('X-XSS-Protection', '1; mode=block');
  next();
});

// Rate limiting
const rateLimit = require('express-rate-limit');
const boopLimiter = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 100, // limit each IP to 100 requests per windowMs
  message: 'Too many BOOP API requests from this IP'
});

app.use('/api/boop', boopLimiter);

📊 Error Handling & Logging

Production Error Handling

Implement comprehensive error handling:
class ProductionErrorHandler {
  static handleBoopError(error, context) {
    // Log error with context
    console.error('BOOP Error:', {
      error: error.message,
      code: error.code,
      context: SecurityValidator.sanitizeLog(context),
      timestamp: new Date().toISOString(),
      stack: process.env.NODE_ENV === 'development' ? error.stack : undefined
    });

    // Send to monitoring service
    this.sendToMonitoring(error, context);

    // Return safe error message to client
    return this.getSafeErrorMessage(error);
  }

  static getSafeErrorMessage(error) {
    const safeMessages = {
      'user-not-found': 'Authentication failed. Please try again.',
      'insufficient-balance': 'Insufficient funds. Please add money to your account.',
      'vendor-not-consented': 'Access not authorized. Please check your permissions.',
      'network-error': 'Service temporarily unavailable. Please try again.',
      'timeout': 'Request timed out. Please try again.'
    };

    return safeMessages[error.code] || 'An error occurred. Please try again.';
  }

  static sendToMonitoring(error, context) {
    // Integrate with your monitoring service
    // Examples: DataDog, New Relic, Sentry, etc.
  }
}

Structured Logging

Configure production-grade logging:
const winston = require('winston');

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.errors({ stack: true }),
    winston.format.json()
  ),
  defaultMeta: {
    service: 'boop-integration',
    environment: process.env.NODE_ENV
  },
  transports: [
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.File({ filename: 'combined.log' }),
    new winston.transports.Console({
      format: winston.format.simple()
    })
  ]
});

// Usage
logger.info('BOOP authentication started', {
  vendorId: 'ven_live_***',
  userId: userId,
  amount: amount
});

logger.error('BOOP authentication failed', {
  error: error.message,
  code: error.code,
  vendorId: 'ven_live_***',
  userId: userId
});

🔧 Environment-Specific Features

Production Rate Limits

Understanding and working with production rate limits:
Endpoint TypeRate LimitBurst LimitWindow
Authentication100 req/min10 req/sec1 minute
API Calls1000 req/min50 req/sec1 minute
WebSocket Messages1000 msg/min100 msg/sec1 minute
User Operations50 req/min5 req/sec1 minute

Feature Flags

Use feature flags for safe production rollouts:
class FeatureFlags {
  constructor() {
    this.flags = {
      useBoopPayments: process.env.ENABLE_BOOP_PAYMENTS === 'true',
      boopTrafficPercentage: parseInt(process.env.BOOP_TRAFFIC_PERCENT || '0'),
      enableBoopAttributes: process.env.ENABLE_BOOP_ATTRIBUTES === 'true',
      boopTimeout: parseInt(process.env.BOOP_TIMEOUT || '30000')
    };
  }

  isEnabled(flag) {
    return this.flags[flag] === true;
  }

  getPercentage(flag) {
    return this.flags[flag] || 0;
  }

  shouldRouteToBoopForUser(userId) {
    const percentage = this.getPercentage('boopTrafficPercentage');
    if (percentage === 0) return false;
    if (percentage === 100) return true;

    // Consistent hashing for gradual rollout
    const hash = this.hashUserId(userId);
    return (hash % 100) < percentage;
  }
}

📈 Monitoring Integration

Health Check Endpoint

Implement a comprehensive health check:
app.get('/health/boop', async (req, res) => {
  const health = {
    status: 'unknown',
    timestamp: new Date().toISOString(),
    checks: {}
  };

  try {
    // Test BOOP connectivity
    const boopResponse = await fetch('https://app.boop.it/health', { timeout: 5000 });
    health.checks.boopConnectivity = {
      status: boopResponse.ok ? 'healthy' : 'unhealthy',
      responseTime: Date.now() - startTime
    };

    // Test WebSocket connectivity
    const wsHealthy = await testWebSocketConnection();
    health.checks.webSocket = {
      status: wsHealthy ? 'healthy' : 'unhealthy'
    };

    // Check authentication capability
    const authHealthy = await testAuthentication();
    health.checks.authentication = {
      status: authHealthy ? 'healthy' : 'unhealthy'
    };

    // Overall status
    const allHealthy = Object.values(health.checks).every(check => check.status === 'healthy');
    health.status = allHealthy ? 'healthy' : 'unhealthy';

    res.status(allHealthy ? 200 : 503).json(health);
  } catch (error) {
    health.status = 'unhealthy';
    health.error = error.message;
    res.status(503).json(health);
  }
});

Metrics Collection

Collect and export metrics for monitoring:
const prometheus = require('prom-client');

// Create metrics
const authCounter = new prometheus.Counter({
  name: 'boop_authentications_total',
  help: 'Total number of BOOP authentications',
  labelNames: ['status', 'vendor_id']
});

const responseTime = new prometheus.Histogram({
  name: 'boop_response_time_seconds',
  help: 'BOOP API response time in seconds',
  buckets: [0.1, 0.5, 1, 2, 5, 10]
});

// Export metrics endpoint
app.get('/metrics', (req, res) => {
  res.set('Content-Type', prometheus.register.contentType);
  res.end(prometheus.register.metrics());
});

🎯 Next Steps

Production Environment Complete! Your BOOP integration is now properly configured for production use with security, performance, and monitoring best practices in place.