UNPKG

supa-seed

Version:

A constraint-aware, framework-agnostic database seeding framework with deep PostgreSQL business logic discovery and MakerKit integration support

1,099 lines (1,098 loc) 55.6 kB
"use strict"; /** * Configuration Validation and Migration System for SupaSeed v2.5.0 * Implements Task 5.3.2: Validation and migration utilities for configuration upgrades * Enhanced from Epic 7 system with advanced layered configuration support */ Object.defineProperty(exports, "__esModule", { value: true }); exports.ConfigValidator = void 0; const schema_adapter_1 = require("../schema-adapter"); const framework_adapter_1 = require("../../features/integration/framework-adapter"); const logger_1 = require("../utils/logger"); class ConfigValidator { constructor(client) { this.client = client; this.schemaAdapter = new schema_adapter_1.SchemaAdapter(client); this.frameworkAdapter = new framework_adapter_1.FrameworkAdapter(client); } /** * Comprehensive configuration validation */ async validateConfiguration(config) { logger_1.Logger.info('🔍 Starting comprehensive configuration validation...'); const errors = []; const warnings = []; const recommendations = []; try { // 1. Basic configuration validation const basicValidation = this.validateBasicConfiguration(config); errors.push(...basicValidation.errors); warnings.push(...basicValidation.warnings); // 2. Framework strategy validation const frameworkValidation = await this.validateFrameworkStrategy(config); errors.push(...frameworkValidation.errors); warnings.push(...frameworkValidation.warnings); // 3. Constraint handler validation const constraintValidation = await this.validateConstraintHandlers(config); errors.push(...constraintValidation.errors); warnings.push(...constraintValidation.warnings); // 4. Schema evolution validation const schemaValidation = this.validateSchemaEvolution(config); errors.push(...schemaValidation.errors); warnings.push(...schemaValidation.warnings); // 5. Data volume validation const volumeValidation = this.validateDataVolumes(config); errors.push(...volumeValidation.errors); warnings.push(...volumeValidation.warnings); // 6. Custom relationships validation const relationshipValidation = await this.validateCustomRelationships(config); errors.push(...relationshipValidation.errors); warnings.push(...relationshipValidation.warnings); // Calculate validation score const totalChecks = 50; // Approximate number of validation checks const failedChecks = errors.length + (warnings.length * 0.5); const score = Math.max(0, (totalChecks - failedChecks) / totalChecks); // Generate recommendations recommendations.push(...this.generateRecommendations(config, errors, warnings)); logger_1.Logger.info(`✅ Configuration validation completed with score: ${(score * 100).toFixed(1)}%`); return { valid: errors.length === 0, errors, warnings, recommendations, score }; } catch (error) { logger_1.Logger.error('Configuration validation failed:', error); return { valid: false, errors: [`Validation process failed: ${error.message}`], warnings: [], recommendations: ['Fix validation errors and retry'], score: 0 }; } } /** * Validate basic configuration structure and required fields */ validateBasicConfiguration(config) { const errors = []; const warnings = []; // Required fields validation if (!config.supabaseUrl) { errors.push('supabaseUrl is required'); } else if (!config.supabaseUrl.startsWith('http')) { warnings.push('supabaseUrl should be a valid HTTP/HTTPS URL'); } if (!config.supabaseServiceKey) { errors.push('supabaseServiceKey is required'); } else if (config.supabaseServiceKey.length < 50) { warnings.push('supabaseServiceKey appears to be too short - ensure it\'s the service role key'); } if (!config.environment || !['local', 'staging', 'production'].includes(config.environment)) { errors.push('environment must be one of: local, staging, production'); } // Numeric validation if (!config.userCount || config.userCount <= 0) { errors.push('userCount must be greater than 0'); } else if (config.userCount > 1000 && config.environment === 'local') { warnings.push('userCount is very high for local environment - consider reducing for faster seeding'); } if (!config.setupsPerUser || config.setupsPerUser <= 0) { errors.push('setupsPerUser must be greater than 0'); } if (!config.imagesPerSetup || config.imagesPerSetup < 0) { errors.push('imagesPerSetup must be 0 or greater'); } // Schema configuration validation if (!config.schema) { errors.push('schema configuration is required'); } else { if (!config.schema.userTable) { errors.push('schema.userTable configuration is required'); } else { if (!config.schema.userTable.name) errors.push('schema.userTable.name is required'); if (!config.schema.userTable.idField) errors.push('schema.userTable.idField is required'); if (!config.schema.userTable.emailField) errors.push('schema.userTable.emailField is required'); if (!config.schema.userTable.nameField) errors.push('schema.userTable.nameField is required'); } if (!config.schema.setupTable) { errors.push('schema.setupTable configuration is required'); } else { if (!config.schema.setupTable.name) errors.push('schema.setupTable.name is required'); if (!config.schema.setupTable.userField) errors.push('schema.setupTable.userField is required'); if (!config.schema.setupTable.titleField) errors.push('schema.setupTable.titleField is required'); if (!config.schema.setupTable.descriptionField) errors.push('schema.setupTable.descriptionField is required'); } } return { valid: errors.length === 0, errors, warnings, recommendations: [], score: 0 }; } /** * Validate framework strategy configuration */ async validateFrameworkStrategy(config) { const errors = []; const warnings = []; if (!config.frameworkStrategy?.enabled) { return { valid: true, errors, warnings, recommendations: [], score: 1 }; } try { // Initialize framework adapter for validation await this.frameworkAdapter.initialize(); const availableStrategies = this.frameworkAdapter.getAvailableStrategies(); // Validate manual override if (config.frameworkStrategy.manualOverride) { if (!availableStrategies.includes(config.frameworkStrategy.manualOverride)) { errors.push(`Invalid framework override: ${config.frameworkStrategy.manualOverride}. Available: ${availableStrategies.join(', ')}`); } } // Validate custom strategies if (config.frameworkStrategy.customStrategies) { for (const strategy of config.frameworkStrategy.customStrategies) { if (!strategy.name) { errors.push('Custom strategy name is required'); } if (typeof strategy.priority !== 'number' || strategy.priority < 0) { errors.push(`Invalid priority for custom strategy '${strategy.name}' - must be a non-negative number`); } if (strategy.moduleUrl && !strategy.moduleUrl.match(/^https?:\/\//)) { warnings.push(`Custom strategy '${strategy.name}' moduleUrl should be a valid HTTP/HTTPS URL`); } } } // Validate fallback behavior if (!['error', 'generic', 'skip'].includes(config.frameworkStrategy.fallbackBehavior)) { errors.push('frameworkStrategy.fallbackBehavior must be one of: error, generic, skip'); } } catch (error) { warnings.push(`Framework strategy validation skipped: ${error.message}`); } return { valid: errors.length === 0, errors, warnings, recommendations: [], score: 0 }; } /** * Validate constraint handlers configuration */ async validateConstraintHandlers(config) { const errors = []; const warnings = []; if (!config.constraintHandlers?.enabled) { return { valid: true, errors, warnings, recommendations: [], score: 1 }; } // Validate custom handlers if (config.constraintHandlers.customHandlers) { for (const handler of config.constraintHandlers.customHandlers) { if (!handler.id) { errors.push('Custom constraint handler ID is required'); } if (!handler.type || !['check', 'foreign_key', 'unique', 'not_null'].includes(handler.type)) { errors.push(`Invalid constraint handler type '${handler.type}' for handler '${handler.id}' - must be one of: check, foreign_key, unique, not_null`); } if (typeof handler.priority !== 'number' || handler.priority < 0) { errors.push(`Invalid priority for constraint handler '${handler.id}' - must be a non-negative number`); } if (!handler.handlerFunction) { errors.push(`Handler function is required for constraint handler '${handler.id}'`); } // Validate table references if specified if (handler.tables) { for (const tableName of handler.tables) { try { const exists = await this.tableExists(tableName); if (!exists) { warnings.push(`Table '${tableName}' referenced in constraint handler '${handler.id}' may not exist`); } } catch (error) { warnings.push(`Could not verify table '${tableName}' for constraint handler '${handler.id}': ${error.message}`); } } } } } return { valid: errors.length === 0, errors, warnings, recommendations: [], score: 0 }; } /** * Validate schema evolution configuration */ validateSchemaEvolution(config) { const errors = []; const warnings = []; if (!config.schemaEvolution?.enabled) { return { valid: true, errors, warnings, recommendations: [], score: 1 }; } // Validate tracking mode if (!['hash', 'timestamp', 'version'].includes(config.schemaEvolution.trackingMode)) { errors.push('schemaEvolution.trackingMode must be one of: hash, timestamp, version'); } // Validate cache location if (!config.schemaEvolution.cacheLocation) { warnings.push('schemaEvolution.cacheLocation not specified - will use default'); } // Validate on schema change behavior if (!['warn', 'error', 'auto-adapt', 'prompt'].includes(config.schemaEvolution.onSchemaChange)) { errors.push('schemaEvolution.onSchemaChange must be one of: warn, error, auto-adapt, prompt'); } // Validate migration strategies for version tracking if (config.schemaEvolution.trackingMode === 'version') { if (!config.schemaEvolution.migrationStrategies?.length) { warnings.push('Version tracking enabled but no migration strategies defined'); } else { for (const migration of config.schemaEvolution.migrationStrategies) { if (!migration.fromVersion || !migration.toVersion) { errors.push('Migration strategy must have fromVersion and toVersion'); } if (!migration.migrationSteps?.length) { warnings.push(`Migration from ${migration.fromVersion} to ${migration.toVersion} has no steps defined`); } } } } return { valid: errors.length === 0, errors, warnings, recommendations: [], score: 0 }; } /** * Validate data volume configuration */ validateDataVolumes(config) { const errors = []; const warnings = []; if (!config.dataVolumes?.enabled) { return { valid: true, errors, warnings, recommendations: [], score: 1 }; } // Validate user distribution pattern if (!['linear', 'realistic', 'exponential', 'custom'].includes(config.dataVolumes.patterns.userDistribution)) { errors.push('dataVolumes.patterns.userDistribution must be one of: linear, realistic, exponential, custom'); } // Validate content ratios const ratios = config.dataVolumes.patterns.contentRatios; const totalRatio = ratios.publicContent + ratios.privateContent + ratios.draftContent; if (Math.abs(totalRatio - 1.0) > 0.01) { errors.push(`Content ratios must sum to 1.0, got ${totalRatio.toFixed(3)}`); } // Validate individual ratios if (ratios.publicContent < 0 || ratios.publicContent > 1) { errors.push('publicContent ratio must be between 0 and 1'); } if (ratios.privateContent < 0 || ratios.privateContent > 1) { errors.push('privateContent ratio must be between 0 and 1'); } if (ratios.draftContent < 0 || ratios.draftContent > 1) { errors.push('draftContent ratio must be between 0 and 1'); } // Validate relationship density const density = config.dataVolumes.patterns.relationshipDensity; if (density.userToContent <= 0) { errors.push('relationshipDensity.userToContent must be greater than 0'); } if (density.crossReferences < 0) { errors.push('relationshipDensity.crossReferences must be 0 or greater'); } if (density.tagConnections < 0) { errors.push('relationshipDensity.tagConnections must be 0 or greater'); } // Validate volume profiles if (config.dataVolumes.volumeProfiles) { for (const profile of config.dataVolumes.volumeProfiles) { if (!profile.name) { errors.push('Volume profile name is required'); } if (profile.userCount <= 0) { errors.push(`Volume profile '${profile.name}' userCount must be greater than 0`); } if (profile.avgItemsPerUser <= 0) { errors.push(`Volume profile '${profile.name}' avgItemsPerUser must be greater than 0`); } if (!['basic', 'rich', 'production'].includes(profile.dataQualityLevel)) { errors.push(`Volume profile '${profile.name}' dataQualityLevel must be one of: basic, rich, production`); } } } return { valid: errors.length === 0, errors, warnings, recommendations: [], score: 0 }; } /** * Validate custom relationships configuration */ async validateCustomRelationships(config) { const errors = []; const warnings = []; if (!config.customRelationships?.enabled) { return { valid: true, errors, warnings, recommendations: [], score: 1 }; } // Validate relationships if (config.customRelationships.relationships) { for (const relationship of config.customRelationships.relationships) { if (!relationship.id) { errors.push('Custom relationship ID is required'); } if (!relationship.fromTable || !relationship.toTable) { errors.push(`Custom relationship '${relationship.id}' must have fromTable and toTable`); } if (!['one_to_one', 'one_to_many', 'many_to_many'].includes(relationship.relationshipType)) { errors.push(`Invalid relationship type '${relationship.relationshipType}' for relationship '${relationship.id}'`); } if (!['sequential', 'random', 'weighted', 'custom'].includes(relationship.generationStrategy)) { errors.push(`Invalid generation strategy '${relationship.generationStrategy}' for relationship '${relationship.id}'`); } // Check if custom generator is provided for custom strategy if (relationship.generationStrategy === 'custom' && !relationship.customGenerator) { errors.push(`Custom generation strategy specified but no customGenerator provided for relationship '${relationship.id}'`); } // Validate table existence try { const fromExists = await this.tableExists(relationship.fromTable); const toExists = await this.tableExists(relationship.toTable); if (!fromExists) { warnings.push(`From table '${relationship.fromTable}' may not exist for relationship '${relationship.id}'`); } if (!toExists) { warnings.push(`To table '${relationship.toTable}' may not exist for relationship '${relationship.id}'`); } } catch (error) { warnings.push(`Could not verify tables for relationship '${relationship.id}': ${error.message}`); } } } // Validate junction tables if (config.customRelationships.junctionTables) { for (const junctionTable of config.customRelationships.junctionTables) { if (!junctionTable.tableName) { errors.push('Junction table name is required'); } if (!junctionTable.leftTable || !junctionTable.rightTable) { errors.push(`Junction table '${junctionTable.tableName}' must have leftTable and rightTable`); } if (!junctionTable.leftColumn || !junctionTable.rightColumn) { errors.push(`Junction table '${junctionTable.tableName}' must have leftColumn and rightColumn`); } // Check table existence try { const exists = await this.tableExists(junctionTable.tableName); if (!exists) { warnings.push(`Junction table '${junctionTable.tableName}' may not exist`); } } catch (error) { warnings.push(`Could not verify junction table '${junctionTable.tableName}': ${error.message}`); } } } return { valid: errors.length === 0, errors, warnings, recommendations: [], score: 0 }; } /** * Generate configuration recommendations based on validation results */ generateRecommendations(config, errors, warnings) { const recommendations = []; // Basic recommendations based on environment if (config.environment === 'local') { recommendations.push('💡 For local development, consider reducing userCount and setupsPerUser for faster seeding'); if (config.enableRealImages) { recommendations.push('💡 Consider disabling real images in local environment to improve seeding speed'); } } if (config.environment === 'production') { if (config.userCount < 10) { recommendations.push('💡 Consider increasing userCount for production environment to generate more realistic data'); } if (!config.enableRealImages) { recommendations.push('💡 Consider enabling real images in production environment for better visual testing'); } } // Framework strategy recommendations if (!config.frameworkStrategy?.enabled) { recommendations.push('💡 Enable framework strategy configuration for better framework-aware seeding'); } // Schema evolution recommendations if (!config.schemaEvolution?.enabled) { recommendations.push('💡 Enable schema evolution detection to handle database schema changes gracefully'); } // Data volume recommendations if (!config.dataVolumes?.enabled) { recommendations.push('💡 Enable data volume configuration for more realistic data generation patterns'); } // Error and warning based recommendations if (errors.length > 0) { recommendations.push(`🚨 Fix ${errors.length} configuration errors before proceeding`); } if (warnings.length > 0) { recommendations.push(`⚠️ Review ${warnings.length} configuration warnings for optimal setup`); } if (errors.length === 0 && warnings.length === 0) { recommendations.push('✅ Configuration validation passed - ready for seeding'); } return recommendations; } /** * Check if a table exists in the database */ async tableExists(tableName) { try { const { error } = await this.client.from(tableName).select('*').limit(1); return !error; } catch { return false; } } /** * Validate configuration against actual database schema */ async validateAgainstSchema(config) { logger_1.Logger.info('🔍 Validating configuration against database schema...'); const errors = []; const warnings = []; const recommendations = []; try { // Detect current schema const schemaInfo = await this.schemaAdapter.detectSchema(); // Validate user table mapping if (config.schema?.userTable) { const userTableExists = await this.tableExists(config.schema.userTable.name); if (!userTableExists) { errors.push(`User table '${config.schema.userTable.name}' does not exist in database`); } else { // Validate column mappings const validation = await this.schemaAdapter.validateTableSchema(config.schema.userTable.name, { id: [config.schema.userTable.idField], email: [config.schema.userTable.emailField], name: [config.schema.userTable.nameField], ...(config.schema.userTable.bioField && { bio: [config.schema.userTable.bioField] }), ...(config.schema.userTable.pictureField && { picture: [config.schema.userTable.pictureField] }) }); if (!validation.valid) { warnings.push(...validation.missingFields.map(field => `User table column mapping issue: '${field}' may not exist`)); recommendations.push(...validation.suggestions); } } } // Validate setup table mapping if (config.schema?.setupTable) { const setupTableExists = await this.tableExists(config.schema.setupTable.name); if (!setupTableExists) { errors.push(`Setup table '${config.schema.setupTable.name}' does not exist in database`); } } // Framework compatibility check if (config.schema?.framework) { const detectedFramework = schemaInfo.frameworkType; if (config.schema.framework === 'makerkit' && detectedFramework !== 'makerkit') { warnings.push(`Configuration specifies MakerKit framework but detected '${detectedFramework}' - consider updating configuration`); } } recommendations.push(`Database schema validation completed for ${Object.keys(schemaInfo).length} detected features`); return { valid: errors.length === 0, errors, warnings, recommendations, score: errors.length === 0 ? 1 : 0.5 }; } catch (error) { logger_1.Logger.error('Schema validation failed:', error); return { valid: false, errors: [`Schema validation failed: ${error.message}`], warnings: [], recommendations: ['Ensure database is accessible and contains expected tables'], score: 0 }; } } /** * Get configuration recommendations for a specific framework */ async getFrameworkRecommendations(frameworkType) { const recommendations = []; switch (frameworkType) { case 'makerkit': recommendations.push({ type: 'framework', priority: 'high', message: 'Enable MakerKit-specific constraint handling for accounts and profiles', suggestedFix: 'Set frameworkStrategy.enabled = true and constraintHandlers.enabled = true', autoFixable: true }); recommendations.push({ type: 'constraint', priority: 'medium', message: 'Configure personal account constraint handler', suggestedFix: 'Add custom constraint handler for accounts_slug_null_if_personal_account_true', autoFixable: false }); break; case 'generic': recommendations.push({ type: 'framework', priority: 'medium', message: 'Consider enabling schema evolution detection for custom schemas', suggestedFix: 'Set schemaEvolution.enabled = true', autoFixable: true }); break; default: recommendations.push({ type: 'general', priority: 'low', message: 'Framework type not recognized - using generic configuration', autoFixable: false }); } return recommendations; } /** * Validate layered configuration with comprehensive analysis * Task 5.3.2: Advanced validation for layered configuration system */ async validateLayeredConfiguration(config, options = {}) { logger_1.Logger.info('🔍 Starting advanced layered configuration validation...'); const startTime = Date.now(); try { // Initialize validation result const result = { valid: true, score: 100, validationTime: 0, layers: { universal: await this.validateConfigurationLayer(config.universal, 'universal', options), detection: await this.validateConfigurationLayer(config.detection, 'detection', options), extensions: await this.validateConfigurationLayer(config.extensions, 'extensions', options) }, errors: [], warnings: [], suggestions: [], autoFixSuggestions: [] }; // Aggregate layer results const allErrors = [ ...result.layers.universal.errors, ...result.layers.detection.errors, ...result.layers.extensions.errors ]; const allWarnings = [ ...result.layers.universal.warnings, ...result.layers.detection.warnings, ...result.layers.extensions.warnings ]; // Cross-layer validation const crossLayerValidation = await this.validateCrossLayerConstraints(config, options); allErrors.push(...crossLayerValidation.errors); allWarnings.push(...crossLayerValidation.warnings); // Compatibility validation if (options.checkCompatibility) { const compatibilityValidation = await this.validateLayeredCompatibility(config); allErrors.push(...compatibilityValidation.errors); allWarnings.push(...compatibilityValidation.warnings); } // Performance validation if (options.validatePerformance) { result.performanceImpact = await this.validateLayeredPerformance(config); if (result.performanceImpact.score < 70) { allWarnings.push({ code: 'PERF_LOW_SCORE', path: 'config', message: `Performance score is low: ${result.performanceImpact.score}/100`, impact: 'high', category: 'performance', layer: 'cross-layer', recommendation: 'Consider optimizing configuration complexity', autoFixable: false }); } } // Migration analysis if (options.migrationSupport) { result.migrationInfo = await this.analyzeLayeredMigrationRequirements(config); } // Generate suggestions result.suggestions = await this.generateLayeredSuggestions(config, allErrors, allWarnings); // Generate auto-fix suggestions if (options.autoFix) { result.autoFixSuggestions = await this.generateLayeredAutoFixSuggestions(allErrors); } // Calculate overall score and validity result.errors = allErrors; result.warnings = options.includeWarnings ? allWarnings : []; result.valid = allErrors.filter(e => e.severity === 'critical' || e.severity === 'high').length === 0; result.score = this.calculateLayeredOverallScore(result.layers, allErrors, allWarnings); result.validationTime = Date.now() - startTime; logger_1.Logger.complete(`Layered configuration validation completed in ${result.validationTime}ms - Score: ${result.score}/100`); return result; } catch (error) { logger_1.Logger.error(`Layered configuration validation failed: ${error.message}`); throw error; } } /** * Validate individual configuration layer */ async validateConfigurationLayer(layer, layerName, options) { const errors = []; const warnings = []; // Layer-specific validation switch (layerName) { case 'universal': await this.validateUniversalLayer(layer, errors, warnings, options); break; case 'detection': await this.validateDetectionLayer(layer, errors, warnings, options); break; case 'extensions': await this.validateExtensionsLayer(layer, errors, warnings, options); break; } // Calculate coverage and constraints const coverage = this.calculateLayerCoverage(layer, layerName); const constraintStats = this.calculateLayerConstraintStats(errors, warnings); return { valid: errors.filter(e => e.severity === 'critical' || e.severity === 'high').length === 0, score: this.calculateLayerScore(errors, warnings, coverage), errors, warnings, coverage, constraints: constraintStats }; } /** * Validate universal layer */ async validateUniversalLayer(layer, errors, warnings, options) { // MakerKit compliance validation if (!layer.makerkit?.enabled) { errors.push({ code: 'MAKERKIT_DISABLED', path: 'layers.universal.makerkit.enabled', message: 'MakerKit compliance is disabled in universal layer', severity: 'high', category: 'constraint', layer: 'universal', autoFixable: true }); } // RLS compliance validation if (layer.security?.rlsCompliance === false) { errors.push({ code: 'RLS_DISABLED', path: 'layers.universal.security.rlsCompliance', message: 'RLS compliance is disabled - security risk', severity: 'critical', category: 'constraint', layer: 'universal', autoFixable: true }); } // Webhook configuration validation if (layer.webhook?.enabled && !Object.keys(layer.webhook.endpoints || {}).length) { warnings.push({ code: 'WEBHOOK_NO_ENDPOINTS', path: 'layers.universal.webhook.endpoints', message: 'Webhook enabled but no endpoints configured', impact: 'medium', category: 'compatibility', layer: 'universal', recommendation: 'Add webhook endpoints or disable webhook support', autoFixable: false }); } } /** * Validate detection layer */ async validateDetectionLayer(layer, errors, warnings, options) { // Platform detection validation if (layer.platform) { if (!['individual', 'team', 'hybrid', 'auto'].includes(layer.platform.architecture)) { errors.push({ code: 'INVALID_ARCHITECTURE', path: 'layers.detection.platform.architecture', message: `Invalid platform architecture: ${layer.platform.architecture}`, severity: 'medium', category: 'type', layer: 'detection', autoFixable: false }); } if (layer.platform.domain && !['outdoor', 'saas', 'ecommerce', 'social', 'generic', 'auto'].includes(layer.platform.domain)) { errors.push({ code: 'INVALID_DOMAIN', path: 'layers.detection.platform.domain', message: `Invalid platform domain: ${layer.platform.domain}`, severity: 'medium', category: 'type', layer: 'detection', autoFixable: false }); } // Confidence validation if (layer.platform.confidence !== undefined && (layer.platform.confidence < 0 || layer.platform.confidence > 1)) { errors.push({ code: 'INVALID_CONFIDENCE', path: 'layers.detection.platform.confidence', message: 'Platform detection confidence must be between 0 and 1', severity: 'medium', category: 'type', layer: 'detection', autoFixable: true }); } } // Auto-configuration validation if (layer.autoConfiguration?.enabled && !layer.autoConfiguration.strategy) { warnings.push({ code: 'AUTOCONFIG_NO_STRATEGY', path: 'layers.detection.autoConfiguration.strategy', message: 'Auto-configuration enabled but no strategy specified', impact: 'medium', category: 'compatibility', layer: 'detection', recommendation: 'Specify auto-configuration strategy', autoFixable: true }); } } /** * Validate extensions layer */ async validateExtensionsLayer(layer, errors, warnings, options) { // Domain extension validation const domainExtensions = ['outdoor', 'saas', 'ecommerce', 'social']; const enabledExtensions = domainExtensions.filter(ext => layer[ext]?.enabled); if (enabledExtensions.length > 3) { warnings.push({ code: 'TOO_MANY_EXTENSIONS', path: 'layers.extensions', message: `${enabledExtensions.length} extensions enabled - may impact performance`, impact: 'medium', category: 'performance', layer: 'extensions', recommendation: 'Consider reducing number of enabled extensions', autoFixable: false }); } // Extension-specific validation for (const extension of enabledExtensions) { const config = layer[extension]; if (config && config.customization && !config.customization.validate) { warnings.push({ code: 'EXTENSION_NO_VALIDATION', path: `layers.extensions.${extension}.customization.validate`, message: `Extension ${extension} has customization but validation is disabled`, impact: 'low', category: 'best-practice', layer: 'extensions', recommendation: 'Enable validation for customized extensions', autoFixable: true }); } } // Archetype system validation if (layer.archetypes?.enabled && !layer.archetypes.customArchetypes?.length) { warnings.push({ code: 'ARCHETYPES_NO_PROFILES', path: 'layers.extensions.archetypes.profiles', message: 'Archetype system enabled but no profiles defined', impact: 'medium', category: 'compatibility', layer: 'extensions', recommendation: 'Define archetype profiles or disable archetype system', autoFixable: false }); } } /** * Validate cross-layer constraints */ async validateCrossLayerConstraints(config, options) { const errors = []; const warnings = []; // Architecture-Extension compatibility if (config.detection?.platform?.architecture && config.extensions) { const architecture = config.detection.platform.architecture; const enabledExtensions = Object.keys(config.extensions).filter(key => config.extensions[key]?.enabled); if (architecture === 'individual' && enabledExtensions.includes('saas')) { warnings.push({ code: 'ARCHITECTURE_EXTENSION_MISMATCH', path: 'layers', message: 'Individual architecture with SaaS extension may not be optimal', impact: 'medium', category: 'compatibility', layer: 'cross-layer', recommendation: 'Consider team or hybrid architecture for SaaS platforms', autoFixable: false }); } if (architecture === 'team' && enabledExtensions.includes('outdoor')) { warnings.push({ code: 'ARCHITECTURE_EXTENSION_MISMATCH', path: 'layers', message: 'Team architecture with outdoor extension may not be optimal', impact: 'medium', category: 'compatibility', layer: 'cross-layer', recommendation: 'Consider individual or hybrid architecture for outdoor platforms', autoFixable: false }); } } // Universal-Detection compatibility if (config.universal?.makerkit?.accountType && config.detection?.platform?.architecture) { const accountType = config.universal.makerkit.accountType; const architecture = config.detection.platform.architecture; if (accountType === 'individual' && architecture === 'team') { errors.push({ code: 'ACCOUNT_ARCHITECTURE_CONFLICT', path: 'layers', message: 'Personal account type conflicts with team architecture', severity: 'high', category: 'compatibility', layer: 'cross-layer', autoFixable: true }); } } return { errors, warnings }; } /** * Validate layered configuration compatibility */ async validateLayeredCompatibility(config) { const errors = []; const warnings = []; // Version compatibility const configVersion = config.metadata?.version || '2.4.1'; if (configVersion < '2.4.1') { warnings.push({ code: 'OLD_CONFIG_VERSION', path: 'metadata.version', message: `Configuration version ${configVersion} is outdated`, impact: 'medium', category: 'compatibility', layer: 'cross-layer', recommendation: 'Upgrade configuration to v2.4.1', autoFixable: true }); } // Layer structure validation if (!config.universal || !config.detection || !config.extensions) { errors.push({ code: 'MISSING_LAYERS', path: 'layers', message: 'Layered configuration missing required layer properties', severity: 'critical', category: 'structure', layer: 'cross-layer', autoFixable: false }); } return { errors, warnings }; } /** * Validate layered configuration performance */ async validateLayeredPerformance(config) { // Analyze layer complexity const universalComplexity = this.analyzeLayerComplexity(config.universal); const detectionComplexity = this.analyzeLayerComplexity(config.detection); const extensionComplexity = this.analyzeLayerComplexity(config.extensions); const crossLayerComplexity = this.analyzeCrossLayerComplexity(config); const overallComplexity = (universalComplexity + detectionComplexity + extensionComplexity + crossLayerComplexity) / 4; const score = Math.max(0, 100 - (overallComplexity * 10)); return { score, estimatedSlowdown: Math.min(50, overallComplexity * 5), memoryImpact: Math.min(100, overallComplexity * 2), complexityAnalysis: { universalComplexity, detectionComplexity, extensionComplexity, crossLayerComplexity }, recommendations: this.generateLayeredPerformanceRecommendations(overallComplexity), optimizations: this.generateLayeredOptimizationSuggestions(config), layerImpact: { universal: universalComplexity, detection: detectionComplexity, extensions: extensionComplexity } }; } /** * Analyze migration requirements for layered configuration */ async analyzeLayeredMigrationRequirements(config) { const currentVersion = config.metadata?.version || '2.4.1'; const targetVersion = '2.4.1'; // Check if migration is needed const migrationRequired = currentVersion !== targetVersion; return { required: migrationRequired, fromVersion: currentVersion, toVersion: targetVersion, migrationSteps: [], estimatedDuration: 0, riskAssessment: 'low', backupRecommended: migrationRequired, rollbackSupported: true, layerMigrations: { universal: [], detection: [], extensions: [] } }; } /** * Generate improvement suggestions for layered configuration */ async generateLayeredSuggestions(config, errors, warnings) { const suggestions = []; // Performance optimization suggestions const extensionComplexity = this.analyzeLayerComplexity(config.extensions); if (extensionComplexity > 5) { suggestions.push({ type: 'optimization', priority: 'medium', description: 'Extension layer complexity is high, consider simplification', impact: 'Improved performance and maintainability', implementation: [ 'Disable unused extensions', 'Simplify extension configurations', 'Use extension templates' ], estimatedBenefit: '10-30% performance improvement', affectedLayers: ['extensions'] }); } // Migration suggestions const compatibilityErrors = errors.filter(e => e.category === 'compatibility'); if (compatibilityErrors.length > 0) { suggestions.push({ type: 'migration', priority: 'high', description: 'Configuration compatibility issues detected', impact: 'Improved compatibility and reduced errors', implementation: [ 'Run configuration migration utility', 'Update deprecated configurations', 'Test migrated configuration' ], estimatedBenefit: 'Improved compatibility and reduced errors', affectedLayers: ['universal', 'detection', 'extensions'] }); } return suggestions; } /** * Generate auto-fix suggestions for layered configuration */ async generateLayeredAutoFixSuggestions(errors) { const autoFixSuggestions = []; for (const error of errors.filter(e => e.autoFixable)) { switch (error.code) { case 'MAKERKIT_DISABLED': autoFixSuggestions.push({ errorCode: error.code, path: error.path, description: 'Enable MakerKit compliance in universal layer', action: 'modify', suggestedValue: true, riskLevel: 'safe', backupRequired: false, affectedLayers: ['universal'] }); break; case 'RLS_DISABLED': autoFixSuggestions.push({ errorCode: error.code, path: error.path, description: 'Enable RLS compliance for security', action: 'modify', suggestedValue: true, riskLevel: 'moderate', backupRequired: true, affectedLayers: ['universal'] }); break; case 'INVALID_CONFIDENCE': autoFixSuggestions.push({ errorCode: error.code, path: error.path, description: 'Fix detection confidence value', action: 'modify', suggestedValue: 0.8, riskLevel: 'safe', backupRequired: false, affectedLayers: ['detection'] }); break; } } return autoFixSuggestions; } /** * Utility methods for layered validation */ calculateLayerCoverage(layer, layerName) { if (!layer) return { totalFields: 0, validatedFields: 0, percentage: 0 }; const totalFields = this.getExpectedFieldsForLayer(layerName); const validatedFields = Object.keys(layer).length; return { totalFields, validatedFields, percentage: totalFields > 0 ? (validatedFields / totalFields) * 100 : 100