Skip to content

Latest commit

Β 

History

History
703 lines (554 loc) Β· 15.4 KB

File metadata and controls

703 lines (554 loc) Β· 15.4 KB

βš™οΈ Environment Configuration

This guide covers environment setup, configuration management, and deployment environment variables for OpenLN.

πŸ—οΈ Environment Overview

OpenLN uses different configurations for different environments:

  • Development: Local development with hot reloading
  • Testing: Automated testing environment
  • Staging: Pre-production environment for testing
  • Production: Live application environment

πŸ“ Environment Files Structure

project-root/
β”œβ”€β”€ client/
β”‚   β”œβ”€β”€ .env.local          # Local development (gitignored)
β”‚   β”œβ”€β”€ .env.development    # Development defaults
β”‚   β”œβ”€β”€ .env.staging        # Staging environment
β”‚   β”œβ”€β”€ .env.production     # Production environment
β”‚   └── .env.example        # Template file
β”œβ”€β”€ server/
β”‚   β”œβ”€β”€ .env                # Local development (gitignored)
β”‚   β”œβ”€β”€ .env.development    # Development defaults
β”‚   β”œβ”€β”€ .env.staging        # Staging environment
β”‚   β”œβ”€β”€ .env.production     # Production environment
β”‚   └── .env.example        # Template file
└── .gitignore

🎨 Frontend Environment Configuration

Environment File Precedence (Vite)

  1. .env.local (highest priority, always loaded)
  2. .env.[mode] (e.g., .env.development)
  3. .env (lowest priority)

Frontend Environment Variables

Development (.env.development)

# API Configuration
VITE_API_URL=http://localhost:5000/api/v1
VITE_SERVER_URL=http://localhost:5000

# Environment
VITE_NODE_ENV=development

# Feature Flags
VITE_ENABLE_ANALYTICS=false
VITE_ENABLE_MOCKING=true

# Debug Settings
VITE_DEBUG_MODE=true
VITE_LOG_LEVEL=debug

Staging (.env.staging)

# API Configuration
VITE_API_URL=https://api-staging.openln.dev/api/v1
VITE_SERVER_URL=https://api-staging.openln.dev

# Environment
VITE_NODE_ENV=staging

# Feature Flags
VITE_ENABLE_ANALYTICS=true
VITE_ENABLE_MOCKING=false

# Debug Settings
VITE_DEBUG_MODE=true
VITE_LOG_LEVEL=info

# Sentry (Error Tracking)
VITE_SENTRY_DSN=your-staging-sentry-dsn

# Analytics
VITE_GOOGLE_ANALYTICS_ID=GA-STAGING-ID

Production (.env.production)

# API Configuration
VITE_API_URL=https://api.openln.dev/api/v1
VITE_SERVER_URL=https://api.openln.dev

# Environment
VITE_NODE_ENV=production

# Feature Flags
VITE_ENABLE_ANALYTICS=true
VITE_ENABLE_MOCKING=false

# Debug Settings
VITE_DEBUG_MODE=false
VITE_LOG_LEVEL=error

# Sentry (Error Tracking)
VITE_SENTRY_DSN=your-production-sentry-dsn

# Analytics
VITE_GOOGLE_ANALYTICS_ID=GA-PRODUCTION-ID

# CDN Configuration
VITE_CDN_URL=https://cdn.openln.dev

Local Development (.env.local)

# Override any environment variables for local development
# This file is gitignored and should contain sensitive data

# Google AI (for local testing)
VITE_GOOGLE_AI_API_KEY=your-local-api-key

# Local feature overrides
VITE_ENABLE_EXPERIMENTAL_FEATURES=true

Using Environment Variables in Frontend

React Component Example

// src/config/environment.ts
export const config = {
  apiUrl: import.meta.env.VITE_API_URL,
  serverUrl: import.meta.env.VITE_SERVER_URL,
  nodeEnv: import.meta.env.VITE_NODE_ENV,
  
  // Feature flags
  enableAnalytics: import.meta.env.VITE_ENABLE_ANALYTICS === 'true',
  enableMocking: import.meta.env.VITE_ENABLE_MOCKING === 'true',
  
  // Debug settings
  debugMode: import.meta.env.VITE_DEBUG_MODE === 'true',
  logLevel: import.meta.env.VITE_LOG_LEVEL || 'info',
  
  // External services
  sentryDsn: import.meta.env.VITE_SENTRY_DSN,
  googleAnalyticsId: import.meta.env.VITE_GOOGLE_ANALYTICS_ID,
} as const;

