Rustelo/info/config_readme.md
Jesús Pérex 2f0f807331 feat: add dark mode functionality and improve navigation system
- Add complete dark mode system with theme context and toggle
- Implement dark mode toggle component in navigation menu
- Add client-side routing with SSR-safe signal handling
- Fix language selector styling for better dark mode compatibility
- Add documentation system with mdBook integration
- Improve navigation menu with proper external/internal link handling
- Add comprehensive project documentation and configuration
- Enhance theme system with localStorage persistence
- Fix arena panic issues during server-side rendering
- Add proper TypeScript configuration and build optimizations

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-11 20:53:20 +01:00

20 KiB

Configuration System

This project uses a comprehensive TOML-based configuration system with environment variable overrides. The configuration system supports multiple environments, feature flags, and secure credential management.

Quick Start

  1. Copy one of the example configuration files to config.toml:

    cp config.dev.toml config.toml
    
  2. Set environment-specific variables:

    export DATABASE_URL="postgresql://user:pass@localhost:5432/mydb"
    export SESSION_SECRET="your-secret-key-here"
    
  3. Run your application:

    cargo run
    

Configuration Files

File Priority

The configuration system looks for files in this order:

  1. $CONFIG_FILE (if environment variable is set)
  2. config.{environment}.toml (e.g., config.dev.toml, config.prod.toml)
  3. config.toml (default fallback)

Environment Detection

The environment is determined by the ENVIRONMENT variable:

  • development or dev → looks for config.dev.toml
  • production or prod → looks for config.prod.toml
  • Default → looks for config.toml

Configuration Structure

Server Configuration

[server]
protocol = "http"          # "http" or "https"
host = "127.0.0.1"         # Server bind address
port = 3030                # Server port
environment = "development" # "development" or "production"
log_level = "info"         # "trace", "debug", "info", "warn", "error"

# TLS Configuration (required when protocol = "https")
[server.tls]
cert_path = "certs/server.crt"
key_path = "certs/server.key"

Database Configuration

[database]
url = "postgresql://user:pass@localhost:5432/dbname"
max_connections = 10
min_connections = 1
connect_timeout = 30       # seconds
idle_timeout = 600         # seconds
max_lifetime = 1800        # seconds

Session Configuration

[session]
secret = "your-session-secret-here"
cookie_name = "session_id"
cookie_secure = false      # Set to true in production with HTTPS
cookie_http_only = true
cookie_same_site = "lax"   # "strict", "lax", or "none"
max_age = 3600            # Session duration in seconds

CORS Configuration

[cors]
allowed_origins = ["http://localhost:3030"]
allowed_methods = ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
allowed_headers = ["Content-Type", "Authorization"]
allow_credentials = true
max_age = 3600

Security Configuration

[security]
enable_csrf = true
csrf_token_name = "csrf_token"
rate_limit_requests = 100  # Requests per window
rate_limit_window = 60     # Window size in seconds
bcrypt_cost = 12          # BCrypt hashing cost

OAuth Configuration

[oauth]
enabled = true

[oauth.google]
client_id = "your-google-client-id"
client_secret = "your-google-client-secret"
redirect_uri = "http://localhost:3030/auth/google/callback"

[oauth.github]
client_id = "your-github-client-id"
client_secret = "your-github-client-secret"
redirect_uri = "http://localhost:3030/auth/github/callback"

Email Configuration

[email]
# Enable/disable email functionality
enabled = true

# Email provider: "smtp", "sendgrid", or "console"
provider = "console"

# Default sender information
from_email = "noreply@yourapp.com"
from_name = "Your App Name"

# Template directory for internationalized email templates
template_dir = "templates/email"

# SMTP Configuration (when provider = "smtp")
smtp_host = "smtp.gmail.com"
smtp_port = 587
smtp_username = "your-email@gmail.com"
smtp_password = "your-app-password"
smtp_use_tls = false
smtp_use_starttls = true

# SendGrid Configuration (when provider = "sendgrid")
sendgrid_api_key = ""
sendgrid_endpoint = "https://api.sendgrid.com/v3/mail/send"

