2026-02-08 20:07:09 +00:00
# Rustelo Foundation Integration Guide
## Overview
The Rustelo Foundation provides a complete ecosystem of library crates for building modern web applications. This guide shows how all foundation crates work together to create powerful, maintainable applications.
## Foundation Architecture
```
Application Layer (Your Implementation)
├── main.rs (imports and uses foundation libraries)
├── build.rs (uses foundation build utilities)
└── Cargo.toml (depends on foundation crates)
Foundation Library Layer
├── server/ # Server-side library with importable main functions
├── client/ # Client-side library with app mounting functions
├── components/ # Reusable UI component library
├── pages/ # Page generation and template system
├── core-lib/ # Shared utilities and business logic
└── core-types/ # Shared type definitions
```
## Complete Application Example
### 1. Application Structure
```
my-rustelo-app/
├── Cargo.toml # Workspace and dependencies
├── build.rs # Build-time page generation
├── src/
│ ├── main.rs # Application entry point
│ └── lib.rs # Application library code
├── content/ # Markdown content and configuration
├── templates/ # Page templates
└── public/ # Static assets
```
### 2. Cargo.toml - Foundation Dependencies
```toml
[package]
name = "my-rustelo-app"
version = "0.1.0"
edition = "2021"
[dependencies]
# Foundation crates
server = { path = "path/to/rustelo/crates/foundation/crates/server" }
client = { path = "path/to/rustelo/crates/foundation/crates/client" }
components = { path = "path/to/rustelo/crates/foundation/crates/components" }
pages = { path = "path/to/rustelo/crates/foundation/crates/pages" }
core-lib = { path = "path/to/rustelo/crates/foundation/crates/core-lib" }
core-types = { path = "path/to/rustelo/crates/foundation/crates/core-types" }
# Leptos framework
leptos = { version = "0.8", features = ["ssr", "hydrate"] }
leptos_router = "0.8"
leptos_axum = "0.8"
# Additional dependencies
tokio = { version = "1.0", features = ["full"] }
axum = "0.8"
[features]
default = []
ssr = ["leptos/ssr", "server/ssr", "pages/ssr", "components/ssr"]
hydrate = ["leptos/hydrate", "client/hydrate", "pages/hydrate", "components/hydrate"]
[[bin]]
name = "server"
path = "src/main.rs"
required-features = ["ssr"]
[lib]
name = "my_rustelo_app"
crate-type = ["cdylib", "rlib"]
```
### 3. build.rs - Foundation Build Integration
```rust
//! Build script using foundation build utilities
use std::error::Error;
fn main() -> Result< (), Box< dyn Error > > {
// Use server foundation build utilities
server::build::build_foundation()?;
// Use pages foundation for page generation
pages::build::generate_pages_from_content("content/")?;
// Use core-lib for configuration processing
core_lib::build::process_configuration("config/")?;
// Set up rerun conditions
println!("cargo:rerun-if-changed=content/");
println!("cargo:rerun-if-changed=templates/");
println!("cargo:rerun-if-changed=config/");
Ok(())
}
```
### 4. src/main.rs - Complete Application Integration
```rust
//! Complete Rustelo application using all foundation crates
use server::{run_server_with_config, ServerConfig};
use client::{create_base_app, ClientConfig};
use components::{
navigation::{BrandHeader, Footer},
content::{UnifiedContentCard, ContentManager},
theme::{ThemeProvider, ThemeConfig},
};
use pages::{
HomePage, AboutPage, ContactPage,
content::{ContentIndexPage, ContentCategoryPage},
PostViewerPage,
};
use core_lib::{
config::{load_app_config, AppConfig},
i18n::{setup_translations, TranslationManager},
content::{ContentService, MarkdownProcessor},
};
use core_types::{
ContentItem, Route, User, AppError,
config::{DatabaseConfig, I18nConfig},
};
use leptos::*;
use leptos_router::*;
#[tokio::main]
async fn main() -> Result< (), AppError> {
// 1. Load application configuration using core-lib
let app_config: AppConfig = load_app_config("config/app.toml")?;
// 2. Setup internationalization using core-lib
let translation_manager = setup_translations(&app_config.i18n)?;
// 3. Initialize content service using core-lib
let content_service = ContentService::new(&app_config.content_path)?;
// 4. Configure server using server foundation
let server_config = ServerConfig::builder()
.from_app_config(& app_config)
.content_service(content_service.clone())
.translation_manager(translation_manager.clone())
.enable_features(["content", "auth", "i18n"])
.build();
// 5. Start server using foundation main function
run_server_with_config(server_config).await?;
Ok(())
}
/// Application component integrating all foundation components
#[component]
pub fn App() -> impl IntoView {
// Load app configuration
let app_config = use_context::< AppConfig > ().unwrap();
// Setup theme configuration
let theme_config = ThemeConfig::builder()
.from_app_config(& app_config)
.build();
view! {
// Theme provider from components foundation
< ThemeProvider config = theme_config >
// Router setup
< Router >
< div class = "min-h-screen flex flex-col" >
// Header using components foundation
< AppHeader / >
// Main content with routing using pages foundation
< main class = "flex-1" >
< Routes >
// Home page from pages foundation
< Route path = "/" view = HomePage / >
// Static pages from pages foundation
< Route path = "/about" view = AboutPage / >
< Route path = "/contact" view = ContactPage / >
// Content pages using pages foundation
< Route path = "/blog" view = || {
ContentIndexPage {
content_type: "blog".to_string(),
layout: "grid".to_string(),
per_page: Some(10),
}
} />
< Route path = "/blog/:category" view = ContentCategoryPage / >
< Route path = "/blog/post/:slug" view = || {
PostViewerPage {
content_type: "blog".to_string(),
show_related: true,
enable_comments: true,
}
} />
// Portfolio section
< Route path = "/portfolio" view = || {
ContentIndexPage {
content_type: "portfolio".to_string(),
layout: "cards".to_string(),
per_page: Some(12),
}
} />
// 404 page
< Route path = "/*any" view = pages::NotFoundPage / >
< / Routes >
< / main >
// Footer using components foundation
< AppFooter / >
< / div >
< / Router >
< / ThemeProvider >
}
}
/// Application header component
#[component]
fn AppHeader() -> impl IntoView {
let app_config = use_context::< AppConfig > ().unwrap();
view! {
< BrandHeader
brand_name=app_config.site_name.clone()
logo_url=app_config.logo_url.clone()
>
// Navigation using components foundation
< components::navigation::NavMenu orientation = "horizontal" >
< components::ui::SpaLink href = "/" active_class = "text-blue-600" >
"Home"
< / components::ui::SpaLink >
< components::ui::SpaLink href = "/about" active_class = "text-blue-600" >
"About"
< / components::ui::SpaLink >
< components::ui::SpaLink href = "/blog" active_class = "text-blue-600" >
"Blog"
< / components::ui::SpaLink >
< components::ui::SpaLink href = "/portfolio" active_class = "text-blue-600" >
"Portfolio"
< / components::ui::SpaLink >
< components::ui::SpaLink href = "/contact" active_class = "text-blue-600" >
"Contact"
< / components::ui::SpaLink >
< / components::navigation::NavMenu >
// Language selector if i18n enabled
{if app_config.i18n.enabled {
view! {
< components::navigation::LanguageSelector
current_lang=app_config.i18n.default_language.clone()
available_langs=app_config.i18n.supported_languages.clone()
/>
}.into_view()
} else {
view! {}.into_view()
}}
< / BrandHeader >
}
}
/// Application footer component
#[component]
fn AppFooter() -> impl IntoView {
let app_config = use_context::< AppConfig > ().unwrap();
view! {
< Footer copyright = format!("© 2024 { } " , app_config . site_name ) >
< div class = "grid md:grid-cols-3 gap-8" >
// Site links
< div >
< h4 class = "font-semibold mb-4" > "Site"< / h4 >
< div class = "space-y-2" >
< components::ui::SpaLink href = "/about" class = "block text-gray-600 hover:text-gray-800" >
"About"
< / components::ui::SpaLink >
< components::ui::SpaLink href = "/blog" class = "block text-gray-600 hover:text-gray-800" >
"Blog"
< / components::ui::SpaLink >
< components::ui::SpaLink href = "/portfolio" class = "block text-gray-600 hover:text-gray-800" >
"Portfolio"
< / components::ui::SpaLink >
< / div >
< / div >
// Content links
< div >
< h4 class = "font-semibold mb-4" > "Content"< / h4 >
< div class = "space-y-2" >
< components::ui::SpaLink href = "/blog/category/tutorials" class = "block text-gray-600 hover:text-gray-800" >
"Tutorials"
< / components::ui::SpaLink >
< components::ui::SpaLink href = "/blog/category/news" class = "block text-gray-600 hover:text-gray-800" >
"News"
< / components::ui::SpaLink >
< components::ui::SpaLink href = "/portfolio" class = "block text-gray-600 hover:text-gray-800" >
"Work"
< / components::ui::SpaLink >
< / div >
< / div >
// Legal links
< div >
< h4 class = "font-semibold mb-4" > "Legal"< / h4 >
< div class = "space-y-2" >
< components::ui::SpaLink href = "/privacy" class = "block text-gray-600 hover:text-gray-800" >
"Privacy Policy"
< / components::ui::SpaLink >
< components::ui::SpaLink href = "/terms" class = "block text-gray-600 hover:text-gray-800" >
"Terms of Service"
< / components::ui::SpaLink >
< / div >
< / div >
< / div >
< / Footer >
}
}
/// Client-side hydration using client foundation
#[cfg(feature = "hydrate")]
#[wasm_bindgen::prelude::wasm_bindgen]
pub fn hydrate() {
use client::{hydrate_app_with_config, ClientConfig};
let client_config = ClientConfig::builder()
.mount_selector("#app ")
.enable_hydration(true)
.enable_router(true)
.build();
hydrate_app_with_config(|| view! { < App / > }, client_config);
}
/// Server-side rendering setup
#[cfg(feature = "ssr")]
pub fn render_app() -> String {
leptos::ssr::render_to_string(|| view! { < App / > })
}
```
## Cross-Crate Communication Patterns
### 1. Configuration Flow
```rust
// core-lib loads and validates configuration
let app_config = core_lib::config::load_app_config("config/app.toml")?;
// server uses configuration for setup
let server_config = server::ServerConfig::from_app_config(&app_config);
// components use configuration for theming
let theme_config = components::theme::ThemeConfig::from_app_config(&app_config);
// pages use configuration for content processing
let page_config = pages::PageConfig::from_app_config(&app_config);
```
### 2. Content Processing Pipeline
```rust
// core-lib processes raw content
let processor = core_lib::content::MarkdownProcessor::new(&app_config.content_path);
let content_items = processor.process_all().await?;
// pages generates pages from processed content
let page_generator = pages::PageGenerator::new()
.with_content_items(content_items)
.with_templates_from_config(&app_config);
// components display the content
let content_display = components::content::ContentManager::new()
.with_content_source(content_items)
.with_layout("grid");
```
### 3. Type Safety Across Crates
```rust
// core-types defines shared types
use core_types::{ContentItem, User, Route, AppError};
// All crates use the same types for consistency
fn process_content(item: ContentItem) -> Result< ContentItem , AppError > {
// Processing logic
}
fn render_user_profile(user: User) -> impl IntoView {
// Rendering logic
}
fn handle_route(route: Route) -> Result< (), AppError> {
// Routing logic
}
```
## Build System Integration
### 1. Multi-Stage Build Process
```rust
// build.rs orchestrates all foundation build utilities
fn main() -> Result< (), Box< dyn std::error::Error > > {
// Stage 1: Core configuration processing
core_lib::build::process_configuration()?;
// Stage 2: Content processing and validation
core_lib::build::process_content()?;
// Stage 3: Page generation
pages::build::generate_pages()?;
// Stage 4: Route generation
server::build::generate_routes()?;
// Stage 5: Asset processing
process_static_assets()?;
Ok(())
}
```
### 2. Feature Flag Coordination
```toml
# Features are coordinated across all foundation crates
[features]
default = []
# Core features
auth = ["server/auth", "core-lib/auth", "core-types/auth"]
i18n = ["server/i18n", "client/i18n", "pages/i18n", "core-lib/i18n"]
content-db = ["server/content-db", "pages/content-db", "core-lib/content-db"]
# Rendering features
ssr = ["server/ssr", "pages/ssr", "components/ssr"]
hydrate = ["client/hydrate", "pages/hydrate", "components/hydrate"]
# Development features
dev-tools = ["server/dev-tools", "client/dev-tools"]
```
## Advanced Integration Patterns
### 1. Plugin Architecture
```rust
// Define plugin traits in core-types
pub trait ContentProcessor {
fn process(& self, content: & str) -> Result< String , ProcessingError > ;
}
// Implement plugins in various crates
impl ContentProcessor for pages::MarkdownProcessor {
fn process(& self, content: & str) -> Result< String , ProcessingError > {
self.process_markdown(content)
}
}
// Register and use plugins through core-lib
let processor_registry = core_lib::plugins::ProcessorRegistry::new()
.register("markdown", Box::new(pages::MarkdownProcessor::new()))
.register("handlebars", Box::new(templates::HandlebarsProcessor::new()));
```
### 2. Event System
```rust
// Define events in core-types
#[derive(Debug, Clone)]
pub enum AppEvent {
ContentUpdated(ContentItem),
UserAuthenticated(User),
RouteChanged(Route),
ThemeChanged(String),
}
// Emit events from various crates
// In pages crate
self.event_bus.emit(AppEvent::ContentUpdated(content_item));
// In server crate
self.event_bus.emit(AppEvent::UserAuthenticated(user));
// Listen to events in components
self.event_bus.subscribe(|event| match event {
AppEvent::ThemeChanged(theme) => update_theme(theme),
AppEvent::ContentUpdated(item) => refresh_content_display(item),
_ => {}
});
```
### 3. State Management Integration
```rust
// Global state defined in core-types
#[derive(Debug, Clone)]
pub struct AppState {
pub user: Option< User > ,
pub theme: Theme,
pub language: Language,
pub content_cache: HashMap< String , ContentItem > ,
}
// State management in core-lib
pub struct StateManager {
state: RwSignal< AppState > ,
event_bus: EventBus,
}
impl StateManager {
pub fn update_user(& self, user: Option< User > ) {
self.state.update(|state| state.user = user);
if let Some(user) = user {
self.event_bus.emit(AppEvent::UserAuthenticated(user));
}
}
}
// Use state in components
#[component]
pub fn UserProfile() -> impl IntoView {
let state = use_context::< StateManager > ().unwrap();
let user = create_memo(move |_| state.get_user());
view! {
< Show when = move | | user . get ( ) . is_some ( ) >
// Render user profile
< / Show >
}
}
```
## Testing Integration
### 1. Cross-Crate Testing
```rust
// Integration tests that span multiple crates
#[cfg(test)]
mod integration_tests {
use super::*;
#[tokio::test]
async fn test_full_content_pipeline() {
// Use core-lib to load configuration
let config = core_lib::config::load_test_config().await.unwrap();
// Use pages to process content
let content = pages::process_test_content(&config).await.unwrap();
// Use components to render content
let rendered = components::render_test_content(content).await.unwrap();
// Verify the full pipeline
assert!(rendered.contains("expected content"));
}
#[test]
fn test_type_consistency() {
// Verify types work across crate boundaries
let content_item = core_types::ContentItem::new("test", "Test Content");
let processed = core_lib::content::process_item(content_item.clone()).unwrap();
let rendered = components::content::render_item(&processed);
assert_eq!(processed.id, content_item.id);
}
}
```
### 2. End-to-End Testing
```rust
// E2E tests using all foundation crates together
#[cfg(test)]
mod e2e_tests {
use super::*;
#[tokio::test]
async fn test_complete_application() {
// Start server using server foundation
let server_handle = server::test_utils::start_test_server().await;
// Generate test content using pages foundation
pages::test_utils::generate_test_pages().await.unwrap();
// Test client-side functionality
let client_test = client::test_utils::TestClient::new()
.navigate_to("/")
.expect_content("Welcome")
.navigate_to("/blog")
.expect_content("Blog Posts")
.run()
.await;
assert!(client_test.passed());
// Cleanup
server_handle.stop().await;
}
}
```
## Deployment Integration
### 1. Production Build
```bash
#!/bin/bash
# Build script using all foundation capabilities
# Build server with all features
cargo build --release --features "ssr,auth,content-db,i18n,metrics"
# Build client for WebAssembly
wasm-pack build --target web --features "hydrate,router,i18n"
# Generate static pages
cargo run --bin page-generator --features "generation"
# Process and optimize assets
cargo run --bin asset-processor
# Create deployment package
tar -czf rustelo-app.tar.gz target/release/server pkg/ generated/ public/
```
### 2. Docker Integration
```dockerfile
# Multi-stage Docker build using foundation crates
FROM rust:1.70 as builder
# Copy foundation source
COPY rustelo/crates/foundation /app/foundation
COPY . /app/src
WORKDIR /app/src
# Build with all production features
RUN cargo build --release --features "production"
# Build client WASM
RUN wasm-pack build --target web --features "hydrate,router,i18n"
FROM nginx:alpine
# Copy server binary
COPY --from=builder /app/src/target/release/server /usr/local/bin/
# Copy static assets and generated pages
COPY --from=builder /app/src/pkg /var/www/html/pkg
COPY --from=builder /app/src/generated /var/www/html/generated
COPY --from=builder /app/src/public /var/www/html/public
# Copy nginx configuration
COPY nginx.conf /etc/nginx/nginx.conf
# Start script that runs both server and nginx
COPY start.sh /start.sh
RUN chmod +x /start.sh
CMD ["/start.sh"]
```
## Best Practices for Foundation Integration
### 1. Dependency Management
- Use workspace dependencies for version consistency
- Enable only the features you need
- Use path dependencies during development
- Switch to published crates for production
### 2. Configuration Management
- Centralize configuration in core-lib
- Use type-safe configuration structs from core-types
- Validate configuration at startup
- Support environment-specific configs
### 3. Error Handling
- Define common errors in core-types
- Implement From traits for error conversion
- Use Result types consistently across crates
- Provide meaningful error contexts
### 4. Performance Optimization
- Use foundation build utilities for optimization
- Enable appropriate feature flags
- Leverage foundation caching mechanisms
- Profile across crate boundaries
### 5. Testing Strategy
- Test individual crates in isolation
- Write integration tests for crate interactions
- Use foundation test utilities
- Implement E2E testing for complete flows
2026-02-08 20:37:49 +00:00
The Rustelo Foundation provides a complete, integrated development experience where each crate is designed to work seamlessly with the others while maintaining clear separation of concerns and reusability.