// Centralized Application Configuration // This file consolidates all configuration constants and environment variables // to eliminate duplication and provide a single source of truth import { getEnvVar, isProduction, isTest } from '../utils/env'; // Simple console logging for configuration (avoid circular dependency with logger) const configLog = { warn: (message: string) => console.warn(`⚠️ Config: ${message}`), error: (message: string) => console.error(`❌ Config: ${message}`), info: (message: string) => console.warn(`📋 Config: ${message}`), }; /** * Application Configuration Interface */ export interface AppConfig { // Application Identity name: string; version: string; // URLs and Endpoints baseUrl: string; apiUrl: string; // Database Configuration database: { url: string; username: string; password: string; useMock: boolean; }; // Authentication Configuration auth: { jwtSecret: string; jwtExpiresIn: string; refreshTokenExpiresIn: string; emailVerificationExpiresIn: string; }; // Email Configuration email: { mailgun: { apiKey?: string; domain?: string; baseUrl: string; fromName: string; fromEmail?: string; }; }; // OAuth Configuration oauth: { google: { clientId?: string; }; github: { clientId?: string; }; }; // Feature Flags features: { enableEmailVerification: boolean; enableOAuth: boolean; enableAdminInterface: boolean; debugMode: boolean; }; // Environment Information environment: { nodeEnv: string; isProduction: boolean; isTest: boolean; isDevelopment: boolean; }; } /** * Default Configuration Values */ const DEFAULT_CONFIG: Partial = { name: 'RxMinder', version: '1.0.0', baseUrl: 'http://localhost:5173', apiUrl: 'http://localhost:3000/api', database: { url: 'http://localhost:5984', username: 'admin', password: 'password', useMock: false, }, auth: { jwtSecret: 'your-super-secret-jwt-key-change-in-production', jwtExpiresIn: '1h', refreshTokenExpiresIn: '7d', emailVerificationExpiresIn: '24h', }, email: { mailgun: { baseUrl: 'https://api.mailgun.net/v3', fromName: 'RxMinder', }, }, features: { enableEmailVerification: true, enableOAuth: true, enableAdminInterface: true, debugMode: false, }, }; /** * Load configuration from environment variables with fallbacks */ function loadConfig(): AppConfig { const nodeEnv = getEnvVar('NODE_ENV') || 'development'; const isProd = isProduction(); const isTestEnv = isTest(); const isDev = nodeEnv === 'development'; return { // Application Identity name: getEnvVar('VITE_APP_NAME') || getEnvVar('APP_NAME') || DEFAULT_CONFIG.name!, version: getEnvVar('VITE_APP_VERSION') || DEFAULT_CONFIG.version!, // URLs and Endpoints baseUrl: getEnvVar('APP_BASE_URL') || getEnvVar('VITE_BASE_URL') || DEFAULT_CONFIG.baseUrl!, apiUrl: getEnvVar('API_URL') || getEnvVar('VITE_API_URL') || DEFAULT_CONFIG.apiUrl!, // Database Configuration database: { url: getEnvVar('VITE_COUCHDB_URL') || getEnvVar('COUCHDB_URL') || DEFAULT_CONFIG.database!.url, username: getEnvVar('VITE_COUCHDB_USER') || getEnvVar('COUCHDB_USER') || DEFAULT_CONFIG.database!.username, password: getEnvVar('VITE_COUCHDB_PASSWORD') || getEnvVar('COUCHDB_PASSWORD') || DEFAULT_CONFIG.database!.password, useMock: isTestEnv || getEnvVar('USE_MOCK_DB') === 'true' || (!getEnvVar('VITE_COUCHDB_URL') && !getEnvVar('COUCHDB_URL')), }, // Authentication Configuration auth: { jwtSecret: getEnvVar('JWT_SECRET') || DEFAULT_CONFIG.auth!.jwtSecret, jwtExpiresIn: getEnvVar('JWT_EXPIRES_IN') || DEFAULT_CONFIG.auth!.jwtExpiresIn, refreshTokenExpiresIn: getEnvVar('REFRESH_TOKEN_EXPIRES_IN') || DEFAULT_CONFIG.auth!.refreshTokenExpiresIn, emailVerificationExpiresIn: getEnvVar('EMAIL_VERIFICATION_EXPIRES_IN') || DEFAULT_CONFIG.auth!.emailVerificationExpiresIn, }, // Email Configuration email: { mailgun: { apiKey: getEnvVar('VITE_MAILGUN_API_KEY') || getEnvVar('MAILGUN_API_KEY'), domain: getEnvVar('VITE_MAILGUN_DOMAIN') || getEnvVar('MAILGUN_DOMAIN'), baseUrl: getEnvVar('VITE_MAILGUN_BASE_URL') || getEnvVar('MAILGUN_BASE_URL') || DEFAULT_CONFIG.email!.mailgun!.baseUrl, fromName: getEnvVar('VITE_MAILGUN_FROM_NAME') || getEnvVar('MAILGUN_FROM_NAME') || DEFAULT_CONFIG.email!.mailgun!.fromName, fromEmail: getEnvVar('VITE_MAILGUN_FROM_EMAIL') || getEnvVar('MAILGUN_FROM_EMAIL'), }, }, // OAuth Configuration oauth: { google: { clientId: getEnvVar('VITE_GOOGLE_CLIENT_ID') || getEnvVar('GOOGLE_CLIENT_ID'), }, github: { clientId: getEnvVar('VITE_GITHUB_CLIENT_ID') || getEnvVar('GITHUB_CLIENT_ID'), }, }, // Feature Flags features: { enableEmailVerification: getEnvVar('ENABLE_EMAIL_VERIFICATION') !== 'false', enableOAuth: getEnvVar('ENABLE_OAUTH') !== 'false', enableAdminInterface: getEnvVar('ENABLE_ADMIN_INTERFACE') !== 'false', debugMode: isDev || getEnvVar('DEBUG_MODE') === 'true', }, // Environment Information environment: { nodeEnv, isProduction: isProd, isTest: isTestEnv, isDevelopment: isDev, }, }; } /** * Validate configuration and warn about missing values */ function validateConfig(config: AppConfig): void { const warnings: string[] = []; const errors: string[] = []; // Check critical configuration if (config.environment.isProduction) { if (config.auth.jwtSecret === DEFAULT_CONFIG.auth!.jwtSecret) { errors.push('JWT_SECRET must be changed in production'); } if (config.database.password === DEFAULT_CONFIG.database!.password) { warnings.push( 'Consider changing default database password in production' ); } } // Check email configuration if email verification is enabled if (config.features.enableEmailVerification) { if (!config.email.mailgun.apiKey) { warnings.push( 'MAILGUN_API_KEY not configured - email features will use console logging' ); } if (!config.email.mailgun.domain) { warnings.push( 'MAILGUN_DOMAIN not configured - email features may not work properly' ); } } // Check OAuth configuration if OAuth is enabled if (config.features.enableOAuth) { if (!config.oauth.google.clientId && !config.oauth.github.clientId) { warnings.push( 'No OAuth client IDs configured - OAuth features will be disabled' ); } } // Log warnings and errors if (warnings.length > 0) { configLog.warn('Configuration warnings:'); warnings.forEach(warning => configLog.warn(` - ${warning}`)); } if (errors.length > 0) { configLog.error('Configuration errors:'); errors.forEach(error => configLog.error(` - ${error}`)); throw new Error('Critical configuration errors detected'); } } /** * Load and validate application configuration */ export function createAppConfig(): AppConfig { const config = loadConfig(); // Only validate in non-test environments to avoid test noise if (!config.environment.isTest) { validateConfig(config); } return config; } /** * Singleton application configuration instance */ export const appConfig = createAppConfig(); /** * Utility functions for common configuration access patterns */ export const CONFIG = { // Application APP_NAME: appConfig.name, APP_VERSION: appConfig.version, BASE_URL: appConfig.baseUrl, // Database DATABASE_URL: appConfig.database.url, USE_MOCK_DB: appConfig.database.useMock, // Environment IS_PRODUCTION: appConfig.environment.isProduction, IS_DEVELOPMENT: appConfig.environment.isDevelopment, IS_TEST: appConfig.environment.isTest, DEBUG_MODE: appConfig.features.debugMode, // Features FEATURES: appConfig.features, } as const; /** * Get configuration for specific modules */ export const getAuthConfig = () => appConfig.auth; export const getDatabaseConfig = () => appConfig.database; export const getEmailConfig = () => appConfig.email; export const getOAuthConfig = () => appConfig.oauth; /** * Development helper to log current configuration */ export function logConfig(): void { if (appConfig.features.debugMode) { configLog.info('Application Configuration'); configLog.info(`Environment: ${appConfig.environment.nodeEnv}`); configLog.info(`App Name: ${appConfig.name}`); configLog.info(`Base URL: ${appConfig.baseUrl}`); configLog.info( `Database Strategy: ${appConfig.database.useMock ? 'Mock' : 'Production'}` ); configLog.info(`Features: ${JSON.stringify(appConfig.features)}`); } } // Auto-log configuration in development if (appConfig.features.debugMode && typeof window !== 'undefined') { logConfig(); }