| .cargo | ||
| crates | ||
| justfiles | ||
| lian-build | ||
| provisioning | ||
| scripts | ||
| site | ||
| xtask | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| .k | ||
| .pre-commit-config.yaml | ||
| bacon.toml | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CHANGELOG.md | ||
| justfile | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| run.sh | ||
| rustelo.manifest.toml | ||
| SETUP.md | ||
| uno.config.ts | ||
Website Implementation - Rustelo Framework
A complete content website with code highlighting built using the Rustelo framework, demonstrating modern multi-crate architecture and PAP compliance.
🎯 Project Overview
This implementation validates Rustelo's project generation capabilities and serves as a reference for content websites that need code display features.
Key Features
- Multi-crate architecture: Client, server, shared, pages with build.rs integration
- Type-safe configuration: Nickel (NCL) for routes, themes, menus with compile-time validation
- Bilingual single-source: Zero duplication - EN/ES in one file
- Code highlighting: Complete syntax highlighting with copy functionality
- Language-agnostic: Supports any language without code changes
- Smart caching: Multi-layer cache system for incremental builds
- PAP compliant: Follows Rustelo's Project Architecture Principles
🚀 Quick Start
Prerequisites
- Rust 1.75+ - Core language and toolchain
- Node.js 18+ - Frontend tooling
- Nickel (Configuration language) - REQUIRED for type-safe configuration
- macOS:
brew install nickel - Linux/Windows:
cargo install nickel-lang-cli - See Nickel Installation Guide
- macOS:
- Site content in
../site/directory
Note
: This project uses Nickel (NCL) for all configuration files (routes, themes, menus, content types). See NCL Configuration section below.
Setup & Development
# Install dependencies
just setup
# Start development server with hot reload
just dev
# Build for production
just build-prod
Development Commands
# Development
just dev # Hot reload with CSS watching
just dev-server # Rust only (no CSS watching)
just dev-css # CSS watching only
# Building
just build # Development build
just build-prod # Production build
just build-rust # Rust components only
just build-css # CSS only
# Quality & Testing
just quality # All quality checks
just test # Run tests
just format # Format code
just lint # Lint code
# Content & Deployment
just validate-content # Validate site content
just deploy-staging # Deploy to staging
just status # Project status
🏗️ Architecture
Multi-Crate Structure
website-impl/
├── crates/
│ ├── shared/ # Route generation & shared types
│ ├── pages/ # Custom page component generation
│ ├── client/ # WASM frontend with asset processing
│ ├── server/ # Axum backend with configuration
│ └── plugin-example-theme/ # Example plugin (theme + i18n)
├── config.toml # Application configuration
├── uno.config.ts # UnoCSS configuration (synced with @website)
├── package.json # Code highlighting & build tools
├── justfile # Development automation
└── scripts/ # Build scripts for themes & highlighting
🔌 Plugin System
This implementation demonstrates Rustelo's Level 5 Plugin Architecture - a trait-based plugin system for unlimited extensibility without framework coupling.
Included Plugins
- WebsiteResourceContributor (core): Provides themes, menus, and i18n
- plugin-example-theme (example): Complete working theme plugin with tests
Plugin Features
- ✅ ResourceContributor Trait: Contribute themes, menus, translations
- ✅ Type-Safe Registration: Compile-time validation
- ✅ Zero Conditional Compilation: Framework code is pure Rust
- ✅ Configuration-Driven: Resources from TOML/FTL files
- ✅ Self-Contained: Plugins are independent crates
Creating Custom Plugins
Step 1: Create plugin crate
cd crates/
cargo new --lib my-custom-plugin
Step 2: Implement ResourceContributor
use rustelo_core_lib::registration::ResourceContributor;
pub struct MyPlugin;
impl ResourceContributor for MyPlugin {
fn contribute_themes(&self) -> HashMap<String, String> {
let mut themes = HashMap::new();
themes.insert("my-theme".to_string(),
include_str!("../config/themes/my-theme.toml").to_string());
themes
}
fn name(&self) -> &str {
"my-plugin"
}
}
Step 3: Add to workspace
- Add to main
Cargo.tomlworkspace members - Create configuration files in
config/themes/andconfig/i18n/
Step 4: Register at startup
// In crates/server/src/resources.rs
rustelo_core_lib::register_contributor(&MyPlugin)?;
Plugin Types
| Type | Purpose | Example |
|---|---|---|
| Resource-Only | Themes, menus, translations | Custom theme plugin |
| Page Provider | Custom page components | Analytics dashboard |
| Composite | Resources + pages | Feature module |
Example Plugin Walkthrough
See crates/plugin-example-theme/ for a complete, production-ready example:
- Analytics dashboard theme configuration
- English and Spanish translations
- 10/10 passing unit tests
- Comprehensive documentation
Plugin Documentation
- Quick Start: See this README's "Creating Custom Plugins" section above
- Complete Guide: Plugin Development Guide
- Architecture: Rustelo Plugin Architecture
- Example Plugin:
./crates/plugin-example-theme/README.md
🎨 Code Highlighting Features
Syntax Highlighting
- highlight.js: Multi-language syntax highlighting
- highlightjs-copy: One-click code copying
- Theme system: Light/dark mode with custom themes
- UnoCSS integration: Built-in code styling with design system
Design System Integration
Uses complete design system from @website:
ds-*prefixed utility classes- Theme variables for consistent styling
- Built-in dark mode support
- Code block styling with proper contrast
📝 NCL Configuration
This project uses Nickel (NCL) for type-safe, DRY configuration. All configuration files use .ncl format with TOML fallback support.
Why NCL?
✅ Type Safety: Compile-time validation catches errors before runtime ✅ Zero Duplication: Bilingual configs in single file (no separate en.toml/es.toml) ✅ DRY Principles: Shared defaults and helper functions ✅ Better Tooling: Syntax highlighting, LSP support, validation
Configuration Files
site/
├── schemas/ # Reusable NCL type definitions
│ ├── content/
│ │ ├── contracts.ncl # Type contracts for content
│ │ └── defaults.ncl # Shared defaults + helpers
│ ├── menus/
│ │ ├── contracts.ncl
│ │ └── defaults.ncl
│ ├── footer/
│ │ ├── contracts.ncl
│ │ └── defaults.ncl
│ └── themes/
│ ├── contracts.ncl
│ └── defaults.ncl
├── config/
│ └── themes/
│ ├── default.ncl # Default theme
│ └── dark.ncl # Dark theme variant
├── content/
│ └── content-kinds.ncl # Content type definitions
└── ui/
├── menus/
│ └── menu.ncl # Navigation menu (bilingual)
└── footer/
└── footer.ncl # Footer config (bilingual)
Example: Bilingual Menu (Before vs After)
Before (TOML - 130 lines across 2 files):
# en.toml
[[items]]
route = "/services"
label = "Services"
# es.toml
[[items]]
route = "/servicios"
label = "Servicios"
After (NCL - 115 lines, single file):
{
items = [
make_menu_item {
routes = { en = "/services", es = "/servicios" },
labels = { en = "Services", es = "Servicios" },
},
]
}
Working with NCL Configs
Export to JSON:
nickel export --format json site/ui/menus/menu.ncl | jq '.'
Validate:
nickel typecheck site/ui/menus/menu.ncl
Auto-Detection:
Build system automatically prefers .ncl files over .toml:
site/config/themes/dark.ncl ✅ Used
site/config/themes/dark.toml ⏭️ Ignored (fallback)
Documentation
- Configuration Guide: ../../docs/guides/nickel-configuration-guide.md
- Installation: ../../docs/guides/nickel-installation.md
- ADR: ../../docs/adr/0002-nickel-configuration-language.md
- Implementation Summary: ./.coder/info/summaries/2026-02-09-nickel-config-implementation-complete.md
Metrics
| Config Type | Lines | Duplication Reduced |
|---|---|---|
| Content-Kinds | 29 | ~60% less |
| Menus | 115 | 100% (bilingual) |
| Footers | 63 | 29% smaller |
| Themes | 4 × 14 | Variants from base |
Total: ~140 lines of config + ~920 lines of reusable schemas
🔧 Configuration
Site Integration
# Links to site content structure
[content]
root_path = "../site" # Site content directory
public_path = "../site/public" # Static assets
content_url = "/content" # Content API URL
types = ["blog", "recipes"] # Available content types
languages = ["en", "es"] # Supported languages
default_language = "en" # Default language
🧪 PAP Compliance
✅ Configuration-driven: All routes, themes, menus from NCL files with type-safety
✅ Language-agnostic: No hardcoded languages, bilingual single-source configs
✅ Custom routing: Uses Rustelo routing, NOT Leptos router
✅ Error handling: Proper Result<T, E> patterns, no unwrap()
✅ Modular design: Feature-based architecture with plugin system
✅ Type-safe configuration: Nickel contracts validate at compile-time
✅ No hardcoding: All paths and routes configurable
✅ Self-describing: Architecture tracked via on+re protocol — .ontology/ + adrs/
🔍 Architecture Self-Description (on+re)
This project implements the Ontoref on+re protocol. The .ontology/ and adrs/ directories provide a machine- and agent-readable description of the project's architecture, current state, and invariants as a Rustelo consumer (Service kind).
.ontology/ files
| File | Contents |
|---|---|
core.ncl |
Knowledge graph: axioms (rustelo-consumer, bilingual-content), tensions (hydration complexity, build-time vs runtime), project nodes |
state.ncl |
State dimensions: deployment-readiness (pre-production), hydration-stability (zero-mismatch), auth-system (operational), css-pipeline (correct) |
gate.ncl |
Membranes: hydration-parity (Low permeability), content-integrity (Medium), rbac-correctness (Low) |
manifest.ncl |
Service manifest: EndUser, Developer, Agent consumption modes; implementation, content, self-description layers |
ADR System (adrs/)
| ADR | Decision |
|---|---|
adr-001 |
NCL (Nickel) over TOML for site configuration |
adr-002 |
SsrTranslator in both SSR and WASM targets for hydration parity — 4 hard constraints |
adr-003 |
WebSocket broadcast for RBAC hot-reload without server restart |
Browsing the architecture
# What this project is and how it can be consumed
nickel export .ontology/manifest.ncl
# Current state across all tracked dimensions
nickel export .ontology/state.ncl
# Active architecture constraints and gates
nickel export .ontology/gate.ncl
# Cross-project: browse Rustelo framework capabilities
# (rustelo-browse operational mode in manifest.ncl)
nickel export ../../rustelo/.ontology/core.ncl
📖 Documentation
- Setup Guide:
info/setup_from_rustelo_plan.md- Complete implementation journey - Enhancements:
info/enhancements/- Proposed improvements for Rustelo
📄 License
MIT License - Part of the Rustelo framework ecosystem.