๐Ÿš€Transform your business with AI-powered process optimization
Technical Specifications
โš™๏ธ Configuration Management
โš™๏ธ Implementation Specification

Configuration Management Technical Specification

This technical specification provides the detailed implementation design for the Configuration Management Service (sindhan-config) Rust crate, showcasing the application of multiple software design patterns to create a robust, extensible, and type-safe configuration system.

Design Patterns Applied

The implementation leverages multiple software design patterns to achieve flexibility, maintainability, and extensibility:

  • Builder Pattern: For configuration builders and complex object construction
  • Factory Pattern: For parser creation and format detection
  • Strategy Pattern: For merge strategies and validation approaches
  • Observer Pattern: For configuration change notifications
  • Chain of Responsibility Pattern: For validation pipeline and discovery chain
  • Adapter Pattern: For external system integration
  • Decorator Pattern: For configuration enhancement and transformation
  • Singleton Pattern: For global configuration registry
  • Template Method Pattern: For configuration loading workflows
  • Command Pattern: For configuration operations and undo functionality

Core Type System and Traits

Base Configuration Traits

use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::Arc;
use tokio::sync::RwLock;
use anyhow::{Result, Context};
use serde::{Deserialize, Serialize};
use async_trait::async_trait;
 
/// Core trait defining configuration schema behavior with schema manager integration
/// **Pattern Applied: Template Method Pattern**
pub trait ConfigurationSchema: Send + Sync + 'static {
    type ConfigType: for<'de> Deserialize<'de> + Serialize + Clone + Send + Sync + 'static;
    
    fn schema_name() -> &'static str;
    fn schema_version() -> &'static str;
    fn schema_file_patterns() -> Vec<&'static str> {
        vec![
            &format!("schemas/{}.schema.toml", Self::schema_name()),
            &format!("schemas/{}.schema.yaml", Self::schema_name()),
            &format!("schemas/{}.schema.json", Self::schema_name()),
        ]
    }
    fn default_configuration() -> Self::ConfigType;
    fn validation_rules() -> Vec<Box<dyn ValidationRule<Self::ConfigType>>>;
    fn schema_dependencies() -> Vec<&'static str> { vec![] }
    fn schema_inheritance() -> Option<&'static str> { None }
    
    /// Template method defining the standard loading workflow
    async fn load_configuration(discovery: &ConfigurationDiscovery) -> Result<Self::ConfigType> {
        // Step 1: Discover configuration files
        let discovered = discovery.discover_files(Self::schema_name()).await?;
        
        // Step 2: Parse discovered files
        let parsed = Self::parse_configurations(discovered).await?;
        
        // Step 3: Merge configurations
        let merged = Self::merge_configurations(parsed).await?;
        
        // Step 4: Validate final configuration
        Self::validate_configuration(&merged).await?;
        
        Ok(merged)
    }
    
    async fn parse_configurations(files: Vec<DiscoveredFile>) -> Result<Vec<Self::ConfigType>>;
    async fn merge_configurations(configs: Vec<Self::ConfigType>) -> Result<Self::ConfigType>;
    async fn validate_configuration(config: &Self::ConfigType) -> Result<()>;
}
 
/// Trait for configuration validation rules
/// **Pattern Applied: Strategy Pattern**
pub trait ValidationRule<T>: Send + Sync {
    fn name(&self) -> &'static str;
    fn validate(&self, config: &T) -> Result<ValidationResult>;
    fn severity(&self) -> ValidationSeverity;
}
 
/// Configuration change observer trait
/// **Pattern Applied: Observer Pattern**
#[async_trait]
pub trait ConfigurationObserver: Send + Sync {
    async fn on_configuration_changed(&self, change: ConfigurationChange) -> Result<()>;
    async fn on_validation_failed(&self, error: ValidationError) -> Result<()>;
    async fn on_reload_completed(&self, success: bool) -> Result<()>;
}

Configuration Discovery Engine

/// Configuration discovery engine implementing chain of responsibility
/// **Pattern Applied: Chain of Responsibility Pattern**
pub struct ConfigurationDiscovery {
    discovery_chain: Vec<Box<dyn DiscoveryHandler>>,
    format_factory: Arc<FormatParserFactory>,
    schema_manager: Arc<SchemaManager>,
}
 
/// Schema Manager handles schema discovery, loading, and caching
/// **Pattern Applied: Singleton Pattern + Factory Pattern**
pub struct SchemaManager {
    schema_cache: Arc<RwLock<HashMap<String, CachedSchema>>>,
    schema_discovery: SchemaDiscoveryEngine,
    schema_loader: SchemaLoader,
    schema_validator: SchemaValidator,
}
 
struct CachedSchema {
    metadata: SchemaMetadata,
    definition: SchemaDefinition,
    loaded_at: std::time::Instant,
    dependencies: Vec<String>,
}
 
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SchemaMetadata {
    pub name: String,
    pub version: semver::Version,
    pub compatible_versions: Vec<semver::VersionReq>,
    pub description: String,
    pub author: String,
    pub created: chrono::DateTime<chrono::Utc>,
    pub last_modified: chrono::DateTime<chrono::Utc>,
    pub tags: Vec<String>,
    pub inheritance: Option<SchemaInheritance>,
    pub dependencies: SchemaDependencies,
}
 
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SchemaInheritance {
    pub parent_schema: String,
    pub override_mode: OverrideMode,
    pub excluded_fields: Vec<String>,
    pub included_fields: Option<Vec<String>>,
}
 
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SchemaDependencies {
    pub required_schemas: Vec<String>,
    pub optional_schemas: Vec<String>,
    pub version_constraints: HashMap<String, semver::VersionReq>,
}
 
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OverrideMode {
    DeepMerge,
    ShallowMerge,
    SelectiveMerge,
    Replace,
}
 
impl ConfigurationDiscovery {
    /// **Pattern Applied: Builder Pattern**
    pub fn builder() -> ConfigurationDiscoveryBuilder {
        ConfigurationDiscoveryBuilder::new()
    }
    
    pub async fn discover_files(&self, module_name: &str) -> Result<Vec<DiscoveredFile>> {
        // First, load the schema for this module
        let schema = self.schema_manager.load_schema(module_name).await?;
        
        // Use schema information to guide discovery
        for handler in &self.discovery_chain {
            if let Some(files) = handler.discover_with_schema(module_name, &schema).await? {
                return Ok(files);
            }
        }
        
        // Return default configuration if no files found
        Ok(vec![DiscoveredFile::default_with_schema(module_name, schema)])
    }
    
    pub async fn discover_schema_files(&self, module_name: &str) -> Result<Vec<DiscoveredSchemaFile>> {
        let mut discovered_schemas = Vec::new();
        
        // Search in all schema locations
        for handler in &self.discovery_chain {
            if let Some(schema_files) = handler.discover_schemas(module_name).await? {
                discovered_schemas.extend(schema_files);
            }
        }
        
        Ok(discovered_schemas)
    }
}
 
/// Builder for configuration discovery
/// **Pattern Applied: Builder Pattern**
pub struct ConfigurationDiscoveryBuilder {
    discovery_handlers: Vec<Box<dyn DiscoveryHandler>>,
    custom_search_paths: Vec<PathBuf>,
    format_precedence: Vec<ConfigurationFormat>,
    enable_environment_overrides: bool,
    enable_hot_reload: bool,
}
 
impl ConfigurationDiscoveryBuilder {
    pub fn new() -> Self {
        Self {
            discovery_handlers: Vec::new(),
            custom_search_paths: Vec::new(),
            format_precedence: vec![
                ConfigurationFormat::Toml,
                ConfigurationFormat::Yaml,
                ConfigurationFormat::Json,
            ],
            enable_environment_overrides: true,
            enable_hot_reload: false,
        }
    }
    
    pub fn build(self) -> Result<ConfigurationDiscovery> {
        let mut discovery_handlers: Vec<Box<dyn DiscoveryHandler>> = vec![
            Box::new(ProjectSchemaDiscoveryHandler::new()),
            Box::new(UserSchemaDiscoveryHandler::new()),
            Box::new(SystemSchemaDiscoveryHandler::new()),
            Box::new(EmbeddedSchemaDiscoveryHandler::new()),
        ];
        
        // Add custom handlers
        discovery_handlers.extend(self.discovery_handlers);
        
        let schema_manager = Arc::new(SchemaManager::new(
            SchemaDiscoveryEngine::new(self.custom_search_paths.clone()),
            SchemaLoader::new(),
            SchemaValidator::new(),
        ));
        
        Ok(ConfigurationDiscovery {
            discovery_chain: discovery_handlers,
            format_factory: Arc::new(FormatParserFactory::new()),
            schema_manager,
        })
    }
    