# Environment-specific email settings
[environments.development]
email.enabled = true
email.provider = "console"

[environments.production]
email.enabled = true
email.provider = "sendgrid"
email.sendgrid_api_key = "${SENDGRID_API_KEY}"
email.from_email = "noreply@yourdomain.com"

Feature Flags

[features]
auth = true               # Enable authentication
tls = false              # Enable TLS support
content_db = true        # Enable database content management
two_factor_auth = false  # Enable 2FA
email = true             # Enable email functionality

Environment Variable Overrides

Environment variables take precedence over TOML file values. Use the following format:

Server Overrides

  • SERVER_PROTOCOLserver.protocol
  • SERVER_HOSTserver.host
  • SERVER_PORTserver.port
  • ENVIRONMENTserver.environment
  • LOG_LEVELserver.log_level

TLS Overrides

  • TLS_CERT_PATHserver.tls.cert_path
  • TLS_KEY_PATHserver.tls.key_path

Database Overrides

  • DATABASE_URLdatabase.url

Session Overrides

  • SESSION_SECRETsession.secret

Example Environment Variables

# Server configuration
export SERVER_HOST="0.0.0.0"
export SERVER_PORT="8080"
export ENVIRONMENT="production"
export SERVER_PROTOCOL="https"

# Database
export DATABASE_URL="postgresql://prod_user:${DB_PASSWORD}@db.example.com:5432/prod_db"

# Security
export SESSION_SECRET="super-secret-production-key"
export TLS_CERT_PATH="/etc/ssl/certs/server.crt"
export TLS_KEY_PATH="/etc/ssl/private/server.key"

# OAuth
export GOOGLE_CLIENT_ID="your-google-client-id"
export GOOGLE_CLIENT_SECRET="your-google-client-secret"
export GITHUB_CLIENT_ID="your-github-client-id"
export GITHUB_CLIENT_SECRET="your-github-client-secret"

# Email
export EMAIL_PROVIDER="sendgrid"
export EMAIL_FROM_ADDRESS="noreply@yourdomain.com"
export EMAIL_FROM_NAME="Your Production App"
export SENDGRID_API_KEY="your-sendgrid-api-key"
export SMTP_HOST="smtp.gmail.com"
export SMTP_USERNAME="your-email@gmail.com"
export SMTP_PASSWORD="your-app-password"

Environment Variable Substitution

You can use environment variable substitution in TOML files:

[database]
url = "postgresql://user:${DATABASE_PASSWORD}@localhost:5432/db"

[session]
secret = "${SESSION_SECRET}"

[oauth.google]
client_id = "${GOOGLE_CLIENT_ID}"
client_secret = "${GOOGLE_CLIENT_SECRET}"

[email]
provider = "${EMAIL_PROVIDER}"
from_email = "${EMAIL_FROM_ADDRESS}"
sendgrid_api_key = "${SENDGRID_API_KEY}"
smtp_password = "${SMTP_PASSWORD}"

Usage in Code

Loading Configuration

use server::config::Config;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Load configuration
    let config = Config::load()?;
    
    // Use configuration
    println!("Server: {}:{}", config.server.host, config.server.port);
    println!("Database: {}", config.database.url);
    
    Ok(())
}

Configuration Methods

let config = Config::load()?;

// Helper methods
let server_addr = config.server_address();      // "127.0.0.1:3030"
let server_url = config.server_url();           // "http://127.0.0.1:3030"
let is_dev = config.is_development();           // true/false
let is_prod = config.is_production();           // true/false
let needs_tls = config.requires_tls();          // true/false

// Database pool configuration
let pool_config = config.database_pool_config();

// Email configuration
let email_enabled = config.email.enabled;
let email_provider = &config.email.provider;
let template_dir = &config.email.template_dir;

Custom Configuration

let custom_config = Config {
    server: ServerConfig {
        protocol: Protocol::Http,
        host: "localhost".to_string(),
        port: 3000,
        environment: Environment::Development,
        log_level: "debug".to_string(),
        tls: None,
    },
    app: AppConfig {
        name: "My App".to_string(),
        version: "1.0.0".to_string(),
        debug: true,
        ..Default::default()
    },
    ..Default::default()
};