// Type-safe environment access
export const isDevelopment = config.nodeEnv === 'development';
export const isProduction = config.nodeEnv === 'production';
export const isStaging = config.nodeEnv === 'staging';

API Service Configuration

// src/services/api.ts
import { config } from '../config/environment';

class ApiService {
  private baseURL: string;
  
  constructor() {
    this.baseURL = config.apiUrl;
  }
  
  async request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
    const url = `${this.baseURL}${endpoint}`;
    
    const response = await fetch(url, {
      headers: {
        'Content-Type': 'application/json',
        ...options.headers,
      },
      ...options,
    });
    
    if (!response.ok) {
      throw new Error(`API Error: ${response.status}`);
    }
    
    return response.json();
  }
}

export const api = new ApiService();

βš™οΈ Backend Environment Configuration

Environment Variables

Development (.env.development)

# Server Configuration
NODE_ENV=development
PORT=5000
HOST=localhost

# Database
MONGODB_URI=mongodb://localhost:27017/openln-dev

# JWT Configuration
JWT_SECRET=dev-jwt-secret-key-not-for-production
JWT_EXPIRE=24h

# CORS
CLIENT_URL=http://localhost:5173
ALLOWED_ORIGINS=http://localhost:5173,http://localhost:3000

# Google AI
GOOGLE_AI_API_KEY=your-development-api-key

# OAuth (Development)
GOOGLE_CLIENT_ID=your-dev-google-client-id
GOOGLE_CLIENT_SECRET=your-dev-google-client-secret

# Email (Development - Optional)
SMTP_HOST=smtp.mailtrap.io
SMTP_PORT=587
SMTP_USER=your-mailtrap-user
SMTP_PASS=your-mailtrap-pass

# Rate Limiting (Relaxed for development)
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=1000

# Logging
LOG_LEVEL=debug
LOG_FILE=logs/development.log

# Debug Settings
DEBUG_MODE=true
ENABLE_REQUEST_LOGGING=true

Staging (.env.staging)

# Server Configuration
NODE_ENV=staging
PORT=5000

# Database
MONGODB_URI=mongodb+srv://username:password@staging-cluster.mongodb.net/openln-staging

# JWT Configuration
JWT_SECRET=staging-jwt-secret-key-32-characters-minimum
JWT_EXPIRE=7d

# CORS
CLIENT_URL=https://staging.openln.dev
ALLOWED_ORIGINS=https://staging.openln.dev

# Google AI
GOOGLE_AI_API_KEY=your-staging-api-key

# OAuth
GOOGLE_CLIENT_ID=your-staging-google-client-id
GOOGLE_CLIENT_SECRET=your-staging-google-client-secret

# Email
SMTP_HOST=smtp.sendgrid.net
SMTP_PORT=587
SMTP_USER=apikey
SMTP_PASS=your-sendgrid-api-key

# Rate Limiting
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=100

# Logging
LOG_LEVEL=info
LOG_FILE=logs/staging.log

# Monitoring
SENTRY_DSN=your-staging-sentry-dsn

# Redis (if using)
REDIS_URL=redis://staging-redis:6379

Production (.env.production)

# Server Configuration
NODE_ENV=production
PORT=5000

# Database
MONGODB_URI=mongodb+srv://username:password@production-cluster.mongodb.net/openln-production

# JWT Configuration
JWT_SECRET=super-secure-production-jwt-secret-key-64-characters-minimum
JWT_EXPIRE=7d

# CORS
CLIENT_URL=https://openln.dev
ALLOWED_ORIGINS=https://openln.dev,https://www.openln.dev

# Google AI
GOOGLE_AI_API_KEY=your-production-api-key

# OAuth
GOOGLE_CLIENT_ID=your-production-google-client-id
GOOGLE_CLIENT_SECRET=your-production-google-client-secret

# Email
SMTP_HOST=smtp.sendgrid.net
SMTP_PORT=587
SMTP_USER=apikey
SMTP_PASS=your-production-sendgrid-api-key

# Rate Limiting
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=100

# Logging
LOG_LEVEL=warn
LOG_FILE=logs/production.log

# Monitoring
SENTRY_DSN=your-production-sentry-dsn

# Redis
REDIS_URL=redis://production-redis:6379

# Security
ENABLE_HELMET=true
ENABLE_RATE_LIMITING=true
TRUST_PROXY=true

