Configuration

Learn how to configure your Strav application for different environments and customize its behavior.

Configuration Files

Strav uses a centralized configuration system. All configuration files are stored in the config/ directory:

config/
├── app.ts         # Application settings
├── database.ts    # Database connections
├── cache.ts       # Cache stores
├── mail.ts        # Mail drivers
├── queue.ts       # Queue connections
├── storage.ts     # File storage
├── session.ts     # Session configuration
├── auth.ts        # Authentication settings
└── services.ts    # Third-party services

Environment Variables

Strav uses environment variables for sensitive data and environment-specific settings. The .env file in your project root contains these variables.

Loading Environment Variables

Environment variables are loaded automatically when the application starts. Use the env() helper in config files:

import { env } from '@strav/kernel'

export default {
  name: env('APP_NAME', 'My App'),           // With default value
  debug: env.bool('APP_DEBUG', false),       // Boolean casting
  port: env.int('APP_PORT', 3000),          // Integer casting
  rate: env.float('RATE_LIMIT', 0.5),       // Float casting
  // For arrays, use config helpers or parse manually:
  features: env('FEATURES', '').split(',').filter(Boolean),
  // For required values, throw manually if needed:
  apiKey: env('API_KEY') || (() => { throw new Error('API_KEY required') })()
}

Environment File Priority

Strav loads environment files in this order (later files override earlier ones):

  1. .env - Default values
  2. .env.local - Local overrides (gitignored)
  3. .env.[environment] - Environment-specific (e.g., .env.production)
  4. .env.[environment].local - Local environment overrides (gitignored)

Application Configuration

config/app.ts

import { env } from '@strav/kernel'

export default {
  // Application name
  name: env('APP_NAME', 'Strav Application'),

  // Environment (local, development, staging, production)
  env: env('APP_ENV', 'production'),

  // Debug mode
  debug: env.bool('APP_DEBUG', false),

  // Application URL
  url: env('APP_URL', 'http://localhost:3000'),

  // Server port
  port: env.int('APP_PORT', 3000),

  // Encryption key for cookies and sessions
  key: env('APP_KEY'),

  // Timezone
  timezone: 'UTC',

  // Locale
  locale: 'en',

  // Available locales
  locales: ['en', 'es', 'fr', 'de'],

  // Logging
  log: {
    level: env('LOG_LEVEL', 'info'),
    channels: ['file', 'console'],
  },
}

Database Configuration

config/database.ts

import { env } from '@strav/kernel'

export default {
  // Default connection
  default: env('DB_CONNECTION', 'postgres'),

  // Connection configurations
  connections: {
    postgres: {
      driver: 'postgres',
      host: env('DB_HOST', '127.0.0.1'),
      port: env.int('DB_PORT', 5432),
      database: env('DB_DATABASE', 'strav'),
      username: env('DB_USER', 'postgres'),
      password: env('DB_PASSWORD', ''),

      // Connection pool settings
      pool: {
        min: env.int('DB_POOL_MIN', 2),
        max: env.int('DB_POOL_MAX', 10),
      },

      // SSL configuration
      ssl: env.bool('DB_SSL', false) ? {
        rejectUnauthorized: false,
        ca: env('DB_SSL_CA'),
      } : false,
    },

    // Read replica configuration
    read: {
      driver: 'postgres',
      host: env('DB_READ_HOST', '127.0.0.1'),
      port: env.int('DB_READ_PORT', 5432),
      database: env('DB_DATABASE', 'strav'),
      username: env('DB_READ_USER', 'postgres'),
      password: env('DB_READ_PASSWORD', ''),
    },
  },

  // Migration settings
  migrations: {
    table: '_strav_migrations',
    directory: './database/migrations',
  },
}

Cache Configuration

config/cache.ts

import { env } from '@strav/kernel'

export default {
  // Default cache store
  default: env('CACHE_DRIVER', 'memory'),

  // Cache stores
  stores: {
    memory: {
      driver: 'memory',
      max: 100,  // Maximum items
      ttl: 3600, // Default TTL in seconds
    },

    redis: {
      driver: 'redis',
      connection: 'cache',
    },

    database: {
      driver: 'database',
      table: 'cache',
      connection: 'postgres',
    },

    file: {
      driver: 'file',
      path: './storage/cache',
    },
  },

  // Cache key prefix
  prefix: env('CACHE_PREFIX', 'strav_cache_'),
}

Session Configuration

config/session.ts

import { env } from '@strav/kernel'

export default {
  // Session driver (cookie, database, redis, memory)
  driver: env('SESSION_DRIVER', 'cookie'),

  // Session cookie name
  name: 'strav_session',

  // Session lifetime in seconds
  lifetime: env.int('SESSION_LIFETIME', 7200), // 2 hours

  // Expire on browser close
  expire_on_close: false,

  // Encrypt session data
  encrypt: true,

  // Session cookie path
  path: '/',

  // Session cookie domain
  domain: env('SESSION_DOMAIN'),

  // HTTPS only cookies
  secure: env('APP_ENV') === 'production',

  // HTTP only (no JavaScript access)
  httpOnly: true,

  // Same-site cookie attribute
  sameSite: 'lax',

  // Database table (when using database driver)
  table: 'sessions',

  // Redis connection (when using redis driver)
  connection: 'session',
}