    pub fn add_search_path(mut self, path: PathBuf) -> Self {
        self.custom_search_paths.push(path);
        self
    }
    
    pub fn with_format_precedence(mut self, formats: Vec<ConfigurationFormat>) -> Self {
        self.format_precedence = formats;
        self
    }
    
    pub fn enable_hot_reload(mut self) -> Self {
        self.enable_hot_reload = true;
        self
    }
    
    pub fn with_schema_directory(mut self, schema_dir: PathBuf) -> Self {
        self.custom_search_paths.push(schema_dir.join("schemas"));
        self
    }
    
    pub fn with_embedded_schemas(mut self, embedded: bool) -> Self {
        if embedded {
            // Add embedded schema handler
        }
        self
    }
    
    pub fn disable_environment_overrides(mut self) -> Self {
        self.enable_environment_overrides = false;
        self
    }
}
 
// Schema discovery handlers implementing specific search strategies
/// **Pattern Applied: Chain of Responsibility Pattern**
 
/// Project-level schema discovery handler
pub struct ProjectSchemaDiscoveryHandler {
    search_paths: Vec<PathBuf>,
}
 
impl ProjectSchemaDiscoveryHandler {
    pub fn new() -> Self {
        Self {
            search_paths: vec![
                PathBuf::from("./schemas"),
                PathBuf::from("./config/schemas"),
                PathBuf::from("./.sindhan/schemas"),
            ],
        }
    }
}
 
#[async_trait]
impl SchemaDiscoveryHandler for ProjectSchemaDiscoveryHandler {
    async fn discover_schemas(&self, module_name: &str) -> Result<Option<Vec<DiscoveredSchemaFile>>> {
        for base_path in &self.search_paths {
            let schema_patterns = vec![
                format!("{}.schema.toml", module_name),
                format!("{}.schema.yaml", module_name),
                format!("{}.schema.yml", module_name),
                format!("{}.schema.json", module_name),
            ];
            
            for pattern in schema_patterns {
                let schema_path = base_path.join(&pattern);
                if schema_path.exists() {
                    return Ok(Some(vec![DiscoveredSchemaFile {
                        path: schema_path,
                        source: SchemaSource::Project,
                        format: SchemaFormat::from_extension(&pattern)?,
                        priority: 1,
                    }]));
                }
            }
        }
        Ok(None)
    }
    
    fn priority(&self) -> u8 { 1 }
    fn name(&self) -> &'static str { "Project Schema Discovery" }
}
 
/// User-level schema discovery handler
pub struct UserSchemaDiscoveryHandler {
    user_schema_dir: PathBuf,
}
 
impl UserSchemaDiscoveryHandler {
    pub fn new() -> Self {
        let home_dir = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
        Self {
            user_schema_dir: home_dir.join(".sindhan").join("schemas"),
        }
    }
}
 
#[async_trait]
impl SchemaDiscoveryHandler for UserSchemaDiscoveryHandler {
    async fn discover_schemas(&self, module_name: &str) -> Result<Option<Vec<DiscoveredSchemaFile>>> {
        let schema_patterns = vec![
            format!("{}.schema.toml", module_name),
            format!("{}.schema.yaml", module_name),
            format!("{}.schema.yml", module_name),
            format!("{}.schema.json", module_name),
        ];
        
        for pattern in schema_patterns {
            let schema_path = self.user_schema_dir.join(&pattern);
            if schema_path.exists() {
                return Ok(Some(vec![DiscoveredSchemaFile {
                    path: schema_path,
                    source: SchemaSource::User,
                    format: SchemaFormat::from_extension(&pattern)?,
                    priority: 2,
                }]));
            }
        }
        Ok(None)
    }
    
    fn priority(&self) -> u8 { 2 }
    fn name(&self) -> &'static str { "User Schema Discovery" }
}
 
/// System-level schema discovery handler
pub struct SystemSchemaDiscoveryHandler {
    system_schema_dir: Option<PathBuf>,
}
 
impl SystemSchemaDiscoveryHandler {
    pub fn new() -> Self {
        let system_dir = std::env::var("SINDHAN_SCHEMA_DIR")
            .ok()
            .map(|dir| PathBuf::from(dir).join("schemas"));
        
        Self {
            system_schema_dir: system_dir,
        }
    }
}
 
#[async_trait]
impl SchemaDiscoveryHandler for SystemSchemaDiscoveryHandler {
    async fn discover_schemas(&self, module_name: &str) -> Result<Option<Vec<DiscoveredSchemaFile>>> {
        if let Some(ref schema_dir) = self.system_schema_dir {
            let schema_patterns = vec![
                format!("{}.schema.toml", module_name),
                format!("{}.schema.yaml", module_name),
                format!("{}.schema.yml", module_name),
                format!("{}.schema.json", module_name),
            ];
            
            for pattern in schema_patterns {
                let schema_path = schema_dir.join(&pattern);
                if schema_path.exists() {
                    return Ok(Some(vec![DiscoveredSchemaFile {
                        path: schema_path,
                        source: SchemaSource::System,
                        format: SchemaFormat::from_extension(&pattern)?,
                        priority: 3,
                    }]));
                }
            }
        }
        Ok(None)
    }
    
    fn priority(&self) -> u8 { 3 }
    fn name(&self) -> &'static str { "System Schema Discovery" }
}
 
/// Embedded schema discovery handler for built-in schemas
pub struct EmbeddedSchemaDiscoveryHandler {
    embedded_registry: Arc<EmbeddedSchemaRegistry>,
}
 
impl EmbeddedSchemaDiscoveryHandler {
    pub fn new() -> Self {
        Self {
            embedded_registry: Arc::new(EmbeddedSchemaRegistry::default()),
        }
    }
}
 
#[async_trait]
impl SchemaDiscoveryHandler for EmbeddedSchemaDiscoveryHandler {
    async fn discover_schemas(&self, module_name: &str) -> Result<Option<Vec<DiscoveredSchemaFile>>> {
        if let Some(embedded_schema) = self.embedded_registry.get_schema(module_name) {
            return Ok(Some(vec![DiscoveredSchemaFile {
                path: PathBuf::from(format!("embedded://{}.schema.toml", module_name)),
                source: SchemaSource::Embedded,
                format: SchemaFormat::Toml,
                priority: 4,
            }]));
        }
        Ok(None)
    }
    
    fn priority(&self) -> u8 { 4 }
    fn name(&self) -> &'static str { "Embedded Schema Discovery" }
}
 
/// Registry for embedded schemas compiled into the binary
pub struct EmbeddedSchemaRegistry {
    schemas: HashMap<String, &'static str>,
}
 
impl Default for EmbeddedSchemaRegistry {
    fn default() -> Self {
        let mut schemas = HashMap::new();
        
        // Built-in schemas for core modules
        schemas.insert("global".to_string(), include_str!("../schemas/global.schema.toml"));
        schemas.insert("agent-identity".to_string(), include_str!("../schemas/agent-identity.schema.toml"));
        schemas.insert("memory-systems".to_string(), include_str!("../schemas/memory-systems.schema.toml"));
        schemas.insert("context-management".to_string(), include_str!("../schemas/context-management.schema.toml"));
        schemas.insert("environment-awareness".to_string(), include_str!("../schemas/environment-awareness.schema.toml"));
        schemas.insert("observability".to_string(), include_str!("../schemas/observability.schema.toml"));
        schemas.insert("tools-mcp".to_string(), include_str!("../schemas/tools-mcp.schema.toml"));
        schemas.insert("agent-interface".to_string(), include_str!("../schemas/agent-interface.schema.toml"));
        
        Self { schemas }
    }
}
 
impl EmbeddedSchemaRegistry {
    pub fn get_schema(&self, module_name: &str) -> Option<&'static str> {
        self.schemas.get(module_name).copied()
    }
    
    pub fn register_schema(&mut self, module_name: String, schema_content: &'static str) {
        self.schemas.insert(module_name, schema_content);
    }
}
 