Local Development (.env)

# Local overrides and sensitive data
# This file is gitignored

# Local database
MONGODB_URI=mongodb://localhost:27017/openln-local

# Local secrets
JWT_SECRET=local-development-secret-key
GOOGLE_AI_API_KEY=your-local-google-ai-key

# Local OAuth (optional)
GOOGLE_CLIENT_ID=your-local-google-client-id
GOOGLE_CLIENT_SECRET=your-local-google-client-secret

# Debug settings
DEBUG=openln:*
NODE_DEBUG=cluster,net,http,fs,tls,module,timers

Using Environment Variables in Backend

Configuration Module

// server/config/environment.js
import dotenv from 'dotenv';

// Load environment file based on NODE_ENV
const envFile = process.env.NODE_ENV ? `.env.${process.env.NODE_ENV}` : '.env';
dotenv.config({ path: envFile });

export const config = {
  // Server
  nodeEnv: process.env.NODE_ENV || 'development',
  port: parseInt(process.env.PORT) || 5000,
  host: process.env.HOST || 'localhost',
  
  // Database
  mongodbUri: process.env.MONGODB_URI || 'mongodb://localhost:27017/openln',
  
  // JWT
  jwt: {
    secret: process.env.JWT_SECRET,
    expire: process.env.JWT_EXPIRE || '7d',
  },
  
  // CORS
  cors: {
    clientUrl: process.env.CLIENT_URL || 'http://localhost:5173',
    allowedOrigins: process.env.ALLOWED_ORIGINS?.split(',') || ['http://localhost:5173'],
  },
  
  // External APIs
  googleAI: {
    apiKey: process.env.GOOGLE_AI_API_KEY,
  },
  
  // OAuth
  oauth: {
    google: {
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    },
  },
  
  // Email
  email: {
    host: process.env.SMTP_HOST,
    port: parseInt(process.env.SMTP_PORT) || 587,
    user: process.env.SMTP_USER,
    pass: process.env.SMTP_PASS,
  },
  
  // Rate Limiting
  rateLimit: {
    windowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS) || 900000,
    maxRequests: parseInt(process.env.RATE_LIMIT_MAX_REQUESTS) || 100,
  },
  
  // Logging
  logging: {
    level: process.env.LOG_LEVEL || 'info',
    file: process.env.LOG_FILE || 'logs/app.log',
  },
  
  // Monitoring
  sentry: {
    dsn: process.env.SENTRY_DSN,
  },
  
  // Redis
  redis: {
    url: process.env.REDIS_URL,
  },
  
  // Feature flags
  features: {
    enableHelmet: process.env.ENABLE_HELMET === 'true',
    enableRateLimiting: process.env.ENABLE_RATE_LIMITING === 'true',
    debugMode: process.env.DEBUG_MODE === 'true',
  },
};

// Validation
const requiredEnvVars = [
  'MONGODB_URI',
  'JWT_SECRET',
];

const missingEnvVars = requiredEnvVars.filter(
  envVar => !process.env[envVar]
);

if (missingEnvVars.length > 0) {
  throw new Error(
    `Missing required environment variables: ${missingEnvVars.join(', ')}`
  );
}

export const isDevelopment = config.nodeEnv === 'development';
export const isProduction = config.nodeEnv === 'production';
export const isStaging = config.nodeEnv === 'staging';

Database Configuration

// server/config/database.js
import mongoose from 'mongoose';
import { config, isDevelopment } from './environment.js';
import { logger } from '../utils/logger.js';

export const connectDatabase = async () => {
  try {
    const options = {
      // Connection settings
      maxPoolSize: 10,
      serverSelectionTimeoutMS: 5000,
      socketTimeoutMS: 45000,
      bufferCommands: false,
      bufferMaxEntries: 0,
    };

    // Development-specific settings
    if (isDevelopment) {
      mongoose.set('debug', true);
      options.maxPoolSize = 5;
    }

    await mongoose.connect(config.mongodbUri, options);
    
    logger.info(`MongoDB connected: ${mongoose.connection.host}`);
  } catch (error) {
    logger.error('Database connection error:', error);
    process.exit(1);
  }
};

// Handle connection events
mongoose.connection.on('connected', () => {
  logger.info('MongoDB connected successfully');
});

mongoose.connection.on('error', (err) => {
  logger.error('MongoDB connection error:', err);
});

mongoose.connection.on('disconnected', () => {
  logger.warn('MongoDB disconnected');
});