Best Practices

Development

  1. Use config.dev.toml for development settings
  2. Enable debug logging and relaxed security
  3. Use local database connections
  4. Disable TLS for easier development

Production

  1. Use config.prod.toml for production settings
  2. Enable all security features
  3. Use environment variables for secrets
  4. Enable TLS and secure cookies
  5. Use restrictive CORS policies

Security

  1. Never commit secrets to version control
  2. Use environment variables for sensitive data
  3. Use strong session secrets (32+ characters)
  4. Enable CSRF protection in production
  5. Use secure cookies with HTTPS
  6. Implement rate limiting

Docker

# Copy configuration files
COPY config.prod.toml /app/config.toml

# Set environment variables
ENV ENVIRONMENT=production
ENV DATABASE_URL=${DATABASE_URL}
ENV SESSION_SECRET=${SESSION_SECRET}

Kubernetes

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  config.toml: |
    [server]
    protocol = "https"
    host = "0.0.0.0"
    port = 8080
    environment = "production"
    
    [database]
    url = "postgresql://user:${DATABASE_PASSWORD}@postgres:5432/app"
---
apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
data:
  DATABASE_PASSWORD: <base64-encoded-password>
  SESSION_SECRET: <base64-encoded-secret>

Configuration Examples

Development Environment

[server]
protocol = "http"
host = "127.0.0.1"
port = 3030
environment = "development"
log_level = "debug"

[database]
url = "postgresql://dev:dev@localhost:5432/app_dev"
max_connections = 5

[security]
enable_csrf = false
rate_limit_requests = 1000
bcrypt_cost = 4

[session]
cookie_secure = false
max_age = 7200

[email]
enabled = true
provider = "console"
template_dir = "templates/email"

Production Environment

[server]
protocol = "https"
host = "0.0.0.0"
port = 443
environment = "production"
log_level = "info"

[server.tls]
cert_path = "/etc/ssl/certs/app.crt"
key_path = "/etc/ssl/private/app.key"

[database]
url = "postgresql://app:${DATABASE_PASSWORD}@db.example.com:5432/app_prod"
max_connections = 20

[security]
enable_csrf = true
rate_limit_requests = 50
bcrypt_cost = 12

[session]
secret = "${SESSION_SECRET}"
cookie_secure = true
cookie_same_site = "strict"
max_age = 3600

[email]
enabled = true
provider = "sendgrid"
sendgrid_api_key = "${SENDGRID_API_KEY}"
from_email = "noreply@yourdomain.com"
from_name = "Your Production App"
template_dir = "templates/email"

Troubleshooting

Configuration Not Found

Error: Configuration file not found: config.toml

Solution: Create a configuration file or set the CONFIG_FILE environment variable.

Environment Variable Not Found

Error: Environment variable 'DATABASE_PASSWORD' not found

Solution: Set the required environment variable or remove the substitution from the TOML file.

TLS Configuration Error

Error: TLS certificate path is required when using HTTPS

Solution: Either set protocol = "http" or provide valid TLS certificate paths.

Database Connection Error

Error: Failed to connect to database

Solution: Check the database URL and ensure the database is running and accessible.

Migration from Environment-Only Configuration

If you're migrating from a purely environment-based configuration:

  1. Create a config.toml file with your current settings
  2. Move sensitive values to environment variables
  3. Use environment variable substitution in TOML
  4. Test the configuration loading

Example migration:

# Old way (environment only)
export SERVER_HOST="0.0.0.0"
export SERVER_PORT="3030"
export DATABASE_URL="postgresql://..."

# New way (TOML + environment)
# config.toml
[server]
host = "0.0.0.0"
port = 3030

[database]
url = "${DATABASE_URL}"

Testing Configuration

Run the configuration example to test your setup:

cargo run --example config_example

This will show you how your configuration is being loaded and what values are being used.

Email Template Configuration

The email system uses an internationalized template structure with automatic language fallback:

Template Directory Structure