Mail Configuration

config/mail.ts

import { env } from '@strav/kernel'

export default {
  // Default mailer
  default: env('MAIL_DRIVER', 'smtp'),

  // Mailer configurations
  mailers: {
    smtp: {
      transport: 'smtp',
      host: env('MAIL_HOST', 'smtp.mailgun.org'),
      port: env.int('MAIL_PORT', 587),
      encryption: env('MAIL_ENCRYPTION', 'tls'),
      username: env('MAIL_USERNAME'),
      password: env('MAIL_PASSWORD'),
    },

    sendmail: {
      transport: 'sendmail',
      path: '/usr/sbin/sendmail -bs',
    },

    log: {
      transport: 'log',
      channel: 'mail',
    },

    array: {
      transport: 'array',
    },
  },

  // Global "from" address
  from: {
    address: env('MAIL_FROM_ADDRESS', 'hello@example.com'),
    name: env('MAIL_FROM_NAME', 'Example'),
  },

  // Markdown mail settings
  markdown: {
    theme: 'default',
    paths: ['./resources/views/emails'],
  },
}

Storage Configuration

config/storage.ts

import { env } from '@strav/kernel'

export default {
  // Default disk
  default: env('STORAGE_DISK', 'local'),

  // Storage disks
  disks: {
    local: {
      driver: 'local',
      root: './storage/app',
      url: '/storage',
      visibility: 'private',
    },

    public: {
      driver: 'local',
      root: './storage/app/public',
      url: '/storage',
      visibility: 'public',
    },

    s3: {
      driver: 's3',
      key: env('AWS_ACCESS_KEY_ID'),
      secret: env('AWS_SECRET_ACCESS_KEY'),
      region: env('AWS_DEFAULT_REGION', 'us-east-1'),
      bucket: env('AWS_BUCKET'),
      url: env('AWS_URL'),
      endpoint: env('AWS_ENDPOINT'),
    },

    temp: {
      driver: 'local',
      root: './storage/temp',
      visibility: 'private',
      // Auto-delete files older than 24 hours
      cleanup: true,
      cleanupAge: 86400,
    },
  },

  // File upload settings
  uploads: {
    maxSize: '10MB',
    allowedTypes: ['image/jpeg', 'image/png', 'application/pdf'],
    directory: 'uploads',
  },
}

Custom Configuration Files

You can create custom configuration files for your application:

config/payment.ts

import { env } from '@strav/kernel'

export default {
  stripe: {
    key: env('STRIPE_KEY'),
    secret: env('STRIPE_SECRET'),
    webhook: env('STRIPE_WEBHOOK_SECRET'),
    currency: 'usd',
  },

  paypal: {
    client: env('PAYPAL_CLIENT_ID'),
    secret: env('PAYPAL_SECRET'),
    mode: env('PAYPAL_MODE', 'sandbox'),
  },
}

Accessing Configuration

Use the Configuration service to access config values:

import { config } from '@strav/kernel'

// Get a config value
const appName = config.get('app.name')
const dbHost = config.get('database.connections.postgres.host')

// Get with default value
const timeout = config.get('app.timeout', 30)

// Get entire config file
const mailConfig = config.get('mail')

// Check if config exists
if (config.has('services.stripe')) {
  // Stripe is configured
}

// Set config at runtime (not persisted)
config.set('app.maintenance', true)

Environment-Specific Configuration

Load different configurations based on environment:

import { env } from '@strav/kernel'

const environment = env('APP_ENV', 'production')

export default {
  features: {
    registration: environment !== 'production',
    api: ['production', 'staging'].includes(environment),
    debug_toolbar: environment === 'local',
  },

  services: environment === 'production' ? {
    cdn: 'https://cdn.example.com',
    analytics: true,
  } : {
    cdn: '',
    analytics: false,
  },
}

Security Best Practices

  • Never commit .env files with sensitive data to version control
  • Use .env.example as a template with dummy values
  • Rotate APP_KEY periodically
  • Use different database credentials for different environments
  • Enable SSL/TLS for production databases
  • Use secrets management services in production (AWS Secrets Manager, HashiCorp Vault)

Configuration Validation

Validate your configuration at startup:

// app/providers/config_validator.ts
import { ServiceProvider, ConfigurationException } from '@strav/kernel'

export class ConfigValidatorProvider extends ServiceProvider {
  name = 'config-validator'

  boot(app) {
    const config = app.resolve(Configuration)

    // Validate required configurations
    const required = [
      'app.key',
      'database.connections.postgres.host',
      'mail.from.address',
    ]

    for (const key of required) {
      if (!config.has(key) || !config.get(key)) {
        throw new ConfigurationException(`Missing required config: ${key}`)
      }
    }

    // Validate config values
    const port = config.get('app.port')
    if (port < 1 || port > 65535) {
      throw new ConfigurationException('Invalid port number')
    }
  }
}