export default () => ({ nodeEnv: process.env.NODE_ENV || 'development', port: parseInt(process.env.PORT || '4000', 10), database: { host: process.env.DB_HOST || 'localhost', port: parseInt(process.env.DB_PORT || '5432', 10), username: process.env.DB_USERNAME || 'cloudhost', password: process.env.DB_PASSWORD || 'cloudhost_secret', name: process.env.DB_DATABASE || 'cloudhost', }, jwt: { secret: process.env.JWT_SECRET || 'default-jwt-secret', expiresIn: process.env.JWT_EXPIRES_IN || '1h', refreshSecret: process.env.JWT_REFRESH_SECRET || 'default-refresh-secret', refreshExpiresIn: process.env.JWT_REFRESH_EXPIRES_IN || '7d', }, redis: { host: process.env.REDIS_HOST || 'localhost', port: parseInt(process.env.REDIS_PORT || '6379', 10), }, registry: { url: process.env.REGISTRY_URL || 'registry.cloudhost-builds.svc.cluster.local:5000', pullUrl: process.env.REGISTRY_PULL_URL || process.env.REGISTRY_URL || 'localhost:30500', username: process.env.REGISTRY_USERNAME || 'admin', password: process.env.REGISTRY_PASSWORD || '', }, build: { namespace: process.env.BUILD_NAMESPACE || 'cloudhost-builds', serviceAccount: process.env.BUILD_SERVICE_ACCOUNT || 'kaniko-builder', }, elasticsearch: { /** API host for log search. Use cluster DNS in-cluster; 127.0.0.1 + port-forward when backend runs locally. */ host: process.env.ELASTICSEARCH_HOST || 'elasticsearch.logging.svc.cluster.local', port: parseInt(process.env.ELASTICSEARCH_PORT || '9200', 10), /** In development with loopback host, start kubectl port-forward on API boot (set false to manage manually). */ autoPortForward: process.env.ELASTICSEARCH_AUTO_PORT_FORWARD ?? 'true', password: process.env.ELASTIC_PASSWORD || 'CloudHost2024!Secure', fluentbitPassword: process.env.FLUENTBIT_PASSWORD || 'FluentBit2024!Writer', kibanaPassword: process.env.KIBANA_SYSTEM_PASSWORD || 'Kibana2024!System', /** Override when cluster nodes cannot reach docker.elastic.co (mirror to local registry). */ images: { elasticsearch: process.env.LOGGING_ELASTICSEARCH_IMAGE || 'docker.elastic.co/elasticsearch/elasticsearch:8.12.0', kibana: process.env.LOGGING_KIBANA_IMAGE || 'docker.elastic.co/kibana/kibana:8.12.0', }, }, platform: { domain: process.env.PLATFORM_DOMAIN || 'apps.cloudhost.local', uploadDir: process.env.UPLOAD_DIR || './uploads', /** StorageClass for new PVCs; must support allowVolumeExpansion for disk resize */ storageClass: process.env.PLATFORM_STORAGE_CLASS || 'cloudhost-expandable', /** Install cloudhost-expandable StorageClass via Helm on each app deploy */ createStorageClass: process.env.PLATFORM_CREATE_STORAGE_CLASS !== 'false', storageProvisioner: process.env.PLATFORM_STORAGE_PROVISIONER || 'rancher.io/local-path', }, // Lifecycle defaults (can be overridden via PlatformSettings entity by admin) lifecycle: { // How long after plan expires to suspend the app (scale to 0) hourly: { suspendAfterMs: parseInt(process.env.LIFECYCLE_HOURLY_SUSPEND_MS || String(0), 10), // immediately on expiry deleteAfterMs: parseInt(process.env.LIFECYCLE_HOURLY_DELETE_MS || String(24 * 3600 * 1000), 10), // 24h after suspend }, monthly: { suspendAfterMs: parseInt(process.env.LIFECYCLE_MONTHLY_SUSPEND_MS || String(0), 10), deleteAfterMs: parseInt(process.env.LIFECYCLE_MONTHLY_DELETE_MS || String(3 * 24 * 3600 * 1000), 10), // 3 days }, yearly: { suspendAfterMs: parseInt(process.env.LIFECYCLE_YEARLY_SUSPEND_MS || String(0), 10), deleteAfterMs: parseInt(process.env.LIFECYCLE_YEARLY_DELETE_MS || String(7 * 24 * 3600 * 1000), 10), // 7 days }, // Cron interval for the lifecycle scanner scanIntervalMs: parseInt(process.env.LIFECYCLE_SCAN_INTERVAL_MS || String(60_000), 10), // 1 min }, });