templates/email/
├── en_/                    # English templates (default)
│   ├── html/              # HTML email templates
│   │   ├── contact.hbs    # Contact form template
│   │   └── notification.hbs # Notification template
│   └── text/              # Plain text templates
│       ├── contact.hbs
│       └── notification.hbs
├── es_/                   # Spanish templates
│   ├── html/
│   └── text/
└── README.md              # Template documentation

Template Naming Convention

Templates are registered with the pattern: {language}_{template_name}_{format}

Examples:

  • en_contact_html - English contact form HTML template
  • es_notification_text - Spanish notification text template

Language Detection and Fallback

The system automatically detects language preferences from:

  1. User Profile: Authenticated user's saved language preference
  2. Request Headers: Accept-Language HTTP header
  3. Default Fallback: English (en)

Template Configuration

[email]
# Template directory (relative to project root)
template_dir = "templates/email"

# Default language for fallback
default_language = "en"

# Supported languages
supported_languages = ["en", "es", "fr", "de"]

Creating New Templates

  1. Create language directory:

    mkdir -p templates/email/fr_/html
    mkdir -p templates/email/fr_/text
    
  2. Add template files:

    # Create French contact template
    touch templates/email/fr_/html/contact.hbs
    touch templates/email/fr_/text/contact.hbs
    
  3. Template variables:

    {{name}}          # User's name
    {{email}}         # User's email
    {{subject}}       # Message subject
    {{message}}       # Message content
    {{submitted_at}}  # Timestamp
    

Available Handlebars Helpers

  • {{date_format submitted_at "%B %d, %Y at %I:%M %p UTC"}}
  • {{capitalize form_type}}
  • {{truncate user_agent 100}}
  • {{default action_text "Click Here"}}
  • {{url_encode email}}

Environment-Specific Email Settings

# Development - Print emails to console
[environments.development]
email.enabled = true
email.provider = "console"

# Staging - Use test SMTP server
[environments.staging]
email.enabled = true
email.provider = "smtp"
email.smtp_host = "smtp.mailtrap.io"
email.smtp_port = 2525

# Production - Use SendGrid
[environments.production]
email.enabled = true
email.provider = "sendgrid"
email.sendgrid_api_key = "${SENDGRID_API_KEY}"

For detailed email template documentation, see templates/email/README.md.

Configuration Encryption System

The Rustelo framework includes a comprehensive encryption system for securing sensitive configuration values using AES-256-GCM encryption with automatic key management.

Overview

The encryption system provides:

  • AES-256-GCM encryption for sensitive configuration values
  • Automatic key generation and management via .k file
  • Simple syntax - encrypted values start with @
  • Automatic decryption during configuration loading
  • CLI tools for managing encrypted values
  • Environment variable compatibility alongside encryption

Quick Start

  1. Generate Encryption Key:

    cargo run --bin config_crypto_tool generate-key
    
  2. Encrypt Sensitive Values:

    cargo run --bin config_crypto_tool encrypt "my_secret_password"
    # Output: @AbCdEf123456...
    
  3. Use in Configuration:

    [session]
    secret = "@AbCdEf123456..."
    
    [database]
    url = "postgresql://user:@ZW5jcnlwdGVk@localhost:5432/db"
    
  4. Verify Setup:

    cargo run --bin config_crypto_tool verify
    

Encryption Integration in Configuration

Configuration values starting with @ are automatically decrypted during loading:

# config.prod.toml
[session]
secret = "@c2Vzc2lvbl9zZWNyZXRfZXhhbXBsZQ=="  # Encrypted session secret

[database]
url = "postgresql://user:@ZW5jcnlwdGVkX3Bhc3N3b3Jk@localhost:5432/mydb"

[oauth.google]
client_id = "${GOOGLE_CLIENT_ID}"  # Environment variable
client_secret = "@Z29vZ2xlX2NsaWVudF9zZWNyZXQ="  # Encrypted value

[email]
sendgrid_api_key = "@c2VuZGdyaWRfYXBpX2tleQ=="
smtp_password = "@c210cF9wYXNzd29yZA=="

Mixed Configuration Approach

You can combine encrypted values with environment variables for maximum flexibility:

[database]
url = "${DATABASE_URL}"  # Environment variable (highest priority)