/// Schema Manager implementation
impl SchemaManager {
    pub fn new(
        discovery_engine: SchemaDiscoveryEngine,
        loader: SchemaLoader,
        validator: SchemaValidator,
    ) -> Self {
        Self {
            schema_cache: Arc::new(RwLock::new(HashMap::new())),
            schema_discovery: discovery_engine,
            schema_loader: loader,
            schema_validator: validator,
        }
    }
    
    /// Load a schema for the specified module
    pub async fn load_schema(&self, module_name: &str) -> Result<SchemaDefinition> {
        let cache_key = format!("{}:latest", module_name);
        
        // Check cache first
        {
            let cache = self.schema_cache.read().await;
            if let Some(cached) = cache.get(&cache_key) {
                // Check if cache is still valid (e.g., not expired)
                if cached.loaded_at.elapsed() < std::time::Duration::from_secs(300) {
                    return Ok(cached.definition.clone());
                }
            }
        }
        
        // Discover schema files
        let discovered_files = self.schema_discovery.discover_schema_files(module_name).await?;
        
        if discovered_files.is_empty() {
            return Err(anyhow::anyhow!("No schema found for module: {}", module_name));
        }
        
        // Load the highest priority schema
        let primary_schema_file = discovered_files
            .iter()
            .min_by_key(|file| file.priority)
            .unwrap();
        
        let schema_definition = self.schema_loader
            .load_schema_file(&primary_schema_file.path)
            .await?;
        
        // Validate schema
        self.schema_validator.validate_schema(&schema_definition).await?;
        
        // Process inheritance if specified
        let final_schema = if let Some(inheritance) = &schema_definition.metadata.inheritance {
            self.process_schema_inheritance(&schema_definition, inheritance).await?
        } else {
            schema_definition
        };
        
        // Cache the loaded schema
        {
            let mut cache = self.schema_cache.write().await;
            cache.insert(cache_key, CachedSchema {
                metadata: final_schema.metadata.clone(),
                definition: final_schema.clone(),
                loaded_at: std::time::Instant::now(),
                dependencies: final_schema.metadata.dependencies.required_schemas.clone(),
            });
        }
        
        Ok(final_schema)
    }
    
    /// Process schema inheritance by loading and merging parent schemas
    async fn process_schema_inheritance(
        &self,
        child_schema: &SchemaDefinition,
        inheritance: &SchemaInheritance,
    ) -> Result<SchemaDefinition> {
        // Load parent schema
        let parent_schema = self.load_schema(&inheritance.parent_schema).await?;
        
        // Merge schemas based on override mode
        match inheritance.override_mode {
            OverrideMode::DeepMerge => {
                self.deep_merge_schemas(&parent_schema, child_schema, inheritance).await
            },
            OverrideMode::ShallowMerge => {
                self.shallow_merge_schemas(&parent_schema, child_schema, inheritance).await
            },
            OverrideMode::SelectiveMerge => {
                self.selective_merge_schemas(&parent_schema, child_schema, inheritance).await
            },
            OverrideMode::Replace => {
                Ok(child_schema.clone())
            },
        }
    }
    
    async fn deep_merge_schemas(
        &self,
        parent: &SchemaDefinition,
        child: &SchemaDefinition,
        inheritance: &SchemaInheritance,
    ) -> Result<SchemaDefinition> {
        // Implementation for deep merging schemas
        // This would recursively merge all schema sections
        todo!("Implement deep schema merging")
    }
    
    async fn shallow_merge_schemas(
        &self,
        parent: &SchemaDefinition,
        child: &SchemaDefinition,
        inheritance: &SchemaInheritance,
    ) -> Result<SchemaDefinition> {
        // Implementation for shallow merging schemas
        // This would merge only top-level sections
        todo!("Implement shallow schema merging")
    }
    
    async fn selective_merge_schemas(
        &self,
        parent: &SchemaDefinition,
        child: &SchemaDefinition,
        inheritance: &SchemaInheritance,
    ) -> Result<SchemaDefinition> {
        // Implementation for selective merging schemas
        // This would merge only specified fields
        todo!("Implement selective schema merging")
    }
}
 
/// Schema-aware discovery handler trait
#[async_trait]
pub trait SchemaDiscoveryHandler: Send + Sync {
    async fn discover_schemas(&self, module_name: &str) -> Result<Option<Vec<DiscoveredSchemaFile>>>;
    fn priority(&self) -> u8;
    fn name(&self) -> &'static str;
}
 
/// Discovered schema file information
#[derive(Debug, Clone)]
pub struct DiscoveredSchemaFile {
    pub path: PathBuf,
    pub source: SchemaSource,
    pub format: SchemaFormat,
    pub priority: u8,
}
 
#[derive(Debug, Clone, PartialEq)]
pub enum SchemaSource {
    Project,
    User,
    System,
    Embedded,
    Remote,
}
 
#[derive(Debug, Clone, PartialEq)]
pub enum SchemaFormat {
    Toml,
    Yaml,
    Json,
}
 
impl SchemaFormat {
    fn from_extension(filename: &str) -> Result<Self> {
        match filename.split('.').last() {
            Some("toml") => Ok(SchemaFormat::Toml),
            Some("yaml") | Some("yml") => Ok(SchemaFormat::Yaml),
            Some("json") => Ok(SchemaFormat::Json),
            _ => Err(anyhow::anyhow!("Unsupported schema format")),
        }
    }
}
 
/// Complete schema definition structure
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SchemaDefinition {
    pub metadata: SchemaMetadata,
    pub config_structure: ConfigStructure,
    pub validation_rules: ValidationRules,
}
 
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConfigStructure {
    pub fields: HashMap<String, FieldDefinition>,
    pub sections: HashMap<String, SectionDefinition>,
}
 
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FieldDefinition {
    pub field_type: FieldType,
    pub required: bool,
    pub default_value: Option<serde_json::Value>,
    pub validation: Option<FieldValidation>,
    pub description: String,
    pub sensitive: bool,
    pub encrypted: bool,
}
 
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum FieldType {
    String,
    Integer,
    Float,
    Boolean,
    Array(Box<FieldType>),
    Object(ConfigStructure),
    Enum(Vec<String>),
    Duration,
    Url,
    Path,
}
 
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FieldValidation {
    pub pattern: Option<String>,
    pub min_length: Option<usize>,
    pub max_length: Option<usize>,
    pub min_value: Option<f64>,
    pub max_value: Option<f64>,
    pub custom_validator: Option<String>,
}
 
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SectionDefinition {
    pub required: bool,
    pub fields: HashMap<String, FieldDefinition>,
    pub subsections: HashMap<String, SectionDefinition>,
    pub description: String,
}
 
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidationRules {
    pub field_rules: HashMap<String, Vec<ValidationRule>>,
    pub section_rules: HashMap<String, Vec<ValidationRule>>,
    pub global_rules: Vec<ValidationRule>,
}
 
/// Discovery handler trait for chain of responsibility
/// **Pattern Applied: Chain of Responsibility Pattern**
#[async_trait]
pub trait DiscoveryHandler: Send + Sync {
    async fn discover(&self, module_name: &str) -> Result<Option<Vec<DiscoveredFile>>>;
    async fn discover_with_schema(
        &self, 
        module_name: &str, 
        schema: &SchemaDefinition
    ) -> Result<Option<Vec<DiscoveredFile>>> {
        // Default implementation falls back to standard discovery
        self.discover(module_name).await
    }
    async fn discover_schemas(&self, module_name: &str) -> Result<Option<Vec<DiscoveredSchemaFile>>> {
        // Default implementation returns None for non-schema handlers
        Ok(None)
    }
    fn priority(&self) -> u8;
    fn name(&self) -> &'static str;
}
 
/// Current directory discovery handler
pub struct CurrentDirectoryHandler {
    format_precedence: Vec<ConfigurationFormat>,
}
 
#[async_trait]
impl DiscoveryHandler for CurrentDirectoryHandler {
    async fn discover(&self, module_name: &str) -> Result<Option<Vec<DiscoveredFile>>> {
        let current_dir = std::env::current_dir()
            .context("Failed to get current directory")?;
        
        for format in &self.format_precedence {
            let filename = format!("{}.{}", module_name, format.extension());
            let config_path = current_dir.join(&filename);
            
            if config_path.exists() {
                return Ok(Some(vec![DiscoveredFile {
                    path: config_path,
                    format: *format,
                    source: DiscoverySource::CurrentDirectory,
                    priority: self.priority(),
                }]));
            }
        }
        
        Ok(None)
    }
    
