UNPKG

@restnfeel/agentc-starter-kit

Version:

한국어 기업용 CMS 모듈 - Task Master AI와 함께 빠르게 웹사이트를 구현할 수 있는 재사용 가능한 컴포넌트 시스템

820 lines (765 loc) 20.8 kB
import { EnvironmentConfig, EnvironmentType, SSLConfig, CDNConfig, DatabaseConfig, MonitoringConfig, } from "./types"; /** * Environment Configuration Manager * Handles configuration for different deployment environments */ export class EnvironmentConfigManager { private configs: Map<string, EnvironmentConfig> = new Map(); private templates: Map<string, Partial<EnvironmentConfig>> = new Map(); constructor() { this.loadDefaultTemplates(); } /** * Load default environment templates */ private loadDefaultTemplates(): void { // Development environment template this.templates.set("development", { type: "development", provider: "docker", region: "local", instances: [ { id: "dev-instance-1", name: "Development Instance", type: "development", count: 1, cpu: 1, memory: 2, storage: { type: "gp2", size: 20, encrypted: false, backupRetention: 1, }, subnet: "dev-subnet", securityGroups: ["dev-sg"], tags: { Environment: "development", Project: "AgentC", }, }, ], variables: { NODE_ENV: "development", LOG_LEVEL: "debug", API_TIMEOUT: "5000", CACHE_TTL: "300", }, secrets: { DATABASE_URL: "postgresql://dev:dev@localhost:5432/agentc_dev", JWT_SECRET: "dev-jwt-secret", API_KEY: "dev-api-key", }, features: [ { id: "debug-mode", name: "Debug Mode", enabled: true, }, { id: "hot-reload", name: "Hot Reload", enabled: true, }, ], deploymentStrategy: "immediate", autoScale: { enabled: false, minInstances: 1, maxInstances: 1, cpuThreshold: 80, memoryThreshold: 80, requestThreshold: 100, scaleUpCooldown: 300, scaleDownCooldown: 300, }, healthCheck: { enabled: true, path: "/health", protocol: "http", port: 3000, interval: 30, timeout: 5, healthyThreshold: 2, unhealthyThreshold: 3, expectedStatus: 200, }, protected: false, }); // Testing environment template this.templates.set("testing", { type: "testing", provider: "docker", region: "us-east-1", instances: [ { id: "test-instance-1", name: "Testing Instance", type: "t3.small", count: 1, cpu: 1, memory: 2, storage: { type: "gp3", size: 30, encrypted: true, backupRetention: 3, }, subnet: "test-subnet", securityGroups: ["test-sg"], tags: { Environment: "testing", Project: "AgentC", }, }, ], variables: { NODE_ENV: "test", LOG_LEVEL: "info", API_TIMEOUT: "10000", CACHE_TTL: "600", }, secrets: { DATABASE_URL: "postgresql://test:test@test-db:5432/agentc_test", JWT_SECRET: "test-jwt-secret", API_KEY: "test-api-key", }, features: [ { id: "test-data", name: "Test Data", enabled: true, }, { id: "performance-monitoring", name: "Performance Monitoring", enabled: true, }, ], deploymentStrategy: "blue_green", autoScale: { enabled: false, minInstances: 1, maxInstances: 2, cpuThreshold: 70, memoryThreshold: 70, requestThreshold: 200, scaleUpCooldown: 300, scaleDownCooldown: 600, }, healthCheck: { enabled: true, path: "/health", protocol: "https", port: 443, interval: 30, timeout: 10, healthyThreshold: 2, unhealthyThreshold: 2, expectedStatus: 200, }, protected: false, }); // Staging environment template this.templates.set("staging", { type: "staging", provider: "aws", region: "us-east-1", instances: [ { id: "staging-instance-1", name: "Staging Instance", type: "t3.medium", count: 1, cpu: 2, memory: 4, storage: { type: "gp3", size: 50, encrypted: true, backupRetention: 7, }, subnet: "staging-subnet", securityGroups: ["staging-sg"], tags: { Environment: "staging", Project: "AgentC", }, }, ], variables: { NODE_ENV: "staging", LOG_LEVEL: "info", API_TIMEOUT: "15000", CACHE_TTL: "1800", }, secrets: { DATABASE_URL: "postgresql://staging:staging@staging-db:5432/agentc_staging", JWT_SECRET: "staging-jwt-secret", API_KEY: "staging-api-key", }, features: [ { id: "analytics", name: "Analytics", enabled: true, }, { id: "rate-limiting", name: "Rate Limiting", enabled: true, }, ], deploymentStrategy: "blue_green", autoScale: { enabled: true, minInstances: 1, maxInstances: 3, cpuThreshold: 70, memoryThreshold: 70, requestThreshold: 500, scaleUpCooldown: 300, scaleDownCooldown: 600, }, healthCheck: { enabled: true, path: "/health", protocol: "https", port: 443, interval: 15, timeout: 10, healthyThreshold: 2, unhealthyThreshold: 2, expectedStatus: 200, }, protected: true, }); // Production environment template this.templates.set("production", { type: "production", provider: "aws", region: "us-east-1", instances: [ { id: "prod-instance-1", name: "Production Instance", type: "t3.large", count: 2, cpu: 2, memory: 8, storage: { type: "gp3", size: 100, encrypted: true, backupRetention: 30, }, subnet: "prod-subnet", securityGroups: ["prod-sg"], tags: { Environment: "production", Project: "AgentC", }, }, ], variables: { NODE_ENV: "production", LOG_LEVEL: "warn", API_TIMEOUT: "30000", CACHE_TTL: "3600", }, secrets: { DATABASE_URL: "postgresql://prod:prod@prod-db:5432/agentc_prod", JWT_SECRET: "prod-jwt-secret", API_KEY: "prod-api-key", }, features: [ { id: "analytics", name: "Analytics", enabled: true, }, { id: "rate-limiting", name: "Rate Limiting", enabled: true, }, { id: "security-monitoring", name: "Security Monitoring", enabled: true, }, ], deploymentStrategy: "blue_green", autoScale: { enabled: true, minInstances: 2, maxInstances: 10, cpuThreshold: 60, memoryThreshold: 60, requestThreshold: 1000, scaleUpCooldown: 300, scaleDownCooldown: 900, }, healthCheck: { enabled: true, path: "/health", protocol: "https", port: 443, interval: 10, timeout: 5, healthyThreshold: 2, unhealthyThreshold: 2, expectedStatus: 200, }, protected: true, }); } /** * Get environment configuration by ID */ getEnvironment(id: string): EnvironmentConfig | undefined { return this.configs.get(id); } /** * Get all environment configurations */ getAllEnvironments(): EnvironmentConfig[] { return Array.from(this.configs.values()); } /** * Get environments by type */ getEnvironmentsByType(type: EnvironmentType): EnvironmentConfig[] { return Array.from(this.configs.values()).filter( (config) => config.type === type ); } /** * Create environment from template */ createFromTemplate( templateName: string, overrides: Partial<EnvironmentConfig> ): EnvironmentConfig { const template = this.templates.get(templateName); if (!template) { throw new Error(`Template ${templateName} not found`); } if (!template.type) { throw new Error(`Template ${templateName} missing required type`); } const config: EnvironmentConfig = { id: this.generateId(), name: overrides.name || `${ templateName.charAt(0).toUpperCase() + templateName.slice(1) } Environment`, type: template.type, description: overrides.description || `${templateName} environment for AgentC`, provider: template.provider || "docker", region: template.region || "local", instances: template.instances || [], variables: template.variables || {}, secrets: template.secrets || {}, features: template.features || [], domain: overrides.domain || this.generateDomain(templateName), subdomains: overrides.subdomains || [], ssl: overrides.ssl || this.getDefaultSSLConfig(), cdn: overrides.cdn || this.getDefaultCDNConfig(), database: overrides.database || this.getDefaultDatabaseConfig(templateName), monitoring: overrides.monitoring || this.getDefaultMonitoringConfig(templateName), deploymentStrategy: template.deploymentStrategy || "immediate", autoScale: template.autoScale || { enabled: false, minInstances: 1, maxInstances: 1, cpuThreshold: 80, memoryThreshold: 80, requestThreshold: 100, scaleUpCooldown: 300, scaleDownCooldown: 300, }, healthCheck: template.healthCheck || { enabled: true, path: "/health", protocol: "http", port: 3000, interval: 30, timeout: 5, healthyThreshold: 2, unhealthyThreshold: 3, expectedStatus: 200, }, active: true, protected: template.protected || false, createdBy: "system", createdAt: new Date(), updatedAt: new Date(), ...overrides, }; this.configs.set(config.id, config); return config; } /** * Update environment configuration */ updateEnvironment( id: string, updates: Partial<EnvironmentConfig> ): EnvironmentConfig { const config = this.configs.get(id); if (!config) { throw new Error(`Environment ${id} not found`); } const updatedConfig: EnvironmentConfig = { ...config, ...updates, updatedAt: new Date(), }; this.configs.set(id, updatedConfig); return updatedConfig; } /** * Delete environment configuration */ deleteEnvironment(id: string): boolean { const config = this.configs.get(id); if (!config) { return false; } if (config.protected) { throw new Error(`Cannot delete protected environment ${id}`); } return this.configs.delete(id); } /** * Validate environment configuration */ validateEnvironment(config: EnvironmentConfig): string[] { const errors: string[] = []; // Basic validation if (!config.name || config.name.trim().length === 0) { errors.push("Environment name is required"); } if (!config.domain || config.domain.trim().length === 0) { errors.push("Domain is required"); } // Instance validation if (!config.instances || config.instances.length === 0) { errors.push("At least one instance is required"); } config.instances?.forEach((instance, index) => { if (instance.count < 1) { errors.push(`Instance ${index + 1}: count must be at least 1`); } if (instance.cpu < 0.5) { errors.push(`Instance ${index + 1}: CPU must be at least 0.5`); } if (instance.memory < 1) { errors.push(`Instance ${index + 1}: memory must be at least 1GB`); } }); // Auto-scale validation if (config.autoScale.enabled) { if (config.autoScale.minInstances > config.autoScale.maxInstances) { errors.push("Auto-scale min instances cannot exceed max instances"); } if ( config.autoScale.cpuThreshold < 10 || config.autoScale.cpuThreshold > 100 ) { errors.push("Auto-scale CPU threshold must be between 10-100%"); } } // Health check validation if (config.healthCheck.enabled) { if ( !config.healthCheck.path || !config.healthCheck.path.startsWith("/") ) { errors.push("Health check path must start with '/'"); } if (config.healthCheck.port < 1 || config.healthCheck.port > 65535) { errors.push("Health check port must be between 1-65535"); } } return errors; } /** * Clone environment configuration */ cloneEnvironment( sourceId: string, targetName: string, targetType?: EnvironmentType ): EnvironmentConfig { const sourceConfig = this.configs.get(sourceId); if (!sourceConfig) { throw new Error(`Source environment ${sourceId} not found`); } const clonedConfig: EnvironmentConfig = { ...JSON.parse(JSON.stringify(sourceConfig)), // Deep clone id: this.generateId(), name: targetName, type: targetType || sourceConfig.type, domain: this.generateDomain(targetName), createdAt: new Date(), updatedAt: new Date(), lastDeployment: undefined, }; this.configs.set(clonedConfig.id, clonedConfig); return clonedConfig; } /** * Get environment health status */ getEnvironmentHealth(id: string): { status: "healthy" | "degraded" | "unhealthy"; issues: string[]; } { const config = this.configs.get(id); if (!config) { return { status: "unhealthy", issues: ["Environment not found"] }; } const issues: string[] = []; // Check if environment is active if (!config.active) { issues.push("Environment is inactive"); } // Check instance health (mock implementation) config.instances.forEach((instance, index) => { if (instance.count === 0) { issues.push(`Instance ${index + 1} has no running instances`); } }); // Check health check configuration if (!config.healthCheck.enabled) { issues.push("Health checks are disabled"); } // Determine overall status let status: "healthy" | "degraded" | "unhealthy"; if (issues.length === 0) { status = "healthy"; } else if (issues.length <= 2) { status = "degraded"; } else { status = "unhealthy"; } return { status, issues }; } /** * Generate environment ID */ private generateId(): string { return `env_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } /** * Generate domain for environment */ private generateDomain(name: string): string { const sanitized = name.toLowerCase().replace(/[^a-z0-9]/g, "-"); return `${sanitized}.agentc.dev`; } /** * Get default SSL configuration */ private getDefaultSSLConfig(): SSLConfig { return { enabled: true, certificateProvider: "letsencrypt", autoRenewal: true, }; } /** * Get default CDN configuration */ private getDefaultCDNConfig(): CDNConfig { return { enabled: true, provider: "cloudflare", cacheRules: [ { path: "/static/*", ttl: 86400, cacheHeaders: ["Cache-Control", "ETag"], }, { path: "/api/*", ttl: 300, cacheHeaders: ["Cache-Control"], }, ], origins: [ { id: "primary", url: "https://api.agentc.dev", weight: 100, healthCheck: true, }, ], }; } /** * Get default database configuration */ private getDefaultDatabaseConfig(environment: string): DatabaseConfig { return { provider: "postgresql", host: `${environment}-db.agentc.dev`, port: 5432, database: `agentc_${environment}`, username: "agentc", password: "encrypted_password", minConnections: 5, maxConnections: 20, backupSchedule: "0 2 * * *", // Daily at 2 AM backupRetention: environment === "production" ? 30 : 7, replication: environment === "production", readReplicas: environment === "production" ? 1 : 0, }; } /** * Get default monitoring configuration */ private getDefaultMonitoringConfig(environment: string): MonitoringConfig { return { enabled: true, provider: "prometheus", customMetrics: [ { name: "request_duration", type: "histogram", description: "Request duration in milliseconds", labels: ["method", "route", "status"], }, { name: "active_connections", type: "gauge", description: "Number of active connections", labels: ["type"], }, ], alerts: [ { id: "high_cpu", name: "High CPU Usage", condition: "cpu_usage > 80", threshold: 80, severity: "medium", channels: [ { type: "email", target: "alerts@agentc.dev", enabled: true, }, ], enabled: true, cooldown: 15, }, { id: "high_error_rate", name: "High Error Rate", condition: "error_rate > 5", threshold: 5, severity: "high", channels: [ { type: "slack", target: "#alerts", enabled: true, }, ], enabled: true, cooldown: 5, }, ], logging: { level: environment === "production" ? "warn" : "info", retention: environment === "production" ? 30 : 7, structured: true, aggregation: environment !== "development", aggregationProvider: environment !== "development" ? "elasticsearch" : undefined, }, apm: { enabled: environment !== "development", provider: "datadog", tracing: true, profiling: environment === "production", }, }; } /** * Export environment configuration as YAML */ exportAsYAML(id: string): string { const config = this.configs.get(id); if (!config) { throw new Error(`Environment ${id} not found`); } // Simple YAML export (in production, use a proper YAML library) return JSON.stringify(config, null, 2); } /** * Import environment configuration from YAML */ importFromYAML(yaml: string): EnvironmentConfig { try { const config = JSON.parse(yaml) as EnvironmentConfig; // Validate imported config const errors = this.validateEnvironment(config); if (errors.length > 0) { throw new Error(`Validation errors: ${errors.join(", ")}`); } // Assign new ID and update timestamps config.id = this.generateId(); config.createdAt = new Date(); config.updatedAt = new Date(); this.configs.set(config.id, config); return config; } catch (error) { throw new Error( `Failed to import configuration: ${ error instanceof Error ? error.message : "Unknown error" }` ); } } /** * Get configuration template names */ getTemplateNames(): string[] { return Array.from(this.templates.keys()); } /** * Create all default environments */ createDefaultEnvironments(): EnvironmentConfig[] { const environments: EnvironmentConfig[] = []; for (const templateName of this.getTemplateNames()) { const config = this.createFromTemplate(templateName, { name: `${ templateName.charAt(0).toUpperCase() + templateName.slice(1) } Environment`, description: `Default ${templateName} environment for AgentC Starter Kit`, }); environments.push(config); } return environments; } } // Export singleton instance export const environmentConfig = new EnvironmentConfigManager();