Environment Variables

WI-CARPOOL uses environment variables to configure different aspects of the application for various deployment environments.

Environment Variables (.env)

# API Configuration
VITE_API_BASE_URL=http://localhost:3000/api
VITE_API_TIMEOUT=30000

# Google Maps Configuration
VITE_GOOGLE_MAPS_API_KEY=your_google_maps_api_key_here

# Firebase Configuration (if using Firebase)
VITE_FIREBASE_API_KEY=your_firebase_api_key
VITE_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
VITE_FIREBASE_PROJECT_ID=your-project-id

# Payment Integration
VITE_STRIPE_PUBLISHABLE_KEY=pk_test_your_stripe_key
VITE_PAYPAL_CLIENT_ID=your_paypal_client_id

# Application Configuration
VITE_APP_NAME=WI-CARPOOL
VITE_APP_VERSION=1.0.0
VITE_APP_ENVIRONMENT=development

# Feature Flags
VITE_ENABLE_ANALYTICS=true
VITE_ENABLE_PUSH_NOTIFICATIONS=true
VITE_ENABLE_GEOLOCATION=true

# CDN and Asset URLs
VITE_CDN_URL=https://cdn.example.com
VITE_UPLOAD_URL=https://upload.example.com

Environment-Specific Configurations

Development Environment

.env.development

# Development specific settings
VITE_API_BASE_URL=http://localhost:3000/api
VITE_APP_ENVIRONMENT=development
VITE_ENABLE_DEBUG_TOOLS=true
VITE_LOG_LEVEL=debug

# Use development versions of services
VITE_GOOGLE_MAPS_API_KEY=development_api_key
VITE_STRIPE_PUBLISHABLE_KEY=pk_test_development_key

# Local storage and caching
VITE_ENABLE_SERVICE_WORKER=false
VITE_CACHE_DURATION=300

Production Environment

.env.production

# Production specific settings
VITE_API_BASE_URL=https://api.wicarpool.com
VITE_APP_ENVIRONMENT=production
VITE_ENABLE_DEBUG_TOOLS=false
VITE_LOG_LEVEL=error

# Production service keys
VITE_GOOGLE_MAPS_API_KEY=production_api_key
VITE_STRIPE_PUBLISHABLE_KEY=pk_live_production_key

# Performance optimizations
VITE_ENABLE_SERVICE_WORKER=true
VITE_CACHE_DURATION=3600

# Security settings
VITE_ENABLE_CSP=true
VITE_SECURE_COOKIES=true

Staging Environment

.env.staging

# Staging specific settings
VITE_API_BASE_URL=https://staging-api.wicarpool.com
VITE_APP_ENVIRONMENT=staging
VITE_ENABLE_DEBUG_TOOLS=true
VITE_LOG_LEVEL=info

# Staging service keys
VITE_GOOGLE_MAPS_API_KEY=staging_api_key
VITE_STRIPE_PUBLISHABLE_KEY=pk_test_staging_key

# Testing configurations
VITE_ENABLE_E2E_HELPERS=true
[email protected]

Configuration Management

Configuration Provider

Environment Configuration Hook

// src/hooks/useConfig.ts
import { useMemo } from 'react'

interface AppConfig {
  apiBaseUrl: string
  environment: 'development' | 'staging' | 'production'
  googleMapsApiKey: string
  stripePublishableKey: string
  enableAnalytics: boolean
  enablePushNotifications: boolean
  logLevel: 'debug' | 'info' | 'warn' | 'error'
}

export function useConfig(): AppConfig {
  return useMemo(() => ({
    apiBaseUrl: import.meta.env.VITE_API_BASE_URL,
    environment: import.meta.env.VITE_APP_ENVIRONMENT,
    googleMapsApiKey: import.meta.env.VITE_GOOGLE_MAPS_API_KEY,
    stripePublishableKey: import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY,
    enableAnalytics: import.meta.env.VITE_ENABLE_ANALYTICS === 'true',
    enablePushNotifications: import.meta.env.VITE_ENABLE_PUSH_NOTIFICATIONS === 'true',
    logLevel: import.meta.env.VITE_LOG_LEVEL || 'info',
  }), [])
}

// Usage in components
function MyComponent() {
  const config = useConfig()
  
  if (config.environment === 'development') {
    console.log('Running in development mode')
  }
  
  return <div>App Environment: {config.environment}</div>
}

Runtime Configuration

Dynamic Configuration Loading

// src/config/runtime.ts
interface RuntimeConfig {
  features: {
    chat: boolean
    payments: boolean
    notifications: boolean
  }
  limits: {
    maxFileSize: number
    maxImages: number
    searchRadius: number
  }
  api: {
    timeout: number
    retries: number
  }
}

class ConfigManager {
  private config: RuntimeConfig | null = null

  async loadConfig(): Promise<RuntimeConfig> {
    if (this.config) return this.config

    try {
      const response = await fetch('/config.json')
      this.config = await response.json()
      return this.config
    } catch (error) {
      console.warn('Failed to load runtime config, using defaults')
      return this.getDefaultConfig()
    }
  }