    fn priority(&self) -> u8 { 1 }
    fn name(&self) -> &'static str { "CurrentDirectory" }
}
 
/// Home directory discovery handler
pub struct HomeDirectoryHandler {
    format_precedence: Vec<ConfigurationFormat>,
}
 
#[async_trait]
impl DiscoveryHandler for HomeDirectoryHandler {
    async fn discover(&self, module_name: &str) -> Result<Option<Vec<DiscoveredFile>>> {
        let home_dir = dirs::home_dir()
            .context("Failed to get home directory")?;
        let sindhan_dir = home_dir.join(".sindhan");
        
        if !sindhan_dir.exists() {
            return Ok(None);
        }
        
        for format in &self.format_precedence {
            let filename = format!("{}.{}", module_name, format.extension());
            let config_path = sindhan_dir.join(&filename);
            
            if config_path.exists() {
                return Ok(Some(vec![DiscoveredFile {
                    path: config_path,
                    format: *format,
                    source: DiscoverySource::HomeDirectory,
                    priority: self.priority(),
                }]));
            }
        }
        
        Ok(None)
    }
    
    fn priority(&self) -> u8 { 2 }
    fn name(&self) -> &'static str { "HomeDirectory" }
}
 
/// Environment directory discovery handler
pub struct EnvironmentDirectoryHandler {
    format_precedence: Vec<ConfigurationFormat>,
}
 
#[async_trait]
impl DiscoveryHandler for EnvironmentDirectoryHandler {
    async fn discover(&self, module_name: &str) -> Result<Option<Vec<DiscoveredFile>>> {
        let env_dir = match std::env::var("SINDHAN_CONFIG_DIR") {
            Ok(dir) => PathBuf::from(dir),
            Err(_) => return Ok(None),
        };
        
        if !env_dir.exists() {
            return Ok(None);
        }
        
        for format in &self.format_precedence {
            let filename = format!("{}.{}", module_name, format.extension());
            let config_path = env_dir.join(&filename);
            
            if config_path.exists() {
                return Ok(Some(vec![DiscoveredFile {
                    path: config_path,
                    format: *format,
                    source: DiscoverySource::EnvironmentDirectory,
                    priority: self.priority(),
                }]));
            }
        }
        
        Ok(None)
    }
    
    fn priority(&self) -> u8 { 3 }
    fn name(&self) -> &'static str { "EnvironmentDirectory" }
}

Format Parser Factory

/// Factory for creating format-specific parsers
/// **Pattern Applied: Factory Pattern**
pub struct FormatParserFactory {
    parsers: HashMap<ConfigurationFormat, Box<dyn ConfigurationParser>>,
}
 
impl FormatParserFactory {
    pub fn new() -> Self {
        let mut parsers: HashMap<ConfigurationFormat, Box<dyn ConfigurationParser>> = HashMap::new();
        
        parsers.insert(ConfigurationFormat::Toml, Box::new(TomlParser::new()));
        parsers.insert(ConfigurationFormat::Yaml, Box::new(YamlParser::new()));
        parsers.insert(ConfigurationFormat::Json, Box::new(JsonParser::new()));
        
        Self { parsers }
    }
    
    pub fn create_parser(&self, format: ConfigurationFormat) -> Result<&dyn ConfigurationParser> {
        self.parsers.get(&format)
            .map(|p| p.as_ref())
            .context(format!("No parser available for format: {:?}", format))
    }
    
    /// Register a custom parser
    pub fn register_parser(&mut self, format: ConfigurationFormat, parser: Box<dyn ConfigurationParser>) {
        self.parsers.insert(format, parser);
    }
}
 
/// Configuration parser trait
/// **Pattern Applied: Strategy Pattern**
#[async_trait]
pub trait ConfigurationParser: Send + Sync {
    async fn parse<T>(&self, content: &str) -> Result<T> 
    where 
        T: for<'de> Deserialize<'de>;
    
    fn format(&self) -> ConfigurationFormat;
    fn can_parse(&self, content: &str) -> bool;
}
 
/// TOML parser implementation
pub struct TomlParser;
 
impl TomlParser {
    pub fn new() -> Self {
        Self
    }
}
 
#[async_trait]
impl ConfigurationParser for TomlParser {
    async fn parse<T>(&self, content: &str) -> Result<T> 
    where 
        T: for<'de> Deserialize<'de>
    {
        toml::from_str(content)
            .context("Failed to parse TOML configuration")
    }
    
    fn format(&self) -> ConfigurationFormat {
        ConfigurationFormat::Toml
    }
    
    fn can_parse(&self, content: &str) -> bool {
        // Simple heuristic - check for TOML-specific syntax
        content.contains('[') && content.contains('=') && !content.contains('{')
    }
}
 
/// YAML parser implementation
pub struct YamlParser;
 
impl YamlParser {
    pub fn new() -> Self {
        Self
    }
}
 
#[async_trait]
impl ConfigurationParser for YamlParser {
    async fn parse<T>(&self, content: &str) -> Result<T> 
    where 
        T: for<'de> Deserialize<'de>
    {
        serde_yaml::from_str(content)
            .context("Failed to parse YAML configuration")
    }
    
    fn format(&self) -> ConfigurationFormat {
        ConfigurationFormat::Yaml
    }
    
    fn can_parse(&self, content: &str) -> bool {
        // Simple heuristic - check for YAML-specific syntax
        content.contains(':') && (content.contains("---") || content.contains("  "))
    }
}
 
/// JSON parser implementation
pub struct JsonParser;
 
impl JsonParser {
    pub fn new() -> Self {
        Self
    }
}
 
#[async_trait]
impl ConfigurationParser for JsonParser {
    async fn parse<T>(&self, content: &str) -> Result<T> 
    where 
        T: for<'de> Deserialize<'de>
    {
        serde_json::from_str(content)
            .context("Failed to parse JSON configuration")
    }
    
    fn format(&self) -> ConfigurationFormat {
        ConfigurationFormat::Json
    }
    
    fn can_parse(&self, content: &str) -> bool {
        // Simple heuristic - check for JSON-specific syntax
        content.trim().starts_with('{') && content.trim().ends_with('}')
    }
}

Configuration Merge Strategies

/// Configuration merge strategy trait
/// **Pattern Applied: Strategy Pattern**
pub trait MergeStrategy<T>: Send + Sync {
    fn merge(&self, base: T, override_config: T) -> Result<T>;
    fn strategy_name(&self) -> &'static str;
    fn supports_type(&self) -> bool;
}
 
/// Deep merge strategy for complex nested configurations
pub struct DeepMergeStrategy;
 
impl<T> MergeStrategy<T> for DeepMergeStrategy 
where 
    T: Serialize + for<'de> Deserialize<'de> + Clone
{
    fn merge(&self, base: T, override_config: T) -> Result<T> {
        // Convert to JSON values for deep merging
        let mut base_value: serde_json::Value = serde_json::to_value(base)?;
        let override_value: serde_json::Value = serde_json::to_value(override_config)?;
        
        self.deep_merge_values(&mut base_value, override_value);
        
        // Convert back to the target type
        serde_json::from_value(base_value)
            .context("Failed to deserialize merged configuration")
    }
    
    fn strategy_name(&self) -> &'static str {
        "DeepMerge"
    }
    
    fn supports_type(&self) -> bool {
        true
    }
}
 
impl DeepMergeStrategy {
    fn deep_merge_values(&self, base: &mut serde_json::Value, override_val: serde_json::Value) {
        match (base, override_val) {
            (serde_json::Value::Object(base_map), serde_json::Value::Object(override_map)) => {
                for (key, value) in override_map {
                    match base_map.entry(key) {
                        serde_json::map::Entry::Occupied(mut entry) => {
                            self.deep_merge_values(entry.get_mut(), value);
                        }
                        serde_json::map::Entry::Vacant(entry) => {
                            entry.insert(value);
                        }
                    }
                }
            }
            (base_val, override_val) => {
                *base_val = override_val;
            }
        }
    }
}
 
/// Shallow merge strategy for simple configurations
pub struct ShallowMergeStrategy;
 
