feat: improve unified config system and build process

- Enhance unified config environment variable loading with better precedence
- Add environment-aware validation (production validation only when NODE_ENV=production)
- Add environment-specific build commands (build:dev, build:prod, build:staging)
- Improve configuration debugging with cleaner logging
- Remove unnecessary development warnings
- Provides more flexible and maintainable configuration system
This commit is contained in:
William Valentin
2025-09-08 20:43:02 -07:00
parent 9132d78bfa
commit 25b68ee67d
2 changed files with 36 additions and 29 deletions

View File

@@ -512,14 +512,24 @@ const defaultConfig: UnifiedConfig = {
/**
* Get environment variable with fallback
* Reads from .env file via process.env or import.meta.env
*/
function getEnvVar(key: string, fallback: string = ''): string {
if (typeof process !== 'undefined' && process.env) {
return process.env[key] || fallback;
// First try process.env (Node.js, includes .env via dotenv or build process)
if (typeof process !== 'undefined' && process.env && process.env[key]) {
return process.env[key]!;
}
if (typeof import.meta !== 'undefined' && import.meta.env) {
return import.meta.env[key] || fallback;
// Then try import.meta.env (Vite/browser, includes .env via Vite's loadEnv)
if (
typeof import.meta !== 'undefined' &&
import.meta.env &&
import.meta.env[key]
) {
return import.meta.env[key];
}
// Use fallback if not found
return fallback;
}
@@ -543,7 +553,8 @@ function getNumberEnvVar(key: string, fallback: number = 0): number {
}
/**
* Load configuration from environment variables
* Load configuration from environment variables (.env file)
* This provides environment-specific overrides for the unified config
*/
function loadFromEnvironment(config: UnifiedConfig): UnifiedConfig {
return {
@@ -701,8 +712,9 @@ function validateConfig(config: UnifiedConfig): void {
const errors: string[] = [];
const warnings: string[] = [];
// Production-specific validations
if (config.app.environment === 'production') {
// Production-specific validations (only when NODE_ENV is explicitly production)
const isActualProduction = getEnvVar('NODE_ENV') === 'production';
if (config.app.environment === 'production' && isActualProduction) {
if (config.auth.jwtSecret === defaultConfig.auth.jwtSecret) {
errors.push('JWT_SECRET must be changed in production');
}
@@ -718,22 +730,6 @@ function validateConfig(config: UnifiedConfig): void {
}
}
// Development warnings for default secrets
if (config.app.environment === 'development') {
if (config.auth.jwtSecret === defaultConfig.auth.jwtSecret) {
warnings.push(
'Using default JWT_SECRET in development - change for production'
);
}
if (
config.security.sessionSecret === defaultConfig.security.sessionSecret
) {
warnings.push(
'Using default SESSION_SECRET in development - change for production'
);
}
}
// Email configuration validation
if (
config.features.enableEmailVerification &&
@@ -768,9 +764,10 @@ function validateConfig(config: UnifiedConfig): void {
/**
* Create unified configuration
* Uses .env file as primary source for environment-specific overrides
*/
export function createUnifiedConfig(): UnifiedConfig {
// Determine environment
// Determine environment from .env file or NODE_ENV
const nodeEnv = getEnvVar('NODE_ENV', 'development') as Environment;
const environment = ['development', 'staging', 'production', 'test'].includes(
nodeEnv
@@ -783,6 +780,7 @@ export function createUnifiedConfig(): UnifiedConfig {
/**
* Create unified configuration for specific environment
* Priority: .env file overrides > environment-specific config > defaults
*/
export function createUnifiedConfigForEnvironment(
environment: Environment
@@ -791,15 +789,15 @@ export function createUnifiedConfigForEnvironment(
let config = { ...defaultConfig };
config.app.environment = environment;
// Apply environment-specific overrides
// Apply environment-specific overrides (lower priority)
if (environmentConfigs[environment]) {
config = deepMerge(config, environmentConfigs[environment]);
}
// Apply environment variable overrides
// Apply .env file overrides (highest priority)
config = loadFromEnvironment(config);
// Compute derived values
// Compute derived values after all overrides
config.container.imageUrl = `${config.container.registry}/${config.container.repository}:${config.container.tag}`;
// Validate configuration
@@ -927,7 +925,7 @@ export function exportAsEnvVars(
*/
export function logConfig(): void {
if (unifiedConfig.features.debugMode) {
console.warn('🔧 Unified Configuration:', {
console.warn('🔧 Unified Configuration (Single Source of Truth):', {
environment: unifiedConfig.app.environment,
app: unifiedConfig.app.name,
version: unifiedConfig.app.version,
@@ -936,7 +934,13 @@ export function logConfig(): void {
url: unifiedConfig.database.url,
useMock: unifiedConfig.database.useMock,
},
container: {
registry: unifiedConfig.container.registry,
repository: unifiedConfig.container.repository,
imageUrl: unifiedConfig.container.imageUrl,
},
features: unifiedConfig.features,
configSource: '.env file overrides applied',
});
}
}