@restnfeel/agentc-starter-kit
Version:
한국어 기업용 CMS 모듈 - Task Master AI와 함께 빠르게 웹사이트를 구현할 수 있는 재사용 가능한 컴포넌트 시스템
820 lines (765 loc) • 20.8 kB
text/typescript
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();