impl<T> MergeStrategy<T> for ShallowMergeStrategy 
where 
    T: Serialize + for<'de> Deserialize<'de> + Clone
{
    fn merge(&self, _base: T, override_config: T) -> Result<T> {
        // Shallow merge simply returns the override configuration
        Ok(override_config)
    }
    
    fn strategy_name(&self) -> &'static str {
        "ShallowMerge"
    }
    
    fn supports_type(&self) -> bool {
        true
    }
}
 
/// Array append strategy for configurations with array values
pub struct ArrayAppendStrategy;
 
impl<T> MergeStrategy<T> for ArrayAppendStrategy 
where 
    T: Serialize + for<'de> Deserialize<'de> + Clone
{
    fn merge(&self, base: T, override_config: T) -> Result<T> {
        let mut base_value: serde_json::Value = serde_json::to_value(base)?;
        let override_value: serde_json::Value = serde_json::to_value(override_config)?;
        
        self.append_arrays(&mut base_value, override_value);
        
        serde_json::from_value(base_value)
            .context("Failed to deserialize merged configuration")
    }
    
    fn strategy_name(&self) -> &'static str {
        "ArrayAppend"
    }
    
    fn supports_type(&self) -> bool {
        true
    }
}
 
impl ArrayAppendStrategy {
    fn append_arrays(&self, base: &mut serde_json::Value, override_val: serde_json::Value) {
        match (base, override_val) {
            (serde_json::Value::Array(base_array), serde_json::Value::Array(override_array)) => {
                base_array.extend(override_array);
            }
            (serde_json::Value::Object(base_map), serde_json::Value::Object(override_map)) => {
                for (key, value) in override_map {
                    match base_map.entry(key) {
                        serde_json::map::Entry::Occupied(mut entry) => {
                            self.append_arrays(entry.get_mut(), value);
                        }
                        serde_json::map::Entry::Vacant(entry) => {
                            entry.insert(value);
                        }
                    }
                }
            }
            (base_val, override_val) => {
                *base_val = override_val;
            }
        }
    }
}

Configuration Manager

/// Main configuration manager implementing multiple patterns
/// **Pattern Applied: Singleton Pattern, Observer Pattern**
pub struct ConfigurationManager<T: ConfigurationSchema> {
    config: Arc<RwLock<T::ConfigType>>,
    discovery: ConfigurationDiscovery,
    observers: Arc<RwLock<Vec<Arc<dyn ConfigurationObserver>>>>,
    merge_strategy: Box<dyn MergeStrategy<T::ConfigType>>,
    validator: ValidationPipeline<T::ConfigType>,
    hot_reload_enabled: bool,
    _file_watcher: Option<tokio::task::JoinHandle<()>>,
}
 
impl<T: ConfigurationSchema> ConfigurationManager<T> {
    /// **Pattern Applied: Builder Pattern**
    pub fn builder() -> ConfigurationManagerBuilder<T> {
        ConfigurationManagerBuilder::new()
    }
    
    pub async fn load_configuration(&self) -> Result<()> {
        let config = T::load_configuration(&self.discovery).await?;
        
        // Validate the loaded configuration
        let validation_result = self.validator.validate(&config).await?;
        
        if !validation_result.is_valid() {
            return Err(anyhow::anyhow!("Configuration validation failed: {:?}", validation_result.errors()));
        }
        
        // Update the configuration
        let mut config_guard = self.config.write().await;
        *config_guard = config.clone();
        drop(config_guard);
        
        // Notify observers
        self.notify_observers(ConfigurationChange::Loaded { config }).await?;
        
        Ok(())
    }
    
    pub async fn get_configuration(&self) -> T::ConfigType {
        self.config.read().await.clone()
    }
    
    pub async fn update_configuration(&self, new_config: T::ConfigType) -> Result<()> {
        // Validate the new configuration
        let validation_result = self.validator.validate(&new_config).await?;
        
        if !validation_result.is_valid() {
            return Err(anyhow::anyhow!("Configuration validation failed: {:?}", validation_result.errors()));
        }
        
        let old_config = {
            let mut config_guard = self.config.write().await;
            let old = config_guard.clone();
            *config_guard = new_config.clone();
            old
        };
        
        // Notify observers
        self.notify_observers(ConfigurationChange::Updated { 
            old_config, 
            new_config 
        }).await?;
        
        Ok(())
    }
    
    /// **Pattern Applied: Observer Pattern**
    pub async fn add_observer(&self, observer: Arc<dyn ConfigurationObserver>) {
        let mut observers = self.observers.write().await;
        observers.push(observer);
    }
    
    async fn notify_observers(&self, change: ConfigurationChange) -> Result<()> {
        let observers = self.observers.read().await;
        
        for observer in observers.iter() {
            if let Err(e) = observer.on_configuration_changed(change.clone()).await {
                eprintln!("Observer notification failed: {}", e);
            }
        }
        
        Ok(())
    }
    
    async fn start_file_watcher(&self) -> Result<tokio::task::JoinHandle<()>> {
        // File watching implementation would go here
        // This is a placeholder for the actual file watching logic
        Ok(tokio::spawn(async {
            // File watching loop
        }))
    }
}
 
/// Builder for configuration manager
/// **Pattern Applied: Builder Pattern**
pub struct ConfigurationManagerBuilder<T: ConfigurationSchema> {
    discovery_builder: Option<ConfigurationDiscoveryBuilder>,
    merge_strategy: Option<Box<dyn MergeStrategy<T::ConfigType>>>,
    validation_rules: Vec<Box<dyn ValidationRule<T::ConfigType>>>,
    hot_reload_enabled: bool,
    initial_observers: Vec<Arc<dyn ConfigurationObserver>>,
}
 
impl<T: ConfigurationSchema> ConfigurationManagerBuilder<T> {
    pub fn new() -> Self {
        Self {
            discovery_builder: None,
            merge_strategy: None,
            validation_rules: T::validation_rules(),
            hot_reload_enabled: false,
            initial_observers: Vec::new(),
        }
    }
    
    pub fn with_discovery(mut self, discovery_builder: ConfigurationDiscoveryBuilder) -> Self {
        self.discovery_builder = Some(discovery_builder);
        self
    }
    
    pub fn with_merge_strategy(mut self, strategy: Box<dyn MergeStrategy<T::ConfigType>>) -> Self {
        self.merge_strategy = Some(strategy);
        self
    }
    
    pub fn add_validation_rule(mut self, rule: Box<dyn ValidationRule<T::ConfigType>>) -> Self {
        self.validation_rules.push(rule);
        self
    }
    
    pub fn enable_hot_reload(mut self) -> Self {
        self.hot_reload_enabled = true;
        self
    }
    
    pub fn add_observer(mut self, observer: Arc<dyn ConfigurationObserver>) -> Self {
        self.initial_observers.push(observer);
        self
    }
    
    pub async fn build(self) -> Result<ConfigurationManager<T>> {
        let discovery = self.discovery_builder
            .unwrap_or_else(|| ConfigurationDiscovery::builder())
            .build()?;
        
        let merge_strategy = self.merge_strategy
            .unwrap_or_else(|| Box::new(DeepMergeStrategy));
        
        let validator = ValidationPipeline::new(self.validation_rules);
        
        let config = Arc::new(RwLock::new(T::default_configuration()));
        let observers = Arc::new(RwLock::new(self.initial_observers));
        
        let mut manager = ConfigurationManager {
            config,
            discovery,
            observers,
            merge_strategy,
            validator,
            hot_reload_enabled: self.hot_reload_enabled,
            _file_watcher: None,
        };
        
        if manager.hot_reload_enabled {
            let file_watcher = manager.start_file_watcher().await?;
            manager._file_watcher = Some(file_watcher);
        }
        
        Ok(manager)
    }
}

Validation Pipeline

/// Validation pipeline implementing chain of responsibility
/// **Pattern Applied: Chain of Responsibility Pattern**
pub struct ValidationPipeline<T> {
    validators: Vec<Box<dyn ValidationRule<T>>>,
}
 
impl<T> ValidationPipeline<T> {
    pub fn new(validators: Vec<Box<dyn ValidationRule<T>>>) -> Self {
        Self { validators }
    }
    
