Rustelo/docs/architecture/layered-override-system.md

352 lines
9.5 KiB
Markdown
Raw Normal View History

2026-02-08 20:12:31 +00:00
# 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
```rust
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
```rust
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
```bash
# 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
```bash
# 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**:
```toml
[dependencies]
leptos = "0.6"
serde = "1.0"
```
**Feature Layer (analytics)**:
```toml
[dependencies]
prometheus = "0.13"
chrono = "0.4"
```
**Local Layer**:
```toml
[dependencies]
leptos = "0.7" # Override template version
anyhow = "1.0" # Add local dependency
```
**Final Result**:
```toml
[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**:
```typescript
export default {
theme: {
colors: {
primary: '#3b82f6',
}
}
}
```
**Feature Layer (analytics)**:
```typescript
export default {
theme: {
colors: {
analytics: '#10b981',
}
},
shortcuts: {
'metric-card': 'bg-white shadow-md rounded-lg p-4',
}
}
```
**Local Layer**:
```typescript
export default {
theme: {
colors: {
primary: '#ef4444', // Override template primary
brand: '#8b5cf6', // Add local color
}
}
}
```
**Final Result**:
```typescript
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
2026-02-08 20:37:49 +00:00
This layered override system ensures that Rustelo provides maximum flexibility while maintaining the reliability and update safety that production applications require.