Rustelo/docs/architecture/layered-override-system.md
Jesús Pérez 98e2d4e783
Some checks failed
CI/CD Pipeline / Test Suite (push) Has been cancelled
CI/CD Pipeline / Security Audit (push) Has been cancelled
CI/CD Pipeline / Build Docker Image (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / Performance Benchmarks (push) Has been cancelled
CI/CD Pipeline / Cleanup (push) Has been cancelled
chore: update docs
2026-02-08 20:12:31 +00:00

9.5 KiB

Rustelo Layered Override System

🎯 Architecture Overview

The layered override system enables customization at multiple levels while maintaining framework integrity and update safety. This system follows a clear precedence hierarchy:

Precedence Order: Local > Feature > Template > Framework

🏗️ Layer Definitions

1. Framework Layer (Bottom - Never Modified)

  • Location: Framework crates in dependencies
  • Content: Core rustelo functionality
  • Modification: Never modified directly
  • Updates: Automatic via cargo rustelo update

2. Template Layer (Foundation)

  • Location: Project templates from /rustelo/templates/
  • Content: Default project structure and configurations
  • Modification: Not modified directly in projects
  • Updates: Synced via cargo rustelo sync templates

3. Feature Layer (Additive)

  • Location: Feature-specific additions from /rustelo/features/*/templates/
  • Content: Feature configurations, dependencies, tooling
  • Modification: Can be overridden by local layer
  • Updates: Managed via cargo rustelo add/remove <feature>

4. Local Layer (Top - Full Control)

  • Location: Project-specific files and customizations
  • Content: Local customizations, overrides, project-specific code
  • Modification: Full control by developers
  • Updates: Always preserved during framework updates

🔧 Override Resolution Process

Configuration Files (Cargo.toml, justfile, package.json)

Resolution Order:
1. Check for local override: `config/local/Cargo.toml`
2. Check for feature configs: `config/features/*/Cargo.toml`
3. Check template default: `config/templates/Cargo.toml`
4. Fall back to framework defaults

Merge Strategy: Hierarchical merge with higher layers taking precedence

Component Overrides (Pages, Components)

Resolution Order:
1. Local components: `src/components/local/`
2. Feature components: `src/components/features/*/`
3. Template components: `src/components/templates/`
4. Framework components: Framework crates

Selection Strategy: First found wins (no merging for components)

Route Definitions

Resolution Order:
1. Local routes: `config/routes/local/`
2. Feature routes: `config/routes/features/*/`
3. Template routes: `config/routes/templates/`
4. Framework routes: Generated defaults

Merge Strategy: Route sets are merged with local routes overriding conflicts

Styling (CSS, UnoCSS)

Resolution Order:
1. Local styles: `styles/local/`
2. Feature styles: `styles/features/*/`
3. Template styles: `styles/templates/`
4. Framework styles: Default framework styles

Merge Strategy: CSS cascade with local styles having highest specificity

📁 Directory Structure

my-rustelo-project/
├── config/
│   ├── local/              # Local overrides (highest precedence)
│   │   ├── Cargo.toml
│   │   ├── justfile
│   │   └── app.toml
│   ├── features/           # Feature-specific configs
│   │   ├── analytics/
│   │   ├── smart-build/
│   │   └── debugging-tools/
│   └── templates/          # Template defaults (lowest precedence)
├── src/
│   ├── components/
│   │   ├── local/          # Local component overrides
│   │   ├── features/       # Feature components
│   │   └── templates/      # Template components
│   └── pages/
│       ├── local/          # Local page overrides
│       ├── features/       # Feature pages
│       └── templates/      # Template pages
├── routes/
│   ├── local/              # Local route definitions
│   ├── features/           # Feature routes
│   └── templates/          # Template routes
├── styles/
│   ├── local/              # Local styling
│   ├── features/           # Feature styles
│   └── templates/          # Template styles
└── scripts/
    ├── local/              # Local scripts
    ├── features/           # Feature scripts
    └── templates/          # Template scripts

⚙️ Implementation

Configuration Resolution Engine

pub struct LayeredConfig {
    layers: Vec<ConfigLayer>,
}

#[derive(Debug, Clone)]
pub enum ConfigLayer {
    Local(PathBuf),
    Feature(String, PathBuf),
    Template(PathBuf),
    Framework,
}

impl LayeredConfig {
    pub fn resolve<T>(&self, config_name: &str) -> Result<T, ConfigError> 
    where 
        T: DeserializeOwned + Merge
    {
        let mut result = T::default();
        
        // Apply layers from lowest to highest precedence
        for layer in &self.layers {
            if let Some(config) = self.load_config_from_layer(layer, config_name)? {
                result.merge(config);
            }
        }
        
        Ok(result)
    }
}

Component Resolution Engine

pub struct LayeredComponents {
    component_dirs: Vec<ComponentDir>,
}

#[derive(Debug, Clone)]
pub enum ComponentDir {
    Local(PathBuf),
    Feature(String, PathBuf),
    Template(PathBuf),
    Framework,
}

impl LayeredComponents {
    pub fn find_component(&self, name: &str) -> Option<PathBuf> {
        // Search from highest to lowest precedence
        for dir in &self.component_dirs {
            if let Some(path) = self.search_component_in_dir(dir, name) {
                return Some(path);
            }
        }
        None
    }
}

🚀 CLI Integration

Automatic Layer Setup

# Create layered structure when adding features
cargo rustelo add analytics
# Creates: config/features/analytics/, src/components/features/analytics/, etc.

# Create local override
cargo rustelo override component Header
# Creates: src/components/local/Header.rs (overrides template/feature version)

# Create local config override  
cargo rustelo override config Cargo.toml
# Creates: config/local/Cargo.toml (merges with other layers)

Override Management

# List all overrides
cargo rustelo list-overrides

# Show override hierarchy for specific item
cargo rustelo trace component Header
# Output:
# Header component resolution:
# ✅ src/components/local/Header.rs (USED)
# 🔸 src/components/features/analytics/Header.rs 
# 🔸 src/components/templates/Header.rs

# Remove local override (fall back to next layer)
cargo rustelo remove-override component Header

🛡️ Update Safety

Framework Updates

When running cargo rustelo update:

  1. Framework crates are updated to latest versions
  2. Template defaults are refreshed (but not applied)
  3. Feature configs are updated if compatible
  4. Local overrides are never modified
  5. Conflict detection warns of incompatibilities

Feature Updates

When running cargo rustelo add/remove <feature>:

  1. Feature layer is added/removed
  2. Local overrides take precedence over new feature configs
  3. Dependency conflicts are resolved in favor of local choices
  4. Migration warnings provided for breaking changes

🎨 Configuration Merging Examples

Cargo.toml Merging

Template Layer:

[dependencies]
leptos = "0.6"
serde = "1.0"

Feature Layer (analytics):

[dependencies] 
prometheus = "0.13"
chrono = "0.4"

Local Layer:

[dependencies]
leptos = "0.7"  # Override template version
anyhow = "1.0"  # Add local dependency

Final Result:

[dependencies]
leptos = "0.7"        # Local override
serde = "1.0"         # From template
prometheus = "0.13"   # From analytics feature
chrono = "0.4"        # From analytics feature  
anyhow = "1.0"        # Local addition

UnoCSS Configuration Merging

Template Layer:

export default {
  theme: {
    colors: {
      primary: '#3b82f6',
    }
  }
}

Feature Layer (analytics):

export default {
  theme: {
    colors: {
      analytics: '#10b981',
    }
  },
  shortcuts: {
    'metric-card': 'bg-white shadow-md rounded-lg p-4',
  }
}

Local Layer:

export default {
  theme: {
    colors: {
      primary: '#ef4444',  // Override template primary
      brand: '#8b5cf6',    // Add local color
    }
  }
}

Final Result:

export default {
  theme: {
    colors: {
      primary: '#ef4444',     // Local override
      analytics: '#10b981',   // From analytics feature
      brand: '#8b5cf6',       // Local addition
    }
  },
  shortcuts: {
    'metric-card': 'bg-white shadow-md rounded-lg p-4',  // From analytics
  }
}

📋 Benefits

For Developers

  • Full customization without losing update capability
  • Clear precedence - always know which config wins
  • Safe experimentation - local changes never affect framework
  • Easy rollback - remove local override to revert to defaults

for Framework Maintainers

  • Update safety - never break user customizations
  • Feature composability - features don't conflict with each other
  • Clear boundaries - framework, template, feature, and local concerns separated
  • Debugging support - trace resolution path for any configuration

For Teams

  • Consistent structure - all projects follow same layered approach
  • Shared overrides - commit local layer for team-wide customizations
  • Feature experimentation - test features without permanent changes
  • Migration safety - gradual migration between framework versions

This layered override system ensures that Rustelo provides maximum flexibility while maintaining the reliability and update safety that production applications require.