    pub async fn validate(&self, config: &T) -> Result<ValidationResult> {
        let mut results = Vec::new();
        let mut has_errors = false;
        
        for validator in &self.validators {
            match validator.validate(config) {
                Ok(result) => {
                    if result.severity == ValidationSeverity::Error {
                        has_errors = true;
                    }
                    results.push(result);
                }
                Err(e) => {
                    has_errors = true;
                    results.push(ValidationResult {
                        rule_name: validator.name().to_string(),
                        message: format!("Validation rule failed: {}", e),
                        severity: ValidationSeverity::Error,
                        field_path: None,
                    });
                }
            }
        }
        
        Ok(ValidationResult::aggregate(results, !has_errors))
    }
    
    pub fn add_validator(&mut self, validator: Box<dyn ValidationRule<T>>) {
        self.validators.push(validator);
    }
}
 
/// Example validation rules
pub struct RequiredFieldValidator {
    field_name: String,
}
 
impl RequiredFieldValidator {
    pub fn new(field_name: String) -> Self {
        Self { field_name }
    }
}
 
impl<T> ValidationRule<T> for RequiredFieldValidator 
where 
    T: Serialize
{
    fn name(&self) -> &'static str {
        "RequiredField"
    }
    
    fn validate(&self, config: &T) -> Result<ValidationResult> {
        let value = serde_json::to_value(config)?;
        
        if let Some(obj) = value.as_object() {
            if obj.contains_key(&self.field_name) {
                Ok(ValidationResult {
                    rule_name: self.name().to_string(),
                    message: format!("Required field '{}' is present", self.field_name),
                    severity: ValidationSeverity::Info,
                    field_path: Some(self.field_name.clone()),
                })
            } else {
                Ok(ValidationResult {
                    rule_name: self.name().to_string(),
                    message: format!("Required field '{}' is missing", self.field_name),
                    severity: ValidationSeverity::Error,
                    field_path: Some(self.field_name.clone()),
                })
            }
        } else {
            Ok(ValidationResult {
                rule_name: self.name().to_string(),
                message: "Configuration is not an object".to_string(),
                severity: ValidationSeverity::Error,
                field_path: None,
            })
        }
    }
    
    fn severity(&self) -> ValidationSeverity {
        ValidationSeverity::Error
    }
}
 
/// Range validation rule
pub struct RangeValidator {
    field_name: String,
    min_value: f64,
    max_value: f64,
}
 
impl RangeValidator {
    pub fn new(field_name: String, min_value: f64, max_value: f64) -> Self {
        Self { field_name, min_value, max_value }
    }
}
 
impl<T> ValidationRule<T> for RangeValidator 
where 
    T: Serialize
{
    fn name(&self) -> &'static str {
        "Range"
    }
    
    fn validate(&self, config: &T) -> Result<ValidationResult> {
        let value = serde_json::to_value(config)?;
        
        if let Some(obj) = value.as_object() {
            if let Some(field_value) = obj.get(&self.field_name) {
                if let Some(num) = field_value.as_f64() {
                    if num >= self.min_value && num <= self.max_value {
                        Ok(ValidationResult {
                            rule_name: self.name().to_string(),
                            message: format!("Field '{}' is within range [{}, {}]", self.field_name, self.min_value, self.max_value),
                            severity: ValidationSeverity::Info,
                            field_path: Some(self.field_name.clone()),
                        })
                    } else {
                        Ok(ValidationResult {
                            rule_name: self.name().to_string(),
                            message: format!("Field '{}' value {} is outside range [{}, {}]", self.field_name, num, self.min_value, self.max_value),
                            severity: ValidationSeverity::Error,
                            field_path: Some(self.field_name.clone()),
                        })
                    }
                } else {
                    Ok(ValidationResult {
                        rule_name: self.name().to_string(),
                        message: format!("Field '{}' is not a number", self.field_name),
                        severity: ValidationSeverity::Error,
                        field_path: Some(self.field_name.clone()),
                    })
                }
            } else {
                Ok(ValidationResult {
                    rule_name: self.name().to_string(),
                    message: format!("Field '{}' not found for range validation", self.field_name),
                    severity: ValidationSeverity::Warning,
                    field_path: Some(self.field_name.clone()),
                })
            }
        } else {
            Ok(ValidationResult {
                rule_name: self.name().to_string(),
                message: "Configuration is not an object".to_string(),
                severity: ValidationSeverity::Error,
                field_path: None,
            })
        }
    }
    
    fn severity(&self) -> ValidationSeverity {
        ValidationSeverity::Error
    }
}

Configuration Decorators and Adapters

/// Configuration decorator for adding encryption support
/// **Pattern Applied: Decorator Pattern**
pub struct EncryptedConfigurationDecorator<T: ConfigurationSchema> {
    inner: Arc<ConfigurationManager<T>>,
    encryption_key: Vec<u8>,
    encrypted_fields: Vec<String>,
}
 
impl<T: ConfigurationSchema> EncryptedConfigurationDecorator<T> {
    pub fn new(
        inner: Arc<ConfigurationManager<T>>, 
        encryption_key: Vec<u8>,
        encrypted_fields: Vec<String>
    ) -> Self {
        Self {
            inner,
            encryption_key,
            encrypted_fields,
        }
    }
    
    pub async fn get_configuration(&self) -> Result<T::ConfigType> {
        let mut config = self.inner.get_configuration().await;
        
        // Decrypt encrypted fields
        self.decrypt_fields(&mut config)?;
        
        Ok(config)
    }
    
    pub async fn update_configuration(&self, mut config: T::ConfigType) -> Result<()> {
        // Encrypt sensitive fields before storing
        self.encrypt_fields(&mut config)?;
        
        self.inner.update_configuration(config).await
    }
    
    fn encrypt_fields(&self, config: &mut T::ConfigType) -> Result<()> {
        let mut value = serde_json::to_value(&*config)?;
        
        for field_path in &self.encrypted_fields {
            if let Some(field_value) = self.get_field_mut(&mut value, field_path) {
                if let Some(string_value) = field_value.as_str() {
                    let encrypted = self.encrypt_string(string_value)?;
                    *field_value = serde_json::Value::String(encrypted);
                }
            }
        }
        
        *config = serde_json::from_value(value)?;
        Ok(())
    }
    
    fn decrypt_fields(&self, config: &mut T::ConfigType) -> Result<()> {
        let mut value = serde_json::to_value(&*config)?;
        
        for field_path in &self.encrypted_fields {
            if let Some(field_value) = self.get_field_mut(&mut value, field_path) {
                if let Some(string_value) = field_value.as_str() {
                    let decrypted = self.decrypt_string(string_value)?;
                    *field_value = serde_json::Value::String(decrypted);
                }
            }
        }
        
        *config = serde_json::from_value(value)?;
        Ok(())
    }
    
    fn get_field_mut<'a>(&self, value: &'a mut serde_json::Value, path: &str) -> Option<&'a mut serde_json::Value> {
        let parts: Vec<&str> = path.split('.').collect();
        let mut current = value;
        
        for part in parts {
            current = current.get_mut(part)?;
        }
        
        Some(current)
    }
    
    fn encrypt_string(&self, input: &str) -> Result<String> {
        // Placeholder encryption - in real implementation, use proper encryption
        let encrypted = base64::encode(format!("ENCRYPTED:{}", input));
        Ok(encrypted)
    }
    
    fn decrypt_string(&self, input: &str) -> Result<String> {
        // Placeholder decryption - in real implementation, use proper decryption
        let decoded = base64::decode(input)?;
        let decoded_str = String::from_utf8(decoded)?;
        
        if let Some(stripped) = decoded_str.strip_prefix("ENCRYPTED:") {
            Ok(stripped.to_string())
        } else {
            Ok(input.to_string()) // Return as-is if not encrypted
        }
    }
}
 
/// Adapter for external configuration sources
/// **Pattern Applied: Adapter Pattern**
pub struct ExternalConfigurationAdapter {
    source_url: String,
    client: reqwest::Client,
    auth_token: Option<String>,
}
 
impl ExternalConfigurationAdapter {
    pub fn new(source_url: String, auth_token: Option<String>) -> Self {
        Self {
            source_url,
            client: reqwest::Client::new(),
            auth_token,
        }
    }
    
    pub async fn fetch_configuration<T>(&self) -> Result<T> 
    where 
        T: for<'de> Deserialize<'de>
    {
        let mut request = self.client.get(&self.source_url);
        
        if let Some(token) = &self.auth_token {
            request = request.bearer_auth(token);
        }
        
        let response = request.send().await?;
        let config: T = response.json().await?;
        
        Ok(config)
    }
}
 