[session]
secret = "@encrypted_session_secret"  # Encrypted value

[oauth.google]
client_id = "${GOOGLE_CLIENT_ID}"  # Environment variable
client_secret = "@encrypted_google_secret"  # Encrypted value

[redis]
url = "@encrypted_redis_url"  # Encrypted Redis URL with credentials

Configuration Loading Order

  1. Environment variables (highest priority)
  2. Encrypted values (decrypted automatically)
  3. Plain text values (lowest priority)

The framework includes a built-in encryption system for securing sensitive configuration values using AES-256-GCM encryption.

How It Works

  1. Encryption Key: A .k file in the project root contains the encryption key
  2. Encrypted Values: Configuration values starting with @ are automatically decrypted
  3. Automatic Management: The system handles key generation and value decryption seamlessly

Quick Start

# Generate encryption key
cargo run --bin config_crypto_tool generate-key

# Encrypt a sensitive value
cargo run --bin config_crypto_tool encrypt "your_secret_value"
# Output: @AbCdEf123456...

# Use in configuration
echo 'session.secret = "@AbCdEf123456..."' >> config.toml

# Verify encryption works
cargo run --bin config_crypto_tool verify

Configuration Examples

# Example encrypted configuration
[session]
secret = "@encrypted_session_secret"

[database]
url = "postgresql://user:@encrypted_password@localhost:5432/db"

[oauth.google]
client_secret = "@encrypted_google_client_secret"

[email]
sendgrid_api_key = "@encrypted_sendgrid_api_key"
smtp_password = "@encrypted_smtp_password"

CLI Commands

# Key management
cargo run --bin config_crypto_tool generate-key       # Generate new key
cargo run --bin config_crypto_tool key-info          # Show key information
cargo run --bin config_crypto_tool verify            # Verify key works
cargo run --bin config_crypto_tool rotate-key --confirm  # Rotate key

# Value encryption/decryption
cargo run --bin config_crypto_tool encrypt "value"   # Encrypt a value
cargo run --bin config_crypto_tool decrypt "@..."    # Decrypt a value

# Configuration management
cargo run --bin config_crypto_tool find-encrypted -c config.toml
cargo run --bin config_crypto_tool show-decrypted -c config.toml
cargo run --bin config_crypto_tool encrypt-config -c config.toml -k "secret,api_key"

# Interactive mode
cargo run --bin config_crypto_tool interactive

Security Features

  • AES-256-GCM encryption with authenticated encryption
  • Automatic key generation using cryptographically secure random numbers
  • File permissions set to 0600 (read/write for owner only)
  • Key rotation support with backup creation
  • Environment variable compatibility - can mix encrypted and environment values

Best Practices

  1. Never commit .k files to version control
  2. Use different keys for different environments
  3. Backup encryption keys securely
  4. Rotate keys regularly in production
  5. Monitor key file integrity

Mixed Configuration Approach

You can combine encrypted values with environment variables:

[database]
url = "${DATABASE_URL}"  # Environment variable

[session]
secret = "@encrypted_session_secret"  # Encrypted value

[oauth.google]
client_id = "${GOOGLE_CLIENT_ID}"  # Environment variable
client_secret = "@encrypted_google_secret"  # Encrypted value

Deployment Considerations

# Production deployment
# 1. Generate key on production server
cargo run --bin config_crypto_tool generate-key

# 2. Encrypt production secrets
PROD_SECRET=$(cargo run --bin config_crypto_tool encrypt "prod-secret-2024")

# 3. Update configuration with encrypted values
# 4. Ensure .k file is properly secured and backed up

File Structure

project/
├── .k                    # Encryption key (DO NOT COMMIT)
├── config.prod.toml      # Config with encrypted values
├── .gitignore           # Must include .k
└── docs/
    └── ENCRYPTION.md    # Detailed encryption documentation

Error Handling

Common issues and solutions:

  • Key not found: Run cargo run --bin config_crypto_tool generate-key
  • Decryption failed: Verify key with cargo run --bin config_crypto_tool verify
  • Permission denied: Set proper permissions with chmod 600 .k

For comprehensive encryption documentation, see docs/ENCRYPTION.md.