@versatil/sdlc-framework
Version:
🚀 AI-Native SDLC framework with 11-MCP ecosystem, RAG memory, OPERA orchestration, and 6 specialized agents achieving ZERO CONTEXT LOSS. Features complete CI/CD pipeline with 7 GitHub workflows (MCP testing, security scanning, performance benchmarking),
377 lines (327 loc) • 12 kB
text/typescript
/**
* VERSATIL SDLC Framework - Supabase Configuration System
*
* Environment-based configuration for Supabase Vector Store with automatic
* embedding provider selection, edge function URL management, and production settings.
*/
import { VERSATILLogger } from '../utils/logger.js';
import { SupabaseRAGConfig } from '../agents/supabase-agent-integration.js';
export interface SupabaseEnvironmentConfig {
// Core Supabase settings
supabaseUrl: string;
supabaseAnonKey: string;
supabaseServiceKey?: string;
// Embedding provider settings
openaiApiKey?: string;
useLocalEmbeddings?: boolean;
embeddingModel?: string;
// Edge function URLs
mariaRagUrl?: string;
jamesRagUrl?: string;
marcusRagUrl?: string;
// Performance settings
maxRetries?: number;
retryDelay?: number;
cacheSize?: number;
batchSize?: number;
// Feature flags
enableLearning?: boolean;
enableCollaboration?: boolean;
enableMonitoring?: boolean;
enableFallback?: boolean;
// Quality thresholds
patternQualityThreshold?: number;
solutionEffectivenessThreshold?: number;
similarityThreshold?: number;
// Environment settings
environment?: 'development' | 'staging' | 'production';
logLevel?: 'debug' | 'info' | 'warn' | 'error';
}
export class SupabaseConfig {
private static instance: SupabaseConfig;
private config: SupabaseEnvironmentConfig;
private logger: VERSATILLogger;
private isInitialized: boolean = false;
private constructor() {
this.logger = new VERSATILLogger();
this.config = this.loadConfiguration();
this.validateConfiguration();
this.isInitialized = true;
}
/**
* Get singleton instance
*/
static getInstance(): SupabaseConfig {
if (!SupabaseConfig.instance) {
SupabaseConfig.instance = new SupabaseConfig();
}
return SupabaseConfig.instance;
}
/**
* Load configuration from environment variables and defaults
*/
private loadConfiguration(): SupabaseEnvironmentConfig {
const environment = (process.env.NODE_ENV as any) || 'development';
// Load base configuration
const config: SupabaseEnvironmentConfig = {
// Core Supabase (required)
supabaseUrl: process.env.SUPABASE_URL || '',
supabaseAnonKey: process.env.SUPABASE_ANON_KEY || '',
supabaseServiceKey: process.env.SUPABASE_SERVICE_ROLE_KEY,
// Embedding providers
openaiApiKey: process.env.OPENAI_API_KEY,
useLocalEmbeddings: this.parseBoolean(process.env.USE_LOCAL_EMBEDDINGS, false),
embeddingModel: process.env.EMBEDDING_MODEL || 'text-embedding-ada-002',
// Edge function URLs (auto-generated if not provided)
mariaRagUrl: process.env.MARIA_RAG_URL,
jamesRagUrl: process.env.JAMES_RAG_URL,
marcusRagUrl: process.env.MARCUS_RAG_URL,
// Performance settings
maxRetries: parseInt(process.env.SUPABASE_MAX_RETRIES || '3'),
retryDelay: parseInt(process.env.SUPABASE_RETRY_DELAY || '1000'),
cacheSize: parseInt(process.env.PATTERN_CACHE_SIZE || '100'),
batchSize: parseInt(process.env.EMBEDDING_BATCH_SIZE || '10'),
// Feature flags
enableLearning: this.parseBoolean(process.env.ENABLE_AGENT_LEARNING, true),
enableCollaboration: this.parseBoolean(process.env.ENABLE_AGENT_COLLABORATION, true),
enableMonitoring: this.parseBoolean(process.env.ENABLE_RAG_MONITORING, true),
enableFallback: this.parseBoolean(process.env.ENABLE_RAG_FALLBACK, true),
// Quality thresholds
patternQualityThreshold: parseFloat(process.env.PATTERN_QUALITY_THRESHOLD || '0.7'),
solutionEffectivenessThreshold: parseFloat(process.env.SOLUTION_EFFECTIVENESS_THRESHOLD || '0.6'),
similarityThreshold: parseFloat(process.env.SIMILARITY_THRESHOLD || '0.7'),
// Environment
environment,
logLevel: (process.env.LOG_LEVEL as any) || 'info'
};
// Auto-generate edge function URLs if not provided
if (config.supabaseUrl && !config.mariaRagUrl) {
config.mariaRagUrl = `${config.supabaseUrl}/functions/v1/maria-rag`;
config.jamesRagUrl = `${config.supabaseUrl}/functions/v1/james-rag`;
config.marcusRagUrl = `${config.supabaseUrl}/functions/v1/marcus-rag`;
}
// Environment-specific overrides
if (environment === 'production') {
config.useLocalEmbeddings = false; // Prefer OpenAI in production for quality
config.logLevel = 'warn';
config.enableMonitoring = true;
} else if (environment === 'development') {
config.useLocalEmbeddings = !config.openaiApiKey; // Use local if no OpenAI key
config.logLevel = 'debug';
config.enableMonitoring = false;
}
return config;
}
/**
* Validate configuration and log warnings for missing values
*/
private validateConfiguration(): void {
const errors: string[] = [];
const warnings: string[] = [];
// Required fields
if (!this.config.supabaseUrl) {
errors.push('SUPABASE_URL is required');
}
if (!this.config.supabaseAnonKey) {
errors.push('SUPABASE_ANON_KEY is required');
}
// Embedding provider validation
if (!this.config.openaiApiKey && !this.config.useLocalEmbeddings) {
warnings.push('No OpenAI API key provided, falling back to local embeddings');
this.config.useLocalEmbeddings = true;
}
// Production-specific validations
if (this.config.environment === 'production') {
if (!this.config.openaiApiKey) {
warnings.push('OpenAI API key not set for production environment');
}
if (!this.config.supabaseServiceKey) {
warnings.push('Supabase service role key not set for production');
}
}
// URL validation
if (this.config.supabaseUrl && !this.isValidUrl(this.config.supabaseUrl)) {
errors.push('SUPABASE_URL is not a valid URL');
}
// Threshold validation
if (this.config.patternQualityThreshold! < 0 || this.config.patternQualityThreshold! > 1) {
warnings.push('Pattern quality threshold should be between 0 and 1');
this.config.patternQualityThreshold = 0.7;
}
// Log results
if (errors.length > 0) {
this.logger.error('Supabase configuration errors', { errors }, 'supabase-config');
throw new Error(`Supabase configuration errors: ${errors.join(', ')}`);
}
if (warnings.length > 0) {
this.logger.warn('Supabase configuration warnings', { warnings }, 'supabase-config');
}
this.logger.info('Supabase configuration loaded', {
environment: this.config.environment,
embeddingProvider: this.config.useLocalEmbeddings ? 'local' : 'openai',
featuresEnabled: {
learning: this.config.enableLearning,
collaboration: this.config.enableCollaboration,
monitoring: this.config.enableMonitoring
}
}, 'supabase-config');
}
/**
* Get configuration for a specific agent
*/
getAgentConfig(agentId: string): SupabaseRAGConfig {
return {
supabaseUrl: this.config.supabaseUrl,
supabaseKey: this.config.supabaseAnonKey,
openaiKey: this.config.openaiApiKey,
useLocalEmbeddings: this.config.useLocalEmbeddings,
embeddingModel: this.config.embeddingModel,
enableLearning: this.config.enableLearning,
enableCollaboration: this.config.enableCollaboration,
patternQualityThreshold: this.config.patternQualityThreshold,
solutionEffectivenessThreshold: this.config.solutionEffectivenessThreshold,
maxRetries: this.config.maxRetries,
retryDelay: this.config.retryDelay
};
}
/**
* Get edge function URL for specific agent
*/
getEdgeFunctionUrl(agentId: string): string | undefined {
switch (agentId) {
case 'enhanced-maria':
return this.config.mariaRagUrl;
case 'enhanced-james':
return this.config.jamesRagUrl;
case 'enhanced-marcus':
return this.config.marcusRagUrl;
default:
return undefined;
}
}
/**
* Get embedding provider configuration
*/
getEmbeddingConfig(): {
provider: 'openai' | 'local';
apiKey?: string;
model: string;
useLocal: boolean;
} {
return {
provider: this.config.useLocalEmbeddings ? 'local' : 'openai',
apiKey: this.config.openaiApiKey,
model: this.config.embeddingModel || 'text-embedding-ada-002',
useLocal: this.config.useLocalEmbeddings || false
};
}
/**
* Get performance configuration
*/
getPerformanceConfig(): {
maxRetries: number;
retryDelay: number;
cacheSize: number;
batchSize: number;
thresholds: {
patternQuality: number;
solutionEffectiveness: number;
similarity: number;
};
} {
return {
maxRetries: this.config.maxRetries || 3,
retryDelay: this.config.retryDelay || 1000,
cacheSize: this.config.cacheSize || 100,
batchSize: this.config.batchSize || 10,
thresholds: {
patternQuality: this.config.patternQualityThreshold || 0.7,
solutionEffectiveness: this.config.solutionEffectivenessThreshold || 0.6,
similarity: this.config.similarityThreshold || 0.7
}
};
}
/**
* Check if Supabase is properly configured
*/
isSupabaseConfigured(): boolean {
return !!(this.config.supabaseUrl && this.config.supabaseAnonKey);
}
/**
* Check if embeddings are properly configured
*/
isEmbeddingConfigured(): boolean {
return !!(this.config.openaiApiKey || this.config.useLocalEmbeddings);
}
/**
* Get complete configuration (for debugging)
*/
getFullConfig(): SupabaseEnvironmentConfig {
return { ...this.config };
}
/**
* Update configuration at runtime (for testing)
*/
updateConfig(updates: Partial<SupabaseEnvironmentConfig>): void {
this.config = { ...this.config, ...updates };
this.logger.info('Supabase configuration updated', { updates }, 'supabase-config');
}
/**
* Reset configuration to environment defaults
*/
resetConfig(): void {
this.config = this.loadConfiguration();
this.validateConfiguration();
this.logger.info('Supabase configuration reset', {}, 'supabase-config');
}
/**
* Get configuration status for health checks
*/
getConfigStatus(): {
isConfigured: boolean;
embeddingProvider: string;
environment: string;
featuresEnabled: string[];
missingRequirements: string[];
} {
const featuresEnabled = [];
const missingRequirements = [];
if (this.config.enableLearning) featuresEnabled.push('learning');
if (this.config.enableCollaboration) featuresEnabled.push('collaboration');
if (this.config.enableMonitoring) featuresEnabled.push('monitoring');
if (!this.config.supabaseUrl) missingRequirements.push('SUPABASE_URL');
if (!this.config.supabaseAnonKey) missingRequirements.push('SUPABASE_ANON_KEY');
if (!this.config.openaiApiKey && !this.config.useLocalEmbeddings) {
missingRequirements.push('OpenAI API key or local embeddings');
}
return {
isConfigured: this.isSupabaseConfigured() && this.isEmbeddingConfigured(),
embeddingProvider: this.config.useLocalEmbeddings ? 'local' : 'openai',
environment: this.config.environment || 'unknown',
featuresEnabled,
missingRequirements
};
}
// Private helper methods
private parseBoolean(value: string | undefined, defaultValue: boolean): boolean {
if (value === undefined) return defaultValue;
return value.toLowerCase() === 'true' || value === '1';
}
private isValidUrl(url: string): boolean {
try {
new URL(url);
return true;
} catch {
return false;
}
}
}
// Export singleton instance
export const supabaseConfig = SupabaseConfig.getInstance();
// Export configuration factory functions
export function createSupabaseConfigForAgent(agentId: string): SupabaseRAGConfig {
return supabaseConfig.getAgentConfig(agentId);
}
export function getSupabaseConfigStatus(): any {
return supabaseConfig.getConfigStatus();
}