/// External configuration source adapter implementing the discovery handler interface
/// **Pattern Applied: Adapter Pattern**
pub struct ExternalSourceAdapter {
    adapter: ExternalConfigurationAdapter,
    cache_duration: std::time::Duration,
    last_fetch: Arc<RwLock<Option<std::time::Instant>>>,
    cached_config: Arc<RwLock<Option<serde_json::Value>>>,
}
 
#[async_trait]
impl DiscoveryHandler for ExternalSourceAdapter {
    async fn discover(&self, module_name: &str) -> Result<Option<Vec<DiscoveredFile>>> {
        // Check cache validity
        let should_fetch = {
            let last_fetch = self.last_fetch.read().await;
            match *last_fetch {
                Some(time) => time.elapsed() > self.cache_duration,
                None => true,
            }
        };
        
        if should_fetch {
            // Fetch fresh configuration
            let config: serde_json::Value = self.adapter.fetch_configuration().await?;
            
            // Update cache
            {
                let mut cached = self.cached_config.write().await;
                *cached = Some(config);
            }
            {
                let mut last_fetch = self.last_fetch.write().await;
                *last_fetch = Some(std::time::Instant::now());
            }
        }
        
        // Return cached configuration as a virtual file
        let cached_config = self.cached_config.read().await;
        if let Some(config) = cached_config.as_ref() {
            let content = serde_json::to_string_pretty(config)?;
            
            Ok(Some(vec![DiscoveredFile {
                path: PathBuf::from(format!("external://{}", module_name)),
                format: ConfigurationFormat::Json,
                source: DiscoverySource::External,
                priority: 10, // Lower priority than local files
            }]))
        } else {
            Ok(None)
        }
    }
    
    fn priority(&self) -> u8 { 10 }
    fn name(&self) -> &'static str { "ExternalSource" }
}

Configuration Commands and Undo Support

/// Command pattern for configuration operations
/// **Pattern Applied: Command Pattern**
pub trait ConfigurationCommand: Send + Sync {
    fn execute(&self) -> Result<ConfigurationCommandResult>;
    fn undo(&self) -> Result<ConfigurationCommandResult>;
    fn description(&self) -> String;
    fn command_id(&self) -> String;
}
 
/// Update configuration command
pub struct UpdateConfigurationCommand<T: ConfigurationSchema> {
    manager: Arc<ConfigurationManager<T>>,
    new_config: T::ConfigType,
    old_config: Option<T::ConfigType>,
    command_id: String,
}
 
impl<T: ConfigurationSchema> UpdateConfigurationCommand<T> {
    pub fn new(manager: Arc<ConfigurationManager<T>>, new_config: T::ConfigType) -> Self {
        Self {
            manager,
            new_config,
            old_config: None,
            command_id: uuid::Uuid::new_v4().to_string(),
        }
    }
}
 
impl<T: ConfigurationSchema> ConfigurationCommand for UpdateConfigurationCommand<T> {
    fn execute(&self) -> Result<ConfigurationCommandResult> {
        // This would need to be made async in a real implementation
        // For now, this is a synchronous placeholder
        
        Ok(ConfigurationCommandResult {
            command_id: self.command_id.clone(),
            success: true,
            message: "Configuration updated successfully".to_string(),
            timestamp: chrono::Utc::now(),
        })
    }
    
    fn undo(&self) -> Result<ConfigurationCommandResult> {
        if let Some(old_config) = &self.old_config {
            // Restore previous configuration
            Ok(ConfigurationCommandResult {
                command_id: self.command_id.clone(),
                success: true,
                message: "Configuration restored successfully".to_string(),
                timestamp: chrono::Utc::now(),
            })
        } else {
            Err(anyhow::anyhow!("Cannot undo: no previous configuration available"))
        }
    }
    
    fn description(&self) -> String {
        "Update configuration".to_string()
    }
    
    fn command_id(&self) -> String {
        self.command_id.clone()
    }
}
 
/// Configuration command invoker
/// **Pattern Applied: Command Pattern**
pub struct ConfigurationCommandInvoker {
    command_history: Vec<Box<dyn ConfigurationCommand>>,
    undo_stack: Vec<Box<dyn ConfigurationCommand>>,
}
 
impl ConfigurationCommandInvoker {
    pub fn new() -> Self {
        Self {
            command_history: Vec::new(),
            undo_stack: Vec::new(),
        }
    }
    
    pub fn execute_command(&mut self, command: Box<dyn ConfigurationCommand>) -> Result<ConfigurationCommandResult> {
        let result = command.execute()?;
        
        if result.success {
            self.command_history.push(command);
            self.undo_stack.clear(); // Clear redo stack when new command is executed
        }
        
        Ok(result)
    }
    
    pub fn undo_last_command(&mut self) -> Result<ConfigurationCommandResult> {
        if let Some(command) = self.command_history.pop() {
            let result = command.undo()?;
            
            if result.success {
                self.undo_stack.push(command);
            }
            
            Ok(result)
        } else {
            Err(anyhow::anyhow!("No commands to undo"))
        }
    }
    
    pub fn redo_last_command(&mut self) -> Result<ConfigurationCommandResult> {
        if let Some(command) = self.undo_stack.pop() {
            let result = command.execute()?;
            
            if result.success {
                self.command_history.push(command);
            }
            
            Ok(result)
        } else {
            Err(anyhow::anyhow!("No commands to redo"))
        }
    }
}

Usage Examples and Module Integration

/// Example module configuration demonstrating the usage patterns
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentIdentityConfig {
    pub identity_provider: String,
    pub certificate_path: String,
    pub key_rotation_interval: u64,
    pub authentication: AuthenticationConfig,
    pub security: SecurityConfig,
}
 
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuthenticationConfig {
    pub method: String,
    pub timeout_seconds: u32,
    pub max_retry_attempts: u8,
}
 
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityConfig {
    pub encryption_enabled: bool,
    pub secret_key: String,
    pub allowed_origins: Vec<String>,
}
 
/// Implementation of ConfigurationSchema for Agent Identity
impl ConfigurationSchema for AgentIdentityConfigSchema {
    type ConfigType = AgentIdentityConfig;
    
    fn schema_name() -> &'static str {
        "agent-identity"
    }
    
    fn schema_version() -> &'static str {
        "1.0.0"
    }
    
    fn default_configuration() -> Self::ConfigType {
        AgentIdentityConfig {
            identity_provider: "default".to_string(),
            certificate_path: "/etc/sindhan/certs/agent.crt".to_string(),
            key_rotation_interval: 86400, // 24 hours
            authentication: AuthenticationConfig {
                method: "jwt".to_string(),
                timeout_seconds: 30,
                max_retry_attempts: 3,
            },
            security: SecurityConfig {
                encryption_enabled: true,
                secret_key: "default-secret-key".to_string(),
                allowed_origins: vec!["localhost".to_string()],
            },
        }
    }
    
    fn validation_rules() -> Vec<Box<dyn ValidationRule<Self::ConfigType>>> {
        vec![
            Box::new(RequiredFieldValidator::new("identity_provider".to_string())),
            Box::new(RequiredFieldValidator::new("certificate_path".to_string())),
            Box::new(RangeValidator::new("key_rotation_interval".to_string(), 3600.0, 604800.0)), // 1 hour to 1 week
            Box::new(RangeValidator::new("authentication.timeout_seconds".to_string(), 1.0, 300.0)), // 1 second to 5 minutes
        ]
    }
    
    async fn parse_configurations(files: Vec<DiscoveredFile>) -> Result<Vec<Self::ConfigType>> {
        let mut configs = Vec::new();
        
        for file in files {
            let content = tokio::fs::read_to_string(&file.path).await?;
            let factory = FormatParserFactory::new();
            let parser = factory.create_parser(file.format)?;
            let config: Self::ConfigType = parser.parse(&content).await?;
            configs.push(config);
        }
        
        Ok(configs)
    }
    
    async fn merge_configurations(configs: Vec<Self::ConfigType>) -> Result<Self::ConfigType> {
        if configs.is_empty() {
            return Ok(Self::default_configuration());
        }
        
        let strategy = DeepMergeStrategy;
        let mut result = configs[0].clone();
        
        for config in configs.into_iter().skip(1) {
            result = strategy.merge(result, config)?;
        }
        
        Ok(result)
    }
    
    async fn validate_configuration(config: &Self::ConfigType) -> Result<()> {
        // Additional custom validation logic
        if config.authentication.timeout_seconds == 0 {
            return Err(anyhow::anyhow!("Authentication timeout cannot be zero"));
        }
        
        if config.security.secret_key.len() < 16 {
            return Err(anyhow::anyhow!("Secret key must be at least 16 characters"));
        }
        
        Ok(())
    }
}
 