  private getDefaultConfig(): RuntimeConfig {
    return {
      features: {
        chat: true,
        payments: true,
        notifications: true,
      },
      limits: {
        maxFileSize: 5 * 1024 * 1024, // 5MB
        maxImages: 5,
        searchRadius: 50, // km
      },
      api: {
        timeout: 30000,
        retries: 3,
      },
    }
  }
}

export const configManager = new ConfigManager()

Security Best Practices

Environment Variable Security

  • Never commit sensitive keys to version control
  • Use different API keys for different environments
  • Rotate API keys regularly
  • Validate environment variables at runtime

Configuration Validation

Environment Validation

// src/config/validation.ts
import { z } from 'zod'

const envSchema = z.object({
  VITE_API_BASE_URL: z.string().url(),
  VITE_GOOGLE_MAPS_API_KEY: z.string().min(1),
  VITE_APP_ENVIRONMENT: z.enum(['development', 'staging', 'production']),
  VITE_ENABLE_ANALYTICS: z.string().optional(),
  VITE_ENABLE_PUSH_NOTIFICATIONS: z.string().optional(),
})

export function validateEnvironment() {
  const result = envSchema.safeParse(import.meta.env)
  
  if (!result.success) {
    console.error('Invalid environment configuration:', result.error.format())
    throw new Error('Environment validation failed')
  }
  
  return result.data
}

// Call this during app initialization
validateEnvironment()

Build Configuration

Vite Configuration

vite.config.ts Environment Setup

import { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react-swc'
import path from 'path'

export default defineConfig(({ command, mode }) => {
  // Load environment variables
  const env = loadEnv(mode, process.cwd(), '')
  
  return {
    plugins: [react()],
    
    resolve: {
      alias: {
        '@': path.resolve(__dirname, './src'),
      },
    },
    
    define: {
      // Make environment available to the app
      __APP_VERSION__: JSON.stringify(process.env.npm_package_version),
      __BUILD_TIME__: JSON.stringify(new Date().toISOString()),
    },
    
    server: {
      host: '::',
      port: 8080,
      proxy: {
        '/api': {
          target: env.VITE_API_BASE_URL,
          changeOrigin: true,
          rewrite: (path) => path.replace(/^\/api/, ''),
        },
      },
    },
    
    build: {
      sourcemap: mode !== 'production',
      rollupOptions: {
        output: {
          manualChunks: {
            vendor: ['react', 'react-dom'],
            router: ['react-router-dom'],
            ui: ['@radix-ui/react-dialog', '@radix-ui/react-popover'],
          },
        },
      },
    },
  }
})

Local Development Setup

Development Scripts

package.json Scripts

{
  "scripts": {
    "dev": "vite",
    "dev:staging": "vite --mode staging",
    "build": "tsc && vite build",
    "build:staging": "tsc && vite build --mode staging",
    "build:production": "tsc && vite build --mode production",
    "preview": "vite preview",
    "preview:staging": "vite preview --mode staging",
    "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
    "env:check": "node scripts/check-env.js",
    "env:copy": "cp .env.example .env"
  }
}

Environment Setup Script

scripts/setup-env.js

#!/usr/bin/env node

const fs = require('fs')
const path = require('path')
const readline = require('readline')

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
})

async function setupEnvironment() {
  console.log('šŸš€ WI-CARPOOL Environment Setup\n')
  
  const envPath = path.join(process.cwd(), '.env')
  
  if (fs.existsSync(envPath)) {
    console.log('āš ļø  .env file already exists')
    const answer = await question('Do you want to overwrite it? (y/N): ')
    if (answer.toLowerCase() !== 'y') {
      console.log('Setup cancelled')
      process.exit(0)
    }
  }
  
  const config = {}
  
  config.VITE_API_BASE_URL = await question('API Base URL (http://localhost:3000/api): ') || 'http://localhost:3000/api'
  config.VITE_GOOGLE_MAPS_API_KEY = await question('Google Maps API Key: ')
  config.VITE_APP_ENVIRONMENT = await question('Environment (development): ') || 'development'
  
  const envContent = Object.entries(config)
    .map(([key, value]) => `${key}=${value}`)
    .join('\n')
  
  fs.writeFileSync(envPath, envContent)
  console.log('\nāœ… Environment file created successfully!')
  console.log('šŸ”§ Run "npm run dev" to start the development server')
  
  rl.close()
}

function question(prompt) {
  return new Promise((resolve) => {
    rl.question(prompt, resolve)
  })
}

setupEnvironment().catch(console.error)

Troubleshooting

Common Issues

  • Environment variables not loading: Ensure variables start with VITE_ prefix
  • API calls failing: Check VITE_API_BASE_URL is correctly set
  • Maps not working: Verify Google Maps API key and enabled services
  • Build errors: Validate all required environment variables are set

Environment Debugging

Debug Environment Variables

// Add this to your main.tsx for debugging
if (import.meta.env.DEV) {
  console.log('Environment Variables:', {
    API_BASE_URL: import.meta.env.VITE_API_BASE_URL,
    ENVIRONMENT: import.meta.env.VITE_APP_ENVIRONMENT,
    GOOGLE_MAPS_KEY: import.meta.env.VITE_GOOGLE_MAPS_API_KEY ? 'āœ“ Set' : 'āœ— Missing',
  })
}