// Graceful shutdown
process.on('SIGINT', async () => {
  await mongoose.connection.close();
  logger.info('MongoDB connection closed due to app termination');
  process.exit(0);
});

πŸš€ Deployment Environment Setup

Vercel (Frontend)

Environment Variables in Vercel Dashboard

# Production
VITE_API_URL=https://api.openln.dev/api/v1
VITE_NODE_ENV=production
VITE_ENABLE_ANALYTICS=true
VITE_SENTRY_DSN=your-sentry-dsn

# Preview (Staging)
VITE_API_URL=https://api-staging.openln.dev/api/v1
VITE_NODE_ENV=staging
VITE_ENABLE_ANALYTICS=false

Vercel Configuration (vercel.json)

{
  "buildCommand": "cd client && npm run build",
  "outputDirectory": "client/dist",
  "installCommand": "cd client && npm install",
  "env": {
    "VITE_API_URL": "@vite-api-url"
  },
  "build": {
    "env": {
      "VITE_API_URL": "https://api.openln.dev/api/v1"
    }
  }
}

Railway/Heroku (Backend)

Railway Environment Variables

# Set via Railway CLI
railway variables set NODE_ENV=production
railway variables set MONGODB_URI="mongodb+srv://..."
railway variables set JWT_SECRET="your-secret"
railway variables set GOOGLE_AI_API_KEY="your-key"

# Or via Railway dashboard

Heroku Environment Variables

# Set via Heroku CLI
heroku config:set NODE_ENV=production
heroku config:set MONGODB_URI="mongodb+srv://..."
heroku config:set JWT_SECRET="your-secret"
heroku config:set GOOGLE_AI_API_KEY="your-key"

# List all config vars
heroku config

AWS (Advanced Deployment)

Environment Variables in AWS

# Using AWS CLI
aws ssm put-parameter \
  --name "/openln/production/mongodb-uri" \
  --value "mongodb+srv://..." \
  --type "SecureString"

aws ssm put-parameter \
  --name "/openln/production/jwt-secret" \
  --value "your-secret" \
  --type "SecureString"

Docker Environment

# Dockerfile
FROM node:18-alpine

WORKDIR /app

# Copy package files
COPY package*.json ./
RUN npm ci --only=production

# Copy source code
COPY . .

# Expose port
EXPOSE 5000

# Start application
CMD ["npm", "start"]
# docker-compose.yml
version: '3.8'
services:
  app:
    build: .
    ports:
      - "5000:5000"
    environment:
      - NODE_ENV=${NODE_ENV:-production}
      - MONGODB_URI=${MONGODB_URI}
      - JWT_SECRET=${JWT_SECRET}
    env_file:
      - .env.production

πŸ”’ Security Best Practices

Environment Variable Security

  • Never commit .env files with sensitive data
  • Use different secrets for each environment
  • Rotate secrets regularly
  • Use a secrets management service for production
  • Validate required environment variables on startup

Example .gitignore

# Environment files
.env
.env.local
.env.*.local

# But allow example files
!.env.example
!.env.*.example

# Logs
logs/
*.log

# Dependencies
node_modules/

# Build outputs
dist/
build/

Environment Validation

// server/utils/validateEnv.js
import Joi from 'joi';

const envSchema = Joi.object({
  NODE_ENV: Joi.string().valid('development', 'staging', 'production').required(),
  PORT: Joi.number().default(5000),
  MONGODB_URI: Joi.string().uri().required(),
  JWT_SECRET: Joi.string().min(32).required(),
  GOOGLE_AI_API_KEY: Joi.string().required(),
}).unknown();

export const validateEnvironment = () => {
  const { error, value } = envSchema.validate(process.env);
  
  if (error) {
    throw new Error(`Environment validation error: ${error.message}`);
  }
  
  return value;
};

πŸ“‹ Environment Checklist

Development Setup

  • Node.js 18+ installed
  • MongoDB running locally
  • Environment files created
  • Dependencies installed
  • Services accessible

Staging Deployment

  • Staging environment configured
  • Environment variables set
  • Database connection tested
  • SSL certificates configured
  • Monitoring enabled

Production Deployment

  • Production secrets secured
  • Database backups configured
  • Monitoring and alerting set up
  • Error tracking enabled
  • Performance monitoring active
  • Security headers configured

Proper environment configuration ensures your application runs consistently across all stages of development and deployment. Always prioritize security when handling sensitive configuration data.