pub struct AgentIdentityConfigSchema;
 
/// Example usage of the configuration system
pub async fn example_usage() -> Result<()> {
    // **Pattern Applied: Builder Pattern**
    let discovery = ConfigurationDiscovery::builder()
        .add_search_path(PathBuf::from("/etc/sindhan/config"))
        .enable_hot_reload()
        .build()?;
    
    // **Pattern Applied: Builder Pattern**
    let manager = ConfigurationManager::<AgentIdentityConfigSchema>::builder()
        .with_discovery(ConfigurationDiscovery::builder())
        .with_merge_strategy(Box::new(DeepMergeStrategy))
        .add_validation_rule(Box::new(RequiredFieldValidator::new("identity_provider".to_string())))
        .enable_hot_reload()
        .build()
        .await?;
    
    // Load initial configuration
    manager.load_configuration().await?;
    
    // Get configuration
    let config = manager.get_configuration().await;
    println!("Identity Provider: {}", config.identity_provider);
    
    // **Pattern Applied: Decorator Pattern**
    let encrypted_manager = Arc::new(EncryptedConfigurationDecorator::new(
        Arc::new(manager),
        vec![0u8; 32], // 32-byte encryption key
        vec!["security.secret_key".to_string()],
    ));
    
    // Use encrypted configuration
    let secure_config = encrypted_manager.get_configuration().await?;
    println!("Secure config loaded with encrypted fields");
    
    // **Pattern Applied: Observer Pattern**
    let observer = Arc::new(ConfigurationLogger::new());
    encrypted_manager.inner.add_observer(observer).await;
    
    // **Pattern Applied: Command Pattern**
    let mut command_invoker = ConfigurationCommandInvoker::new();
    
    let mut new_config = secure_config.clone();
    new_config.authentication.timeout_seconds = 60;
    
    let update_command = Box::new(UpdateConfigurationCommand::new(
        encrypted_manager.inner.clone(),
        new_config,
    ));
    
    let result = command_invoker.execute_command(update_command)?;
    println!("Command executed: {}", result.message);
    
    // Undo the last command
    let undo_result = command_invoker.undo_last_command()?;
    println!("Command undone: {}", undo_result.message);
    
    Ok(())
}
 
/// Example configuration observer
/// **Pattern Applied: Observer Pattern**
pub struct ConfigurationLogger {
    log_level: String,
}
 
impl ConfigurationLogger {
    pub fn new() -> Self {
        Self {
            log_level: "INFO".to_string(),
        }
    }
}
 
#[async_trait]
impl ConfigurationObserver for ConfigurationLogger {
    async fn on_configuration_changed(&self, change: ConfigurationChange) -> Result<()> {
        match change {
            ConfigurationChange::Loaded { .. } => {
                println!("[{}] Configuration loaded successfully", self.log_level);
            }
            ConfigurationChange::Updated { .. } => {
                println!("[{}] Configuration updated successfully", self.log_level);
            }
            ConfigurationChange::ValidationFailed { error } => {
                println!("[ERROR] Configuration validation failed: {:?}", error);
            }
        }
        Ok(())
    }
    
    async fn on_validation_failed(&self, error: ValidationError) -> Result<()> {
        println!("[ERROR] Validation failed: {:?}", error);
        Ok(())
    }
    
    async fn on_reload_completed(&self, success: bool) -> Result<()> {
        if success {
            println!("[{}] Configuration reload completed successfully", self.log_level);
        } else {
            println!("[ERROR] Configuration reload failed");
        }
        Ok(())
    }
}

Supporting Data Structures

/// Configuration format enumeration
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ConfigurationFormat {
    Toml,
    Yaml,
    Json,
}
 
impl ConfigurationFormat {
    pub fn extension(&self) -> &'static str {
        match self {
            ConfigurationFormat::Toml => "toml",
            ConfigurationFormat::Yaml => "yaml",
            ConfigurationFormat::Json => "json",
        }
    }
}
 
/// Discovered file information
#[derive(Debug, Clone)]
pub struct DiscoveredFile {
    pub path: PathBuf,
    pub format: ConfigurationFormat,
    pub source: DiscoverySource,
    pub priority: u8,
}
 
impl DiscoveredFile {
    pub fn default(module_name: &str) -> Self {
        Self {
            path: PathBuf::from(format!("default://{}", module_name)),
            format: ConfigurationFormat::Toml,
            source: DiscoverySource::Default,
            priority: 255, // Lowest priority
        }
    }
}
 
/// Discovery source enumeration
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DiscoverySource {
    CurrentDirectory,
    HomeDirectory,
    EnvironmentDirectory,
    External,
    Default,
}
 
/// Validation result structure
#[derive(Debug, Clone)]
pub struct ValidationResult {
    pub rule_name: String,
    pub message: String,
    pub severity: ValidationSeverity,
    pub field_path: Option<String>,
}
 
impl ValidationResult {
    pub fn aggregate(results: Vec<ValidationResult>, is_valid: bool) -> Self {
        let error_count = results.iter().filter(|r| r.severity == ValidationSeverity::Error).count();
        let warning_count = results.iter().filter(|r| r.severity == ValidationSeverity::Warning).count();
        
        Self {
            rule_name: "Aggregate".to_string(),
            message: format!("Validation complete: {} errors, {} warnings", error_count, warning_count),
            severity: if is_valid { ValidationSeverity::Info } else { ValidationSeverity::Error },
            field_path: None,
        }
    }
    
    pub fn is_valid(&self) -> bool {
        self.severity != ValidationSeverity::Error
    }
    
    pub fn errors(&self) -> Vec<String> {
        if self.severity == ValidationSeverity::Error {
            vec![self.message.clone()]
        } else {
            vec![]
        }
    }
}
 
/// Validation severity levels
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ValidationSeverity {
    Info,
    Warning,
    Error,
}
 
/// Configuration change enumeration
#[derive(Debug, Clone)]
pub enum ConfigurationChange {
    Loaded { config: serde_json::Value },
    Updated { old_config: serde_json::Value, new_config: serde_json::Value },
    ValidationFailed { error: ValidationError },
}
 
/// Validation error structure
#[derive(Debug, Clone)]
pub struct ValidationError {
    pub message: String,
    pub field_path: Option<String>,
    pub error_code: String,
}
 
/// Configuration command result
#[derive(Debug, Clone)]
pub struct ConfigurationCommandResult {
    pub command_id: String,
    pub success: bool,
    pub message: String,
    pub timestamp: chrono::DateTime<chrono::Utc>,
}

Design Pattern Summary

This technical specification demonstrates the comprehensive application of multiple software design patterns:

  1. Builder Pattern: Used extensively for constructing complex configuration objects, discovery engines, and managers with optional parameters and fluent APIs.

  2. Factory Pattern: Applied in FormatParserFactory for creating format-specific parsers based on configuration format types.

  3. Strategy Pattern: Implemented in merge strategies, validation rules, and parser selection, allowing runtime algorithm selection.

  4. Observer Pattern: Used for configuration change notifications, enabling reactive updates across the system.

  5. Chain of Responsibility Pattern: Applied in discovery handlers and validation pipelines, providing flexible processing chains.

  6. Adapter Pattern: Used for integrating external configuration sources and adapting different data formats.

  7. Decorator Pattern: Implemented for adding encryption and other enhancements to existing configuration managers.

  8. Singleton Pattern: Applied in configuration registry and global state management.

  9. Template Method Pattern: Used in ConfigurationSchema trait to define standard loading workflows.

  10. Command Pattern: Implemented for configuration operations with undo/redo support.

This implementation provides a robust, extensible, and maintainable configuration management system that serves as the foundation for all Sindhan AI platform modules while demonstrating best practices in software architecture and design patterns.