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>
This commit is contained in:
parent
03550c29a4
commit
2f0f807331
38
.claude/settings.local.json
Normal file
38
.claude/settings.local.json
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(curl:*)",
|
||||||
|
"Bash(cargo:*)",
|
||||||
|
"Bash(pkill:*)",
|
||||||
|
"Bash(RUST_LOG=debug leptos serve watch)",
|
||||||
|
"Bash(RUST_LOG=debug cargo leptos watch)",
|
||||||
|
"Bash(rm:*)",
|
||||||
|
"Bash(sqlite3:*)",
|
||||||
|
"Bash(lsof:*)",
|
||||||
|
"Bash(RUST_LOG=info cargo leptos watch)",
|
||||||
|
"Bash(RUST_LOG=info ./target/debug/server)",
|
||||||
|
"Bash(env)",
|
||||||
|
"Bash(cat:*)",
|
||||||
|
"Bash(grep:*)",
|
||||||
|
"Bash(ENVIRONMENT=development cargo run --bin server)",
|
||||||
|
"Bash(ls:*)",
|
||||||
|
"Bash(CONFIG_FILE=config.dev.toml cargo run --bin server)",
|
||||||
|
"Bash(git checkout:*)",
|
||||||
|
"Bash(CONFIG_FILE=/Users/Akasha/Development/rustelo/template/config.dev.toml cargo run --bin server)",
|
||||||
|
"Bash(ENVIRONMENT=development CONFIG_FILE=config.dev.toml cargo run --bin server)",
|
||||||
|
"Bash(find:*)",
|
||||||
|
"Bash(ln:*)",
|
||||||
|
"Bash(cp:*)",
|
||||||
|
"Bash(npm run build:css:*)",
|
||||||
|
"Bash(killall:*)",
|
||||||
|
"Bash(true)",
|
||||||
|
"Bash(mv:*)",
|
||||||
|
"Bash(LEPTOS_OUTPUT_NAME=website cargo leptos build)",
|
||||||
|
"Bash(LEPTOS_OUTPUT_NAME=website cargo leptos serve --hot-reload)",
|
||||||
|
"Bash(pgrep:*)",
|
||||||
|
"Bash(./scripts/link-pkg-files.sh:*)",
|
||||||
|
"Bash(LEPTOS_OUTPUT_NAME=website cargo run --bin server)"
|
||||||
|
],
|
||||||
|
"deny": []
|
||||||
|
}
|
||||||
|
}
|
||||||
88
.env.example
Normal file
88
.env.example
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
# Server Configuration
|
||||||
|
# Copy this file to .env and modify the values as needed
|
||||||
|
|
||||||
|
# Root Path Configuration
|
||||||
|
# Base directory for all relative paths in the configuration
|
||||||
|
# If not set, defaults to current working directory
|
||||||
|
ROOT_PATH=.
|
||||||
|
|
||||||
|
# Server Protocol (http or https)
|
||||||
|
SERVER_PROTOCOL=http
|
||||||
|
|
||||||
|
# Server Host
|
||||||
|
SERVER_HOST=127.0.0.1
|
||||||
|
|
||||||
|
# Server Port
|
||||||
|
SERVER_PORT=3030
|
||||||
|
|
||||||
|
# TLS Configuration (only used when SERVER_PROTOCOL=https)
|
||||||
|
# Path to TLS certificate file
|
||||||
|
TLS_CERT_PATH=./certs/cert.pem
|
||||||
|
|
||||||
|
# Path to TLS private key file
|
||||||
|
TLS_KEY_PATH=./certs/key.pem
|
||||||
|
|
||||||
|
# Environment (development, production, dev, prod)
|
||||||
|
ENVIRONMENT=development
|
||||||
|
|
||||||
|
# Log Level (error, warn, info, debug, trace)
|
||||||
|
LOG_LEVEL=info
|
||||||
|
|
||||||
|
# Reload Port (for development)
|
||||||
|
RELOAD_PORT=3031
|
||||||
|
|
||||||
|
# Static Files Directory
|
||||||
|
STATIC_DIR=target/site
|
||||||
|
|
||||||
|
# Assets Directory
|
||||||
|
ASSETS_DIR=public
|
||||||
|
|
||||||
|
# Site Package Directory
|
||||||
|
SITE_PKG_DIR=pkg
|
||||||
|
|
||||||
|
# CORS Configuration
|
||||||
|
CORS_ALLOWED_ORIGINS=http://localhost:3030,http://127.0.0.1:3030
|
||||||
|
|
||||||
|
# Session Configuration
|
||||||
|
SESSION_SECRET=your-session-secret-key-change-this-in-production
|
||||||
|
|
||||||
|
# Database Configuration (if using a database)
|
||||||
|
# DATABASE_URL=postgresql://user:password@localhost/dbname
|
||||||
|
|
||||||
|
# Redis Configuration (if using Redis)
|
||||||
|
# REDIS_URL=redis://localhost:6379
|
||||||
|
|
||||||
|
# JWT Configuration
|
||||||
|
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
|
||||||
|
JWT_ISSUER=rustelo-auth
|
||||||
|
JWT_ACCESS_TOKEN_EXPIRES_IN=15
|
||||||
|
JWT_REFRESH_TOKEN_EXPIRES_IN=7
|
||||||
|
|
||||||
|
# OAuth Configuration
|
||||||
|
OAUTH_REDIRECT_BASE_URL=http://localhost:3030/auth/callback
|
||||||
|
|
||||||
|
# Google OAuth (optional)
|
||||||
|
# GOOGLE_CLIENT_ID=your-google-client-id
|
||||||
|
# GOOGLE_CLIENT_SECRET=your-google-client-secret
|
||||||
|
|
||||||
|
# GitHub OAuth (optional)
|
||||||
|
# GITHUB_CLIENT_ID=your-github-client-id
|
||||||
|
# GITHUB_CLIENT_SECRET=your-github-client-secret
|
||||||
|
|
||||||
|
# Discord OAuth (optional)
|
||||||
|
# DISCORD_CLIENT_ID=your-discord-client-id
|
||||||
|
# DISCORD_CLIENT_SECRET=your-discord-client-secret
|
||||||
|
|
||||||
|
# Microsoft OAuth (optional)
|
||||||
|
# MICROSOFT_CLIENT_ID=your-microsoft-client-id
|
||||||
|
# MICROSOFT_CLIENT_SECRET=your-microsoft-client-secret
|
||||||
|
# MICROSOFT_TENANT_ID=common
|
||||||
|
|
||||||
|
# External API Configuration
|
||||||
|
# API_BASE_URL=https://api.example.com
|
||||||
|
# API_KEY=your-api-key
|
||||||
|
|
||||||
|
# Feature Flags
|
||||||
|
ENABLE_METRICS=false
|
||||||
|
ENABLE_HEALTH_CHECK=true
|
||||||
|
ENABLE_COMPRESSION=true
|
||||||
@ -35,7 +35,7 @@ web-sys = { version = "0.3.77" , features = ["Clipboard", "Window", "Navigator",
|
|||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = "0.3"
|
tracing-subscriber = "0.3"
|
||||||
toml = "0.8"
|
toml = "0.9"
|
||||||
fluent = "0.17"
|
fluent = "0.17"
|
||||||
fluent-bundle = "0.16"
|
fluent-bundle = "0.16"
|
||||||
unic-langid = "0.9"
|
unic-langid = "0.9"
|
||||||
@ -52,6 +52,8 @@ site-root = "target/site"
|
|||||||
# The site-root relative folder where all compiled output (JS, WASM and CSS) is written
|
# The site-root relative folder where all compiled output (JS, WASM and CSS) is written
|
||||||
# Defaults to pkg
|
# Defaults to pkg
|
||||||
site-pkg-dir = "pkg"
|
site-pkg-dir = "pkg"
|
||||||
|
# Add hash to JS/WASM files for cache busting
|
||||||
|
hash-files = true
|
||||||
# The tailwind input file. Not needed if tailwind-input-file is not set
|
# The tailwind input file. Not needed if tailwind-input-file is not set
|
||||||
# Optional, Activates the tailwind build
|
# Optional, Activates the tailwind build
|
||||||
#tailwind-input-file = "input.css"
|
#tailwind-input-file = "input.css"
|
||||||
@ -59,7 +61,7 @@ site-pkg-dir = "pkg"
|
|||||||
# [Optional] Files in the asset-dir will be copied to the site-root directory
|
# [Optional] Files in the asset-dir will be copied to the site-root directory
|
||||||
assets-dir = "public"
|
assets-dir = "public"
|
||||||
# The IP and port (ex: 127.0.0.1:3000) where the server serves the content. Use it in your server setup.
|
# The IP and port (ex: 127.0.0.1:3000) where the server serves the content. Use it in your server setup.
|
||||||
site-addr = "127.0.0.1:3030"
|
site-addr = "0.0.0.0:3030"
|
||||||
# The port to use for automatic reload monitoring
|
# The port to use for automatic reload monitoring
|
||||||
reload-port = 3031
|
reload-port = 3031
|
||||||
|
|
||||||
|
|||||||
@ -180,7 +180,7 @@ ENABLE_CONTENT_DB=true
|
|||||||
ENABLE_TLS=false
|
ENABLE_TLS=false
|
||||||
|
|
||||||
# Database (choose one)
|
# Database (choose one)
|
||||||
DATABASE_URL=sqlite:database.db # SQLite (simple)
|
DATABASE_URL=sqlite://database.db # SQLite (simple)
|
||||||
# DATABASE_URL=postgresql://user:pass@localhost:5432/db # PostgreSQL (production)
|
# DATABASE_URL=postgresql://user:pass@localhost:5432/db # PostgreSQL (production)
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
|
|||||||
@ -403,7 +403,7 @@ The application automatically detects your database type from the connection URL
|
|||||||
DATABASE_URL=postgresql://user:pass@localhost/db
|
DATABASE_URL=postgresql://user:pass@localhost/db
|
||||||
|
|
||||||
# SQLite
|
# SQLite
|
||||||
DATABASE_URL=sqlite:data/app.db
|
DATABASE_URL=sqlite://data/app.db
|
||||||
```
|
```
|
||||||
|
|
||||||
### Migration System
|
### Migration System
|
||||||
|
|||||||
8
TODO.md
Normal file
8
TODO.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
- [X] Configuration builder
|
||||||
|
- [X] Admin Dashboard
|
||||||
|
- [ ] User profile manager
|
||||||
|
- [ ] Remove python script are in docs ?
|
||||||
|
|
||||||
|
- [ ] Add file upload capabilities** for media management?
|
||||||
|
- [ ] **Enhance the dashboard** with content analytics?
|
||||||
|
- [ ] **Show how to configure** the content sources (DB vs Files vs Both)?
|
||||||
85
book.toml
Normal file
85
book.toml
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
[book]
|
||||||
|
title = "Rustelo Documentation"
|
||||||
|
description = "A comprehensive guide to building web applications with Rustelo - a modular Rust web application template"
|
||||||
|
authors = ["Rustelo Contributors"]
|
||||||
|
language = "en"
|
||||||
|
multilingual = false
|
||||||
|
src = "book"
|
||||||
|
book = "_book"
|
||||||
|
|
||||||
|
[rust]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[build]
|
||||||
|
build-dir = "_book"
|
||||||
|
create-missing = true
|
||||||
|
preprocess = ["links", "index"]
|
||||||
|
use-default-preprocessors = true
|
||||||
|
|
||||||
|
[preprocessor.links]
|
||||||
|
# Process relative links and convert them to proper mdBook links
|
||||||
|
|
||||||
|
[preprocessor.index]
|
||||||
|
# Generate index pages automatically
|
||||||
|
|
||||||
|
[output.html]
|
||||||
|
default-theme = "light"
|
||||||
|
preferred-dark-theme = "navy"
|
||||||
|
smart-punctuation = true
|
||||||
|
mathjax-support = false
|
||||||
|
copy-fonts = true
|
||||||
|
|
||||||
|
edit-url-template = "https://github.com/yourusername/rustelo/edit/main/book/{path}"
|
||||||
|
site-url = "/docs/"
|
||||||
|
cname = ""
|
||||||
|
git-repository-url = "https://github.com/yourusername/rustelo"
|
||||||
|
git-repository-icon = "fa-github"
|
||||||
|
|
||||||
|
# Logo configuration
|
||||||
|
# additional-css = ["theme/custom.css"]
|
||||||
|
# additional-js = ["theme/custom.js"]
|
||||||
|
|
||||||
|
[output.html.print]
|
||||||
|
enable = true
|
||||||
|
page-break = true
|
||||||
|
|
||||||
|
[output.html.search]
|
||||||
|
enable = true
|
||||||
|
limit-results = 30
|
||||||
|
teaser-word-count = 30
|
||||||
|
use-boolean-and = true
|
||||||
|
boost-title = 2
|
||||||
|
boost-hierarchy = 1
|
||||||
|
boost-paragraph = 1
|
||||||
|
expand = true
|
||||||
|
heading-split-level = 3
|
||||||
|
|
||||||
|
[output.html.redirect]
|
||||||
|
# Add redirects for moved pages if needed
|
||||||
|
|
||||||
|
[output.html.fold]
|
||||||
|
enable = false
|
||||||
|
level = 0
|
||||||
|
|
||||||
|
[output.html.playground]
|
||||||
|
runnable = true
|
||||||
|
copyable = true
|
||||||
|
copy-js = true
|
||||||
|
line-numbers = false
|
||||||
|
editable = false
|
||||||
|
|
||||||
|
# [output.linkcheck]
|
||||||
|
# # Check for broken links
|
||||||
|
# optional = true
|
||||||
|
# follow-web-links = false
|
||||||
|
# traverse-parent-directories = false
|
||||||
|
# exclude = [ "private" ]
|
||||||
|
# # Temporarily disabled due to broken links
|
||||||
|
|
||||||
|
# Optional: Generate PDF output
|
||||||
|
# [output.pdf]
|
||||||
|
# enable = true
|
||||||
|
|
||||||
|
# Optional: Generate EPUB output
|
||||||
|
# [output.epub]
|
||||||
|
# enable = true
|
||||||
176
book/SUMMARY.md
Normal file
176
book/SUMMARY.md
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
# Summary
|
||||||
|
|
||||||
|
[Introduction](./introduction.md)
|
||||||
|
|
||||||
|
# Getting Started
|
||||||
|
|
||||||
|
- [What is Rustelo?](./getting-started/what-is-rustelo.md)
|
||||||
|
- [Quick Installation](./getting-started/installation.md)
|
||||||
|
- [First Run & Setup](./getting-started/first-run.md)
|
||||||
|
- [First App](./getting-started/first-app.md)
|
||||||
|
- [Basic Configuration](./getting-started/configuration.md)
|
||||||
|
|
||||||
|
# For End Users
|
||||||
|
|
||||||
|
## Using the Application
|
||||||
|
|
||||||
|
- [User Interface Guide](./users/interface.md)
|
||||||
|
- [User Registration & Login](./users/authentication.md)
|
||||||
|
- [Managing Your Profile](./users/profile.md)
|
||||||
|
- [Content Publishing](./users/content.md)
|
||||||
|
- [File & Media Management](./users/media.md)
|
||||||
|
|
||||||
|
## Features & Functionality
|
||||||
|
|
||||||
|
- [Authentication & Security](./users/features/auth.md)
|
||||||
|
- [Content Management](./users/features/content.md)
|
||||||
|
- [Email & Notifications](./users/features/email.md)
|
||||||
|
- [Search & Discovery](./users/features/search.md)
|
||||||
|
- [Mobile Experience](./users/features/mobile.md)
|
||||||
|
|
||||||
|
## Administration
|
||||||
|
|
||||||
|
- [Admin Dashboard](./users/admin/dashboard.md)
|
||||||
|
- [User Management](./users/admin/users.md)
|
||||||
|
- [Content Moderation](./users/admin/content.md)
|
||||||
|
- [System Settings](./users/admin/settings.md)
|
||||||
|
- [Monitoring & Analytics](./users/admin/monitoring.md)
|
||||||
|
|
||||||
|
# For Developers
|
||||||
|
|
||||||
|
## Development Setup
|
||||||
|
|
||||||
|
- [Development Environment](./developers/setup/environment.md)
|
||||||
|
- [Project Structure](./developers/setup/structure.md)
|
||||||
|
- [Build System & Tools](./developers/setup/build.md)
|
||||||
|
- [Development Workflow](./developers/setup/workflow.md)
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
- [System Overview](./developers/architecture/overview.md)
|
||||||
|
- [Frontend Architecture](./developers/architecture/frontend.md)
|
||||||
|
- [Backend Architecture](./developers/architecture/backend.md)
|
||||||
|
- [Database Design](./developers/architecture/database.md)
|
||||||
|
- [Security Model](./developers/architecture/security.md)
|
||||||
|
|
||||||
|
## Core Components
|
||||||
|
|
||||||
|
- [Components Overview](./developers/components/README.md)
|
||||||
|
- [Authentication System](./developers/components/auth.md)
|
||||||
|
- [Content Management](./developers/components/content.md)
|
||||||
|
- [Email System](./developers/components/email.md)
|
||||||
|
- [Template Engine](./developers/components/templates.md)
|
||||||
|
- [Configuration System](./developers/components/config.md)
|
||||||
|
|
||||||
|
## Feature Development
|
||||||
|
|
||||||
|
- [Adding New Features](./developers/features/adding-features.md)
|
||||||
|
- [Feature Flags & Modules](./developers/features/feature-flags.md)
|
||||||
|
- [Database Migrations](./developers/features/migrations.md)
|
||||||
|
- [API Endpoints](./developers/features/api-endpoints.md)
|
||||||
|
- [Frontend Components](./developers/features/frontend-components.md)
|
||||||
|
|
||||||
|
## Brand & Design
|
||||||
|
|
||||||
|
- [Logo Usage Guide](./developers/brand/logo-usage.md)
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
- [Testing Strategy](./developers/testing/strategy.md)
|
||||||
|
- [Unit Testing](./developers/testing/unit.md)
|
||||||
|
- [Integration Testing](./developers/testing/integration.md)
|
||||||
|
- [End-to-End Testing](./developers/testing/e2e.md)
|
||||||
|
- [Performance Testing](./developers/testing/performance.md)
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
|
||||||
|
- [Configuration Overview](./configuration/README.md)
|
||||||
|
- [Environment Variables](./configuration/environment.md)
|
||||||
|
- [Configuration Files](./configuration/files.md)
|
||||||
|
- [Features Configuration](./configuration/features.md)
|
||||||
|
- [Database Configuration](./configuration/database.md)
|
||||||
|
- [Security Settings](./configuration/security.md)
|
||||||
|
- [Performance Tuning](./configuration/performance.md)
|
||||||
|
|
||||||
|
# Deployment
|
||||||
|
|
||||||
|
- [Production Setup](./deployment/production.md)
|
||||||
|
- [Docker Deployment](./deployment/docker.md)
|
||||||
|
- [Cloud Platforms](./deployment/cloud.md)
|
||||||
|
- [SSL/TLS Configuration](./deployment/ssl.md)
|
||||||
|
- [Monitoring & Logging](./deployment/monitoring.md)
|
||||||
|
- [Backup & Recovery](./deployment/backup.md)
|
||||||
|
|
||||||
|
# API Reference
|
||||||
|
|
||||||
|
- [REST API Overview](./api/overview.md)
|
||||||
|
- [Authentication Endpoints](./api/auth.md)
|
||||||
|
- [Content Management API](./api/content.md)
|
||||||
|
- [User Management API](./api/users.md)
|
||||||
|
- [Email & Notifications API](./api/email.md)
|
||||||
|
- [Error Handling](./api/errors.md)
|
||||||
|
- [Rate Limiting](./api/rate-limiting.md)
|
||||||
|
|
||||||
|
# Security
|
||||||
|
|
||||||
|
- [Security Overview](./security/overview.md)
|
||||||
|
- [Authentication & Authorization](./security/auth.md)
|
||||||
|
- [Data Protection](./security/data-protection.md)
|
||||||
|
- [CSRF & XSS Prevention](./security/web-security.md)
|
||||||
|
- [TLS & Encryption](./security/encryption.md)
|
||||||
|
- [Security Best Practices](./security/best-practices.md)
|
||||||
|
|
||||||
|
# Performance
|
||||||
|
|
||||||
|
- [Performance Overview](./performance/overview.md)
|
||||||
|
- [Database Optimization](./performance/database.md)
|
||||||
|
- [Caching Strategies](./performance/caching.md)
|
||||||
|
- [Frontend Optimization](./performance/frontend.md)
|
||||||
|
- [Memory Management](./performance/memory.md)
|
||||||
|
- [Profiling & Monitoring](./performance/monitoring.md)
|
||||||
|
|
||||||
|
# Troubleshooting
|
||||||
|
|
||||||
|
- [Common Issues](./troubleshooting/common.md)
|
||||||
|
- [Installation Problems](./troubleshooting/installation.md)
|
||||||
|
- [Authentication Issues](./troubleshooting/auth.md)
|
||||||
|
- [Database Problems](./troubleshooting/database.md)
|
||||||
|
- [Performance Issues](./troubleshooting/performance.md)
|
||||||
|
- [Build & Development Issues](./troubleshooting/development.md)
|
||||||
|
- [Getting Help & Support](./troubleshooting/support.md)
|
||||||
|
|
||||||
|
# Advanced Topics
|
||||||
|
|
||||||
|
- [Custom Features & Extensions](./advanced/extensions.md)
|
||||||
|
- [Plugin Development](./advanced/plugins.md)
|
||||||
|
- [Theme Customization](./advanced/themes.md)
|
||||||
|
- [Integration Examples](./advanced/integrations.md)
|
||||||
|
- [Scaling & High Availability](./advanced/scaling.md)
|
||||||
|
- [Migration Strategies](./advanced/migrations.md)
|
||||||
|
|
||||||
|
# Contributing
|
||||||
|
|
||||||
|
- [Contributing Guidelines](./contributing/guidelines.md)
|
||||||
|
- [Development Setup](./contributing/setup.md)
|
||||||
|
- [Code Standards](./contributing/standards.md)
|
||||||
|
- [Testing Guidelines](./contributing/testing.md)
|
||||||
|
- [Documentation Guidelines](./contributing/docs.md)
|
||||||
|
- [Release Process](./contributing/releases.md)
|
||||||
|
|
||||||
|
# Reference
|
||||||
|
|
||||||
|
- [Configuration Options](./reference/config.md)
|
||||||
|
- [Environment Variables](./reference/env-vars.md)
|
||||||
|
- [CLI Commands](./reference/cli.md)
|
||||||
|
- [Database Schema](./reference/schema.md)
|
||||||
|
- [Error Codes](./reference/error-codes.md)
|
||||||
|
- [Feature Matrix](./reference/features.md)
|
||||||
|
- [System Requirements](./reference/requirements.md)
|
||||||
|
- [FAQ](./reference/faq.md)
|
||||||
|
- [Configuration Migration Guide](./reference/config-migration.md)
|
||||||
|
- [Environment Migration Guide](./reference/env-migration.md)
|
||||||
|
- [Feature Migration Guide](./reference/feature-migration.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[Glossary](./glossary.md)
|
||||||
0
book/advanced/custom-content.md
Normal file
0
book/advanced/custom-content.md
Normal file
0
book/advanced/custom-features.md
Normal file
0
book/advanced/custom-features.md
Normal file
0
book/advanced/extending-auth.md
Normal file
0
book/advanced/extending-auth.md
Normal file
1
book/advanced/extensions.md
Normal file
1
book/advanced/extensions.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Custom Features & Extensions
|
||||||
0
book/advanced/integrations.md
Normal file
0
book/advanced/integrations.md
Normal file
1
book/advanced/migrations.md
Normal file
1
book/advanced/migrations.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Migration Strategies
|
||||||
0
book/advanced/performance-tuning.md
Normal file
0
book/advanced/performance-tuning.md
Normal file
1
book/advanced/plugins.md
Normal file
1
book/advanced/plugins.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Plugin Development
|
||||||
1
book/advanced/scaling.md
Normal file
1
book/advanced/scaling.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Scaling & High Availability
|
||||||
1
book/advanced/themes.md
Normal file
1
book/advanced/themes.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Theme Customization
|
||||||
0
book/api/auth.md
Normal file
0
book/api/auth.md
Normal file
0
book/api/content.md
Normal file
0
book/api/content.md
Normal file
1
book/api/email.md
Normal file
1
book/api/email.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Email & Notifications API
|
||||||
0
book/api/errors.md
Normal file
0
book/api/errors.md
Normal file
0
book/api/overview.md
Normal file
0
book/api/overview.md
Normal file
0
book/api/rate-limiting.md
Normal file
0
book/api/rate-limiting.md
Normal file
1
book/api/users.md
Normal file
1
book/api/users.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# User Management API
|
||||||
0
book/appendices/cli-commands.md
Normal file
0
book/appendices/cli-commands.md
Normal file
51
book/appendices/env-variables.md
Normal file
51
book/appendices/env-variables.md
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# Environment Variables Reference
|
||||||
|
|
||||||
|
This document lists all environment variables used by Rustelo.
|
||||||
|
|
||||||
|
## Core Variables
|
||||||
|
|
||||||
|
| Variable | Description | Default | Required |
|
||||||
|
|----------|-------------|---------|----------|
|
||||||
|
| `SERVER_HOST` | Server bind address | `127.0.0.1` | No |
|
||||||
|
| `SERVER_PORT` | Server port | `3030` | No |
|
||||||
|
| `SERVER_PROTOCOL` | Protocol (http/https) | `http` | No |
|
||||||
|
| `ENVIRONMENT` | Environment (DEV/PROD) | `DEV` | No |
|
||||||
|
| `LOG_LEVEL` | Log level | `info` | No |
|
||||||
|
|
||||||
|
## Database Variables (auth, content-db features)
|
||||||
|
|
||||||
|
| Variable | Description | Default | Required |
|
||||||
|
|----------|-------------|---------|----------|
|
||||||
|
| `DATABASE_URL` | Database connection URL | - | Yes |
|
||||||
|
| `DATABASE_MAX_CONNECTIONS` | Maximum connections | `10` | No |
|
||||||
|
| `DATABASE_MIN_CONNECTIONS` | Minimum connections | `1` | No |
|
||||||
|
|
||||||
|
## Authentication Variables (auth feature)
|
||||||
|
|
||||||
|
| Variable | Description | Default | Required |
|
||||||
|
|----------|-------------|---------|----------|
|
||||||
|
| `JWT_SECRET` | JWT signing secret | - | Yes |
|
||||||
|
| `JWT_EXPIRATION_HOURS` | JWT expiration | `24` | No |
|
||||||
|
| `GOOGLE_CLIENT_ID` | Google OAuth client ID | - | No |
|
||||||
|
| `GOOGLE_CLIENT_SECRET` | Google OAuth secret | - | No |
|
||||||
|
| `GITHUB_CLIENT_ID` | GitHub OAuth client ID | - | No |
|
||||||
|
| `GITHUB_CLIENT_SECRET` | GitHub OAuth secret | - | No |
|
||||||
|
|
||||||
|
## TLS Variables (tls feature)
|
||||||
|
|
||||||
|
| Variable | Description | Default | Required |
|
||||||
|
|----------|-------------|---------|----------|
|
||||||
|
| `TLS_CERT_PATH` | TLS certificate path | - | Yes |
|
||||||
|
| `TLS_KEY_PATH` | TLS private key path | - | Yes |
|
||||||
|
|
||||||
|
## Email Variables (email feature)
|
||||||
|
|
||||||
|
| Variable | Description | Default | Required |
|
||||||
|
|----------|-------------|---------|----------|
|
||||||
|
| `EMAIL_PROVIDER` | Email provider | `console` | No |
|
||||||
|
| `EMAIL_FROM_ADDRESS` | Default from address | - | Yes |
|
||||||
|
| `EMAIL_FROM_NAME` | Default from name | - | No |
|
||||||
|
| `SMTP_HOST` | SMTP server host | - | Conditional |
|
||||||
|
| `SMTP_PORT` | SMTP server port | `587` | Conditional |
|
||||||
|
| `SMTP_USERNAME` | SMTP username | - | Conditional |
|
||||||
|
| `SMTP_PASSWORD` | SMTP password | - | Conditional |
|
||||||
0
book/appendices/faq.md
Normal file
0
book/appendices/faq.md
Normal file
38
book/appendices/feature-matrix.md
Normal file
38
book/appendices/feature-matrix.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# Feature Matrix
|
||||||
|
|
||||||
|
This matrix shows which features are available in different configurations.
|
||||||
|
|
||||||
|
| Feature | Minimal | Auth | Content | Email | TLS | Full |
|
||||||
|
|---------|---------|------|---------|-------|-----|------|
|
||||||
|
| Static Files | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| Routing | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| Security Headers | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| JWT Auth | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ |
|
||||||
|
| OAuth2 | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ |
|
||||||
|
| 2FA/TOTP | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ |
|
||||||
|
| Database Content | ❌ | ❌ | ✅ | ❌ | ❌ | ✅ |
|
||||||
|
| Markdown Rendering | ❌ | ❌ | ✅ | ❌ | ❌ | ✅ |
|
||||||
|
| Email System | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ |
|
||||||
|
| HTTPS/TLS | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ |
|
||||||
|
|
||||||
|
## Build Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Minimal
|
||||||
|
cargo build --no-default-features
|
||||||
|
|
||||||
|
# Authentication only
|
||||||
|
cargo build --no-default-features --features "auth"
|
||||||
|
|
||||||
|
# Content management only
|
||||||
|
cargo build --no-default-features --features "content-db"
|
||||||
|
|
||||||
|
# Email only
|
||||||
|
cargo build --no-default-features --features "email"
|
||||||
|
|
||||||
|
# TLS only
|
||||||
|
cargo build --no-default-features --features "tls"
|
||||||
|
|
||||||
|
# Full featured
|
||||||
|
cargo build --features "auth,content-db,email,tls"
|
||||||
|
```
|
||||||
0
book/appendices/migration-guide.md
Normal file
0
book/appendices/migration-guide.md
Normal file
424
book/configuration/README.md
Normal file
424
book/configuration/README.md
Normal file
@ -0,0 +1,424 @@
|
|||||||
|
# Rustelo Configuration
|
||||||
|
|
||||||
|
Welcome to the Rustelo Configuration documentation! This comprehensive guide covers all aspects of configuring your Rustelo application for different environments and use cases.
|
||||||
|
|
||||||
|
## 📋 Configuration Overview
|
||||||
|
|
||||||
|
Rustelo uses a powerful, modular configuration system that allows you to:
|
||||||
|
|
||||||
|
- **Environment-specific configurations** - Different settings for dev, staging, production
|
||||||
|
- **Feature-based configuration** - Enable/disable features as needed
|
||||||
|
- **Secure secret management** - Environment variables for sensitive data
|
||||||
|
- **Modular composition** - Build configurations from reusable components
|
||||||
|
- **Runtime validation** - Ensure configurations are valid before startup
|
||||||
|
|
||||||
|
## 🎯 Quick Start
|
||||||
|
|
||||||
|
### Basic Configuration
|
||||||
|
```bash
|
||||||
|
# Build development configuration
|
||||||
|
./config/scripts/build-config.sh dev
|
||||||
|
|
||||||
|
# Build production configuration
|
||||||
|
./config/scripts/build-config.sh prod config.prod.toml
|
||||||
|
|
||||||
|
# View configuration status
|
||||||
|
./config/scripts/debug-manage.sh status
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
```bash
|
||||||
|
# Create .env file
|
||||||
|
cat > .env << EOF
|
||||||
|
DATABASE_URL=sqlite//:app.db
|
||||||
|
SESSION_SECRET=your-session-secret
|
||||||
|
JWT_SECRET=your-jwt-secret
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Load environment
|
||||||
|
source .env
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📖 Configuration Guides
|
||||||
|
|
||||||
|
### Core Configuration
|
||||||
|
- **[Database Configuration](./database.md)** - Database connections, migrations, and pooling
|
||||||
|
- **[Environment Variables](./environment.md)** - Managing secrets and environment-specific settings
|
||||||
|
- **[Security Configuration](./security.md)** - Authentication, authorization, and security settings
|
||||||
|
- **[Performance Configuration](./performance.md)** - Optimization and performance tuning
|
||||||
|
|
||||||
|
### Advanced Configuration
|
||||||
|
- **[Feature Configuration](./features.md)** - Enable/disable application features
|
||||||
|
- **[Configuration Files](./files.md)** - Understanding configuration file structure
|
||||||
|
- **[Configuration Files](./files.md)** - Understanding configuration file structure
|
||||||
|
- **[Security Configuration](./security.md)** - Security settings and best practices
|
||||||
|
|
||||||
|
## 🏗️ Configuration Architecture
|
||||||
|
|
||||||
|
### File Structure
|
||||||
|
```
|
||||||
|
config/
|
||||||
|
├── base/ # Base configurations
|
||||||
|
│ ├── dev.toml # Development base
|
||||||
|
│ ├── prod.toml # Production base
|
||||||
|
│ └── example.toml # Example/documentation
|
||||||
|
├── features/ # Feature-specific configs
|
||||||
|
│ ├── auth/ # Authentication features
|
||||||
|
│ ├── content/ # Content management
|
||||||
|
│ ├── email/ # Email system
|
||||||
|
│ ├── metrics/ # Monitoring & metrics
|
||||||
|
│ └── tls/ # TLS/SSL configuration
|
||||||
|
└── scripts/ # Configuration tools
|
||||||
|
├── build-config.sh # Build configurations
|
||||||
|
├── debug-manage.sh # Debug and management
|
||||||
|
└── validate-config.sh # Validation tools
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration Layers
|
||||||
|
|
||||||
|
1. **Base Configuration** - Core application settings
|
||||||
|
2. **Feature Configuration** - Feature-specific settings
|
||||||
|
3. **Environment Variables** - Runtime secrets and overrides
|
||||||
|
4. **Command Line Arguments** - Runtime parameter overrides
|
||||||
|
|
||||||
|
## 🔧 Configuration Types
|
||||||
|
|
||||||
|
### Application Configuration
|
||||||
|
```toml
|
||||||
|
[app]
|
||||||
|
name = "My Rustelo App"
|
||||||
|
version = "1.0.0"
|
||||||
|
environment = "development"
|
||||||
|
debug = true
|
||||||
|
|
||||||
|
[server]
|
||||||
|
host = "127.0.0.1"
|
||||||
|
port = 3030
|
||||||
|
workers = 4
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database Configuration
|
||||||
|
```toml
|
||||||
|
[database]
|
||||||
|
url = "${DATABASE_URL}"
|
||||||
|
max_connections = 10
|
||||||
|
min_connections = 2
|
||||||
|
connect_timeout = 30
|
||||||
|
idle_timeout = 300
|
||||||
|
```
|
||||||
|
|
||||||
|
### Feature Configuration
|
||||||
|
```toml
|
||||||
|
[features]
|
||||||
|
auth = true
|
||||||
|
content_db = true
|
||||||
|
email = false
|
||||||
|
metrics = true
|
||||||
|
tls = false
|
||||||
|
```
|
||||||
|
|
||||||
|
### Security Configuration
|
||||||
|
```toml
|
||||||
|
[security]
|
||||||
|
session_secret = "${SESSION_SECRET}"
|
||||||
|
jwt_secret = "${JWT_SECRET}"
|
||||||
|
csrf_protection = true
|
||||||
|
rate_limiting = true
|
||||||
|
secure_cookies = true
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🌍 Environment Management
|
||||||
|
|
||||||
|
### Development Environment
|
||||||
|
```bash
|
||||||
|
# Development configuration
|
||||||
|
DATABASE_URL=sqlite//:dev.db
|
||||||
|
SESSION_SECRET=dev-session-secret
|
||||||
|
LOG_LEVEL=debug
|
||||||
|
ENABLE_HOT_RELOAD=true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Production Environment
|
||||||
|
```bash
|
||||||
|
# Production configuration
|
||||||
|
DATABASE_URL=postgresql://user:pass@host:5432/db
|
||||||
|
SESSION_SECRET=secure-random-secret
|
||||||
|
LOG_LEVEL=info
|
||||||
|
ENABLE_HOT_RELOAD=false
|
||||||
|
DOMAIN=myapp.com
|
||||||
|
```
|
||||||
|
|
||||||
|
### Staging Environment
|
||||||
|
```bash
|
||||||
|
# Staging configuration
|
||||||
|
DATABASE_URL=postgresql://user:pass@staging-host:5432/db
|
||||||
|
SESSION_SECRET=staging-secret
|
||||||
|
LOG_LEVEL=info
|
||||||
|
ENABLE_DEBUG=false
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔐 Secret Management
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
```bash
|
||||||
|
# Required secrets
|
||||||
|
export SESSION_SECRET=$(openssl rand -base64 32)
|
||||||
|
export JWT_SECRET=$(openssl rand -base64 32)
|
||||||
|
export DATABASE_URL="postgresql://user:pass@host:5432/db"
|
||||||
|
|
||||||
|
# Optional secrets
|
||||||
|
export SMTP_PASSWORD="your-smtp-password"
|
||||||
|
export OAUTH_CLIENT_SECRET="your-oauth-secret"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Secret Management Tools
|
||||||
|
```bash
|
||||||
|
# Generate secure secrets
|
||||||
|
./config/scripts/generate-secrets.sh
|
||||||
|
|
||||||
|
# Encrypt/decrypt configuration
|
||||||
|
./config/scripts/encrypt-config.sh
|
||||||
|
./config/scripts/decrypt-config.sh
|
||||||
|
|
||||||
|
# Validate secrets
|
||||||
|
./config/scripts/validate-secrets.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎛️ Feature Management
|
||||||
|
|
||||||
|
### Enabling Features
|
||||||
|
```toml
|
||||||
|
[features]
|
||||||
|
# Authentication system
|
||||||
|
auth = true
|
||||||
|
|
||||||
|
# Content management
|
||||||
|
content_db = true
|
||||||
|
|
||||||
|
# Email functionality
|
||||||
|
email = true
|
||||||
|
|
||||||
|
# Monitoring and metrics
|
||||||
|
metrics = true
|
||||||
|
|
||||||
|
# TLS/SSL support
|
||||||
|
tls = true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Feature Dependencies
|
||||||
|
```toml
|
||||||
|
[features.auth]
|
||||||
|
enabled = true
|
||||||
|
dependencies = ["crypto", "database"]
|
||||||
|
|
||||||
|
[features.content_db]
|
||||||
|
enabled = true
|
||||||
|
dependencies = ["database", "auth"]
|
||||||
|
|
||||||
|
[features.email]
|
||||||
|
enabled = false
|
||||||
|
dependencies = ["auth"]
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 Configuration Best Practices
|
||||||
|
|
||||||
|
### Development Best Practices
|
||||||
|
- Use SQLite for development databases
|
||||||
|
- Enable debug logging
|
||||||
|
- Use relaxed security settings
|
||||||
|
- Enable hot reloading
|
||||||
|
- Use local file storage
|
||||||
|
|
||||||
|
### Production Best Practices
|
||||||
|
- Use PostgreSQL for production databases
|
||||||
|
- Enable minimal logging
|
||||||
|
- Use strict security settings
|
||||||
|
- Disable debug features
|
||||||
|
- Use cloud storage services
|
||||||
|
|
||||||
|
### Security Best Practices
|
||||||
|
- Never commit secrets to version control
|
||||||
|
- Use environment variables for sensitive data
|
||||||
|
- Rotate secrets regularly
|
||||||
|
- Use strong encryption keys
|
||||||
|
- Enable HTTPS in production
|
||||||
|
|
||||||
|
## 📊 Configuration Validation
|
||||||
|
|
||||||
|
### Validation Scripts
|
||||||
|
```bash
|
||||||
|
# Validate current configuration
|
||||||
|
./config/scripts/validate-config.sh
|
||||||
|
|
||||||
|
# Validate specific environment
|
||||||
|
./config/scripts/validate-config.sh prod
|
||||||
|
|
||||||
|
# Check configuration completeness
|
||||||
|
./config/scripts/check-config.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Schema Validation
|
||||||
|
```toml
|
||||||
|
[validation]
|
||||||
|
strict_mode = true
|
||||||
|
required_fields = ["database.url", "security.session_secret"]
|
||||||
|
allowed_environments = ["dev", "staging", "prod"]
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔄 Configuration Updates
|
||||||
|
|
||||||
|
### Runtime Updates
|
||||||
|
```bash
|
||||||
|
# Reload configuration (if supported)
|
||||||
|
kill -HUP $(pidof rustelo-server)
|
||||||
|
|
||||||
|
# Update feature flags
|
||||||
|
./config/scripts/update-features.sh --enable email
|
||||||
|
|
||||||
|
# Apply configuration changes
|
||||||
|
./config/scripts/apply-config.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration Deployment
|
||||||
|
```bash
|
||||||
|
# Deploy configuration to staging
|
||||||
|
./config/scripts/deploy-config.sh staging
|
||||||
|
|
||||||
|
# Deploy configuration to production
|
||||||
|
./config/scripts/deploy-config.sh prod
|
||||||
|
|
||||||
|
# Rollback configuration
|
||||||
|
./config/scripts/rollback-config.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🧪 Testing Configuration
|
||||||
|
|
||||||
|
### Configuration Tests
|
||||||
|
```bash
|
||||||
|
# Test configuration validity
|
||||||
|
just config-test
|
||||||
|
|
||||||
|
# Test feature configurations
|
||||||
|
just config-test-features
|
||||||
|
|
||||||
|
# Test environment configurations
|
||||||
|
just config-test-env prod
|
||||||
|
```
|
||||||
|
|
||||||
|
### Integration Tests
|
||||||
|
```bash
|
||||||
|
# Test configuration integration
|
||||||
|
cargo test --test config_integration
|
||||||
|
|
||||||
|
# Test feature integration
|
||||||
|
cargo test --test feature_integration
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔍 Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
#### Configuration Not Found
|
||||||
|
```bash
|
||||||
|
# Check configuration file exists
|
||||||
|
ls -la config.toml
|
||||||
|
|
||||||
|
# Rebuild configuration
|
||||||
|
./config/scripts/build-config.sh dev
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Environment Variables Missing
|
||||||
|
```bash
|
||||||
|
# Check environment variables
|
||||||
|
env | grep -E "(DATABASE_URL|SESSION_SECRET|JWT_SECRET)"
|
||||||
|
|
||||||
|
# Load environment file
|
||||||
|
source .env
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Feature Configuration Conflicts
|
||||||
|
```bash
|
||||||
|
# Check feature dependencies
|
||||||
|
./config/scripts/debug-manage.sh check-features
|
||||||
|
|
||||||
|
# Resolve conflicts
|
||||||
|
./config/scripts/resolve-conflicts.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Debug Tools
|
||||||
|
```bash
|
||||||
|
# Debug configuration
|
||||||
|
./config/scripts/debug-manage.sh debug
|
||||||
|
|
||||||
|
# Show configuration tree
|
||||||
|
./config/scripts/debug-manage.sh tree
|
||||||
|
|
||||||
|
# Validate configuration
|
||||||
|
./config/scripts/debug-manage.sh validate
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📚 Configuration Examples
|
||||||
|
|
||||||
|
### Minimal Configuration
|
||||||
|
```toml
|
||||||
|
[app]
|
||||||
|
name = "My App"
|
||||||
|
environment = "development"
|
||||||
|
|
||||||
|
[database]
|
||||||
|
url = "sqlite://app.db"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
auth = true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Full-Featured Configuration
|
||||||
|
```toml
|
||||||
|
[app]
|
||||||
|
name = "Production App"
|
||||||
|
environment = "production"
|
||||||
|
debug = false
|
||||||
|
|
||||||
|
[server]
|
||||||
|
host = "0.0.0.0"
|
||||||
|
port = 443
|
||||||
|
workers = 8
|
||||||
|
|
||||||
|
[database]
|
||||||
|
url = "${DATABASE_URL}"
|
||||||
|
max_connections = 20
|
||||||
|
ssl_mode = "require"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
auth = true
|
||||||
|
content_db = true
|
||||||
|
email = true
|
||||||
|
metrics = true
|
||||||
|
tls = true
|
||||||
|
|
||||||
|
[security]
|
||||||
|
session_secret = "${SESSION_SECRET}"
|
||||||
|
jwt_secret = "${JWT_SECRET}"
|
||||||
|
csrf_protection = true
|
||||||
|
rate_limiting = true
|
||||||
|
secure_cookies = true
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎯 Next Steps
|
||||||
|
|
||||||
|
1. **[Database Configuration](./database.md)** - Set up your database
|
||||||
|
2. **[Environment Variables](./environment.md)** - Configure environment-specific settings
|
||||||
|
3. **[Security Configuration](./security.md)** - Secure your application
|
||||||
|
4. **[Feature Configuration](./features.md)** - Enable the features you need
|
||||||
|
5. **[Performance Configuration](./performance.md)** - Optimize for production
|
||||||
|
|
||||||
|
## 🆘 Getting Help
|
||||||
|
|
||||||
|
- **[Common Issues](../troubleshooting/common.md)** - Solutions to common problems
|
||||||
|
- **[Configuration Files Guide](./files.md)** - Understanding configuration structure
|
||||||
|
- **[Environment Guide](./environment.md)** - Environment variable management
|
||||||
|
- **Community Support** - Discord, GitHub Issues, Stack Overflow
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Master your Rustelo configuration!** 🦀⚙️
|
||||||
343
book/configuration/database.md
Normal file
343
book/configuration/database.md
Normal file
@ -0,0 +1,343 @@
|
|||||||
|
# Database Configuration
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<img src="../../logos/rustelo_dev-logo-h.svg" alt="RUSTELO" width="300" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
This guide covers how to configure and use databases in RUSTELO. The application supports both **PostgreSQL** and **SQLite** databases through SQLx's unified interface, with automatic database type detection based on the connection URL.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### SQLite (Recommended for Development)
|
||||||
|
```toml
|
||||||
|
[database]
|
||||||
|
url = "sqlite://database.db"
|
||||||
|
```
|
||||||
|
|
||||||
|
### PostgreSQL (Recommended for Production)
|
||||||
|
```toml
|
||||||
|
[database]
|
||||||
|
url = "postgresql://username:password@localhost:5432/database_name"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Database URL Formats
|
||||||
|
|
||||||
|
### SQLite URLs
|
||||||
|
- `sqlite://database.db` - Relative path to database file
|
||||||
|
- `sqlite:///path/to/database.db` - Absolute path to database file
|
||||||
|
- `sqlite::memory:` - In-memory database (testing only)
|
||||||
|
|
||||||
|
### PostgreSQL URLs
|
||||||
|
- `postgresql://user:password@host:port/database`
|
||||||
|
- `postgres://user:password@host:port/database`
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
You can override the database URL using environment variables:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export DATABASE_URL="sqlite//:my_database.db"
|
||||||
|
# or
|
||||||
|
export DATABASE_URL="postgresql://user:pass@localhost:5432/mydb"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Database-Specific Features
|
||||||
|
|
||||||
|
### SQLite
|
||||||
|
- **Pros:**
|
||||||
|
- Zero configuration setup
|
||||||
|
- Single file database
|
||||||
|
- Perfect for development and testing
|
||||||
|
- No separate server process required
|
||||||
|
- ACID compliant
|
||||||
|
|
||||||
|
- **Cons:**
|
||||||
|
- Limited concurrent writes
|
||||||
|
- No network access
|
||||||
|
- Fewer advanced features
|
||||||
|
- File-based storage
|
||||||
|
|
||||||
|
### PostgreSQL
|
||||||
|
- **Pros:**
|
||||||
|
- Full ACID compliance
|
||||||
|
- Excellent concurrent access
|
||||||
|
- Advanced features (JSONB, arrays, etc.)
|
||||||
|
- Network accessible
|
||||||
|
- Production-ready scalability
|
||||||
|
|
||||||
|
- **Cons:**
|
||||||
|
- Requires PostgreSQL server
|
||||||
|
- More complex setup
|
||||||
|
- Resource overhead
|
||||||
|
|
||||||
|
## Configuration Examples
|
||||||
|
|
||||||
|
### Development Configuration
|
||||||
|
```toml
|
||||||
|
# config.dev.toml
|
||||||
|
[database]
|
||||||
|
url = "sqlite://dev_database.db"
|
||||||
|
max_connections = 5
|
||||||
|
min_connections = 1
|
||||||
|
connect_timeout = 30
|
||||||
|
idle_timeout = 300
|
||||||
|
max_lifetime = 1800
|
||||||
|
```
|
||||||
|
|
||||||
|
### Production Configuration
|
||||||
|
```toml
|
||||||
|
# config.prod.toml
|
||||||
|
[database]
|
||||||
|
url = "postgresql://prod_user:${DATABASE_PASSWORD}@db.example.com:5432/prod_database"
|
||||||
|
max_connections = 20
|
||||||
|
min_connections = 5
|
||||||
|
connect_timeout = 30
|
||||||
|
idle_timeout = 600
|
||||||
|
max_lifetime = 3600
|
||||||
|
```
|
||||||
|
|
||||||
|
## Connection Pool Settings
|
||||||
|
|
||||||
|
| Setting | Description | SQLite | PostgreSQL |
|
||||||
|
|---------|-------------|--------|------------|
|
||||||
|
| `max_connections` | Maximum pool size | 1 (recommended) | 10-50 |
|
||||||
|
| `min_connections` | Minimum pool size | 1 | 1-5 |
|
||||||
|
| `connect_timeout` | Connection timeout (seconds) | 30 | 30 |
|
||||||
|
| `idle_timeout` | Idle connection timeout (seconds) | 300 | 600 |
|
||||||
|
| `max_lifetime` | Maximum connection lifetime (seconds) | 1800 | 3600 |
|
||||||
|
|
||||||
|
## Database Setup
|
||||||
|
|
||||||
|
### SQLite Setup
|
||||||
|
No setup required! The database file will be created automatically when the application starts.
|
||||||
|
|
||||||
|
### PostgreSQL Setup
|
||||||
|
|
||||||
|
#### Using Docker
|
||||||
|
```bash
|
||||||
|
# Start PostgreSQL container
|
||||||
|
docker run -d \
|
||||||
|
--name postgres \
|
||||||
|
-e POSTGRES_PASSWORD=password \
|
||||||
|
-e POSTGRES_DB=myapp \
|
||||||
|
-p 5432:5432 \
|
||||||
|
postgres:15
|
||||||
|
|
||||||
|
# Connect to database
|
||||||
|
docker exec -it postgres psql -U postgres -d myapp
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Using Local Installation
|
||||||
|
|
||||||
|
**macOS (Homebrew):**
|
||||||
|
```bash
|
||||||
|
brew install postgresql
|
||||||
|
brew services start postgresql
|
||||||
|
createdb myapp
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ubuntu/Debian:**
|
||||||
|
```bash
|
||||||
|
sudo apt-get install postgresql postgresql-contrib
|
||||||
|
sudo systemctl start postgresql
|
||||||
|
sudo -u postgres createdb myapp
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration Support
|
||||||
|
|
||||||
|
The application automatically creates the necessary tables for both database types:
|
||||||
|
|
||||||
|
### SQLite Tables
|
||||||
|
- Uses `TEXT` for IDs (UUID format)
|
||||||
|
- Uses `DATETIME` for timestamps
|
||||||
|
- Uses `TEXT` for JSON storage
|
||||||
|
- Uses `BOOLEAN` for boolean values
|
||||||
|
|
||||||
|
### PostgreSQL Tables
|
||||||
|
- Uses `UUID` for IDs with `gen_random_uuid()`
|
||||||
|
- Uses `TIMESTAMPTZ` for timestamps
|
||||||
|
- Uses `JSONB` for JSON storage
|
||||||
|
- Uses `BOOLEAN` for boolean values
|
||||||
|
|
||||||
|
## Switching Between Databases
|
||||||
|
|
||||||
|
You can switch between databases by simply changing the `DATABASE_URL`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Switch to SQLite
|
||||||
|
export DATABASE_URL="sqlite://database.db"
|
||||||
|
|
||||||
|
# Switch to PostgreSQL
|
||||||
|
export DATABASE_URL="postgresql://user:pass@localhost:5432/mydb"
|
||||||
|
```
|
||||||
|
|
||||||
|
The application will automatically:
|
||||||
|
1. Detect the database type
|
||||||
|
2. Use appropriate SQL syntax
|
||||||
|
3. Create compatible table schemas
|
||||||
|
4. Handle data type differences
|
||||||
|
|
||||||
|
## Performance Considerations
|
||||||
|
|
||||||
|
### SQLite
|
||||||
|
- **Best for:**
|
||||||
|
- Single-user applications
|
||||||
|
- Development and testing
|
||||||
|
- Small to medium datasets
|
||||||
|
- Read-heavy workloads
|
||||||
|
|
||||||
|
- **Optimization tips:**
|
||||||
|
- Use WAL mode: `PRAGMA journal_mode=WAL`
|
||||||
|
- Set appropriate timeout: `PRAGMA busy_timeout=5000`
|
||||||
|
- Use transactions for bulk operations
|
||||||
|
|
||||||
|
### PostgreSQL
|
||||||
|
- **Best for:**
|
||||||
|
- Multi-user applications
|
||||||
|
- Production environments
|
||||||
|
- Large datasets
|
||||||
|
- High concurrency requirements
|
||||||
|
|
||||||
|
- **Optimization tips:**
|
||||||
|
- Configure appropriate connection pool size
|
||||||
|
- Use indexes on frequently queried columns
|
||||||
|
- Monitor and tune PostgreSQL configuration
|
||||||
|
- Use connection pooling (PgBouncer) for high traffic
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common SQLite Issues
|
||||||
|
- **Database locked**: Check for long-running transactions
|
||||||
|
- **File permissions**: Ensure write access to database file and directory
|
||||||
|
- **Disk space**: Verify sufficient disk space for database growth
|
||||||
|
|
||||||
|
### Common PostgreSQL Issues
|
||||||
|
- **Connection refused**: Check PostgreSQL server status
|
||||||
|
- **Authentication failed**: Verify username/password and pg_hba.conf
|
||||||
|
- **Too many connections**: Adjust max_connections or use connection pooling
|
||||||
|
|
||||||
|
### Debug Connection Issues
|
||||||
|
```bash
|
||||||
|
# Test SQLite connection
|
||||||
|
sqlite3 database.db "SELECT 1;"
|
||||||
|
|
||||||
|
# Test PostgreSQL connection
|
||||||
|
psql "postgresql://user:pass@localhost:5432/mydb" -c "SELECT 1;"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environment-Specific Configuration
|
||||||
|
|
||||||
|
### Development
|
||||||
|
```bash
|
||||||
|
# .env.development
|
||||||
|
DATABASE_URL=sqlite://dev_database.db
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
```bash
|
||||||
|
# .env.test
|
||||||
|
DATABASE_URL=sqlite::memory:
|
||||||
|
```
|
||||||
|
|
||||||
|
### Production
|
||||||
|
```bash
|
||||||
|
# .env.production
|
||||||
|
DATABASE_URL=postgresql://user:${DATABASE_PASSWORD}@db.internal:5432/prod_db
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
### SQLite Security
|
||||||
|
- Protect database file permissions (600 or 640)
|
||||||
|
- Backup database files securely
|
||||||
|
- Consider encryption for sensitive data
|
||||||
|
|
||||||
|
### PostgreSQL Security
|
||||||
|
- Use strong passwords
|
||||||
|
- Enable SSL/TLS connections
|
||||||
|
- Restrict network access
|
||||||
|
- Regular security updates
|
||||||
|
- Use connection pooling with authentication
|
||||||
|
|
||||||
|
## Backup and Recovery
|
||||||
|
|
||||||
|
### SQLite Backup
|
||||||
|
```bash
|
||||||
|
# Simple file copy
|
||||||
|
cp database.db database_backup.db
|
||||||
|
|
||||||
|
# Using SQLite backup command
|
||||||
|
sqlite3 database.db ".backup database_backup.db"
|
||||||
|
```
|
||||||
|
|
||||||
|
### PostgreSQL Backup
|
||||||
|
```bash
|
||||||
|
# Database dump
|
||||||
|
pg_dump myapp > myapp_backup.sql
|
||||||
|
|
||||||
|
# Restore from dump
|
||||||
|
psql myapp < myapp_backup.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
## Monitoring and Maintenance
|
||||||
|
|
||||||
|
### SQLite Maintenance
|
||||||
|
```sql
|
||||||
|
-- Analyze database
|
||||||
|
ANALYZE;
|
||||||
|
|
||||||
|
-- Vacuum database
|
||||||
|
VACUUM;
|
||||||
|
|
||||||
|
-- Check integrity
|
||||||
|
PRAGMA integrity_check;
|
||||||
|
```
|
||||||
|
|
||||||
|
### PostgreSQL Maintenance
|
||||||
|
```sql
|
||||||
|
-- Analyze tables
|
||||||
|
ANALYZE;
|
||||||
|
|
||||||
|
-- Vacuum tables
|
||||||
|
VACUUM;
|
||||||
|
|
||||||
|
-- Check database size
|
||||||
|
SELECT pg_size_pretty(pg_database_size('myapp'));
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Use environment variables** for database URLs in production
|
||||||
|
2. **Configure appropriate connection pools** based on your workload
|
||||||
|
3. **Monitor database performance** and adjust settings as needed
|
||||||
|
4. **Regular backups** are essential for production databases
|
||||||
|
5. **Test migrations** on both database types if supporting both
|
||||||
|
6. **Use transactions** for data consistency
|
||||||
|
7. **Index frequently queried columns** for better performance
|
||||||
|
8. **Monitor connection pool usage** to prevent exhaustion
|
||||||
|
|
||||||
|
## Feature Compatibility Matrix
|
||||||
|
|
||||||
|
| Feature | SQLite | PostgreSQL |
|
||||||
|
|---------|--------|------------|
|
||||||
|
| ACID Transactions | ✅ | ✅ |
|
||||||
|
| Concurrent Reads | ✅ | ✅ |
|
||||||
|
| Concurrent Writes | ⚠️ Limited | ✅ |
|
||||||
|
| JSON Support | ✅ (TEXT) | ✅ (JSONB) |
|
||||||
|
| Full-text Search | ✅ (FTS) | ✅ (Built-in) |
|
||||||
|
| Network Access | ❌ | ✅ |
|
||||||
|
| Replication | ❌ | ✅ |
|
||||||
|
| Partitioning | ❌ | ✅ |
|
||||||
|
| Custom Functions | ✅ | ✅ |
|
||||||
|
| Triggers | ✅ | ✅ |
|
||||||
|
| Views | ✅ | ✅ |
|
||||||
|
| Stored Procedures | ❌ | ✅ |
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- [Database Migrations](../developers/features/migrations.md)
|
||||||
|
- [Performance Optimization](../performance/database.md)
|
||||||
|
- [Security Best Practices](../security/data-protection.md)
|
||||||
|
- [Backup Strategies](../deployment/backup.md)
|
||||||
|
|
||||||
|
This guide should help you choose and configure the right database for your needs. Both options are fully supported and the application will work seamlessly with either choice.
|
||||||
543
book/configuration/environment.md
Normal file
543
book/configuration/environment.md
Normal file
@ -0,0 +1,543 @@
|
|||||||
|
# Environment Variables
|
||||||
|
|
||||||
|
Rustelo uses environment variables to configure sensitive settings, deployment-specific values, and runtime parameters. This approach ensures that secrets are kept separate from the codebase while allowing flexible configuration across different environments.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Environment variables in Rustelo are used for:
|
||||||
|
|
||||||
|
- **Sensitive Information**: Database credentials, API keys, secrets
|
||||||
|
- **Environment-Specific Settings**: URLs, domains, feature flags
|
||||||
|
- **Runtime Configuration**: Debug modes, logging levels, performance tuning
|
||||||
|
- **Third-Party Integration**: External service configuration
|
||||||
|
|
||||||
|
## Variable Categories
|
||||||
|
|
||||||
|
### Core System Variables
|
||||||
|
|
||||||
|
#### `RUSTELO_ENV`
|
||||||
|
- **Description**: Application environment
|
||||||
|
- **Values**: `development`, `production`, `staging`, `test`
|
||||||
|
- **Default**: `development`
|
||||||
|
- **Example**: `RUSTELO_ENV=production`
|
||||||
|
|
||||||
|
#### `RUSTELO_CONFIG_FILE`
|
||||||
|
- **Description**: Path to configuration file
|
||||||
|
- **Default**: `config.toml`
|
||||||
|
- **Example**: `RUSTELO_CONFIG_FILE=/etc/rustelo/config.prod.toml`
|
||||||
|
|
||||||
|
#### `RUSTELO_LOG_LEVEL`
|
||||||
|
- **Description**: Global log level override
|
||||||
|
- **Values**: `error`, `warn`, `info`, `debug`, `trace`
|
||||||
|
- **Default**: From config file
|
||||||
|
- **Example**: `RUSTELO_LOG_LEVEL=info`
|
||||||
|
|
||||||
|
### Database Configuration
|
||||||
|
|
||||||
|
#### `DATABASE_URL`
|
||||||
|
- **Description**: Database connection string
|
||||||
|
- **Required**: Yes (production)
|
||||||
|
- **Format**: `postgresql://user:password@host:port/database`
|
||||||
|
- **Example**: `DATABASE_URL=postgresql://rustelo:password@localhost:5432/rustelo_prod`
|
||||||
|
|
||||||
|
#### `DATABASE_MAX_CONNECTIONS`
|
||||||
|
- **Description**: Maximum database connections
|
||||||
|
- **Default**: From config file
|
||||||
|
- **Example**: `DATABASE_MAX_CONNECTIONS=20`
|
||||||
|
|
||||||
|
#### `DATABASE_SSL_MODE`
|
||||||
|
- **Description**: Database SSL mode
|
||||||
|
- **Values**: `disable`, `allow`, `prefer`, `require`
|
||||||
|
- **Default**: `prefer`
|
||||||
|
- **Example**: `DATABASE_SSL_MODE=require`
|
||||||
|
|
||||||
|
### Authentication & Security
|
||||||
|
|
||||||
|
#### `SESSION_SECRET`
|
||||||
|
- **Description**: Session encryption secret
|
||||||
|
- **Required**: Yes
|
||||||
|
- **Min Length**: 32 characters
|
||||||
|
- **Example**: `SESSION_SECRET=your-very-long-and-secure-session-secret-here`
|
||||||
|
|
||||||
|
#### `JWT_SECRET`
|
||||||
|
- **Description**: JWT signing secret
|
||||||
|
- **Required**: Yes (if JWT enabled)
|
||||||
|
- **Min Length**: 32 characters
|
||||||
|
- **Example**: `JWT_SECRET=your-jwt-signing-secret-here`
|
||||||
|
|
||||||
|
#### `ENCRYPTION_KEY`
|
||||||
|
- **Description**: Application-level encryption key
|
||||||
|
- **Required**: Yes (if encryption enabled)
|
||||||
|
- **Length**: 32 bytes (base64 encoded)
|
||||||
|
- **Example**: `ENCRYPTION_KEY=your-base64-encoded-encryption-key`
|
||||||
|
|
||||||
|
#### `CSRF_SECRET`
|
||||||
|
- **Description**: CSRF protection secret
|
||||||
|
- **Required**: No (auto-generated if not provided)
|
||||||
|
- **Example**: `CSRF_SECRET=your-csrf-secret-here`
|
||||||
|
|
||||||
|
### Email Configuration
|
||||||
|
|
||||||
|
#### `SMTP_HOST`
|
||||||
|
- **Description**: SMTP server hostname
|
||||||
|
- **Required**: Yes (if email enabled)
|
||||||
|
- **Example**: `SMTP_HOST=smtp.gmail.com`
|
||||||
|
|
||||||
|
#### `SMTP_PORT`
|
||||||
|
- **Description**: SMTP server port
|
||||||
|
- **Default**: `587`
|
||||||
|
- **Example**: `SMTP_PORT=587`
|
||||||
|
|
||||||
|
#### `SMTP_USERNAME`
|
||||||
|
- **Description**: SMTP authentication username
|
||||||
|
- **Required**: Yes (if SMTP auth enabled)
|
||||||
|
- **Example**: `SMTP_USERNAME=your-app@gmail.com`
|
||||||
|
|
||||||
|
#### `SMTP_PASSWORD`
|
||||||
|
- **Description**: SMTP authentication password
|
||||||
|
- **Required**: Yes (if SMTP auth enabled)
|
||||||
|
- **Example**: `SMTP_PASSWORD=your-app-password`
|
||||||
|
|
||||||
|
#### `FROM_EMAIL`
|
||||||
|
- **Description**: Default sender email address
|
||||||
|
- **Required**: Yes (if email enabled)
|
||||||
|
- **Example**: `FROM_EMAIL=noreply@yourapp.com`
|
||||||
|
|
||||||
|
#### `FROM_NAME`
|
||||||
|
- **Description**: Default sender name
|
||||||
|
- **Default**: Application name
|
||||||
|
- **Example**: `FROM_NAME=Your App Name`
|
||||||
|
|
||||||
|
### Web Server Configuration
|
||||||
|
|
||||||
|
#### `RUSTELO_HOST`
|
||||||
|
- **Description**: Server bind address
|
||||||
|
- **Default**: `127.0.0.1` (dev), `0.0.0.0` (prod)
|
||||||
|
- **Example**: `RUSTELO_HOST=0.0.0.0`
|
||||||
|
|
||||||
|
#### `RUSTELO_PORT`
|
||||||
|
- **Description**: Server port
|
||||||
|
- **Default**: `3030`
|
||||||
|
- **Example**: `RUSTELO_PORT=8080`
|
||||||
|
|
||||||
|
#### `RUSTELO_WORKERS`
|
||||||
|
- **Description**: Number of worker threads
|
||||||
|
- **Default**: CPU core count
|
||||||
|
- **Example**: `RUSTELO_WORKERS=4`
|
||||||
|
|
||||||
|
#### `DOMAIN`
|
||||||
|
- **Description**: Application domain for cookies and CORS
|
||||||
|
- **Required**: Yes (production)
|
||||||
|
- **Example**: `DOMAIN=yourapp.com`
|
||||||
|
|
||||||
|
#### `FRONTEND_URL`
|
||||||
|
- **Description**: Frontend application URL
|
||||||
|
- **Required**: Yes (if separate frontend)
|
||||||
|
- **Example**: `FRONTEND_URL=https://app.yourapp.com`
|
||||||
|
|
||||||
|
### Redis Configuration
|
||||||
|
|
||||||
|
#### `REDIS_URL`
|
||||||
|
- **Description**: Redis connection string
|
||||||
|
- **Required**: Yes (if Redis enabled)
|
||||||
|
- **Example**: `REDIS_URL=redis://localhost:6379`
|
||||||
|
|
||||||
|
#### `REDIS_PASSWORD`
|
||||||
|
- **Description**: Redis authentication password
|
||||||
|
- **Required**: No (if Redis auth disabled)
|
||||||
|
- **Example**: `REDIS_PASSWORD=your-redis-password`
|
||||||
|
|
||||||
|
#### `REDIS_DATABASE`
|
||||||
|
- **Description**: Redis database number
|
||||||
|
- **Default**: `0`
|
||||||
|
- **Example**: `REDIS_DATABASE=1`
|
||||||
|
|
||||||
|
### SSL/TLS Configuration
|
||||||
|
|
||||||
|
#### `TLS_CERT_FILE`
|
||||||
|
- **Description**: Path to TLS certificate file
|
||||||
|
- **Required**: Yes (if HTTPS enabled)
|
||||||
|
- **Example**: `TLS_CERT_FILE=/etc/ssl/certs/yourapp.crt`
|
||||||
|
|
||||||
|
#### `TLS_KEY_FILE`
|
||||||
|
- **Description**: Path to TLS private key file
|
||||||
|
- **Required**: Yes (if HTTPS enabled)
|
||||||
|
- **Example**: `TLS_KEY_FILE=/etc/ssl/private/yourapp.key`
|
||||||
|
|
||||||
|
#### `TLS_CA_FILE`
|
||||||
|
- **Description**: Path to TLS CA certificate file
|
||||||
|
- **Required**: No
|
||||||
|
- **Example**: `TLS_CA_FILE=/etc/ssl/certs/ca-certificates.crt`
|
||||||
|
|
||||||
|
### External Services
|
||||||
|
|
||||||
|
#### `OAUTH_GOOGLE_CLIENT_ID`
|
||||||
|
- **Description**: Google OAuth client ID
|
||||||
|
- **Required**: Yes (if Google OAuth enabled)
|
||||||
|
- **Example**: `OAUTH_GOOGLE_CLIENT_ID=your-google-client-id`
|
||||||
|
|
||||||
|
#### `OAUTH_GOOGLE_CLIENT_SECRET`
|
||||||
|
- **Description**: Google OAuth client secret
|
||||||
|
- **Required**: Yes (if Google OAuth enabled)
|
||||||
|
- **Example**: `OAUTH_GOOGLE_CLIENT_SECRET=your-google-client-secret`
|
||||||
|
|
||||||
|
#### `OAUTH_GITHUB_CLIENT_ID`
|
||||||
|
- **Description**: GitHub OAuth client ID
|
||||||
|
- **Required**: Yes (if GitHub OAuth enabled)
|
||||||
|
- **Example**: `OAUTH_GITHUB_CLIENT_ID=your-github-client-id`
|
||||||
|
|
||||||
|
#### `OAUTH_GITHUB_CLIENT_SECRET`
|
||||||
|
- **Description**: GitHub OAuth client secret
|
||||||
|
- **Required**: Yes (if GitHub OAuth enabled)
|
||||||
|
- **Example**: `OAUTH_GITHUB_CLIENT_SECRET=your-github-client-secret`
|
||||||
|
|
||||||
|
### Monitoring & Observability
|
||||||
|
|
||||||
|
#### `PROMETHEUS_ENDPOINT`
|
||||||
|
- **Description**: Prometheus metrics endpoint
|
||||||
|
- **Default**: `/metrics`
|
||||||
|
- **Example**: `PROMETHEUS_ENDPOINT=/prometheus`
|
||||||
|
|
||||||
|
#### `JAEGER_ENDPOINT`
|
||||||
|
- **Description**: Jaeger tracing endpoint
|
||||||
|
- **Required**: No
|
||||||
|
- **Example**: `JAEGER_ENDPOINT=http://localhost:14268/api/traces`
|
||||||
|
|
||||||
|
#### `SENTRY_DSN`
|
||||||
|
- **Description**: Sentry error reporting DSN
|
||||||
|
- **Required**: No
|
||||||
|
- **Example**: `SENTRY_DSN=https://your-sentry-dsn@sentry.io/project-id`
|
||||||
|
|
||||||
|
### Development & Debug
|
||||||
|
|
||||||
|
#### `RUST_LOG`
|
||||||
|
- **Description**: Rust logging configuration
|
||||||
|
- **Default**: `info`
|
||||||
|
- **Example**: `RUST_LOG=rustelo=debug,sqlx=info`
|
||||||
|
|
||||||
|
#### `RUST_BACKTRACE`
|
||||||
|
- **Description**: Enable Rust backtraces
|
||||||
|
- **Values**: `0`, `1`, `full`
|
||||||
|
- **Default**: `0`
|
||||||
|
- **Example**: `RUST_BACKTRACE=1`
|
||||||
|
|
||||||
|
#### `RUSTELO_DEBUG`
|
||||||
|
- **Description**: Enable debug mode
|
||||||
|
- **Values**: `true`, `false`
|
||||||
|
- **Default**: `false`
|
||||||
|
- **Example**: `RUSTELO_DEBUG=true`
|
||||||
|
|
||||||
|
#### `RUSTELO_MOCK_EXTERNAL`
|
||||||
|
- **Description**: Mock external services
|
||||||
|
- **Values**: `true`, `false`
|
||||||
|
- **Default**: `false`
|
||||||
|
- **Example**: `RUSTELO_MOCK_EXTERNAL=true`
|
||||||
|
|
||||||
|
## Environment-Specific Configuration
|
||||||
|
|
||||||
|
### Development Environment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Core settings
|
||||||
|
RUSTELO_ENV=development
|
||||||
|
RUSTELO_LOG_LEVEL=debug
|
||||||
|
RUSTELO_DEBUG=true
|
||||||
|
|
||||||
|
# Database
|
||||||
|
DATABASE_URL=sqlite//:dev_database.db
|
||||||
|
|
||||||
|
# Authentication
|
||||||
|
SESSION_SECRET=dev-session-secret-change-in-production
|
||||||
|
JWT_SECRET=dev-jwt-secret-change-in-production
|
||||||
|
|
||||||
|
# Email (console output)
|
||||||
|
SMTP_HOST=localhost
|
||||||
|
SMTP_PORT=1025
|
||||||
|
FROM_EMAIL=dev@localhost
|
||||||
|
|
||||||
|
# Features
|
||||||
|
RUSTELO_MOCK_EXTERNAL=true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Production Environment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Core settings
|
||||||
|
RUSTELO_ENV=production
|
||||||
|
RUSTELO_LOG_LEVEL=info
|
||||||
|
RUSTELO_DEBUG=false
|
||||||
|
|
||||||
|
# Server
|
||||||
|
RUSTELO_HOST=0.0.0.0
|
||||||
|
RUSTELO_PORT=443
|
||||||
|
DOMAIN=yourapp.com
|
||||||
|
FRONTEND_URL=https://yourapp.com
|
||||||
|
|
||||||
|
# Database
|
||||||
|
DATABASE_URL=postgresql://rustelo:password@db-server:5432/rustelo_prod
|
||||||
|
DATABASE_MAX_CONNECTIONS=20
|
||||||
|
DATABASE_SSL_MODE=require
|
||||||
|
|
||||||
|
# Authentication
|
||||||
|
SESSION_SECRET=your-production-session-secret-64-chars-long
|
||||||
|
JWT_SECRET=your-production-jwt-secret-64-chars-long
|
||||||
|
ENCRYPTION_KEY=your-base64-encoded-encryption-key
|
||||||
|
|
||||||
|
# Email
|
||||||
|
SMTP_HOST=smtp.gmail.com
|
||||||
|
SMTP_PORT=587
|
||||||
|
SMTP_USERNAME=your-app@gmail.com
|
||||||
|
SMTP_PASSWORD=your-app-password
|
||||||
|
FROM_EMAIL=noreply@yourapp.com
|
||||||
|
FROM_NAME=Your App
|
||||||
|
|
||||||
|
# Redis
|
||||||
|
REDIS_URL=redis://redis-server:6379
|
||||||
|
REDIS_PASSWORD=your-redis-password
|
||||||
|
|
||||||
|
# TLS
|
||||||
|
TLS_CERT_FILE=/etc/ssl/certs/yourapp.crt
|
||||||
|
TLS_KEY_FILE=/etc/ssl/private/yourapp.key
|
||||||
|
|
||||||
|
# OAuth
|
||||||
|
OAUTH_GOOGLE_CLIENT_ID=your-google-client-id
|
||||||
|
OAUTH_GOOGLE_CLIENT_SECRET=your-google-client-secret
|
||||||
|
|
||||||
|
# Monitoring
|
||||||
|
SENTRY_DSN=https://your-sentry-dsn@sentry.io/project-id
|
||||||
|
```
|
||||||
|
|
||||||
|
### Staging Environment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Core settings
|
||||||
|
RUSTELO_ENV=staging
|
||||||
|
RUSTELO_LOG_LEVEL=info
|
||||||
|
RUSTELO_DEBUG=true
|
||||||
|
|
||||||
|
# Server
|
||||||
|
RUSTELO_HOST=0.0.0.0
|
||||||
|
RUSTELO_PORT=443
|
||||||
|
DOMAIN=staging.yourapp.com
|
||||||
|
FRONTEND_URL=https://staging.yourapp.com
|
||||||
|
|
||||||
|
# Database
|
||||||
|
DATABASE_URL=postgresql://rustelo:password@staging-db:5432/rustelo_staging
|
||||||
|
DATABASE_MAX_CONNECTIONS=10
|
||||||
|
DATABASE_SSL_MODE=prefer
|
||||||
|
|
||||||
|
# Authentication (use staging secrets)
|
||||||
|
SESSION_SECRET=staging-session-secret-64-chars-long
|
||||||
|
JWT_SECRET=staging-jwt-secret-64-chars-long
|
||||||
|
|
||||||
|
# Email (test configuration)
|
||||||
|
SMTP_HOST=smtp.mailtrap.io
|
||||||
|
SMTP_PORT=2525
|
||||||
|
SMTP_USERNAME=your-mailtrap-username
|
||||||
|
SMTP_PASSWORD=your-mailtrap-password
|
||||||
|
FROM_EMAIL=staging@yourapp.com
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environment File Management
|
||||||
|
|
||||||
|
### `.env` Files
|
||||||
|
|
||||||
|
Create environment-specific `.env` files:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# .env.development
|
||||||
|
RUSTELO_ENV=development
|
||||||
|
DATABASE_URL=sqlite:dev_database.db
|
||||||
|
SESSION_SECRET=dev-session-secret
|
||||||
|
JWT_SECRET=dev-jwt-secret
|
||||||
|
|
||||||
|
# .env.production
|
||||||
|
RUSTELO_ENV=production
|
||||||
|
DATABASE_URL=postgresql://user:pass@host:5432/db
|
||||||
|
SESSION_SECRET=prod-session-secret
|
||||||
|
JWT_SECRET=prod-jwt-secret
|
||||||
|
|
||||||
|
# .env.staging
|
||||||
|
RUSTELO_ENV=staging
|
||||||
|
DATABASE_URL=postgresql://user:pass@staging-host:5432/db
|
||||||
|
SESSION_SECRET=staging-session-secret
|
||||||
|
JWT_SECRET=staging-jwt-secret
|
||||||
|
```
|
||||||
|
|
||||||
|
### Loading Environment Files
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Load development environment
|
||||||
|
source .env.development
|
||||||
|
|
||||||
|
# Load production environment
|
||||||
|
source .env.production
|
||||||
|
|
||||||
|
# Load with dotenv (if using dotenv tool)
|
||||||
|
dotenv -f .env.production -- ./rustelo-server
|
||||||
|
```
|
||||||
|
|
||||||
|
## Docker Configuration
|
||||||
|
|
||||||
|
### Docker Compose
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# docker-compose.yml
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build: .
|
||||||
|
environment:
|
||||||
|
- RUSTELO_ENV=production
|
||||||
|
- DATABASE_URL=postgresql://rustelo:password@db:5432/rustelo
|
||||||
|
- SESSION_SECRET=your-session-secret
|
||||||
|
- JWT_SECRET=your-jwt-secret
|
||||||
|
- REDIS_URL=redis://redis:6379
|
||||||
|
env_file:
|
||||||
|
- .env.production
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
- redis
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: postgres:15
|
||||||
|
environment:
|
||||||
|
- POSTGRES_DB=rustelo
|
||||||
|
- POSTGRES_USER=rustelo
|
||||||
|
- POSTGRES_PASSWORD=password
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
command: redis-server --requirepass your-redis-password
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dockerfile
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
FROM rust:1.70 as builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY . .
|
||||||
|
RUN cargo build --release
|
||||||
|
|
||||||
|
FROM debian:bookworm-slim
|
||||||
|
|
||||||
|
# Install runtime dependencies
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
ca-certificates \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY --from=builder /app/target/release/rustelo-server /usr/local/bin/
|
||||||
|
COPY --from=builder /app/config.prod.toml /etc/rustelo/config.toml
|
||||||
|
|
||||||
|
# Environment variables can be set here or passed at runtime
|
||||||
|
ENV RUSTELO_ENV=production
|
||||||
|
ENV RUSTELO_CONFIG_FILE=/etc/rustelo/config.toml
|
||||||
|
|
||||||
|
EXPOSE 3030
|
||||||
|
|
||||||
|
CMD ["rustelo-server"]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Best Practices
|
||||||
|
|
||||||
|
### Secret Management
|
||||||
|
|
||||||
|
1. **Use Strong Secrets**
|
||||||
|
- Minimum 32 characters for session secrets
|
||||||
|
- Use cryptographically secure random generators
|
||||||
|
- Rotate secrets regularly
|
||||||
|
|
||||||
|
2. **Environment Separation**
|
||||||
|
- Never use production secrets in development
|
||||||
|
- Use different secrets for each environment
|
||||||
|
- Store secrets in secure vaults (HashiCorp Vault, AWS Secrets Manager)
|
||||||
|
|
||||||
|
3. **Access Control**
|
||||||
|
- Limit access to environment variables
|
||||||
|
- Use least privilege principle
|
||||||
|
- Audit secret access
|
||||||
|
|
||||||
|
### Example Secret Generation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Generate secure session secret
|
||||||
|
openssl rand -base64 64
|
||||||
|
|
||||||
|
# Generate JWT secret
|
||||||
|
openssl rand -base64 64
|
||||||
|
|
||||||
|
# Generate encryption key
|
||||||
|
openssl rand -base64 32
|
||||||
|
|
||||||
|
# Generate CSRF secret
|
||||||
|
openssl rand -base64 32
|
||||||
|
```
|
||||||
|
|
||||||
|
## Validation and Testing
|
||||||
|
|
||||||
|
### Variable Validation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check required variables
|
||||||
|
./scripts/check-env.sh production
|
||||||
|
|
||||||
|
# Validate configuration
|
||||||
|
./config/scripts/build-config.sh prod --validate-only
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing Configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test with environment variables
|
||||||
|
RUSTELO_ENV=test DATABASE_URL=sqlite::memory: cargo test
|
||||||
|
|
||||||
|
# Test configuration loading
|
||||||
|
./rustelo-server --check-config
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
1. **Missing Environment Variables**
|
||||||
|
```bash
|
||||||
|
# Check if variables are set
|
||||||
|
env | grep RUSTELO
|
||||||
|
env | grep DATABASE_URL
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Invalid Variable Format**
|
||||||
|
```bash
|
||||||
|
# Validate database URL format
|
||||||
|
echo $DATABASE_URL | grep -E "^postgresql://"
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Permission Issues**
|
||||||
|
```bash
|
||||||
|
# Check file permissions for certificates
|
||||||
|
ls -la /etc/ssl/certs/yourapp.crt
|
||||||
|
```
|
||||||
|
|
||||||
|
### Debug Environment Loading
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Enable debug logging
|
||||||
|
RUST_LOG=rustelo=debug ./rustelo-server
|
||||||
|
|
||||||
|
# Show loaded configuration
|
||||||
|
./rustelo-server --show-config
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration Guide
|
||||||
|
|
||||||
|
When updating environment variables:
|
||||||
|
|
||||||
|
1. **Add new variables** to all environments
|
||||||
|
2. **Update documentation** with new requirements
|
||||||
|
3. **Provide default values** where possible
|
||||||
|
4. **Test thoroughly** in staging before production
|
||||||
|
5. **Update deployment scripts** and Docker configurations
|
||||||
|
|
||||||
|
For detailed migration instructions, see the [Environment Migration Guide](../reference/env-migration.md).
|
||||||
617
book/configuration/features.md
Normal file
617
book/configuration/features.md
Normal file
@ -0,0 +1,617 @@
|
|||||||
|
# Features Configuration
|
||||||
|
|
||||||
|
Rustelo's modular feature system allows you to enable, disable, and configure individual features based on your application's needs. This chapter covers how to configure features, understand their dependencies, and optimize your application by selecting the right combination of features.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Features in Rustelo are:
|
||||||
|
|
||||||
|
- **Modular**: Each feature can be enabled/disabled independently
|
||||||
|
- **Configurable**: Features have their own configuration settings
|
||||||
|
- **Environment-Aware**: Different settings for development, staging, and production
|
||||||
|
- **Dependency-Aware**: Features can depend on other features
|
||||||
|
- **Performance-Optimized**: Unused features don't impact performance
|
||||||
|
|
||||||
|
## Feature System Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
features/
|
||||||
|
├── auth/ # Authentication & Authorization
|
||||||
|
│ ├── dev.toml # Development settings
|
||||||
|
│ ├── prod.toml # Production settings
|
||||||
|
│ └── example.toml # Example configuration
|
||||||
|
├── content/ # Content Management
|
||||||
|
├── email/ # Email System
|
||||||
|
├── metrics/ # Monitoring & Metrics
|
||||||
|
├── tls/ # SSL/TLS Security
|
||||||
|
├── rbac/ # Role-Based Access Control
|
||||||
|
└── cache/ # Caching System
|
||||||
|
```
|
||||||
|
|
||||||
|
## Core Features
|
||||||
|
|
||||||
|
### Authentication Feature
|
||||||
|
|
||||||
|
The authentication feature provides user authentication, session management, and security controls.
|
||||||
|
|
||||||
|
#### Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[features]
|
||||||
|
auth = true
|
||||||
|
|
||||||
|
[auth.jwt]
|
||||||
|
secret = "${JWT_SECRET}"
|
||||||
|
expiration = 3600 # Token expiration in seconds
|
||||||
|
refresh_token_expiration = 604800 # Refresh token expiration (7 days)
|
||||||
|
algorithm = "HS256" # JWT algorithm
|
||||||
|
issuer = "rustelo-app" # JWT issuer
|
||||||
|
audience = "rustelo-users" # JWT audience
|
||||||
|
|
||||||
|
[auth.password]
|
||||||
|
min_length = 8 # Minimum password length
|
||||||
|
require_uppercase = true # Require uppercase letters
|
||||||
|
require_lowercase = true # Require lowercase letters
|
||||||
|
require_numbers = true # Require numbers
|
||||||
|
require_special_chars = true # Require special characters
|
||||||
|
max_age_days = 90 # Password expiration in days
|
||||||
|
history_count = 5 # Number of previous passwords to remember
|
||||||
|
|
||||||
|
[auth.security]
|
||||||
|
max_login_attempts = 5 # Maximum failed login attempts
|
||||||
|
lockout_duration = 900 # Account lockout duration in seconds
|
||||||
|
session_timeout = 1800 # Session timeout in seconds
|
||||||
|
require_email_verification = true # Require email verification
|
||||||
|
password_reset_timeout = 3600 # Password reset token timeout
|
||||||
|
|
||||||
|
[auth.two_factor]
|
||||||
|
enabled = true # Enable 2FA
|
||||||
|
backup_codes_count = 10 # Number of backup codes
|
||||||
|
totp_issuer = "Rustelo App" # TOTP issuer name
|
||||||
|
totp_digits = 6 # TOTP code length
|
||||||
|
totp_period = 30 # TOTP time period in seconds
|
||||||
|
|
||||||
|
[auth.sessions]
|
||||||
|
cleanup_interval = 3600 # Session cleanup interval in seconds
|
||||||
|
max_concurrent_sessions = 3 # Maximum concurrent sessions per user
|
||||||
|
remember_me_duration = 2592000 # Remember me duration (30 days)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Environment-Specific Settings
|
||||||
|
|
||||||
|
**Development:**
|
||||||
|
```toml
|
||||||
|
[auth.password]
|
||||||
|
min_length = 6
|
||||||
|
require_uppercase = false
|
||||||
|
require_special_chars = false
|
||||||
|
|
||||||
|
[auth.security]
|
||||||
|
max_login_attempts = 10
|
||||||
|
require_email_verification = false
|
||||||
|
```
|
||||||
|
|
||||||
|
**Production:**
|
||||||
|
```toml
|
||||||
|
[auth.password]
|
||||||
|
min_length = 12
|
||||||
|
require_uppercase = true
|
||||||
|
require_special_chars = true
|
||||||
|
|
||||||
|
[auth.security]
|
||||||
|
max_login_attempts = 3
|
||||||
|
require_email_verification = true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Content Management Feature
|
||||||
|
|
||||||
|
The content feature provides content creation, editing, and management capabilities.
|
||||||
|
|
||||||
|
#### Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[features]
|
||||||
|
content = true
|
||||||
|
|
||||||
|
[content]
|
||||||
|
enabled = true
|
||||||
|
content_dir = "content" # Content storage directory
|
||||||
|
cache_enabled = true # Enable content caching
|
||||||
|
cache_ttl = 3600 # Cache TTL in seconds
|
||||||
|
max_file_size = 10485760 # Maximum file size (10MB)
|
||||||
|
allowed_file_types = [ # Allowed file extensions
|
||||||
|
"md", "txt", "html", "css", "js", "json", "toml", "yaml"
|
||||||
|
]
|
||||||
|
|
||||||
|
[content.markdown]
|
||||||
|
enabled = true # Enable Markdown processing
|
||||||
|
syntax_highlighting = true # Enable code syntax highlighting
|
||||||
|
math_support = false # Enable LaTeX math rendering
|
||||||
|
table_of_contents = true # Generate table of contents
|
||||||
|
auto_links = true # Automatically link URLs
|
||||||
|
|
||||||
|
[content.media]
|
||||||
|
enabled = true # Enable media uploads
|
||||||
|
max_image_size = 5242880 # Maximum image size (5MB)
|
||||||
|
max_video_size = 52428800 # Maximum video size (50MB)
|
||||||
|
image_processing = true # Enable image processing
|
||||||
|
thumbnail_generation = true # Generate thumbnails
|
||||||
|
allowed_image_types = ["jpg", "jpeg", "png", "gif", "webp"]
|
||||||
|
allowed_video_types = ["mp4", "webm", "ogg"]
|
||||||
|
|
||||||
|
[content.versioning]
|
||||||
|
enabled = false # Enable content versioning
|
||||||
|
max_versions = 10 # Maximum versions to keep
|
||||||
|
auto_save_interval = 60 # Auto-save interval in seconds
|
||||||
|
|
||||||
|
[content.publishing]
|
||||||
|
draft_mode = true # Enable draft mode
|
||||||
|
scheduled_publishing = true # Enable scheduled publishing
|
||||||
|
approval_workflow = false # Require approval for publishing
|
||||||
|
```
|
||||||
|
|
||||||
|
### Email System Feature
|
||||||
|
|
||||||
|
The email feature provides email sending, templating, and queue management.
|
||||||
|
|
||||||
|
#### Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[features]
|
||||||
|
email = true
|
||||||
|
|
||||||
|
[email]
|
||||||
|
enabled = true
|
||||||
|
provider = "smtp" # Email provider: smtp, sendgrid, console
|
||||||
|
from_email = "${FROM_EMAIL}" # Default sender email
|
||||||
|
from_name = "${FROM_NAME}" # Default sender name
|
||||||
|
reply_to = "" # Reply-to address
|
||||||
|
templates_dir = "templates/email" # Email templates directory
|
||||||
|
queue_enabled = true # Enable email queue
|
||||||
|
max_retries = 3 # Maximum retry attempts
|
||||||
|
retry_delay = 300 # Retry delay in seconds
|
||||||
|
|
||||||
|
[email.smtp]
|
||||||
|
host = "${SMTP_HOST}" # SMTP server host
|
||||||
|
port = 587 # SMTP server port
|
||||||
|
username = "${SMTP_USERNAME}" # SMTP username
|
||||||
|
password = "${SMTP_PASSWORD}" # SMTP password
|
||||||
|
use_tls = true # Use TLS encryption
|
||||||
|
use_starttls = true # Use STARTTLS
|
||||||
|
timeout = 30 # Connection timeout in seconds
|
||||||
|
|
||||||
|
[email.sendgrid]
|
||||||
|
api_key = "${SENDGRID_API_KEY}" # SendGrid API key
|
||||||
|
endpoint = "https://api.sendgrid.com/v3/mail/send" # SendGrid endpoint
|
||||||
|
|
||||||
|
[email.templates]
|
||||||
|
cache_enabled = true # Cache compiled templates
|
||||||
|
cache_ttl = 3600 # Template cache TTL
|
||||||
|
default_language = "en" # Default template language
|
||||||
|
```
|
||||||
|
|
||||||
|
### Metrics & Monitoring Feature
|
||||||
|
|
||||||
|
The metrics feature provides application monitoring, performance tracking, and observability.
|
||||||
|
|
||||||
|
#### Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[features]
|
||||||
|
metrics = true
|
||||||
|
|
||||||
|
[metrics]
|
||||||
|
enabled = true
|
||||||
|
endpoint = "/metrics" # Metrics endpoint path
|
||||||
|
collect_interval = 15 # Collection interval in seconds
|
||||||
|
retention_days = 30 # Metrics retention period
|
||||||
|
|
||||||
|
[metrics.prometheus]
|
||||||
|
enabled = true # Enable Prometheus metrics
|
||||||
|
namespace = "rustelo" # Metrics namespace
|
||||||
|
subsystem = "app" # Metrics subsystem
|
||||||
|
labels = { version = "1.0.0", environment = "production" }
|
||||||
|
|
||||||
|
[metrics.system]
|
||||||
|
enabled = true # Collect system metrics
|
||||||
|
cpu_usage = true # Monitor CPU usage
|
||||||
|
memory_usage = true # Monitor memory usage
|
||||||
|
disk_usage = true # Monitor disk usage
|
||||||
|
network_usage = true # Monitor network usage
|
||||||
|
|
||||||
|
[metrics.application]
|
||||||
|
enabled = true # Collect application metrics
|
||||||
|
request_metrics = true # HTTP request metrics
|
||||||
|
database_metrics = true # Database query metrics
|
||||||
|
cache_metrics = true # Cache hit/miss metrics
|
||||||
|
error_metrics = true # Error rate metrics
|
||||||
|
|
||||||
|
[metrics.custom]
|
||||||
|
enabled = true # Enable custom metrics
|
||||||
|
business_metrics = true # Business-specific metrics
|
||||||
|
user_metrics = true # User activity metrics
|
||||||
|
```
|
||||||
|
|
||||||
|
### TLS/SSL Security Feature
|
||||||
|
|
||||||
|
The TLS feature provides SSL/TLS encryption, certificate management, and security headers.
|
||||||
|
|
||||||
|
#### Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[features]
|
||||||
|
tls = true
|
||||||
|
|
||||||
|
[tls]
|
||||||
|
enabled = true
|
||||||
|
cert_file = "${TLS_CERT_FILE}" # Certificate file path
|
||||||
|
key_file = "${TLS_KEY_FILE}" # Private key file path
|
||||||
|
ca_file = "${TLS_CA_FILE}" # CA certificate file path
|
||||||
|
protocols = ["TLSv1.2", "TLSv1.3"] # Supported TLS protocols
|
||||||
|
ciphers = [ # Allowed cipher suites
|
||||||
|
"TLS_AES_256_GCM_SHA384",
|
||||||
|
"TLS_CHACHA20_POLY1305_SHA256",
|
||||||
|
"TLS_AES_128_GCM_SHA256"
|
||||||
|
]
|
||||||
|
|
||||||
|
[tls.security]
|
||||||
|
force_https = true # Force HTTPS redirects
|
||||||
|
hsts_enabled = true # Enable HSTS
|
||||||
|
hsts_max_age = 31536000 # HSTS max age (1 year)
|
||||||
|
hsts_include_subdomains = true # Include subdomains in HSTS
|
||||||
|
hsts_preload = true # Enable HSTS preload
|
||||||
|
|
||||||
|
[tls.certificates]
|
||||||
|
auto_renewal = true # Enable automatic certificate renewal
|
||||||
|
renewal_threshold = 2592000 # Renewal threshold (30 days)
|
||||||
|
acme_enabled = false # Enable ACME/Let's Encrypt
|
||||||
|
acme_directory = "https://acme-v02.api.letsencrypt.org/directory"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Role-Based Access Control (RBAC)
|
||||||
|
|
||||||
|
The RBAC feature provides fine-grained access control, permissions, and role management.
|
||||||
|
|
||||||
|
#### Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[features]
|
||||||
|
rbac = true
|
||||||
|
|
||||||
|
[rbac]
|
||||||
|
enabled = true
|
||||||
|
default_role = "user" # Default role for new users
|
||||||
|
admin_role = "admin" # Administrator role name
|
||||||
|
super_admin_role = "super_admin" # Super administrator role
|
||||||
|
|
||||||
|
[rbac.permissions]
|
||||||
|
hierarchical = true # Enable hierarchical permissions
|
||||||
|
inheritance = true # Enable permission inheritance
|
||||||
|
caching = true # Cache permission checks
|
||||||
|
cache_ttl = 300 # Permission cache TTL
|
||||||
|
|
||||||
|
[rbac.roles]
|
||||||
|
dynamic_roles = true # Enable dynamic role creation
|
||||||
|
role_templates = true # Enable role templates
|
||||||
|
role_expiration = false # Enable role expiration
|
||||||
|
|
||||||
|
[rbac.audit]
|
||||||
|
enabled = true # Enable audit logging
|
||||||
|
log_level = "info" # Audit log level
|
||||||
|
retention_days = 90 # Audit log retention period
|
||||||
|
```
|
||||||
|
|
||||||
|
### Caching System Feature
|
||||||
|
|
||||||
|
The caching feature provides multi-level caching for improved performance.
|
||||||
|
|
||||||
|
#### Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[features]
|
||||||
|
cache = true
|
||||||
|
|
||||||
|
[cache]
|
||||||
|
enabled = true
|
||||||
|
default_ttl = 3600 # Default cache TTL in seconds
|
||||||
|
max_memory_size = 134217728 # Maximum memory cache size (128MB)
|
||||||
|
cleanup_interval = 300 # Cache cleanup interval in seconds
|
||||||
|
|
||||||
|
[cache.memory]
|
||||||
|
enabled = true # Enable in-memory caching
|
||||||
|
max_entries = 10000 # Maximum cache entries
|
||||||
|
eviction_policy = "lru" # Eviction policy: lru, lfu, random
|
||||||
|
|
||||||
|
[cache.redis]
|
||||||
|
enabled = false # Enable Redis caching
|
||||||
|
url = "${REDIS_URL}" # Redis connection URL
|
||||||
|
database = 0 # Redis database number
|
||||||
|
key_prefix = "rustelo:" # Cache key prefix
|
||||||
|
compression = true # Enable compression
|
||||||
|
|
||||||
|
[cache.file]
|
||||||
|
enabled = false # Enable file-based caching
|
||||||
|
cache_dir = "cache" # Cache directory
|
||||||
|
max_file_size = 1048576 # Maximum file size (1MB)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Feature Dependencies
|
||||||
|
|
||||||
|
Some features depend on others. The system automatically handles these dependencies:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# Feature dependency matrix
|
||||||
|
[feature_dependencies]
|
||||||
|
rbac = ["auth"] # RBAC requires authentication
|
||||||
|
content = ["auth"] # Content management requires authentication
|
||||||
|
email = [] # Email has no dependencies
|
||||||
|
metrics = [] # Metrics has no dependencies
|
||||||
|
tls = [] # TLS has no dependencies
|
||||||
|
cache = [] # Cache has no dependencies
|
||||||
|
```
|
||||||
|
|
||||||
|
## Feature Flags
|
||||||
|
|
||||||
|
Feature flags allow runtime control of features:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[feature_flags]
|
||||||
|
auth_enabled = true
|
||||||
|
content_enabled = true
|
||||||
|
email_enabled = true
|
||||||
|
metrics_enabled = true
|
||||||
|
tls_enabled = true
|
||||||
|
rbac_enabled = false
|
||||||
|
cache_enabled = true
|
||||||
|
|
||||||
|
# Conditional features
|
||||||
|
[feature_flags.conditional]
|
||||||
|
oauth_enabled = false # Enable OAuth (requires auth)
|
||||||
|
two_factor_enabled = true # Enable 2FA (requires auth)
|
||||||
|
file_uploads_enabled = true # Enable file uploads (requires content)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environment-Specific Feature Configuration
|
||||||
|
|
||||||
|
### Development Environment
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[features]
|
||||||
|
auth = true
|
||||||
|
content = true
|
||||||
|
email = true
|
||||||
|
metrics = true
|
||||||
|
tls = false
|
||||||
|
rbac = false
|
||||||
|
cache = true
|
||||||
|
|
||||||
|
[feature_flags]
|
||||||
|
debug_mode = true
|
||||||
|
mock_external_services = true
|
||||||
|
verbose_logging = true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Production Environment
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[features]
|
||||||
|
auth = true
|
||||||
|
content = true
|
||||||
|
email = true
|
||||||
|
metrics = true
|
||||||
|
tls = true
|
||||||
|
rbac = true
|
||||||
|
cache = true
|
||||||
|
|
||||||
|
[feature_flags]
|
||||||
|
debug_mode = false
|
||||||
|
mock_external_services = false
|
||||||
|
verbose_logging = false
|
||||||
|
performance_monitoring = true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance Optimization
|
||||||
|
|
||||||
|
### Feature-Based Optimization
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[optimization]
|
||||||
|
lazy_loading = true # Lazy load features
|
||||||
|
compile_time_optimization = true # Optimize at compile time
|
||||||
|
runtime_checks = false # Disable runtime feature checks in production
|
||||||
|
|
||||||
|
[optimization.features]
|
||||||
|
auth = { priority = "high", preload = true }
|
||||||
|
content = { priority = "medium", preload = false }
|
||||||
|
email = { priority = "low", preload = false }
|
||||||
|
metrics = { priority = "low", preload = false }
|
||||||
|
```
|
||||||
|
|
||||||
|
### Resource Management
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[resource_limits]
|
||||||
|
max_memory_per_feature = 67108864 # 64MB per feature
|
||||||
|
max_cpu_per_feature = 10 # 10% CPU per feature
|
||||||
|
max_connections_per_feature = 100 # 100 connections per feature
|
||||||
|
```
|
||||||
|
|
||||||
|
## Feature Testing
|
||||||
|
|
||||||
|
### Test Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[testing]
|
||||||
|
features_under_test = ["auth", "content"]
|
||||||
|
mock_dependencies = true
|
||||||
|
integration_tests = true
|
||||||
|
performance_tests = false
|
||||||
|
|
||||||
|
[testing.auth]
|
||||||
|
test_users = 1000
|
||||||
|
test_sessions = 100
|
||||||
|
test_roles = 10
|
||||||
|
|
||||||
|
[testing.content]
|
||||||
|
test_documents = 500
|
||||||
|
test_media_files = 100
|
||||||
|
test_versions = 5
|
||||||
|
```
|
||||||
|
|
||||||
|
## Creating Custom Features
|
||||||
|
|
||||||
|
### Feature Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
features/my_feature/
|
||||||
|
├── dev.toml # Development configuration
|
||||||
|
├── prod.toml # Production configuration
|
||||||
|
├── example.toml # Example configuration
|
||||||
|
└── README.md # Feature documentation
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example Custom Feature
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# features/my_feature/dev.toml
|
||||||
|
[features]
|
||||||
|
my_feature = true
|
||||||
|
|
||||||
|
[my_feature]
|
||||||
|
enabled = true
|
||||||
|
debug_mode = true
|
||||||
|
api_endpoint = "http://localhost:8080"
|
||||||
|
timeout = 30
|
||||||
|
retry_count = 3
|
||||||
|
|
||||||
|
[my_feature.settings]
|
||||||
|
option1 = "value1"
|
||||||
|
option2 = 42
|
||||||
|
option3 = true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Feature Management Commands
|
||||||
|
|
||||||
|
### Using Configuration Scripts
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List available features
|
||||||
|
./config/scripts/manage-config.sh list-features
|
||||||
|
|
||||||
|
# Enable a feature
|
||||||
|
./config/scripts/manage-config.sh enable-feature auth
|
||||||
|
|
||||||
|
# Disable a feature
|
||||||
|
./config/scripts/manage-config.sh disable-feature rbac
|
||||||
|
|
||||||
|
# Check feature dependencies
|
||||||
|
./config/scripts/manage-config.sh check-dependencies
|
||||||
|
|
||||||
|
# Validate feature configuration
|
||||||
|
./config/scripts/manage-config.sh validate-features
|
||||||
|
```
|
||||||
|
|
||||||
|
### Runtime Feature Management
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check feature status
|
||||||
|
curl http://localhost:3030/admin/features
|
||||||
|
|
||||||
|
# Enable feature at runtime (if supported)
|
||||||
|
curl -X POST http://localhost:3030/admin/features/auth/enable
|
||||||
|
|
||||||
|
# Disable feature at runtime (if supported)
|
||||||
|
curl -X POST http://localhost:3030/admin/features/auth/disable
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### 1. Feature Selection
|
||||||
|
|
||||||
|
- **Start Small**: Begin with essential features only
|
||||||
|
- **Add Gradually**: Enable additional features as needed
|
||||||
|
- **Monitor Impact**: Watch performance metrics when adding features
|
||||||
|
- **Document Changes**: Keep track of feature changes and their impact
|
||||||
|
|
||||||
|
### 2. Configuration Management
|
||||||
|
|
||||||
|
- **Environment Consistency**: Use consistent feature sets across environments
|
||||||
|
- **Version Control**: Track feature configuration changes
|
||||||
|
- **Testing**: Test feature combinations thoroughly
|
||||||
|
- **Rollback Plan**: Have a plan for disabling problematic features
|
||||||
|
|
||||||
|
### 3. Performance Considerations
|
||||||
|
|
||||||
|
- **Resource Usage**: Monitor resource usage per feature
|
||||||
|
- **Startup Time**: Consider impact on application startup
|
||||||
|
- **Memory Usage**: Track memory consumption of enabled features
|
||||||
|
- **Database Impact**: Monitor database performance with features enabled
|
||||||
|
|
||||||
|
### 4. Security Considerations
|
||||||
|
|
||||||
|
- **Feature Isolation**: Ensure features don't interfere with each other
|
||||||
|
- **Access Control**: Implement proper access controls for feature management
|
||||||
|
- **Audit Logging**: Log feature changes and access
|
||||||
|
- **Security Testing**: Test security implications of feature combinations
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
1. **Feature Not Loading**
|
||||||
|
```bash
|
||||||
|
# Check feature configuration
|
||||||
|
./config/scripts/manage-config.sh validate-features
|
||||||
|
|
||||||
|
# Check feature dependencies
|
||||||
|
./config/scripts/manage-config.sh check-dependencies
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Performance Issues**
|
||||||
|
```bash
|
||||||
|
# Monitor feature resource usage
|
||||||
|
curl http://localhost:3030/metrics | grep feature_
|
||||||
|
|
||||||
|
# Check feature startup time
|
||||||
|
grep "feature.*initialized" logs/app.log
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Configuration Conflicts**
|
||||||
|
```bash
|
||||||
|
# Compare feature configurations
|
||||||
|
./config/scripts/manage-config.sh diff-features dev prod
|
||||||
|
```
|
||||||
|
|
||||||
|
### Debug Mode
|
||||||
|
|
||||||
|
Enable debug mode for detailed feature information:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
RUSTELO_DEBUG=true FEATURE_DEBUG=true ./rustelo-server
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration Guide
|
||||||
|
|
||||||
|
When updating feature configurations:
|
||||||
|
|
||||||
|
1. **Backup Current Configuration**
|
||||||
|
```bash
|
||||||
|
./config/scripts/manage-config.sh backup-features
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Test New Configuration**
|
||||||
|
```bash
|
||||||
|
./config/scripts/manage-config.sh test-features
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Gradual Rollout**
|
||||||
|
- Update staging environment first
|
||||||
|
- Monitor for issues
|
||||||
|
- Update production environment
|
||||||
|
|
||||||
|
4. **Rollback if Needed**
|
||||||
|
```bash
|
||||||
|
./config/scripts/manage-config.sh restore-features backup-file
|
||||||
|
```
|
||||||
|
|
||||||
|
For detailed migration instructions, see the [Feature Migration Guide](../reference/feature-migration.md).
|
||||||
467
book/configuration/files.md
Normal file
467
book/configuration/files.md
Normal file
@ -0,0 +1,467 @@
|
|||||||
|
# Configuration Files
|
||||||
|
|
||||||
|
Rustelo uses a modular configuration system that separates concerns by features and environments. This system allows for flexible configuration management across different deployment scenarios while maintaining clear separation between base settings and feature-specific configurations.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The configuration system consists of:
|
||||||
|
|
||||||
|
- **Base Configurations**: Core settings that apply to all features
|
||||||
|
- **Feature Configurations**: Settings specific to individual features
|
||||||
|
- **Environment-Specific Settings**: Optimized configurations for different environments
|
||||||
|
- **Configuration Management Scripts**: Tools for building, validating, and managing configurations
|
||||||
|
|
||||||
|
## Configuration Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
config/
|
||||||
|
├── base/ # Base configurations
|
||||||
|
│ ├── dev.toml # Development base settings
|
||||||
|
│ ├── prod.toml # Production base settings
|
||||||
|
│ └── example.toml # Example/template base settings
|
||||||
|
├── features/ # Feature-specific configurations
|
||||||
|
│ ├── auth/ # Authentication feature
|
||||||
|
│ ├── email/ # Email feature
|
||||||
|
│ ├── tls/ # TLS/SSL feature
|
||||||
|
│ ├── content/ # Content management feature
|
||||||
|
│ └── metrics/ # Metrics and monitoring feature
|
||||||
|
├── scripts/ # Configuration management scripts
|
||||||
|
├── examples/ # Example configurations
|
||||||
|
└── README.md # Configuration documentation
|
||||||
|
```
|
||||||
|
|
||||||
|
## Base Configuration Files
|
||||||
|
|
||||||
|
Base configurations contain core settings that apply to all features:
|
||||||
|
|
||||||
|
### `base/dev.toml` - Development Environment
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# Server Configuration
|
||||||
|
[server]
|
||||||
|
protocol = "http"
|
||||||
|
host = "127.0.0.1"
|
||||||
|
port = 3030
|
||||||
|
environment = "development"
|
||||||
|
log_level = "debug"
|
||||||
|
|
||||||
|
# Database Configuration
|
||||||
|
[database]
|
||||||
|
url = "sqlite//:dev_database.db"
|
||||||
|
max_connections = 5
|
||||||
|
enable_logging = true
|
||||||
|
|
||||||
|
# Session Management
|
||||||
|
[session]
|
||||||
|
secret = "dev-session-secret"
|
||||||
|
cookie_secure = false
|
||||||
|
max_age = 7200
|
||||||
|
|
||||||
|
# Security Settings (relaxed for development)
|
||||||
|
[security]
|
||||||
|
enable_csrf = false
|
||||||
|
rate_limit_requests = 1000
|
||||||
|
bcrypt_cost = 10
|
||||||
|
```
|
||||||
|
|
||||||
|
### `base/prod.toml` - Production Environment
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# Server Configuration
|
||||||
|
[server]
|
||||||
|
protocol = "https"
|
||||||
|
host = "0.0.0.0"
|
||||||
|
port = 443
|
||||||
|
environment = "production"
|
||||||
|
log_level = "info"
|
||||||
|
|
||||||
|
# Database Configuration
|
||||||
|
[database]
|
||||||
|
url = "${DATABASE_URL}"
|
||||||
|
max_connections = 20
|
||||||
|
ssl_mode = "require"
|
||||||
|
|
||||||
|
# Session Management
|
||||||
|
[session]
|
||||||
|
secret = "${SESSION_SECRET}"
|
||||||
|
cookie_secure = true
|
||||||
|
max_age = 1800
|
||||||
|
|
||||||
|
# Security Settings (strict for production)
|
||||||
|
[security]
|
||||||
|
enable_csrf = true
|
||||||
|
rate_limit_requests = 100
|
||||||
|
bcrypt_cost = 12
|
||||||
|
```
|
||||||
|
|
||||||
|
## Feature Configuration Files
|
||||||
|
|
||||||
|
Feature configurations contain settings specific to individual features:
|
||||||
|
|
||||||
|
### Authentication Feature (`features/auth/`)
|
||||||
|
|
||||||
|
#### `features/auth/dev.toml`
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[features]
|
||||||
|
auth = true
|
||||||
|
|
||||||
|
[auth.jwt]
|
||||||
|
secret = "dev-jwt-secret"
|
||||||
|
expiration = 86400
|
||||||
|
algorithm = "HS256"
|
||||||
|
|
||||||
|
[auth.password]
|
||||||
|
min_length = 6
|
||||||
|
require_uppercase = false
|
||||||
|
require_numbers = true
|
||||||
|
|
||||||
|
[auth.security]
|
||||||
|
max_login_attempts = 10
|
||||||
|
lockout_duration = 300
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `features/auth/prod.toml`
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[features]
|
||||||
|
auth = true
|
||||||
|
|
||||||
|
[auth.jwt]
|
||||||
|
secret = "${JWT_SECRET}"
|
||||||
|
expiration = 1800
|
||||||
|
algorithm = "HS256"
|
||||||
|
|
||||||
|
[auth.password]
|
||||||
|
min_length = 12
|
||||||
|
require_uppercase = true
|
||||||
|
require_numbers = true
|
||||||
|
require_special_chars = true
|
||||||
|
|
||||||
|
[auth.security]
|
||||||
|
max_login_attempts = 5
|
||||||
|
lockout_duration = 900
|
||||||
|
```
|
||||||
|
|
||||||
|
### Email Feature (`features/email/`)
|
||||||
|
|
||||||
|
#### `features/email/dev.toml`
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[features]
|
||||||
|
email = true
|
||||||
|
|
||||||
|
[email]
|
||||||
|
provider = "console"
|
||||||
|
from_email = "dev@localhost"
|
||||||
|
templates_dir = "templates/email"
|
||||||
|
|
||||||
|
[email.smtp]
|
||||||
|
host = "localhost"
|
||||||
|
port = 1025
|
||||||
|
use_tls = false
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `features/email/prod.toml`
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[features]
|
||||||
|
email = true
|
||||||
|
|
||||||
|
[email]
|
||||||
|
provider = "smtp"
|
||||||
|
from_email = "${FROM_EMAIL}"
|
||||||
|
templates_dir = "templates/email"
|
||||||
|
|
||||||
|
[email.smtp]
|
||||||
|
host = "${SMTP_HOST}"
|
||||||
|
port = 587
|
||||||
|
username = "${SMTP_USERNAME}"
|
||||||
|
password = "${SMTP_PASSWORD}"
|
||||||
|
use_tls = true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
Configuration files support environment variable substitution using `${VARIABLE_NAME}` syntax:
|
||||||
|
|
||||||
|
### Required Environment Variables
|
||||||
|
|
||||||
|
#### Development
|
||||||
|
- `DATABASE_URL` (optional, defaults to SQLite)
|
||||||
|
- `SESSION_SECRET` (optional, uses dev default)
|
||||||
|
|
||||||
|
#### Production
|
||||||
|
- `DATABASE_URL` (required)
|
||||||
|
- `SESSION_SECRET` (required)
|
||||||
|
- `JWT_SECRET` (required)
|
||||||
|
- `SMTP_HOST` (required if email enabled)
|
||||||
|
- `SMTP_USERNAME` (required if email enabled)
|
||||||
|
- `SMTP_PASSWORD` (required if email enabled)
|
||||||
|
- `FROM_EMAIL` (required if email enabled)
|
||||||
|
- `FRONTEND_URL` (required for CORS)
|
||||||
|
- `DOMAIN` (required for cookies)
|
||||||
|
|
||||||
|
### Environment Variable Examples
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Development
|
||||||
|
export DATABASE_URL="postgresql://user:password@localhost/rustelo_dev"
|
||||||
|
export SESSION_SECRET="your-session-secret-here"
|
||||||
|
|
||||||
|
# Production
|
||||||
|
export DATABASE_URL="postgresql://user:password@prod-db/rustelo"
|
||||||
|
export SESSION_SECRET="your-production-session-secret"
|
||||||
|
export JWT_SECRET="your-jwt-secret"
|
||||||
|
export SMTP_HOST="smtp.gmail.com"
|
||||||
|
export SMTP_USERNAME="your-app@gmail.com"
|
||||||
|
export SMTP_PASSWORD="your-app-password"
|
||||||
|
export FROM_EMAIL="noreply@yourapp.com"
|
||||||
|
export FRONTEND_URL="https://yourapp.com"
|
||||||
|
export DOMAIN="yourapp.com"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration Building
|
||||||
|
|
||||||
|
### Using Build Scripts
|
||||||
|
|
||||||
|
The configuration system includes scripts for building complete configuration files:
|
||||||
|
|
||||||
|
#### Shell Script
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build development configuration
|
||||||
|
./config/scripts/build-config.sh dev
|
||||||
|
|
||||||
|
# Build production configuration
|
||||||
|
./config/scripts/build-config.sh prod config.prod.toml
|
||||||
|
|
||||||
|
# Build with validation only
|
||||||
|
CONFIG_VALIDATE_ONLY=1 ./config/scripts/build-config.sh dev
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Python Script
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build development configuration
|
||||||
|
./config/scripts/build-config.sh dev
|
||||||
|
|
||||||
|
# Build production configuration
|
||||||
|
./config/scripts/build-config.sh prod config.prod.toml
|
||||||
|
|
||||||
|
# Validate only
|
||||||
|
CONFIG_VALIDATE_ONLY=1 ./config/scripts/build-config.sh dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Management Script
|
||||||
|
|
||||||
|
The management script provides comprehensive configuration operations:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build configurations
|
||||||
|
./config/scripts/manage-config.sh build dev
|
||||||
|
./config/scripts/manage-config.sh build prod config.prod.toml
|
||||||
|
|
||||||
|
# Validate configurations
|
||||||
|
./config/scripts/manage-config.sh validate dev
|
||||||
|
|
||||||
|
# List features and environments
|
||||||
|
./config/scripts/manage-config.sh list-features
|
||||||
|
./config/scripts/manage-config.sh list-environments
|
||||||
|
|
||||||
|
# Compare configurations
|
||||||
|
./config/scripts/manage-config.sh diff dev prod
|
||||||
|
|
||||||
|
# Create backups
|
||||||
|
./config/scripts/manage-config.sh backup prod
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration Validation
|
||||||
|
|
||||||
|
The system includes built-in validation for:
|
||||||
|
|
||||||
|
### Syntax Validation
|
||||||
|
- **TOML Syntax**: Ensures valid TOML structure
|
||||||
|
- **Type Checking**: Validates that values are of expected types
|
||||||
|
- **Required Fields**: Checks for presence of essential configuration sections
|
||||||
|
|
||||||
|
### Semantic Validation
|
||||||
|
- **Port Ranges**: Validates that ports are within valid ranges (1-65535)
|
||||||
|
- **Protocol Values**: Ensures protocols are valid (http, https)
|
||||||
|
- **Connection Limits**: Validates database connection pool settings
|
||||||
|
- **Feature Dependencies**: Checks that required features are enabled
|
||||||
|
|
||||||
|
### Security Validation
|
||||||
|
- **Secret Length**: Validates that secrets meet minimum length requirements
|
||||||
|
- **Password Policies**: Ensures password policies are configured securely
|
||||||
|
- **TLS Settings**: Validates SSL/TLS configuration for production
|
||||||
|
|
||||||
|
## Configuration Examples
|
||||||
|
|
||||||
|
### Complete Development Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# Base settings
|
||||||
|
[server]
|
||||||
|
protocol = "http"
|
||||||
|
host = "127.0.0.1"
|
||||||
|
port = 3030
|
||||||
|
environment = "development"
|
||||||
|
|
||||||
|
[database]
|
||||||
|
url = "sqlite//:dev_database.db"
|
||||||
|
max_connections = 5
|
||||||
|
|
||||||
|
# Feature: Authentication
|
||||||
|
[features]
|
||||||
|
auth = true
|
||||||
|
|
||||||
|
[auth.jwt]
|
||||||
|
secret = "dev-jwt-secret"
|
||||||
|
expiration = 86400
|
||||||
|
|
||||||
|
# Feature: Email
|
||||||
|
[features]
|
||||||
|
email = true
|
||||||
|
|
||||||
|
[email]
|
||||||
|
provider = "console"
|
||||||
|
from_email = "dev@localhost"
|
||||||
|
|
||||||
|
# Build Information
|
||||||
|
[build_info]
|
||||||
|
environment = "dev"
|
||||||
|
build_time = "2024-01-01T12:00:00Z"
|
||||||
|
features = ["auth", "email"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Complete Production Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# Base settings
|
||||||
|
[server]
|
||||||
|
protocol = "https"
|
||||||
|
host = "0.0.0.0"
|
||||||
|
port = 443
|
||||||
|
environment = "production"
|
||||||
|
|
||||||
|
[database]
|
||||||
|
url = "${DATABASE_URL}"
|
||||||
|
max_connections = 20
|
||||||
|
ssl_mode = "require"
|
||||||
|
|
||||||
|
# Feature: Authentication
|
||||||
|
[features]
|
||||||
|
auth = true
|
||||||
|
|
||||||
|
[auth.jwt]
|
||||||
|
secret = "${JWT_SECRET}"
|
||||||
|
expiration = 1800
|
||||||
|
|
||||||
|
[auth.password]
|
||||||
|
min_length = 12
|
||||||
|
require_uppercase = true
|
||||||
|
require_numbers = true
|
||||||
|
require_special_chars = true
|
||||||
|
|
||||||
|
# Feature: Email
|
||||||
|
[features]
|
||||||
|
email = true
|
||||||
|
|
||||||
|
[email]
|
||||||
|
provider = "smtp"
|
||||||
|
from_email = "${FROM_EMAIL}"
|
||||||
|
|
||||||
|
[email.smtp]
|
||||||
|
host = "${SMTP_HOST}"
|
||||||
|
port = 587
|
||||||
|
username = "${SMTP_USERNAME}"
|
||||||
|
password = "${SMTP_PASSWORD}"
|
||||||
|
use_tls = true
|
||||||
|
|
||||||
|
# Build Information
|
||||||
|
[build_info]
|
||||||
|
environment = "prod"
|
||||||
|
build_time = "2024-01-01T12:00:00Z"
|
||||||
|
features = ["auth", "email"]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### 1. Environment-Specific Optimization
|
||||||
|
|
||||||
|
- **Development**: Prioritize developer experience and debugging
|
||||||
|
- **Production**: Prioritize security, performance, and reliability
|
||||||
|
- **Staging**: Mirror production settings with relaxed security for testing
|
||||||
|
|
||||||
|
### 2. Feature Independence
|
||||||
|
|
||||||
|
- Keep feature configurations independent of each other
|
||||||
|
- Use feature flags to enable/disable functionality
|
||||||
|
- Provide sensible defaults for all settings
|
||||||
|
|
||||||
|
### 3. Security
|
||||||
|
|
||||||
|
- Never commit sensitive values to version control
|
||||||
|
- Use environment variables for all secrets
|
||||||
|
- Implement proper validation for security-critical settings
|
||||||
|
- Use strong defaults for production environments
|
||||||
|
|
||||||
|
### 4. Documentation
|
||||||
|
|
||||||
|
- Document all configuration options in example files
|
||||||
|
- Provide clear descriptions for complex settings
|
||||||
|
- Include units and ranges for numeric values
|
||||||
|
- Maintain migration guides for configuration changes
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
1. **Invalid TOML Syntax**
|
||||||
|
```bash
|
||||||
|
# Validate syntax
|
||||||
|
./config/scripts/manage-config.sh validate dev
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Missing Environment Variables**
|
||||||
|
```bash
|
||||||
|
# Check required variables
|
||||||
|
env | grep -E "(DATABASE_URL|SESSION_SECRET|JWT_SECRET)"
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Feature Conflicts**
|
||||||
|
```bash
|
||||||
|
# Compare configurations
|
||||||
|
./config/scripts/manage-config.sh diff dev prod
|
||||||
|
```
|
||||||
|
|
||||||
|
### Debug Mode
|
||||||
|
|
||||||
|
Enable debug output for detailed information:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
CONFIG_DEBUG=1 ./config/scripts/build-config.sh dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Validation Only
|
||||||
|
|
||||||
|
Validate configurations without building:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./config/scripts/manage-config.sh validate dev
|
||||||
|
CONFIG_VALIDATE_ONLY=1 ./config/scripts/build-config.sh prod
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration Guide
|
||||||
|
|
||||||
|
When upgrading configurations:
|
||||||
|
|
||||||
|
1. **Backup existing configurations**
|
||||||
|
2. **Update base configurations** for new settings
|
||||||
|
3. **Update feature configurations** as needed
|
||||||
|
4. **Test in development** before deploying to production
|
||||||
|
5. **Validate configurations** using the build scripts
|
||||||
|
6. **Update environment variables** if required
|
||||||
|
|
||||||
|
For detailed migration instructions, see the [Configuration Migration Guide](../reference/config-migration.md).
|
||||||
532
book/configuration/performance.md
Normal file
532
book/configuration/performance.md
Normal file
@ -0,0 +1,532 @@
|
|||||||
|
# Performance Configuration
|
||||||
|
|
||||||
|
Rustelo provides extensive performance tuning options to optimize your application for different workloads and deployment scenarios. This chapter covers how to configure performance-related settings, optimize resource usage, and monitor application performance.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Performance optimization in Rustelo covers:
|
||||||
|
|
||||||
|
- **Server Configuration**: Worker threads, connection limits, and request handling
|
||||||
|
- **Database Optimization**: Connection pooling, query optimization, and caching
|
||||||
|
- **Memory Management**: Heap size, garbage collection, and memory pools
|
||||||
|
- **Caching Systems**: Multi-level caching strategies and cache invalidation
|
||||||
|
- **Asset Optimization**: Static file serving, compression, and CDN integration
|
||||||
|
- **Monitoring & Profiling**: Performance metrics and bottleneck identification
|
||||||
|
|
||||||
|
## Server Performance Configuration
|
||||||
|
|
||||||
|
### Worker Thread Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[server.performance]
|
||||||
|
workers = 8 # Number of worker threads (default: CPU cores)
|
||||||
|
worker_max_blocking_threads = 32 # Max blocking threads per worker
|
||||||
|
worker_thread_stack_size = 2097152 # Stack size per thread (2MB)
|
||||||
|
worker_thread_keep_alive = 60 # Keep-alive time for idle threads
|
||||||
|
max_connections = 10000 # Maximum concurrent connections
|
||||||
|
connection_timeout = 30 # Connection timeout in seconds
|
||||||
|
keep_alive_timeout = 65 # Keep-alive timeout
|
||||||
|
```
|
||||||
|
|
||||||
|
### Request Handling
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[server.requests]
|
||||||
|
max_request_size = 52428800 # 50MB max request size
|
||||||
|
max_header_size = 32768 # 32KB max header size
|
||||||
|
max_uri_length = 8192 # 8KB max URI length
|
||||||
|
request_timeout = 30 # Request timeout in seconds
|
||||||
|
slow_request_threshold = 1000 # Log slow requests over 1 second
|
||||||
|
max_concurrent_requests = 1000 # Max concurrent requests
|
||||||
|
```
|
||||||
|
|
||||||
|
### Connection Management
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[server.connections]
|
||||||
|
tcp_nodelay = true # Disable Nagle's algorithm
|
||||||
|
tcp_keepalive = true # Enable TCP keepalive
|
||||||
|
keepalive_time = 7200 # Keepalive time (2 hours)
|
||||||
|
keepalive_interval = 75 # Keepalive probe interval
|
||||||
|
keepalive_probes = 9 # Number of keepalive probes
|
||||||
|
reuse_port = true # Enable SO_REUSEPORT
|
||||||
|
backlog = 1024 # Listen backlog queue size
|
||||||
|
```
|
||||||
|
|
||||||
|
## Database Performance Configuration
|
||||||
|
|
||||||
|
### Connection Pool Optimization
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[database.performance]
|
||||||
|
max_connections = 20 # Maximum pool size
|
||||||
|
min_connections = 5 # Minimum pool size
|
||||||
|
acquire_timeout = 30 # Connection acquire timeout
|
||||||
|
idle_timeout = 600 # Idle connection timeout
|
||||||
|
max_lifetime = 1800 # Maximum connection lifetime
|
||||||
|
test_before_acquire = false # Test connections before use
|
||||||
|
```
|
||||||
|
|
||||||
|
### Query Optimization
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[database.queries]
|
||||||
|
statement_timeout = 30000 # Query timeout in milliseconds
|
||||||
|
slow_query_threshold = 1000 # Log slow queries over 1 second
|
||||||
|
enable_query_cache = true # Enable query result caching
|
||||||
|
query_cache_size = 134217728 # Query cache size (128MB)
|
||||||
|
query_cache_ttl = 300 # Query cache TTL in seconds
|
||||||
|
prepared_statement_cache_size = 256 # Prepared statement cache size
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database-Specific Optimizations
|
||||||
|
|
||||||
|
#### PostgreSQL
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[database.postgresql]
|
||||||
|
shared_buffers = "256MB" # Shared buffer size
|
||||||
|
effective_cache_size = "1GB" # Effective cache size
|
||||||
|
work_mem = "4MB" # Work memory per query
|
||||||
|
maintenance_work_mem = "64MB" # Maintenance work memory
|
||||||
|
checkpoint_completion_target = 0.7 # Checkpoint completion target
|
||||||
|
wal_buffers = "16MB" # WAL buffer size
|
||||||
|
default_statistics_target = 100 # Statistics target
|
||||||
|
random_page_cost = 1.1 # Random page cost
|
||||||
|
```
|
||||||
|
|
||||||
|
#### SQLite
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[database.sqlite]
|
||||||
|
journal_mode = "WAL" # Write-Ahead Logging
|
||||||
|
synchronous = "NORMAL" # Synchronous mode
|
||||||
|
cache_size = 10000 # Page cache size
|
||||||
|
temp_store = "memory" # Temporary storage in memory
|
||||||
|
mmap_size = 268435456 # Memory-mapped I/O size (256MB)
|
||||||
|
page_size = 4096 # Page size in bytes
|
||||||
|
```
|
||||||
|
|
||||||
|
## Memory Management
|
||||||
|
|
||||||
|
### Heap Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[memory]
|
||||||
|
initial_heap_size = 134217728 # Initial heap size (128MB)
|
||||||
|
max_heap_size = 2147483648 # Maximum heap size (2GB)
|
||||||
|
gc_threshold = 0.75 # GC threshold (75% of heap)
|
||||||
|
gc_trigger_interval = 60 # GC trigger interval in seconds
|
||||||
|
```
|
||||||
|
|
||||||
|
### Memory Pools
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[memory.pools]
|
||||||
|
buffer_pool_size = 67108864 # Buffer pool size (64MB)
|
||||||
|
string_pool_size = 16777216 # String pool size (16MB)
|
||||||
|
object_pool_size = 33554432 # Object pool size (32MB)
|
||||||
|
connection_pool_memory = 8388608 # Connection pool memory (8MB)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Memory Monitoring
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[memory.monitoring]
|
||||||
|
track_allocations = true # Track memory allocations
|
||||||
|
memory_usage_threshold = 0.8 # Alert when memory usage > 80%
|
||||||
|
enable_memory_profiling = false # Enable memory profiling (dev only)
|
||||||
|
memory_leak_detection = true # Enable memory leak detection
|
||||||
|
```
|
||||||
|
|
||||||
|
## Caching Configuration
|
||||||
|
|
||||||
|
### Multi-Level Caching
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[cache]
|
||||||
|
enabled = true
|
||||||
|
default_ttl = 3600 # Default cache TTL (1 hour)
|
||||||
|
max_memory_size = 268435456 # Max memory cache size (256MB)
|
||||||
|
cleanup_interval = 300 # Cache cleanup interval (5 minutes)
|
||||||
|
compression_enabled = true # Enable cache compression
|
||||||
|
compression_threshold = 1024 # Compress items larger than 1KB
|
||||||
|
```
|
||||||
|
|
||||||
|
### L1 Cache (In-Memory)
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[cache.l1]
|
||||||
|
enabled = true
|
||||||
|
max_entries = 10000 # Maximum cache entries
|
||||||
|
eviction_policy = "lru" # Eviction policy: lru, lfu, fifo
|
||||||
|
segment_count = 16 # Number of cache segments
|
||||||
|
expire_after_write = 3600 # Expire after write (1 hour)
|
||||||
|
expire_after_access = 1800 # Expire after access (30 minutes)
|
||||||
|
```
|
||||||
|
|
||||||
|
### L2 Cache (Redis)
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[cache.l2]
|
||||||
|
enabled = true
|
||||||
|
redis_url = "${REDIS_URL}"
|
||||||
|
database = 0 # Redis database number
|
||||||
|
key_prefix = "rustelo:" # Cache key prefix
|
||||||
|
connection_pool_size = 10 # Redis connection pool size
|
||||||
|
connection_timeout = 5 # Redis connection timeout
|
||||||
|
command_timeout = 5 # Redis command timeout
|
||||||
|
```
|
||||||
|
|
||||||
|
### Application-Level Caching
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[cache.application]
|
||||||
|
page_cache_enabled = true # Enable page caching
|
||||||
|
page_cache_ttl = 1800 # Page cache TTL (30 minutes)
|
||||||
|
api_cache_enabled = true # Enable API response caching
|
||||||
|
api_cache_ttl = 300 # API cache TTL (5 minutes)
|
||||||
|
template_cache_enabled = true # Enable template caching
|
||||||
|
static_file_cache_enabled = true # Enable static file caching
|
||||||
|
```
|
||||||
|
|
||||||
|
## Asset Optimization
|
||||||
|
|
||||||
|
### Static File Serving
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[assets]
|
||||||
|
serve_static_files = true # Serve static files
|
||||||
|
static_file_cache_control = "public, max-age=31536000" # 1 year cache
|
||||||
|
enable_etag = true # Enable ETag headers
|
||||||
|
enable_last_modified = true # Enable Last-Modified headers
|
||||||
|
enable_range_requests = true # Enable range requests
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compression
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[assets.compression]
|
||||||
|
enabled = true
|
||||||
|
algorithms = ["gzip", "deflate", "br"] # Compression algorithms
|
||||||
|
compression_level = 6 # Compression level (1-9)
|
||||||
|
min_file_size = 1024 # Minimum file size to compress
|
||||||
|
compress_types = [ # MIME types to compress
|
||||||
|
"text/html",
|
||||||
|
"text/css",
|
||||||
|
"text/javascript",
|
||||||
|
"application/javascript",
|
||||||
|
"application/json",
|
||||||
|
"text/xml",
|
||||||
|
"application/xml"
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### CDN Integration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[assets.cdn]
|
||||||
|
enabled = false # Enable CDN
|
||||||
|
cdn_url = "https://cdn.example.com" # CDN base URL
|
||||||
|
cdn_paths = ["/static", "/assets"] # Paths to serve from CDN
|
||||||
|
cache_bust_enabled = true # Enable cache busting
|
||||||
|
cache_bust_strategy = "timestamp" # Strategy: timestamp, hash, version
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance Monitoring
|
||||||
|
|
||||||
|
### Metrics Collection
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[performance.metrics]
|
||||||
|
enabled = true
|
||||||
|
collection_interval = 15 # Metrics collection interval (seconds)
|
||||||
|
retention_period = 2592000 # Metrics retention (30 days)
|
||||||
|
high_resolution_metrics = true # Enable high-resolution metrics
|
||||||
|
```
|
||||||
|
|
||||||
|
### Response Time Monitoring
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[performance.response_times]
|
||||||
|
track_percentiles = true # Track response time percentiles
|
||||||
|
percentiles = [50, 75, 90, 95, 99, 99.9] # Percentiles to track
|
||||||
|
slow_request_threshold = 1000 # Slow request threshold (1 second)
|
||||||
|
very_slow_request_threshold = 5000 # Very slow request threshold (5 seconds)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Resource Monitoring
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[performance.resources]
|
||||||
|
monitor_cpu = true # Monitor CPU usage
|
||||||
|
monitor_memory = true # Monitor memory usage
|
||||||
|
monitor_disk = true # Monitor disk I/O
|
||||||
|
monitor_network = true # Monitor network I/O
|
||||||
|
monitor_connections = true # Monitor connection count
|
||||||
|
```
|
||||||
|
|
||||||
|
## Profiling Configuration
|
||||||
|
|
||||||
|
### CPU Profiling
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[profiling.cpu]
|
||||||
|
enabled = false # Enable CPU profiling (dev/staging only)
|
||||||
|
sampling_interval = 10000 # Sampling interval in microseconds
|
||||||
|
profile_duration = 60 # Profile duration in seconds
|
||||||
|
output_format = "flamegraph" # Output format: flamegraph, callgrind
|
||||||
|
```
|
||||||
|
|
||||||
|
### Memory Profiling
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[profiling.memory]
|
||||||
|
enabled = false # Enable memory profiling (dev/staging only)
|
||||||
|
track_allocations = true # Track individual allocations
|
||||||
|
heap_profiling = true # Enable heap profiling
|
||||||
|
leak_detection = true # Enable memory leak detection
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database Profiling
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[profiling.database]
|
||||||
|
enabled = false # Enable database profiling
|
||||||
|
log_all_queries = false # Log all database queries
|
||||||
|
log_slow_queries = true # Log slow queries only
|
||||||
|
explain_slow_queries = true # Add EXPLAIN to slow queries
|
||||||
|
query_plan_cache = true # Cache query execution plans
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environment-Specific Performance
|
||||||
|
|
||||||
|
### Development Environment
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[performance.development]
|
||||||
|
optimize_for_development = true # Enable development optimizations
|
||||||
|
hot_reload_enabled = true # Enable hot reloading
|
||||||
|
debug_mode = true # Enable debug mode
|
||||||
|
profiling_enabled = true # Enable profiling
|
||||||
|
reduced_caching = true # Reduce caching for development
|
||||||
|
```
|
||||||
|
|
||||||
|
### Production Environment
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[performance.production]
|
||||||
|
optimize_for_production = true # Enable production optimizations
|
||||||
|
aggressive_caching = true # Enable aggressive caching
|
||||||
|
connection_pooling = true # Enable connection pooling
|
||||||
|
jit_compilation = true # Enable JIT compilation
|
||||||
|
gc_optimization = true # Enable garbage collection optimization
|
||||||
|
```
|
||||||
|
|
||||||
|
## Load Testing Configuration
|
||||||
|
|
||||||
|
### Test Parameters
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[load_testing]
|
||||||
|
max_virtual_users = 1000 # Maximum virtual users
|
||||||
|
ramp_up_time = 60 # Ramp-up time in seconds
|
||||||
|
test_duration = 300 # Test duration in seconds
|
||||||
|
think_time = 1 # Think time between requests
|
||||||
|
```
|
||||||
|
|
||||||
|
### Performance Targets
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[load_testing.targets]
|
||||||
|
response_time_p95 = 500 # 95th percentile response time (ms)
|
||||||
|
response_time_p99 = 1000 # 99th percentile response time (ms)
|
||||||
|
throughput_rps = 1000 # Requests per second
|
||||||
|
error_rate_threshold = 0.01 # Maximum error rate (1%)
|
||||||
|
cpu_usage_threshold = 0.8 # Maximum CPU usage (80%)
|
||||||
|
memory_usage_threshold = 0.8 # Maximum memory usage (80%)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance Optimization Strategies
|
||||||
|
|
||||||
|
### Database Optimization
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[optimization.database]
|
||||||
|
enable_query_optimization = true
|
||||||
|
index_optimization = true
|
||||||
|
query_caching = true
|
||||||
|
connection_pooling = true
|
||||||
|
read_replicas = false
|
||||||
|
database_sharding = false
|
||||||
|
```
|
||||||
|
|
||||||
|
### Application Optimization
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[optimization.application]
|
||||||
|
lazy_loading = true # Enable lazy loading
|
||||||
|
async_processing = true # Enable async processing
|
||||||
|
batch_operations = true # Enable batch operations
|
||||||
|
response_streaming = true # Enable response streaming
|
||||||
|
request_coalescing = true # Enable request coalescing
|
||||||
|
```
|
||||||
|
|
||||||
|
### System Optimization
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[optimization.system]
|
||||||
|
kernel_bypass = false # Enable kernel bypass (advanced)
|
||||||
|
numa_awareness = true # Enable NUMA awareness
|
||||||
|
cpu_affinity = false # Enable CPU affinity
|
||||||
|
disk_io_optimization = true # Enable disk I/O optimization
|
||||||
|
network_optimization = true # Enable network optimization
|
||||||
|
```
|
||||||
|
|
||||||
|
## Monitoring and Alerting
|
||||||
|
|
||||||
|
### Performance Alerts
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[alerts.performance]
|
||||||
|
enabled = true
|
||||||
|
response_time_threshold = 2000 # Response time alert threshold (2 seconds)
|
||||||
|
throughput_threshold = 100 # Throughput alert threshold (100 RPS)
|
||||||
|
error_rate_threshold = 0.05 # Error rate alert threshold (5%)
|
||||||
|
memory_usage_threshold = 0.9 # Memory usage alert threshold (90%)
|
||||||
|
cpu_usage_threshold = 0.9 # CPU usage alert threshold (90%)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Health Checks
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[health_checks]
|
||||||
|
enabled = true
|
||||||
|
check_interval = 30 # Health check interval (seconds)
|
||||||
|
timeout = 5 # Health check timeout (seconds)
|
||||||
|
failure_threshold = 3 # Consecutive failures before alert
|
||||||
|
```
|
||||||
|
|
||||||
|
## Benchmarking Configuration
|
||||||
|
|
||||||
|
### Benchmark Settings
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[benchmarking]
|
||||||
|
enabled = false # Enable benchmarking
|
||||||
|
benchmark_duration = 60 # Benchmark duration (seconds)
|
||||||
|
warmup_duration = 10 # Warmup duration (seconds)
|
||||||
|
concurrency_levels = [1, 10, 100, 1000] # Concurrency levels to test
|
||||||
|
```
|
||||||
|
|
||||||
|
### Performance Baselines
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[benchmarking.baselines]
|
||||||
|
response_time_baseline = 100 # Response time baseline (ms)
|
||||||
|
throughput_baseline = 1000 # Throughput baseline (RPS)
|
||||||
|
memory_baseline = 134217728 # Memory baseline (128MB)
|
||||||
|
cpu_baseline = 0.5 # CPU baseline (50%)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting Performance Issues
|
||||||
|
|
||||||
|
### Common Performance Problems
|
||||||
|
|
||||||
|
1. **High Response Times**
|
||||||
|
- Check database query performance
|
||||||
|
- Review caching configuration
|
||||||
|
- Monitor resource usage
|
||||||
|
- Analyze request patterns
|
||||||
|
|
||||||
|
2. **Memory Issues**
|
||||||
|
- Monitor memory usage patterns
|
||||||
|
- Check for memory leaks
|
||||||
|
- Review garbage collection settings
|
||||||
|
- Optimize memory allocation
|
||||||
|
|
||||||
|
3. **CPU Bottlenecks**
|
||||||
|
- Profile CPU usage
|
||||||
|
- Check for inefficient algorithms
|
||||||
|
- Review worker thread configuration
|
||||||
|
- Optimize hot code paths
|
||||||
|
|
||||||
|
4. **Database Performance**
|
||||||
|
- Analyze slow queries
|
||||||
|
- Check connection pool settings
|
||||||
|
- Review database configuration
|
||||||
|
- Optimize indexes
|
||||||
|
|
||||||
|
### Performance Debugging
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[debugging.performance]
|
||||||
|
enable_detailed_logging = true # Enable detailed performance logging
|
||||||
|
request_tracing = true # Enable request tracing
|
||||||
|
sql_query_logging = true # Enable SQL query logging
|
||||||
|
memory_tracking = true # Enable memory tracking
|
||||||
|
cpu_profiling = true # Enable CPU profiling
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### Performance Optimization Guidelines
|
||||||
|
|
||||||
|
1. **Measure Before Optimizing**
|
||||||
|
- Establish performance baselines
|
||||||
|
- Use profiling tools
|
||||||
|
- Monitor key metrics
|
||||||
|
- Identify bottlenecks
|
||||||
|
|
||||||
|
2. **Optimize Incrementally**
|
||||||
|
- Make small, measurable changes
|
||||||
|
- Test each optimization
|
||||||
|
- Monitor impact
|
||||||
|
- Rollback if necessary
|
||||||
|
|
||||||
|
3. **Cache Strategically**
|
||||||
|
- Cache frequently accessed data
|
||||||
|
- Use appropriate cache levels
|
||||||
|
- Implement cache invalidation
|
||||||
|
- Monitor cache hit rates
|
||||||
|
|
||||||
|
4. **Database Optimization**
|
||||||
|
- Use appropriate indexes
|
||||||
|
- Optimize query structure
|
||||||
|
- Configure connection pooling
|
||||||
|
- Monitor slow queries
|
||||||
|
|
||||||
|
### Performance Testing
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[testing.performance]
|
||||||
|
automated_testing = true # Enable automated performance testing
|
||||||
|
regression_testing = true # Enable performance regression testing
|
||||||
|
load_testing = true # Enable load testing
|
||||||
|
stress_testing = true # Enable stress testing
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance Checklist
|
||||||
|
|
||||||
|
### Pre-Production Performance Review
|
||||||
|
|
||||||
|
- [ ] Database queries optimized
|
||||||
|
- [ ] Appropriate indexes created
|
||||||
|
- [ ] Connection pooling configured
|
||||||
|
- [ ] Caching strategy implemented
|
||||||
|
- [ ] Static assets optimized
|
||||||
|
- [ ] Compression enabled
|
||||||
|
- [ ] Memory limits configured
|
||||||
|
- [ ] Worker threads optimized
|
||||||
|
- [ ] Performance monitoring enabled
|
||||||
|
- [ ] Load testing completed
|
||||||
|
- [ ] Performance baselines established
|
||||||
|
- [ ] Alerting configured
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- [Database Optimization](../performance/database.md)
|
||||||
|
- [Caching Strategies](../performance/caching.md)
|
||||||
|
- [Frontend Optimization](../performance/frontend.md)
|
||||||
|
- [Memory Management](../performance/memory.md)
|
||||||
|
- [Monitoring & Profiling](../performance/monitoring.md)
|
||||||
605
book/configuration/security.md
Normal file
605
book/configuration/security.md
Normal file
@ -0,0 +1,605 @@
|
|||||||
|
# Security Configuration
|
||||||
|
|
||||||
|
Rustelo provides comprehensive security features to protect your application and user data. This chapter covers how to configure authentication, authorization, encryption, and other security measures to ensure your application meets security best practices.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Rustelo's security system includes:
|
||||||
|
|
||||||
|
- **Authentication**: User identity verification and session management
|
||||||
|
- **Authorization**: Role-based access control (RBAC) and permissions
|
||||||
|
- **Encryption**: Data protection at rest and in transit
|
||||||
|
- **Input Validation**: Protection against injection attacks
|
||||||
|
- **Security Headers**: HTTP security headers and CSP
|
||||||
|
- **Rate Limiting**: Protection against abuse and DoS attacks
|
||||||
|
- **Audit Logging**: Security event tracking and monitoring
|
||||||
|
|
||||||
|
## Authentication Configuration
|
||||||
|
|
||||||
|
### Basic Authentication Settings
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[auth]
|
||||||
|
enabled = true
|
||||||
|
require_authentication = true
|
||||||
|
default_session_timeout = 1800 # 30 minutes
|
||||||
|
max_session_duration = 28800 # 8 hours
|
||||||
|
session_cleanup_interval = 300 # 5 minutes
|
||||||
|
|
||||||
|
[auth.password]
|
||||||
|
min_length = 12
|
||||||
|
max_length = 128
|
||||||
|
require_uppercase = true
|
||||||
|
require_lowercase = true
|
||||||
|
require_numbers = true
|
||||||
|
require_special_chars = true
|
||||||
|
forbidden_passwords = [
|
||||||
|
"password", "123456", "admin", "root"
|
||||||
|
]
|
||||||
|
password_history_count = 5
|
||||||
|
password_expiry_days = 90
|
||||||
|
```
|
||||||
|
|
||||||
|
### JWT Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[auth.jwt]
|
||||||
|
secret = "${JWT_SECRET}"
|
||||||
|
algorithm = "HS256"
|
||||||
|
issuer = "rustelo-app"
|
||||||
|
audience = ["rustelo-users"]
|
||||||
|
access_token_expiry = 900 # 15 minutes
|
||||||
|
refresh_token_expiry = 86400 # 24 hours
|
||||||
|
require_exp = true
|
||||||
|
require_iat = true
|
||||||
|
require_nbf = true
|
||||||
|
clock_skew = 60 # Allow 60 seconds clock skew
|
||||||
|
```
|
||||||
|
|
||||||
|
### Session Management
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[auth.sessions]
|
||||||
|
cookie_name = "rustelo_session"
|
||||||
|
cookie_secure = true # HTTPS only
|
||||||
|
cookie_http_only = true # No JavaScript access
|
||||||
|
cookie_same_site = "Strict"
|
||||||
|
cookie_path = "/"
|
||||||
|
cookie_domain = "" # Current domain only
|
||||||
|
session_regeneration = true # Regenerate session ID on login
|
||||||
|
concurrent_sessions = 3 # Max concurrent sessions per user
|
||||||
|
```
|
||||||
|
|
||||||
|
### Account Security
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[auth.security]
|
||||||
|
max_login_attempts = 5
|
||||||
|
lockout_duration = 900 # 15 minutes
|
||||||
|
progressive_lockout = true # Increase lockout time on repeated failures
|
||||||
|
require_email_verification = true
|
||||||
|
email_verification_expiry = 86400 # 24 hours
|
||||||
|
password_reset_expiry = 3600 # 1 hour
|
||||||
|
```
|
||||||
|
|
||||||
|
## Two-Factor Authentication
|
||||||
|
|
||||||
|
### TOTP Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[auth.two_factor]
|
||||||
|
enabled = true
|
||||||
|
required_for_admin = true
|
||||||
|
backup_codes_count = 10
|
||||||
|
backup_codes_length = 8
|
||||||
|
|
||||||
|
[auth.two_factor.totp]
|
||||||
|
issuer = "Rustelo App"
|
||||||
|
algorithm = "SHA1"
|
||||||
|
digits = 6
|
||||||
|
period = 30
|
||||||
|
window = 1 # Allow 1 step before/after current time
|
||||||
|
```
|
||||||
|
|
||||||
|
### SMS Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[auth.two_factor.sms]
|
||||||
|
enabled = false
|
||||||
|
provider = "twilio" # twilio, aws_sns
|
||||||
|
verification_code_length = 6
|
||||||
|
verification_code_expiry = 300 # 5 minutes
|
||||||
|
rate_limit = 5 # Max 5 SMS per hour per user
|
||||||
|
|
||||||
|
[auth.two_factor.sms.twilio]
|
||||||
|
account_sid = "${TWILIO_ACCOUNT_SID}"
|
||||||
|
auth_token = "${TWILIO_AUTH_TOKEN}"
|
||||||
|
from_number = "${TWILIO_FROM_NUMBER}"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Authorization & RBAC
|
||||||
|
|
||||||
|
### Role-Based Access Control
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[rbac]
|
||||||
|
enabled = true
|
||||||
|
default_role = "user"
|
||||||
|
admin_role = "admin"
|
||||||
|
super_admin_role = "super_admin"
|
||||||
|
guest_role = "guest"
|
||||||
|
|
||||||
|
[rbac.permissions]
|
||||||
|
hierarchical = true # Roles inherit permissions from parent roles
|
||||||
|
cache_enabled = true
|
||||||
|
cache_ttl = 300 # 5 minutes
|
||||||
|
audit_enabled = true
|
||||||
|
|
||||||
|
[rbac.roles]
|
||||||
|
user = {
|
||||||
|
permissions = ["read_own_profile", "update_own_profile"],
|
||||||
|
inherits_from = ["guest"]
|
||||||
|
}
|
||||||
|
moderator = {
|
||||||
|
permissions = ["moderate_content", "view_reports"],
|
||||||
|
inherits_from = ["user"]
|
||||||
|
}
|
||||||
|
admin = {
|
||||||
|
permissions = ["manage_users", "manage_content", "view_logs"],
|
||||||
|
inherits_from = ["moderator"]
|
||||||
|
}
|
||||||
|
super_admin = {
|
||||||
|
permissions = ["*"],
|
||||||
|
inherits_from = []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Resource-Based Permissions
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[rbac.resources]
|
||||||
|
users = ["create", "read", "update", "delete"]
|
||||||
|
content = ["create", "read", "update", "delete", "publish"]
|
||||||
|
reports = ["create", "read", "update", "delete", "resolve"]
|
||||||
|
logs = ["read", "export"]
|
||||||
|
settings = ["read", "update"]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Encryption Configuration
|
||||||
|
|
||||||
|
### Data Encryption
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[encryption]
|
||||||
|
enabled = true
|
||||||
|
algorithm = "AES-256-GCM"
|
||||||
|
key_derivation = "PBKDF2"
|
||||||
|
key_derivation_iterations = 100000
|
||||||
|
salt_length = 32
|
||||||
|
|
||||||
|
[encryption.at_rest]
|
||||||
|
enabled = true
|
||||||
|
encrypt_sensitive_fields = true
|
||||||
|
sensitive_fields = [
|
||||||
|
"password", "email", "phone", "ssn", "credit_card"
|
||||||
|
]
|
||||||
|
|
||||||
|
[encryption.in_transit]
|
||||||
|
min_tls_version = "1.2"
|
||||||
|
cipher_suites = [
|
||||||
|
"TLS_AES_256_GCM_SHA384",
|
||||||
|
"TLS_CHACHA20_POLY1305_SHA256",
|
||||||
|
"TLS_AES_128_GCM_SHA256"
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key Management
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[encryption.keys]
|
||||||
|
rotation_enabled = true
|
||||||
|
rotation_interval = 2592000 # 30 days
|
||||||
|
key_backup_enabled = true
|
||||||
|
key_backup_location = "${KEY_BACKUP_PATH}"
|
||||||
|
master_key = "${MASTER_ENCRYPTION_KEY}"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Input Validation & Sanitization
|
||||||
|
|
||||||
|
### General Validation
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[security.validation]
|
||||||
|
enabled = true
|
||||||
|
strict_mode = true
|
||||||
|
max_request_size = 10485760 # 10MB
|
||||||
|
max_field_length = 1000
|
||||||
|
max_array_length = 100
|
||||||
|
max_nesting_depth = 10
|
||||||
|
|
||||||
|
[security.validation.email]
|
||||||
|
allow_plus_addressing = true
|
||||||
|
allow_internationalized = true
|
||||||
|
require_verification = true
|
||||||
|
blocked_domains = ["tempmail.com", "10minutemail.com"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### SQL Injection Prevention
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[security.sql_injection]
|
||||||
|
use_prepared_statements = true
|
||||||
|
validate_input_types = true
|
||||||
|
escape_special_characters = true
|
||||||
|
log_suspicious_queries = true
|
||||||
|
```
|
||||||
|
|
||||||
|
### XSS Prevention
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[security.xss]
|
||||||
|
enabled = true
|
||||||
|
auto_escape_html = true
|
||||||
|
content_security_policy = true
|
||||||
|
sanitize_user_input = true
|
||||||
|
allowed_html_tags = ["b", "i", "u", "em", "strong", "a"]
|
||||||
|
allowed_attributes = ["href", "title", "alt"]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Headers
|
||||||
|
|
||||||
|
### HTTP Security Headers
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[security.headers]
|
||||||
|
enabled = true
|
||||||
|
|
||||||
|
[security.headers.hsts]
|
||||||
|
enabled = true
|
||||||
|
max_age = 31536000 # 1 year
|
||||||
|
include_subdomains = true
|
||||||
|
preload = true
|
||||||
|
|
||||||
|
[security.headers.csp]
|
||||||
|
enabled = true
|
||||||
|
default_src = ["'self'"]
|
||||||
|
script_src = ["'self'", "'unsafe-inline'"]
|
||||||
|
style_src = ["'self'", "'unsafe-inline'"]
|
||||||
|
img_src = ["'self'", "data:", "https:"]
|
||||||
|
connect_src = ["'self'"]
|
||||||
|
font_src = ["'self'"]
|
||||||
|
object_src = ["'none'"]
|
||||||
|
frame_ancestors = ["'none'"]
|
||||||
|
base_uri = ["'self'"]
|
||||||
|
form_action = ["'self'"]
|
||||||
|
|
||||||
|
[security.headers.other]
|
||||||
|
x_content_type_options = "nosniff"
|
||||||
|
x_frame_options = "DENY"
|
||||||
|
x_xss_protection = "1; mode=block"
|
||||||
|
referrer_policy = "strict-origin-when-cross-origin"
|
||||||
|
permissions_policy = "geolocation=(), microphone=(), camera=()"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rate Limiting
|
||||||
|
|
||||||
|
### API Rate Limiting
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[security.rate_limiting]
|
||||||
|
enabled = true
|
||||||
|
storage = "memory" # memory, redis, database
|
||||||
|
cleanup_interval = 3600 # 1 hour
|
||||||
|
|
||||||
|
[security.rate_limiting.global]
|
||||||
|
requests_per_minute = 100
|
||||||
|
burst_limit = 10
|
||||||
|
|
||||||
|
[security.rate_limiting.per_user]
|
||||||
|
requests_per_minute = 60
|
||||||
|
burst_limit = 5
|
||||||
|
|
||||||
|
[security.rate_limiting.endpoints]
|
||||||
|
"/api/auth/login" = { requests_per_minute = 5, burst_limit = 2 }
|
||||||
|
"/api/auth/register" = { requests_per_minute = 3, burst_limit = 1 }
|
||||||
|
"/api/password/reset" = { requests_per_minute = 2, burst_limit = 1 }
|
||||||
|
"/api/upload" = { requests_per_minute = 10, burst_limit = 3 }
|
||||||
|
```
|
||||||
|
|
||||||
|
### DDoS Protection
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[security.ddos]
|
||||||
|
enabled = true
|
||||||
|
max_connections_per_ip = 10
|
||||||
|
connection_timeout = 30
|
||||||
|
slow_loris_protection = true
|
||||||
|
```
|
||||||
|
|
||||||
|
## CSRF Protection
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[security.csrf]
|
||||||
|
enabled = true
|
||||||
|
token_name = "csrf_token"
|
||||||
|
header_name = "X-CSRF-Token"
|
||||||
|
cookie_name = "csrf_cookie"
|
||||||
|
token_length = 32
|
||||||
|
double_submit_cookie = true
|
||||||
|
same_site_cookie = "Strict"
|
||||||
|
```
|
||||||
|
|
||||||
|
## File Upload Security
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[security.uploads]
|
||||||
|
enabled = true
|
||||||
|
max_file_size = 10485760 # 10MB
|
||||||
|
max_files_per_request = 5
|
||||||
|
allowed_extensions = [
|
||||||
|
"jpg", "jpeg", "png", "gif", "webp",
|
||||||
|
"pdf", "doc", "docx", "txt", "csv"
|
||||||
|
]
|
||||||
|
scan_for_viruses = true
|
||||||
|
quarantine_suspicious_files = true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Audit Logging
|
||||||
|
|
||||||
|
### Security Event Logging
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[security.audit]
|
||||||
|
enabled = true
|
||||||
|
log_level = "info"
|
||||||
|
log_format = "json"
|
||||||
|
log_file = "/var/log/rustelo/security.log"
|
||||||
|
max_log_size = 104857600 # 100MB
|
||||||
|
max_log_files = 10
|
||||||
|
log_retention_days = 90
|
||||||
|
|
||||||
|
[security.audit.events]
|
||||||
|
login_success = true
|
||||||
|
login_failure = true
|
||||||
|
logout = true
|
||||||
|
password_change = true
|
||||||
|
password_reset = true
|
||||||
|
account_lockout = true
|
||||||
|
permission_denied = true
|
||||||
|
data_access = true
|
||||||
|
data_modification = true
|
||||||
|
admin_actions = true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compliance Logging
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[security.compliance]
|
||||||
|
gdpr_logging = true
|
||||||
|
hipaa_logging = false
|
||||||
|
pci_logging = false
|
||||||
|
sox_logging = false
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environment-Specific Security
|
||||||
|
|
||||||
|
### Development Environment
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[security.development]
|
||||||
|
relaxed_cors = true
|
||||||
|
debug_headers = true
|
||||||
|
disable_https_redirect = true
|
||||||
|
allow_http_cookies = true
|
||||||
|
verbose_error_messages = true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Production Environment
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[security.production]
|
||||||
|
strict_mode = true
|
||||||
|
hide_server_info = true
|
||||||
|
disable_debug_endpoints = true
|
||||||
|
require_https = true
|
||||||
|
enable_monitoring = true
|
||||||
|
```
|
||||||
|
|
||||||
|
## SSL/TLS Configuration
|
||||||
|
|
||||||
|
### Certificate Management
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[security.tls]
|
||||||
|
enabled = true
|
||||||
|
cert_file = "${TLS_CERT_FILE}"
|
||||||
|
key_file = "${TLS_KEY_FILE}"
|
||||||
|
ca_file = "${TLS_CA_FILE}"
|
||||||
|
protocols = ["TLSv1.2", "TLSv1.3"]
|
||||||
|
prefer_server_ciphers = true
|
||||||
|
|
||||||
|
[security.tls.auto_renewal]
|
||||||
|
enabled = true
|
||||||
|
provider = "lets_encrypt"
|
||||||
|
renewal_threshold = 2592000 # 30 days
|
||||||
|
notification_email = "${ADMIN_EMAIL}"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Monitoring
|
||||||
|
|
||||||
|
### Intrusion Detection
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[security.monitoring]
|
||||||
|
enabled = true
|
||||||
|
failed_login_threshold = 10
|
||||||
|
suspicious_activity_threshold = 5
|
||||||
|
alert_admin = true
|
||||||
|
auto_block_suspicious_ips = true
|
||||||
|
block_duration = 3600 # 1 hour
|
||||||
|
```
|
||||||
|
|
||||||
|
### Security Metrics
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[security.metrics]
|
||||||
|
enabled = true
|
||||||
|
track_login_attempts = true
|
||||||
|
track_permission_denials = true
|
||||||
|
track_rate_limit_hits = true
|
||||||
|
track_security_violations = true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices Configuration
|
||||||
|
|
||||||
|
### Password Security
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[security.passwords]
|
||||||
|
use_bcrypt = true
|
||||||
|
bcrypt_cost = 12
|
||||||
|
require_password_confirmation = true
|
||||||
|
prevent_password_reuse = true
|
||||||
|
password_strength_meter = true
|
||||||
|
```
|
||||||
|
|
||||||
|
### API Security
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[security.api]
|
||||||
|
require_authentication = true
|
||||||
|
require_https = true
|
||||||
|
validate_content_type = true
|
||||||
|
rate_limit_enabled = true
|
||||||
|
cors_enabled = true
|
||||||
|
cors_allow_credentials = false
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Testing
|
||||||
|
|
||||||
|
### Penetration Testing
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[security.testing]
|
||||||
|
enable_security_tests = true
|
||||||
|
sql_injection_tests = true
|
||||||
|
xss_tests = true
|
||||||
|
csrf_tests = true
|
||||||
|
authentication_tests = true
|
||||||
|
authorization_tests = true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Incident Response
|
||||||
|
|
||||||
|
### Security Incident Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[security.incident_response]
|
||||||
|
enabled = true
|
||||||
|
auto_lockout_on_breach = true
|
||||||
|
notify_admin_on_incident = true
|
||||||
|
incident_log_file = "/var/log/rustelo/incidents.log"
|
||||||
|
emergency_contact = "${SECURITY_CONTACT}"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Compliance Frameworks
|
||||||
|
|
||||||
|
### GDPR Compliance
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[security.gdpr]
|
||||||
|
enabled = true
|
||||||
|
data_retention_days = 2555 # 7 years
|
||||||
|
anonymize_on_deletion = true
|
||||||
|
consent_tracking = true
|
||||||
|
data_export_enabled = true
|
||||||
|
```
|
||||||
|
|
||||||
|
### OWASP Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[security.owasp]
|
||||||
|
top_10_protection = true
|
||||||
|
injection_prevention = true
|
||||||
|
broken_authentication_prevention = true
|
||||||
|
sensitive_data_exposure_prevention = true
|
||||||
|
xml_external_entities_prevention = true
|
||||||
|
broken_access_control_prevention = true
|
||||||
|
security_misconfiguration_prevention = true
|
||||||
|
cross_site_scripting_prevention = true
|
||||||
|
insecure_deserialization_prevention = true
|
||||||
|
known_vulnerabilities_prevention = true
|
||||||
|
insufficient_logging_prevention = true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Checklist
|
||||||
|
|
||||||
|
### Pre-Deployment Security Checks
|
||||||
|
|
||||||
|
- [ ] Strong authentication configured
|
||||||
|
- [ ] HTTPS enabled and enforced
|
||||||
|
- [ ] Security headers implemented
|
||||||
|
- [ ] Input validation enabled
|
||||||
|
- [ ] Rate limiting configured
|
||||||
|
- [ ] Audit logging enabled
|
||||||
|
- [ ] File upload restrictions in place
|
||||||
|
- [ ] Database security configured
|
||||||
|
- [ ] Regular security updates scheduled
|
||||||
|
- [ ] Backup and recovery procedures tested
|
||||||
|
- [ ] Incident response plan documented
|
||||||
|
- [ ] Security monitoring enabled
|
||||||
|
- [ ] Penetration testing completed
|
||||||
|
- [ ] Compliance requirements met
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Security Issues
|
||||||
|
|
||||||
|
1. **Authentication Failures**
|
||||||
|
- Check password policies
|
||||||
|
- Verify JWT configuration
|
||||||
|
- Review session settings
|
||||||
|
|
||||||
|
2. **Authorization Issues**
|
||||||
|
- Validate RBAC configuration
|
||||||
|
- Check permission inheritance
|
||||||
|
- Review role assignments
|
||||||
|
|
||||||
|
3. **SSL/TLS Problems**
|
||||||
|
- Verify certificate validity
|
||||||
|
- Check cipher suite compatibility
|
||||||
|
- Validate TLS version settings
|
||||||
|
|
||||||
|
4. **Rate Limiting Issues**
|
||||||
|
- Monitor rate limit logs
|
||||||
|
- Adjust limits based on usage
|
||||||
|
- Check for IP blocking
|
||||||
|
|
||||||
|
### Security Debugging
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Enable security debug logging
|
||||||
|
RUST_LOG=rustelo::security=debug ./rustelo-server
|
||||||
|
|
||||||
|
# Check security headers
|
||||||
|
curl -I https://yourapp.com
|
||||||
|
|
||||||
|
# Test authentication
|
||||||
|
curl -X POST https://yourapp.com/api/auth/login \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"username":"test","password":"test"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Resources
|
||||||
|
|
||||||
|
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
||||||
|
- [NIST Cybersecurity Framework](https://www.nist.gov/cyberframework)
|
||||||
|
- [Mozilla Security Guidelines](https://infosec.mozilla.org/guidelines/)
|
||||||
|
- [Rust Security Guidelines](https://doc.rust-lang.org/nomicon/security.html)
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- [Authentication System](../developers/components/auth.md)
|
||||||
|
- [Performance Optimization](../performance/overview.md)
|
||||||
|
- [Monitoring & Logging](../deployment/monitoring.md)
|
||||||
|
- [Security Best Practices](../security/best-practices.md)
|
||||||
0
book/contributing/docs.md
Normal file
0
book/contributing/docs.md
Normal file
0
book/contributing/guide.md
Normal file
0
book/contributing/guide.md
Normal file
1
book/contributing/guidelines.md
Normal file
1
book/contributing/guidelines.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Contributing Guidelines
|
||||||
1
book/contributing/releases.md
Normal file
1
book/contributing/releases.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Release Process
|
||||||
0
book/contributing/setup.md
Normal file
0
book/contributing/setup.md
Normal file
0
book/contributing/standards.md
Normal file
0
book/contributing/standards.md
Normal file
0
book/contributing/testing.md
Normal file
0
book/contributing/testing.md
Normal file
0
book/database/abstraction.md
Normal file
0
book/database/abstraction.md
Normal file
332
book/database/configuration.md
Normal file
332
book/database/configuration.md
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
# Database Configuration Guide
|
||||||
|
|
||||||
|
This application supports both **PostgreSQL** and **SQLite** databases through SQLx's unified interface. The database type is automatically detected based on the connection URL.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### SQLite (Recommended for Development)
|
||||||
|
```toml
|
||||||
|
[database]
|
||||||
|
url = "sqlite//:database.db"
|
||||||
|
```
|
||||||
|
|
||||||
|
### PostgreSQL (Recommended for Production)
|
||||||
|
```toml
|
||||||
|
[database]
|
||||||
|
url = "postgresql://username:password@localhost:5432/database_name"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Database URL Formats
|
||||||
|
|
||||||
|
### SQLite URLs
|
||||||
|
- `sqlite//:database.db` - Relative path to database file
|
||||||
|
- `sqlite:///path/to/database.db` - Absolute path to database file
|
||||||
|
- `sqlite::memory:` - In-memory database (testing only)
|
||||||
|
|
||||||
|
### PostgreSQL URLs
|
||||||
|
- `postgresql://user:password@host:port/database`
|
||||||
|
- `postgres://user:password@host:port/database`
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
You can override the database URL using environment variables:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export DATABASE_URL="sqlite//:my_database.db"
|
||||||
|
# or
|
||||||
|
export DATABASE_URL="postgresql://user:pass@localhost:5432/mydb"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Database-Specific Features
|
||||||
|
|
||||||
|
### SQLite
|
||||||
|
- **Pros:**
|
||||||
|
- Zero configuration setup
|
||||||
|
- Single file database
|
||||||
|
- Perfect for development and testing
|
||||||
|
- No separate server process required
|
||||||
|
- ACID compliant
|
||||||
|
|
||||||
|
- **Cons:**
|
||||||
|
- Limited concurrent writes
|
||||||
|
- No network access
|
||||||
|
- Fewer advanced features
|
||||||
|
- File-based storage
|
||||||
|
|
||||||
|
### PostgreSQL
|
||||||
|
- **Pros:**
|
||||||
|
- Full ACID compliance
|
||||||
|
- Excellent concurrent access
|
||||||
|
- Advanced features (JSONB, arrays, etc.)
|
||||||
|
- Network accessible
|
||||||
|
- Production-ready scalability
|
||||||
|
|
||||||
|
- **Cons:**
|
||||||
|
- Requires PostgreSQL server
|
||||||
|
- More complex setup
|
||||||
|
- Resource overhead
|
||||||
|
|
||||||
|
## Configuration Examples
|
||||||
|
|
||||||
|
### Development Configuration
|
||||||
|
```toml
|
||||||
|
# config.dev.toml
|
||||||
|
[database]
|
||||||
|
url = "sqlite//:dev_database.db"
|
||||||
|
max_connections = 5
|
||||||
|
min_connections = 1
|
||||||
|
connect_timeout = 30
|
||||||
|
idle_timeout = 300
|
||||||
|
max_lifetime = 1800
|
||||||
|
```
|
||||||
|
|
||||||
|
### Production Configuration
|
||||||
|
```toml
|
||||||
|
# config.prod.toml
|
||||||
|
[database]
|
||||||
|
url = "postgresql://prod_user:${DATABASE_PASSWORD}@db.example.com:5432/prod_database"
|
||||||
|
max_connections = 20
|
||||||
|
min_connections = 5
|
||||||
|
connect_timeout = 30
|
||||||
|
idle_timeout = 600
|
||||||
|
max_lifetime = 3600
|
||||||
|
```
|
||||||
|
|
||||||
|
## Connection Pool Settings
|
||||||
|
|
||||||
|
| Setting | Description | SQLite | PostgreSQL |
|
||||||
|
|---------|-------------|--------|------------|
|
||||||
|
| `max_connections` | Maximum pool size | 1 (recommended) | 10-50 |
|
||||||
|
| `min_connections` | Minimum pool size | 1 | 1-5 |
|
||||||
|
| `connect_timeout` | Connection timeout (seconds) | 30 | 30 |
|
||||||
|
| `idle_timeout` | Idle connection timeout (seconds) | 300 | 600 |
|
||||||
|
| `max_lifetime` | Maximum connection lifetime (seconds) | 1800 | 3600 |
|
||||||
|
|
||||||
|
## Database Setup
|
||||||
|
|
||||||
|
### SQLite Setup
|
||||||
|
No setup required! The database file will be created automatically when the application starts.
|
||||||
|
|
||||||
|
### PostgreSQL Setup
|
||||||
|
|
||||||
|
#### Using Docker
|
||||||
|
```bash
|
||||||
|
# Start PostgreSQL container
|
||||||
|
docker run -d \
|
||||||
|
--name postgres \
|
||||||
|
-e POSTGRES_PASSWORD=password \
|
||||||
|
-e POSTGRES_DB=myapp \
|
||||||
|
-p 5432:5432 \
|
||||||
|
postgres:15
|
||||||
|
|
||||||
|
# Connect to database
|
||||||
|
docker exec -it postgres psql -U postgres -d myapp
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Using Local Installation
|
||||||
|
|
||||||
|
**macOS (Homebrew):**
|
||||||
|
```bash
|
||||||
|
brew install postgresql
|
||||||
|
brew services start postgresql
|
||||||
|
createdb myapp
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ubuntu/Debian:**
|
||||||
|
```bash
|
||||||
|
sudo apt-get install postgresql postgresql-contrib
|
||||||
|
sudo systemctl start postgresql
|
||||||
|
sudo -u postgres createdb myapp
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration Support
|
||||||
|
|
||||||
|
The application automatically creates the necessary tables for both database types:
|
||||||
|
|
||||||
|
### SQLite Tables
|
||||||
|
- Uses `TEXT` for IDs (UUID format)
|
||||||
|
- Uses `DATETIME` for timestamps
|
||||||
|
- Uses `TEXT` for JSON storage
|
||||||
|
- Uses `BOOLEAN` for boolean values
|
||||||
|
|
||||||
|
### PostgreSQL Tables
|
||||||
|
- Uses `UUID` for IDs with `gen_random_uuid()`
|
||||||
|
- Uses `TIMESTAMPTZ` for timestamps
|
||||||
|
- Uses `JSONB` for JSON storage
|
||||||
|
- Uses `BOOLEAN` for boolean values
|
||||||
|
|
||||||
|
## Switching Between Databases
|
||||||
|
|
||||||
|
You can switch between databases by simply changing the `DATABASE_URL`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Switch to SQLite
|
||||||
|
export DATABASE_URL="sqlite//:database.db"
|
||||||
|
|
||||||
|
# Switch to PostgreSQL
|
||||||
|
export DATABASE_URL="postgresql://user:pass@localhost:5432/mydb"
|
||||||
|
```
|
||||||
|
|
||||||
|
The application will automatically:
|
||||||
|
1. Detect the database type
|
||||||
|
2. Use appropriate SQL syntax
|
||||||
|
3. Create compatible table schemas
|
||||||
|
4. Handle data type differences
|
||||||
|
|
||||||
|
## Performance Considerations
|
||||||
|
|
||||||
|
### SQLite
|
||||||
|
- **Best for:**
|
||||||
|
- Single-user applications
|
||||||
|
- Development and testing
|
||||||
|
- Small to medium datasets
|
||||||
|
- Read-heavy workloads
|
||||||
|
|
||||||
|
- **Optimization tips:**
|
||||||
|
- Use WAL mode: `PRAGMA journal_mode=WAL`
|
||||||
|
- Set appropriate timeout: `PRAGMA busy_timeout=5000`
|
||||||
|
- Use transactions for bulk operations
|
||||||
|
|
||||||
|
### PostgreSQL
|
||||||
|
- **Best for:**
|
||||||
|
- Multi-user applications
|
||||||
|
- Production environments
|
||||||
|
- Large datasets
|
||||||
|
- High concurrency requirements
|
||||||
|
|
||||||
|
- **Optimization tips:**
|
||||||
|
- Configure appropriate connection pool size
|
||||||
|
- Use indexes on frequently queried columns
|
||||||
|
- Monitor and tune PostgreSQL configuration
|
||||||
|
- Use connection pooling (PgBouncer) for high traffic
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common SQLite Issues
|
||||||
|
- **Database locked**: Check for long-running transactions
|
||||||
|
- **File permissions**: Ensure write access to database file and directory
|
||||||
|
- **Disk space**: Verify sufficient disk space for database growth
|
||||||
|
|
||||||
|
### Common PostgreSQL Issues
|
||||||
|
- **Connection refused**: Check PostgreSQL server status
|
||||||
|
- **Authentication failed**: Verify username/password and pg_hba.conf
|
||||||
|
- **Too many connections**: Adjust max_connections or use connection pooling
|
||||||
|
|
||||||
|
### Debug Connection Issues
|
||||||
|
```bash
|
||||||
|
# Test SQLite connection
|
||||||
|
sqlite3 database.db "SELECT 1;"
|
||||||
|
|
||||||
|
# Test PostgreSQL connection
|
||||||
|
psql "postgresql://user:pass@localhost:5432/mydb" -c "SELECT 1;"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environment-Specific Configuration
|
||||||
|
|
||||||
|
### Development
|
||||||
|
```bash
|
||||||
|
# .env.development
|
||||||
|
DATABASE_URL=sqlite//:dev_database.db
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
```bash
|
||||||
|
# .env.test
|
||||||
|
DATABASE_URL=sqlite//::memory:
|
||||||
|
```
|
||||||
|
|
||||||
|
### Production
|
||||||
|
```bash
|
||||||
|
# .env.production
|
||||||
|
DATABASE_URL=postgresql://user:${DATABASE_PASSWORD}@db.internal:5432/prod_db
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
### SQLite Security
|
||||||
|
- Protect database file permissions (600 or 640)
|
||||||
|
- Backup database files securely
|
||||||
|
- Consider encryption for sensitive data
|
||||||
|
|
||||||
|
### PostgreSQL Security
|
||||||
|
- Use strong passwords
|
||||||
|
- Enable SSL/TLS connections
|
||||||
|
- Restrict network access
|
||||||
|
- Regular security updates
|
||||||
|
- Use connection pooling with authentication
|
||||||
|
|
||||||
|
## Backup and Recovery
|
||||||
|
|
||||||
|
### SQLite Backup
|
||||||
|
```bash
|
||||||
|
# Simple file copy
|
||||||
|
cp database.db database_backup.db
|
||||||
|
|
||||||
|
# Using SQLite backup command
|
||||||
|
sqlite3 database.db ".backup database_backup.db"
|
||||||
|
```
|
||||||
|
|
||||||
|
### PostgreSQL Backup
|
||||||
|
```bash
|
||||||
|
# Database dump
|
||||||
|
pg_dump myapp > myapp_backup.sql
|
||||||
|
|
||||||
|
# Restore from dump
|
||||||
|
psql myapp < myapp_backup.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
## Monitoring and Maintenance
|
||||||
|
|
||||||
|
### SQLite Maintenance
|
||||||
|
```sql
|
||||||
|
-- Analyze database
|
||||||
|
ANALYZE;
|
||||||
|
|
||||||
|
-- Vacuum database
|
||||||
|
VACUUM;
|
||||||
|
|
||||||
|
-- Check integrity
|
||||||
|
PRAGMA integrity_check;
|
||||||
|
```
|
||||||
|
|
||||||
|
### PostgreSQL Maintenance
|
||||||
|
```sql
|
||||||
|
-- Analyze tables
|
||||||
|
ANALYZE;
|
||||||
|
|
||||||
|
-- Vacuum tables
|
||||||
|
VACUUM;
|
||||||
|
|
||||||
|
-- Check database size
|
||||||
|
SELECT pg_size_pretty(pg_database_size('myapp'));
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Use environment variables** for database URLs in production
|
||||||
|
2. **Configure appropriate connection pools** based on your workload
|
||||||
|
3. **Monitor database performance** and adjust settings as needed
|
||||||
|
4. **Regular backups** are essential for production databases
|
||||||
|
5. **Test migrations** on both database types if supporting both
|
||||||
|
6. **Use transactions** for data consistency
|
||||||
|
7. **Index frequently queried columns** for better performance
|
||||||
|
8. **Monitor connection pool usage** to prevent exhaustion
|
||||||
|
|
||||||
|
## Feature Compatibility Matrix
|
||||||
|
|
||||||
|
| Feature | SQLite | PostgreSQL |
|
||||||
|
|---------|--------|------------|
|
||||||
|
| ACID Transactions | ✅ | ✅ |
|
||||||
|
| Concurrent Reads | ✅ | ✅ |
|
||||||
|
| Concurrent Writes | ⚠️ Limited | ✅ |
|
||||||
|
| JSON Support | ✅ (TEXT) | ✅ (JSONB) |
|
||||||
|
| Full-text Search | ✅ (FTS) | ✅ (Built-in) |
|
||||||
|
| Network Access | ❌ | ✅ |
|
||||||
|
| Replication | ❌ | ✅ |
|
||||||
|
| Partitioning | ❌ | ✅ |
|
||||||
|
| Custom Functions | ✅ | ✅ |
|
||||||
|
| Triggers | ✅ | ✅ |
|
||||||
|
| Views | ✅ | ✅ |
|
||||||
|
| Stored Procedures | ❌ | ✅ |
|
||||||
|
|
||||||
|
This guide should help you choose and configure the right database for your needs. Both options are fully supported and the application will work seamlessly with either choice.
|
||||||
0
book/database/migrations.md
Normal file
0
book/database/migrations.md
Normal file
0
book/database/overview.md
Normal file
0
book/database/overview.md
Normal file
0
book/database/postgresql.md
Normal file
0
book/database/postgresql.md
Normal file
0
book/database/sqlite.md
Normal file
0
book/database/sqlite.md
Normal file
1
book/deployment/backup.md
Normal file
1
book/deployment/backup.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Backup & Recovery
|
||||||
1
book/deployment/cloud.md
Normal file
1
book/deployment/cloud.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Cloud Platforms
|
||||||
0
book/deployment/docker.md
Normal file
0
book/deployment/docker.md
Normal file
0
book/deployment/environments.md
Normal file
0
book/deployment/environments.md
Normal file
0
book/deployment/monitoring.md
Normal file
0
book/deployment/monitoring.md
Normal file
0
book/deployment/overview.md
Normal file
0
book/deployment/overview.md
Normal file
0
book/deployment/production.md
Normal file
0
book/deployment/production.md
Normal file
1
book/deployment/ssl.md
Normal file
1
book/deployment/ssl.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# SSL/TLS Configuration
|
||||||
1
book/developers/architecture/backend.md
Normal file
1
book/developers/architecture/backend.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Backend Architecture
|
||||||
1
book/developers/architecture/database.md
Normal file
1
book/developers/architecture/database.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Database Design
|
||||||
1
book/developers/architecture/frontend.md
Normal file
1
book/developers/architecture/frontend.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Frontend Architecture
|
||||||
1
book/developers/architecture/overview.md
Normal file
1
book/developers/architecture/overview.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# System Overview
|
||||||
1
book/developers/architecture/security.md
Normal file
1
book/developers/architecture/security.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Security Model
|
||||||
329
book/developers/brand/logo-usage.md
Normal file
329
book/developers/brand/logo-usage.md
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
# Logo Usage Guide
|
||||||
|
|
||||||
|
The Rustelo project includes a comprehensive logo system designed to work across different contexts and themes. This guide explains how to properly use the logos in your applications and documentation.
|
||||||
|
|
||||||
|
## Logo Assets
|
||||||
|
|
||||||
|
The logo system includes the following variants:
|
||||||
|
|
||||||
|
### Available Logo Files
|
||||||
|
|
||||||
|
| File | Usage | Context |
|
||||||
|
|------|-------|---------|
|
||||||
|
| `rustelo_dev-logo-h.svg` | Horizontal logo for normal/light themes | Primary horizontal logo |
|
||||||
|
| `rustelo_dev-logo-b-h.svg` | Horizontal logo for dark themes | Dark theme horizontal logo |
|
||||||
|
| `rustelo_dev-logo-v.svg` | Vertical logo for normal/light themes | Primary vertical logo |
|
||||||
|
| `rustelo_dev-logo-b-v.svg` | Vertical logo for dark themes | Dark theme vertical logo |
|
||||||
|
| `rustelo-imag.svg` | Logo image without text | Icon/favicon usage |
|
||||||
|
|
||||||
|
### Logo Locations
|
||||||
|
|
||||||
|
- **Source**: `logos/` directory (original assets)
|
||||||
|
- **Public**: `public/logos/` directory (web-accessible assets)
|
||||||
|
- **Documentation**: Referenced in mdBook via `../logos/` path
|
||||||
|
|
||||||
|
## Usage Guidelines
|
||||||
|
|
||||||
|
### 1. Web Application Usage
|
||||||
|
|
||||||
|
#### Navigation Logo
|
||||||
|
```rust
|
||||||
|
use crate::components::NavbarLogo;
|
||||||
|
|
||||||
|
// In your navigation component
|
||||||
|
view! {
|
||||||
|
<nav class="navigation">
|
||||||
|
<NavbarLogo size="small".to_string() />
|
||||||
|
// ... other nav items
|
||||||
|
</nav>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Brand Header
|
||||||
|
```rust
|
||||||
|
use crate::components::BrandHeader;
|
||||||
|
|
||||||
|
// For page headers
|
||||||
|
view! {
|
||||||
|
<BrandHeader
|
||||||
|
title="RUSTELO".to_string()
|
||||||
|
subtitle="Modular Rust Web Application Template".to_string()
|
||||||
|
logo_size="large".to_string()
|
||||||
|
class="justify-center".to_string()
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Standalone Logo
|
||||||
|
```rust
|
||||||
|
use crate::components::Logo;
|
||||||
|
|
||||||
|
// Basic logo usage
|
||||||
|
view! {
|
||||||
|
<Logo
|
||||||
|
orientation="horizontal".to_string()
|
||||||
|
size="medium".to_string()
|
||||||
|
show_text={true}
|
||||||
|
class="my-custom-class".to_string()
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Documentation Usage
|
||||||
|
|
||||||
|
#### Markdown Files
|
||||||
|
```markdown
|
||||||
|
<!-- In README.md or other markdown files -->
|
||||||
|
<div align="center">
|
||||||
|
<img src="logos/rustelo_dev-logo-h.svg" alt="RUSTELO" width="300" />
|
||||||
|
|
||||||
|
# Your Page Title
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### mdBook Pages
|
||||||
|
```markdown
|
||||||
|
<!-- In book pages -->
|
||||||
|
<div align="center">
|
||||||
|
<img src="../logos/rustelo_dev-logo-h.svg" alt="RUSTELO" width="400" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
# Welcome to Rustelo
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Size Guidelines
|
||||||
|
|
||||||
|
#### Component Sizes
|
||||||
|
- **small**: 32px height (navbar usage)
|
||||||
|
- **medium**: 48px height (standard usage)
|
||||||
|
- **large**: 64px height (headers)
|
||||||
|
- **xlarge**: 80px height (hero sections)
|
||||||
|
|
||||||
|
#### Documentation Sizes
|
||||||
|
- **Small**: 150-200px width
|
||||||
|
- **Medium**: 250-300px width
|
||||||
|
- **Large**: 350-400px width
|
||||||
|
|
||||||
|
### 4. Responsive Usage
|
||||||
|
|
||||||
|
The logo components automatically adapt to different screen sizes:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Mobile-responsive logo
|
||||||
|
view! {
|
||||||
|
<Logo
|
||||||
|
orientation="horizontal".to_string()
|
||||||
|
size="medium".to_string()
|
||||||
|
show_text={true}
|
||||||
|
class="w-full max-w-xs sm:max-w-sm md:max-w-md".to_string()
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Theme Integration
|
||||||
|
|
||||||
|
### Automatic Theme Detection
|
||||||
|
|
||||||
|
The logo components automatically detect the current theme and switch between light and dark variants:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// This automatically uses the appropriate variant
|
||||||
|
view! {
|
||||||
|
<Logo
|
||||||
|
orientation="horizontal".to_string()
|
||||||
|
size="medium".to_string()
|
||||||
|
show_text={true}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manual Theme Selection
|
||||||
|
|
||||||
|
For static contexts (like documentation), choose the appropriate variant:
|
||||||
|
|
||||||
|
- **Light backgrounds**: Use `rustelo_dev-logo-h.svg` or `rustelo_dev-logo-v.svg`
|
||||||
|
- **Dark backgrounds**: Use `rustelo_dev-logo-b-h.svg` or `rustelo_dev-logo-b-v.svg`
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### DO
|
||||||
|
|
||||||
|
✅ Use the horizontal logo for navigation bars and headers
|
||||||
|
✅ Use the vertical logo for sidebar or narrow layouts
|
||||||
|
✅ Use the image-only logo for favicons and small icons
|
||||||
|
✅ Maintain proper contrast with background colors
|
||||||
|
✅ Use consistent sizing within the same context
|
||||||
|
✅ Include proper alt text: "RUSTELO"
|
||||||
|
|
||||||
|
### DON'T
|
||||||
|
|
||||||
|
❌ Stretch or distort the logo proportions
|
||||||
|
❌ Use light logos on light backgrounds
|
||||||
|
❌ Use dark logos on dark backgrounds
|
||||||
|
❌ Make the logo too small to read (minimum 24px height)
|
||||||
|
❌ Use low-quality or pixelated versions
|
||||||
|
|
||||||
|
## Component API Reference
|
||||||
|
|
||||||
|
### Logo Component
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[component]
|
||||||
|
pub fn Logo(
|
||||||
|
#[prop(default = "horizontal".to_string())] orientation: String,
|
||||||
|
#[prop(default = "normal".to_string())] size: String,
|
||||||
|
#[prop(default = true)] show_text: bool,
|
||||||
|
#[prop(default = "".to_string())] class: String,
|
||||||
|
) -> impl IntoView
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `orientation`: "horizontal" | "vertical"
|
||||||
|
- `size`: "small" | "medium" | "large" | "xlarge"
|
||||||
|
- `show_text`: true (full logo) | false (image only)
|
||||||
|
- `class`: Additional CSS classes
|
||||||
|
|
||||||
|
### LogoLink Component
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[component]
|
||||||
|
pub fn LogoLink(
|
||||||
|
#[prop(default = "horizontal".to_string())] orientation: String,
|
||||||
|
#[prop(default = "normal".to_string())] size: String,
|
||||||
|
#[prop(default = true)] show_text: bool,
|
||||||
|
#[prop(default = "".to_string())] class: String,
|
||||||
|
#[prop(default = "/".to_string())] href: String,
|
||||||
|
) -> impl IntoView
|
||||||
|
```
|
||||||
|
|
||||||
|
**Additional Parameters:**
|
||||||
|
- `href`: Link destination (default: "/")
|
||||||
|
|
||||||
|
### BrandHeader Component
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[component]
|
||||||
|
pub fn BrandHeader(
|
||||||
|
#[prop(default = "RUSTELO".to_string())] title: String,
|
||||||
|
#[prop(default = "".to_string())] subtitle: String,
|
||||||
|
#[prop(default = "medium".to_string())] logo_size: String,
|
||||||
|
#[prop(default = "".to_string())] class: String,
|
||||||
|
) -> impl IntoView
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `title`: Main brand title
|
||||||
|
- `subtitle`: Optional subtitle text
|
||||||
|
- `logo_size`: Logo size variant
|
||||||
|
- `class`: Additional CSS classes
|
||||||
|
|
||||||
|
### NavbarLogo Component
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[component]
|
||||||
|
pub fn NavbarLogo(
|
||||||
|
#[prop(default = "small".to_string())] size: String,
|
||||||
|
#[prop(default = "".to_string())] class: String,
|
||||||
|
) -> impl IntoView
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `size`: Logo size (optimized for navbar)
|
||||||
|
- `class`: Additional CSS classes
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
### Hero Section
|
||||||
|
```rust
|
||||||
|
view! {
|
||||||
|
<section class="hero">
|
||||||
|
<BrandHeader
|
||||||
|
title="RUSTELO".to_string()
|
||||||
|
subtitle="Build fast, secure web applications with Rust".to_string()
|
||||||
|
logo_size="xlarge".to_string()
|
||||||
|
class="text-center".to_string()
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sidebar
|
||||||
|
```rust
|
||||||
|
view! {
|
||||||
|
<aside class="sidebar">
|
||||||
|
<Logo
|
||||||
|
orientation="vertical".to_string()
|
||||||
|
size="medium".to_string()
|
||||||
|
show_text={true}
|
||||||
|
class="mb-4".to_string()
|
||||||
|
/>
|
||||||
|
</aside>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Footer
|
||||||
|
```rust
|
||||||
|
view! {
|
||||||
|
<footer class="footer">
|
||||||
|
<Logo
|
||||||
|
orientation="horizontal".to_string()
|
||||||
|
size="small".to_string()
|
||||||
|
show_text={false}
|
||||||
|
class="opacity-60".to_string()
|
||||||
|
/>
|
||||||
|
</footer>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Logo Not Displaying
|
||||||
|
|
||||||
|
1. **Check file paths**: Ensure logos are copied to `public/logos/`
|
||||||
|
2. **Verify imports**: Make sure components are properly imported
|
||||||
|
3. **Theme detection**: Confirm theme context is available
|
||||||
|
|
||||||
|
### Theme Switching Issues
|
||||||
|
|
||||||
|
1. **Theme provider**: Ensure `ThemeProvider` is properly configured
|
||||||
|
2. **CSS classes**: Check that theme-specific CSS is loaded
|
||||||
|
3. **JavaScript**: Verify theme switching JavaScript is working
|
||||||
|
|
||||||
|
### Performance Optimization
|
||||||
|
|
||||||
|
1. **SVG optimization**: Use optimized SVG files
|
||||||
|
2. **Lazy loading**: Add `loading="lazy"` for non-critical logos
|
||||||
|
3. **Caching**: Ensure proper cache headers for logo assets
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
template/
|
||||||
|
├── logos/ # Source logo files
|
||||||
|
│ ├── rustelo_dev-logo-h.svg
|
||||||
|
│ ├── rustelo_dev-logo-b-h.svg
|
||||||
|
│ ├── rustelo_dev-logo-v.svg
|
||||||
|
│ ├── rustelo_dev-logo-b-v.svg
|
||||||
|
│ └── rustelo-imag.svg
|
||||||
|
├── public/
|
||||||
|
│ └── logos/ # Web-accessible logo files
|
||||||
|
│ ├── rustelo_dev-logo-h.svg
|
||||||
|
│ ├── rustelo_dev-logo-b-h.svg
|
||||||
|
│ ├── rustelo_dev-logo-v.svg
|
||||||
|
│ ├── rustelo_dev-logo-b-v.svg
|
||||||
|
│ └── rustelo-imag.svg
|
||||||
|
└── client/src/components/
|
||||||
|
└── Logo.rs # Logo components
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
When adding new logo variants or updating existing ones:
|
||||||
|
|
||||||
|
1. Update both `logos/` and `public/logos/` directories
|
||||||
|
2. Test with both light and dark themes
|
||||||
|
3. Verify responsive behavior
|
||||||
|
4. Update this documentation
|
||||||
|
5. Test in all supported browsers
|
||||||
|
|
||||||
|
For questions or issues with logo usage, please refer to the [GitHub Issues](https://github.com/yourusername/rustelo/issues) page.
|
||||||
303
book/developers/components/README.md
Normal file
303
book/developers/components/README.md
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
# Rustelo Components
|
||||||
|
|
||||||
|
Welcome to the Rustelo Components documentation! This section covers all the built-in components and utilities available in the Rustelo framework.
|
||||||
|
|
||||||
|
## 📦 Available Components
|
||||||
|
|
||||||
|
### Authentication Components
|
||||||
|
- **[Authentication System](./auth.md)** - User authentication, JWT tokens, and session management
|
||||||
|
- Login/Register forms
|
||||||
|
- Password reset functionality
|
||||||
|
- User profile management
|
||||||
|
- Role-based access control
|
||||||
|
|
||||||
|
### Content Management
|
||||||
|
- **[Content System](./content.md)** - Content creation, editing, and management
|
||||||
|
- Markdown rendering
|
||||||
|
- File uploads and media management
|
||||||
|
- Content versioning
|
||||||
|
- Search functionality
|
||||||
|
|
||||||
|
### Email System
|
||||||
|
- **[Email Components](./email.md)** - Email sending and template management
|
||||||
|
- SMTP configuration
|
||||||
|
- Email templates
|
||||||
|
- Queue management
|
||||||
|
- Notification system
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
- **[Configuration System](./config.md)** - Application configuration management
|
||||||
|
- Environment-based configs
|
||||||
|
- Feature toggles
|
||||||
|
- Runtime configuration
|
||||||
|
- Validation and schema
|
||||||
|
|
||||||
|
### Templates & UI
|
||||||
|
- **[Template System](./templates.md)** - UI templates and components
|
||||||
|
- Responsive layouts
|
||||||
|
- Theme system
|
||||||
|
- Component library
|
||||||
|
- Style utilities
|
||||||
|
|
||||||
|
## 🎯 Component Architecture
|
||||||
|
|
||||||
|
Rustelo follows a modular component architecture where each component is:
|
||||||
|
|
||||||
|
- **Self-contained** - Each component manages its own state and dependencies
|
||||||
|
- **Configurable** - Components can be enabled/disabled via features
|
||||||
|
- **Extensible** - Easy to customize and extend for your needs
|
||||||
|
- **Well-documented** - Complete API documentation and examples
|
||||||
|
|
||||||
|
## 🚀 Getting Started
|
||||||
|
|
||||||
|
### Enable Components
|
||||||
|
|
||||||
|
Components are enabled through Cargo features:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
server = { path = "../server", features = ["auth", "content-db", "email"] }
|
||||||
|
```
|
||||||
|
|
||||||
|
### Basic Usage
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use rustelo::components::{Auth, Content, Email};
|
||||||
|
|
||||||
|
// Initialize components
|
||||||
|
let auth = Auth::new(config.auth)?;
|
||||||
|
let content = Content::new(config.content)?;
|
||||||
|
let email = Email::new(config.email)?;
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📋 Component Status
|
||||||
|
|
||||||
|
| Component | Status | Features | Documentation |
|
||||||
|
|-----------|--------|----------|---------------|
|
||||||
|
| Authentication | ✅ Complete | `auth` | [View](./auth.md) |
|
||||||
|
| Content Management | ✅ Complete | `content-db` | [View](./content.md) |
|
||||||
|
| Email System | ✅ Complete | `email` | [View](./email.md) |
|
||||||
|
| Configuration | ✅ Complete | Always enabled | [View](./config.md) |
|
||||||
|
| Templates | ✅ Complete | Always enabled | [View](./templates.md) |
|
||||||
|
|
||||||
|
## 🔧 Component Development
|
||||||
|
|
||||||
|
### Creating Custom Components
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use rustelo::Component;
|
||||||
|
|
||||||
|
pub struct MyComponent {
|
||||||
|
config: MyConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for MyComponent {
|
||||||
|
type Config = MyConfig;
|
||||||
|
|
||||||
|
fn new(config: Self::Config) -> Result<Self, Error> {
|
||||||
|
Ok(Self { config })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initialize(&mut self) -> Result<(), Error> {
|
||||||
|
// Initialize component
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Component Lifecycle
|
||||||
|
|
||||||
|
1. **Configuration** - Load component configuration
|
||||||
|
2. **Initialization** - Set up component state
|
||||||
|
3. **Registration** - Register routes and handlers
|
||||||
|
4. **Runtime** - Handle requests and events
|
||||||
|
5. **Cleanup** - Graceful shutdown
|
||||||
|
|
||||||
|
## 🎨 Frontend Components
|
||||||
|
|
||||||
|
### Leptos Components
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use leptos::*;
|
||||||
|
use rustelo::components::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn App() -> impl IntoView {
|
||||||
|
view! {
|
||||||
|
<AuthProvider>
|
||||||
|
<ContentProvider>
|
||||||
|
<Router>
|
||||||
|
<Routes>
|
||||||
|
<Route path="/" view=HomePage/>
|
||||||
|
<Route path="/login" view=LoginPage/>
|
||||||
|
<Route path="/dashboard" view=DashboardPage/>
|
||||||
|
</Routes>
|
||||||
|
</Router>
|
||||||
|
</ContentProvider>
|
||||||
|
</AuthProvider>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Styling Components
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use rustelo::ui::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn MyPage() -> impl IntoView {
|
||||||
|
view! {
|
||||||
|
<Page title="My Page">
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<h2>"Welcome"</h2>
|
||||||
|
</CardHeader>
|
||||||
|
<CardBody>
|
||||||
|
<p>"Content goes here"</p>
|
||||||
|
</CardBody>
|
||||||
|
</Card>
|
||||||
|
</Page>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔍 Component APIs
|
||||||
|
|
||||||
|
### Authentication API
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Check if user is authenticated
|
||||||
|
let is_authenticated = auth.is_authenticated(&request)?;
|
||||||
|
|
||||||
|
// Get current user
|
||||||
|
let user = auth.get_current_user(&request)?;
|
||||||
|
|
||||||
|
// Login user
|
||||||
|
let token = auth.login(&credentials)?;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Content API
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Create content
|
||||||
|
let content = content_manager.create(CreateContentRequest {
|
||||||
|
title: "My Article".to_string(),
|
||||||
|
body: "Article content...".to_string(),
|
||||||
|
content_type: ContentType::Article,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Get content
|
||||||
|
let content = content_manager.get_by_id(content_id)?;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Email API
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Send email
|
||||||
|
email_service.send(SendEmailRequest {
|
||||||
|
to: "user@example.com".to_string(),
|
||||||
|
subject: "Welcome!".to_string(),
|
||||||
|
template: "welcome".to_string(),
|
||||||
|
data: serde_json::json!({
|
||||||
|
"name": "John Doe"
|
||||||
|
}),
|
||||||
|
})?;
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📊 Performance Considerations
|
||||||
|
|
||||||
|
### Component Optimization
|
||||||
|
|
||||||
|
- **Lazy Loading** - Components are initialized only when needed
|
||||||
|
- **Caching** - Built-in caching for frequently accessed data
|
||||||
|
- **Connection Pooling** - Efficient database and external service connections
|
||||||
|
- **Async Operations** - Non-blocking I/O operations
|
||||||
|
|
||||||
|
### Resource Management
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Components automatically manage resources
|
||||||
|
impl Drop for MyComponent {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// Cleanup resources
|
||||||
|
self.cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🧪 Testing Components
|
||||||
|
|
||||||
|
### Unit Tests
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use rustelo::testing::*;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_auth_component() {
|
||||||
|
let config = test_config();
|
||||||
|
let auth = Auth::new(config.auth).unwrap();
|
||||||
|
|
||||||
|
// Test authentication
|
||||||
|
assert!(auth.is_authenticated(&test_request()).is_ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Integration Tests
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_component_integration() {
|
||||||
|
let app = test_app().await;
|
||||||
|
|
||||||
|
// Test component interactions
|
||||||
|
let response = app.post("/api/auth/login")
|
||||||
|
.json(&login_request())
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
assert_eq!(response.status(), 200);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔐 Security
|
||||||
|
|
||||||
|
### Security Best Practices
|
||||||
|
|
||||||
|
- **Input Validation** - All inputs are validated and sanitized
|
||||||
|
- **Authentication** - Secure token-based authentication
|
||||||
|
- **Authorization** - Role-based access control
|
||||||
|
- **CSRF Protection** - Built-in CSRF token validation
|
||||||
|
- **Rate Limiting** - Configurable rate limiting
|
||||||
|
|
||||||
|
### Security Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[security]
|
||||||
|
csrf_protection = true
|
||||||
|
rate_limiting = true
|
||||||
|
secure_cookies = true
|
||||||
|
https_only = true
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📚 Next Steps
|
||||||
|
|
||||||
|
1. **[Authentication Guide](./auth.md)** - Set up user authentication
|
||||||
|
2. **[Content Management](./content.md)** - Manage application content
|
||||||
|
3. **[Email System](./email.md)** - Configure email functionality
|
||||||
|
4. **[Configuration](./config.md)** - Understand configuration options
|
||||||
|
5. **[Templates](./templates.md)** - Customize UI templates
|
||||||
|
|
||||||
|
## 🆘 Getting Help
|
||||||
|
|
||||||
|
- **[Common Issues](../../troubleshooting/common.md)** - Solutions to common problems
|
||||||
|
- **[API Reference](../../api/overview.md)** - Complete API documentation
|
||||||
|
- **[Examples](../../advanced/integrations.md)** - Real-world examples
|
||||||
|
- **Community Support** - Discord, GitHub Issues, Stack Overflow
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Happy building with Rustelo components!** 🦀✨
|
||||||
1
book/developers/components/auth.md
Normal file
1
book/developers/components/auth.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Authentication System
|
||||||
1
book/developers/components/config.md
Normal file
1
book/developers/components/config.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Configuration System
|
||||||
1
book/developers/components/content.md
Normal file
1
book/developers/components/content.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Content Management
|
||||||
766
book/developers/components/email.md
Normal file
766
book/developers/components/email.md
Normal file
@ -0,0 +1,766 @@
|
|||||||
|
# Email System
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<img src="../../../logos/rustelo_dev-logo-h.svg" alt="RUSTELO" width="300" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
This guide covers RUSTELO's comprehensive email system, including setup, configuration, usage, and best practices for integrating email functionality into your application.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The RUSTELO email system provides a complete solution for sending emails from your web application with support for multiple providers, template-based emails, form submissions, and both server-side and client-side integration.
|
||||||
|
|
||||||
|
### Architecture
|
||||||
|
|
||||||
|
- **Email Service**: Core service that handles email sending
|
||||||
|
- **Providers**: Pluggable email providers (SMTP, SendGrid, Console)
|
||||||
|
- **Templates**: Handlebars-based email templates
|
||||||
|
- **Forms**: Ready-to-use contact and support form components
|
||||||
|
- **API**: REST endpoints for email operations
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
✨ **Multiple Providers**
|
||||||
|
- SMTP (Gmail, Outlook, custom servers)
|
||||||
|
- SendGrid API
|
||||||
|
- Console output (development)
|
||||||
|
|
||||||
|
📧 **Template System**
|
||||||
|
- Handlebars templates
|
||||||
|
- HTML and text versions
|
||||||
|
- Custom helpers
|
||||||
|
- Variable substitution
|
||||||
|
|
||||||
|
🔧 **Form Integration**
|
||||||
|
- Contact forms
|
||||||
|
- Support forms with priorities
|
||||||
|
- Custom form handling
|
||||||
|
|
||||||
|
🛡️ **Security**
|
||||||
|
- Input validation
|
||||||
|
- Rate limiting
|
||||||
|
- CSRF protection
|
||||||
|
- Secure configuration
|
||||||
|
|
||||||
|
🎨 **Rich Components**
|
||||||
|
- React/Leptos form components
|
||||||
|
- Real-time validation
|
||||||
|
- Error handling
|
||||||
|
- Success feedback
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### 1. Enable Email Feature
|
||||||
|
|
||||||
|
Make sure the email feature is enabled in your `Cargo.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[features]
|
||||||
|
default = ["email"]
|
||||||
|
email = ["lettre", "handlebars", "urlencoding"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Basic Configuration
|
||||||
|
|
||||||
|
Add email configuration to your `config.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[email]
|
||||||
|
enabled = true
|
||||||
|
provider = "console" # Start with console for development
|
||||||
|
from_email = "noreply@yourapp.com"
|
||||||
|
from_name = "Your App"
|
||||||
|
template_dir = "templates/email"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Create Template Directory
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p templates/email/html
|
||||||
|
mkdir -p templates/email/text
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Start Using
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Send a simple email
|
||||||
|
let result = email_service.send_simple_email(
|
||||||
|
"user@example.com",
|
||||||
|
"Welcome!",
|
||||||
|
"Thank you for signing up!"
|
||||||
|
).await?;
|
||||||
|
|
||||||
|
// Send a contact form
|
||||||
|
let result = email_service.send_contact_form(
|
||||||
|
"John Doe",
|
||||||
|
"john@example.com",
|
||||||
|
"Question about pricing",
|
||||||
|
"I'd like to know more about your pricing plans.",
|
||||||
|
"admin@yourapp.com"
|
||||||
|
).await?;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Email Configuration Options
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[email]
|
||||||
|
# Basic settings
|
||||||
|
enabled = true
|
||||||
|
provider = "smtp" # "smtp", "sendgrid", "console"
|
||||||
|
from_email = "noreply@yourapp.com"
|
||||||
|
from_name = "Your App Name"
|
||||||
|
template_dir = "templates/email"
|
||||||
|
|
||||||
|
# SMTP settings (when provider = "smtp")
|
||||||
|
smtp_host = "smtp.gmail.com"
|
||||||
|
smtp_port = 587
|
||||||
|
smtp_username = "your-email@gmail.com"
|
||||||
|
smtp_password = "@encrypted_smtp_password"
|
||||||
|
smtp_use_tls = false
|
||||||
|
smtp_use_starttls = true
|
||||||
|
|
||||||
|
# SendGrid settings (when provider = "sendgrid")
|
||||||
|
sendgrid_api_key = "@encrypted_sendgrid_api_key"
|
||||||
|
sendgrid_endpoint = "https://api.sendgrid.com/v3/mail/send"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment-Specific Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# Development
|
||||||
|
[environments.development]
|
||||||
|
email.provider = "console"
|
||||||
|
email.enabled = true
|
||||||
|
|
||||||
|
# Production
|
||||||
|
[environments.production]
|
||||||
|
email.provider = "sendgrid"
|
||||||
|
email.sendgrid_api_key = "@encrypted_sendgrid_api_key"
|
||||||
|
email.enabled = true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Email Providers
|
||||||
|
|
||||||
|
### Console Provider
|
||||||
|
|
||||||
|
Perfect for development and testing. Prints emails to the console.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[email]
|
||||||
|
provider = "console"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Features:**
|
||||||
|
- No external dependencies
|
||||||
|
- Immediate feedback
|
||||||
|
- Safe for development
|
||||||
|
|
||||||
|
### SMTP Provider
|
||||||
|
|
||||||
|
Use any SMTP server including Gmail, Outlook, or custom servers.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[email]
|
||||||
|
provider = "smtp"
|
||||||
|
smtp_host = "smtp.gmail.com"
|
||||||
|
smtp_port = 587
|
||||||
|
smtp_username = "your-email@gmail.com"
|
||||||
|
smtp_password = "@encrypted_smtp_password"
|
||||||
|
smtp_use_starttls = true
|
||||||
|
```
|
||||||
|
|
||||||
|
**Common SMTP Configurations:**
|
||||||
|
|
||||||
|
**Gmail:**
|
||||||
|
```toml
|
||||||
|
smtp_host = "smtp.gmail.com"
|
||||||
|
smtp_port = 587
|
||||||
|
smtp_use_starttls = true
|
||||||
|
# Requires App Password (not regular password)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Outlook:**
|
||||||
|
```toml
|
||||||
|
smtp_host = "smtp-mail.outlook.com"
|
||||||
|
smtp_port = 587
|
||||||
|
smtp_use_starttls = true
|
||||||
|
```
|
||||||
|
|
||||||
|
**Custom SMTP:**
|
||||||
|
```toml
|
||||||
|
smtp_host = "mail.yourserver.com"
|
||||||
|
smtp_port = 587
|
||||||
|
smtp_use_starttls = true
|
||||||
|
```
|
||||||
|
|
||||||
|
### SendGrid Provider
|
||||||
|
|
||||||
|
Use SendGrid's API for reliable email delivery.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[email]
|
||||||
|
provider = "sendgrid"
|
||||||
|
sendgrid_api_key = "@encrypted_sendgrid_api_key"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Features:**
|
||||||
|
- High deliverability
|
||||||
|
- Built-in analytics
|
||||||
|
- Bounce handling
|
||||||
|
- Reliable service
|
||||||
|
|
||||||
|
## Templates
|
||||||
|
|
||||||
|
### Template Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
templates/email/
|
||||||
|
├── html/
|
||||||
|
│ ├── contact.hbs
|
||||||
|
│ ├── support.hbs
|
||||||
|
│ ├── welcome.hbs
|
||||||
|
│ └── notification.hbs
|
||||||
|
└── text/
|
||||||
|
├── contact.hbs
|
||||||
|
├── support.hbs
|
||||||
|
├── welcome.hbs
|
||||||
|
└── notification.hbs
|
||||||
|
```
|
||||||
|
|
||||||
|
### Template Naming
|
||||||
|
|
||||||
|
- `contact.hbs` - Contact form emails
|
||||||
|
- `support.hbs` - Support form emails
|
||||||
|
- `welcome.hbs` - Welcome/registration emails
|
||||||
|
- `notification.hbs` - General notifications
|
||||||
|
|
||||||
|
### Handlebars Helpers
|
||||||
|
|
||||||
|
Built-in helpers for common email tasks:
|
||||||
|
|
||||||
|
- `{{format_date}}` - Format dates
|
||||||
|
- `{{format_currency}}` - Format money
|
||||||
|
- `{{upper}}` - Uppercase text
|
||||||
|
- `{{lower}}` - Lowercase text
|
||||||
|
- `{{capitalize}}` - Capitalize words
|
||||||
|
|
||||||
|
### Example Template
|
||||||
|
|
||||||
|
**templates/email/html/contact.hbs:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Contact Form Submission</title>
|
||||||
|
<style>
|
||||||
|
body { font-family: Arial, sans-serif; margin: 20px; }
|
||||||
|
.header { background-color: #f8f9fa; padding: 20px; border-radius: 8px; }
|
||||||
|
.content { margin: 20px 0; }
|
||||||
|
.footer { color: #666; font-size: 12px; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="header">
|
||||||
|
<h1>New Contact Form Submission</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
<p><strong>Name:</strong> {{name}}</p>
|
||||||
|
<p><strong>Email:</strong> {{email}}</p>
|
||||||
|
<p><strong>Subject:</strong> {{subject}}</p>
|
||||||
|
<p><strong>Message:</strong></p>
|
||||||
|
<p>{{message}}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer">
|
||||||
|
<p>Sent at {{format_date timestamp}}</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
**templates/email/text/contact.hbs:**
|
||||||
|
|
||||||
|
```text
|
||||||
|
New Contact Form Submission
|
||||||
|
|
||||||
|
Name: {{name}}
|
||||||
|
Email: {{email}}
|
||||||
|
Subject: {{subject}}
|
||||||
|
|
||||||
|
Message:
|
||||||
|
{{message}}
|
||||||
|
|
||||||
|
Sent at {{format_date timestamp}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Endpoints
|
||||||
|
|
||||||
|
### GET /api/email/status
|
||||||
|
|
||||||
|
Check email system status.
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"enabled": true,
|
||||||
|
"provider": "smtp",
|
||||||
|
"configured": true,
|
||||||
|
"templates": ["contact", "support", "welcome", "notification"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### POST /api/email/contact
|
||||||
|
|
||||||
|
Send a contact form email.
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "John Doe",
|
||||||
|
"email": "john@example.com",
|
||||||
|
"subject": "Question about pricing",
|
||||||
|
"message": "I'd like to know more about your pricing plans.",
|
||||||
|
"recipient": "admin@yourapp.com"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"message": "Email sent successfully",
|
||||||
|
"message_id": "abc123def456",
|
||||||
|
"status": "sent"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### POST /api/email/support
|
||||||
|
|
||||||
|
Send a support form email with priority.
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "Jane Smith",
|
||||||
|
"email": "jane@example.com",
|
||||||
|
"subject": "Technical Issue",
|
||||||
|
"message": "Having trouble with login functionality.",
|
||||||
|
"priority": "high",
|
||||||
|
"category": "technical",
|
||||||
|
"recipient": "support@yourapp.com"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### POST /api/email/send
|
||||||
|
|
||||||
|
Send a template-based email.
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"to": "user@example.com",
|
||||||
|
"subject": "Welcome to Our Platform",
|
||||||
|
"template": "welcome",
|
||||||
|
"template_data": {
|
||||||
|
"user_name": "John Doe",
|
||||||
|
"activation_link": "https://yourapp.com/activate/token123"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### POST /api/email/notification
|
||||||
|
|
||||||
|
Send a notification email.
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"to": "user@example.com",
|
||||||
|
"title": "Important Update",
|
||||||
|
"message": "Your account has been updated successfully.",
|
||||||
|
"content": "Additional details about the update..."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Client Components
|
||||||
|
|
||||||
|
### ContactForm Component
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[component]
|
||||||
|
pub fn ContactForm() -> impl IntoView {
|
||||||
|
let (form_data, set_form_data) = create_signal(ContactFormData::default());
|
||||||
|
let (is_submitting, set_is_submitting) = create_signal(false);
|
||||||
|
let (message, set_message) = create_signal(String::new());
|
||||||
|
|
||||||
|
let submit_form = create_action(move |data: &ContactFormData| {
|
||||||
|
let data = data.clone();
|
||||||
|
async move {
|
||||||
|
set_is_submitting(true);
|
||||||
|
let result = send_contact_form(data).await;
|
||||||
|
set_is_submitting(false);
|
||||||
|
match result {
|
||||||
|
Ok(_) => set_message("Thank you for your message! We'll get back to you soon.".to_string()),
|
||||||
|
Err(e) => set_message(format!("Error sending message: {}", e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
view! {
|
||||||
|
<div class="contact-form">
|
||||||
|
<h2>"Contact Us"</h2>
|
||||||
|
<form on:submit=move |ev| {
|
||||||
|
ev.prevent_default();
|
||||||
|
submit_form.dispatch(form_data.get());
|
||||||
|
}>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name">"Name"</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="name"
|
||||||
|
required
|
||||||
|
on:input=move |ev| {
|
||||||
|
set_form_data.update(|data| data.name = event_target_value(&ev));
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="email">"Email"</label>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
id="email"
|
||||||
|
required
|
||||||
|
on:input=move |ev| {
|
||||||
|
set_form_data.update(|data| data.email = event_target_value(&ev));
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="subject">"Subject"</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="subject"
|
||||||
|
required
|
||||||
|
on:input=move |ev| {
|
||||||
|
set_form_data.update(|data| data.subject = event_target_value(&ev));
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="message">"Message"</label>
|
||||||
|
<textarea
|
||||||
|
id="message"
|
||||||
|
required
|
||||||
|
on:input=move |ev| {
|
||||||
|
set_form_data.update(|data| data.message = event_target_value(&ev));
|
||||||
|
}
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" disabled=move || is_submitting.get()>
|
||||||
|
{move || if is_submitting.get() { "Sending..." } else { "Send Message" }}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<Show when=move || !message.get().is_empty()>
|
||||||
|
<div class="message">{move || message.get()}</div>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### SupportForm Component
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[component]
|
||||||
|
pub fn SupportForm() -> impl IntoView {
|
||||||
|
let (form_data, set_form_data) = create_signal(SupportFormData::default());
|
||||||
|
let (is_submitting, set_is_submitting) = create_signal(false);
|
||||||
|
let (message, set_message) = create_signal(String::new());
|
||||||
|
|
||||||
|
let submit_form = create_action(move |data: &SupportFormData| {
|
||||||
|
let data = data.clone();
|
||||||
|
async move {
|
||||||
|
set_is_submitting(true);
|
||||||
|
let result = send_support_form(data).await;
|
||||||
|
set_is_submitting(false);
|
||||||
|
match result {
|
||||||
|
Ok(_) => set_message("Support ticket submitted successfully!".to_string()),
|
||||||
|
Err(e) => set_message(format!("Error submitting ticket: {}", e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
view! {
|
||||||
|
<div class="support-form">
|
||||||
|
<h2>"Support Request"</h2>
|
||||||
|
<form on:submit=move |ev| {
|
||||||
|
ev.prevent_default();
|
||||||
|
submit_form.dispatch(form_data.get());
|
||||||
|
}>
|
||||||
|
// Similar form fields with priority selector
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="priority">"Priority"</label>
|
||||||
|
<select
|
||||||
|
id="priority"
|
||||||
|
on:change=move |ev| {
|
||||||
|
set_form_data.update(|data| data.priority = event_target_value(&ev));
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<option value="low">"Low"</option>
|
||||||
|
<option value="medium">"Medium"</option>
|
||||||
|
<option value="high">"High"</option>
|
||||||
|
<option value="urgent">"Urgent"</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" disabled=move || is_submitting.get()>
|
||||||
|
{move || if is_submitting.get() { "Submitting..." } else { "Submit Ticket" }}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Server Usage
|
||||||
|
|
||||||
|
### Basic Email Sending
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use server::email::{EmailService, EmailConfig};
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let config = EmailConfig::from_file("config.toml")?;
|
||||||
|
let email_service = EmailService::new(config).await?;
|
||||||
|
|
||||||
|
// Send simple email
|
||||||
|
email_service.send_simple_email(
|
||||||
|
"user@example.com",
|
||||||
|
"Welcome!",
|
||||||
|
"Thank you for signing up!"
|
||||||
|
).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Template-Based Emails
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[server(SendWelcomeEmail, "/api/email/welcome")]
|
||||||
|
pub async fn send_welcome_email(
|
||||||
|
email: String,
|
||||||
|
name: String,
|
||||||
|
activation_token: String,
|
||||||
|
) -> Result<String, ServerFnError> {
|
||||||
|
let email_service = get_email_service().await?;
|
||||||
|
|
||||||
|
let mut template_data = HashMap::new();
|
||||||
|
template_data.insert("user_name".to_string(), name);
|
||||||
|
template_data.insert("activation_link".to_string(),
|
||||||
|
format!("https://yourapp.com/activate/{}", activation_token));
|
||||||
|
|
||||||
|
email_service.send_template_email(
|
||||||
|
&email,
|
||||||
|
"Welcome to Our Platform",
|
||||||
|
"welcome",
|
||||||
|
template_data
|
||||||
|
).await?;
|
||||||
|
|
||||||
|
Ok("Welcome email sent successfully".to_string())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Form Handling
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[server(HandleContactForm, "/api/email/contact")]
|
||||||
|
pub async fn handle_contact_form(
|
||||||
|
name: String,
|
||||||
|
email: String,
|
||||||
|
subject: String,
|
||||||
|
message: String,
|
||||||
|
) -> Result<String, ServerFnError> {
|
||||||
|
let email_service = get_email_service().await?;
|
||||||
|
|
||||||
|
// Validate input
|
||||||
|
if name.is_empty() || email.is_empty() || message.is_empty() {
|
||||||
|
return Err(ServerFnError::ServerError("All fields are required".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send email
|
||||||
|
email_service.send_contact_form(
|
||||||
|
&name,
|
||||||
|
&email,
|
||||||
|
&subject,
|
||||||
|
&message,
|
||||||
|
"admin@yourapp.com"
|
||||||
|
).await?;
|
||||||
|
|
||||||
|
Ok("Contact form submitted successfully".to_string())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
### Common Variables
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# SMTP Configuration
|
||||||
|
SMTP_HOST=smtp.gmail.com
|
||||||
|
SMTP_PORT=587
|
||||||
|
SMTP_USERNAME=your-email@gmail.com
|
||||||
|
SMTP_PASSWORD=your-app-password
|
||||||
|
SMTP_USE_STARTTLS=true
|
||||||
|
|
||||||
|
# SendGrid Configuration
|
||||||
|
SENDGRID_API_KEY=your-sendgrid-api-key
|
||||||
|
|
||||||
|
# Email Settings
|
||||||
|
EMAIL_FROM=noreply@yourapp.com
|
||||||
|
EMAIL_FROM_NAME="Your App"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using in Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[email]
|
||||||
|
smtp_username = "${SMTP_USERNAME}"
|
||||||
|
smtp_password = "@encrypted_smtp_password"
|
||||||
|
sendgrid_api_key = "@encrypted_sendgrid_api_key"
|
||||||
|
from_email = "${EMAIL_FROM}"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
### 1. Credential Management
|
||||||
|
|
||||||
|
Always encrypt sensitive credentials:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Encrypt SMTP password
|
||||||
|
cargo run --bin config_crypto_tool encrypt "your-smtp-password"
|
||||||
|
|
||||||
|
# Encrypt SendGrid API key
|
||||||
|
cargo run --bin config_crypto_tool encrypt "your-sendgrid-api-key"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Input Validation
|
||||||
|
|
||||||
|
Always validate email inputs:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use validator::{Validate, ValidationError};
|
||||||
|
|
||||||
|
#[derive(Validate)]
|
||||||
|
struct ContactFormData {
|
||||||
|
#[validate(length(min = 1, message = "Name is required"))]
|
||||||
|
name: String,
|
||||||
|
|
||||||
|
#[validate(email(message = "Invalid email address"))]
|
||||||
|
email: String,
|
||||||
|
|
||||||
|
#[validate(length(min = 1, max = 1000, message = "Message must be between 1 and 1000 characters"))]
|
||||||
|
message: String,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Rate Limiting
|
||||||
|
|
||||||
|
Implement rate limiting for email endpoints:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use tower_governor::{governor::GovernorLayer, GovernorConfigBuilder};
|
||||||
|
|
||||||
|
// Limit to 5 emails per minute per IP
|
||||||
|
let governor_config = GovernorConfigBuilder::default()
|
||||||
|
.per_minute(5)
|
||||||
|
.burst_size(2)
|
||||||
|
.finish()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let governor_layer = GovernorLayer {
|
||||||
|
config: Arc::new(governor_config),
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. CSRF Protection
|
||||||
|
|
||||||
|
Enable CSRF protection for email forms:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use axum_csrf::{CsrfConfig, CsrfLayer};
|
||||||
|
|
||||||
|
let csrf_config = CsrfConfig::default();
|
||||||
|
let csrf_layer = CsrfLayer::new(csrf_config);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
**Email not sending:**
|
||||||
|
- Check provider configuration
|
||||||
|
- Verify credentials
|
||||||
|
- Check network connectivity
|
||||||
|
- Review email service logs
|
||||||
|
|
||||||
|
**Template not found:**
|
||||||
|
- Verify template directory path
|
||||||
|
- Check template file naming
|
||||||
|
- Ensure HTML and text versions exist
|
||||||
|
|
||||||
|
**Authentication failed:**
|
||||||
|
- For Gmail: Use App Password, not regular password
|
||||||
|
- For other providers: Check username/password
|
||||||
|
- Verify server and port settings
|
||||||
|
|
||||||
|
**Rate limiting:**
|
||||||
|
- Check provider limits
|
||||||
|
- Implement proper rate limiting
|
||||||
|
- Consider using queues for bulk emails
|
||||||
|
|
||||||
|
### Debug Mode
|
||||||
|
|
||||||
|
Enable debug logging to troubleshoot issues:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[logging]
|
||||||
|
level = "debug"
|
||||||
|
|
||||||
|
[email]
|
||||||
|
enabled = true
|
||||||
|
debug = true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Use encrypted configuration** for sensitive credentials
|
||||||
|
2. **Implement proper validation** for all email inputs
|
||||||
|
3. **Use rate limiting** to prevent abuse
|
||||||
|
4. **Provide both HTML and text** versions of templates
|
||||||
|
5. **Test with console provider** during development
|
||||||
|
6. **Monitor email delivery** in production
|
||||||
|
7. **Handle errors gracefully** with user-friendly messages
|
||||||
|
8. **Use meaningful subject lines** and sender names
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- [API Reference](../../api/email.md)
|
||||||
|
- [Security Best Practices](../../security/best-practices.md)
|
||||||
|
- [Configuration Guide](../../configuration/files.md)
|
||||||
|
- [Deployment Guide](../../deployment/production.md)
|
||||||
|
|
||||||
|
The email system provides a robust foundation for all your application's communication needs while maintaining security and reliability.
|
||||||
1
book/developers/components/templates.md
Normal file
1
book/developers/components/templates.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Template Engine
|
||||||
1
book/developers/features/adding-features.md
Normal file
1
book/developers/features/adding-features.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Adding New Features
|
||||||
1
book/developers/features/api-endpoints.md
Normal file
1
book/developers/features/api-endpoints.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# API Endpoints
|
||||||
1
book/developers/features/feature-flags.md
Normal file
1
book/developers/features/feature-flags.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Feature Flags & Modules
|
||||||
1
book/developers/features/frontend-components.md
Normal file
1
book/developers/features/frontend-components.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Frontend Components
|
||||||
867
book/developers/features/migrations.md
Normal file
867
book/developers/features/migrations.md
Normal file
@ -0,0 +1,867 @@
|
|||||||
|
# Database Migrations
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<img src="../../../logos/rustelo_dev-logo-h.svg" alt="RUSTELO" width="300" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
This guide covers database migrations in RUSTELO, including the database-agnostic migration system and how to migrate from legacy PostgreSQL-only code to the new multi-database architecture.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
RUSTELO has been upgraded to use a **database-agnostic architecture** that supports both PostgreSQL and SQLite. This guide covers:
|
||||||
|
|
||||||
|
- Database migration patterns and best practices
|
||||||
|
- Migrating from PostgreSQL-only to database-agnostic code
|
||||||
|
- Writing database-specific migration files
|
||||||
|
- Handling data type differences between databases
|
||||||
|
- Testing migration strategies
|
||||||
|
|
||||||
|
## Migration Architecture
|
||||||
|
|
||||||
|
### Before (Legacy PostgreSQL-Only)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Direct PostgreSQL dependency
|
||||||
|
use sqlx::PgPool;
|
||||||
|
|
||||||
|
// Repository tied to PostgreSQL
|
||||||
|
pub struct AuthRepository {
|
||||||
|
pool: PgPool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AuthRepository {
|
||||||
|
pub fn new(pool: PgPool) -> Self {
|
||||||
|
Self { pool }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn find_user(&self, id: Uuid) -> Result<Option<User>> {
|
||||||
|
sqlx::query_as!(User, "SELECT * FROM users WHERE id = $1", id)
|
||||||
|
.fetch_optional(&self.pool)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### After (Database-Agnostic)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Database-agnostic abstractions
|
||||||
|
use crate::database::{DatabaseConnection, DatabaseType};
|
||||||
|
|
||||||
|
// Repository works with any database
|
||||||
|
pub struct AuthRepository {
|
||||||
|
database: DatabaseConnection,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AuthRepository {
|
||||||
|
pub fn new(database: DatabaseConnection) -> Self {
|
||||||
|
Self { database }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn find_user(&self, id: Uuid) -> Result<Option<User>> {
|
||||||
|
match self.database.database_type() {
|
||||||
|
DatabaseType::PostgreSQL => self.find_user_postgres(id).await,
|
||||||
|
DatabaseType::SQLite => self.find_user_sqlite(id).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn find_user_postgres(&self, id: Uuid) -> Result<Option<User>> {
|
||||||
|
let row = self.database
|
||||||
|
.fetch_optional(
|
||||||
|
"SELECT * FROM users WHERE id = $1",
|
||||||
|
&[id.into()],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if let Some(row) = row {
|
||||||
|
Ok(Some(User {
|
||||||
|
id: row.get_uuid("id")?,
|
||||||
|
email: row.get_string("email")?,
|
||||||
|
username: row.get_string("username")?,
|
||||||
|
created_at: row.get_datetime("created_at")?,
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn find_user_sqlite(&self, id: Uuid) -> Result<Option<User>> {
|
||||||
|
let row = self.database
|
||||||
|
.fetch_optional(
|
||||||
|
"SELECT * FROM users WHERE id = ?",
|
||||||
|
&[id.to_string().into()],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if let Some(row) = row {
|
||||||
|
Ok(Some(User {
|
||||||
|
id: row.get_uuid("id")?,
|
||||||
|
email: row.get_string("email")?,
|
||||||
|
username: row.get_string("username")?,
|
||||||
|
created_at: row.get_datetime("created_at")?,
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration Steps
|
||||||
|
|
||||||
|
### 1. Update Repository Constructors
|
||||||
|
|
||||||
|
**Before:**
|
||||||
|
```rust
|
||||||
|
let auth_repository = Arc::new(AuthRepository::new(pool.clone()));
|
||||||
|
```
|
||||||
|
|
||||||
|
**After:**
|
||||||
|
```rust
|
||||||
|
// For the new database-agnostic repositories
|
||||||
|
let auth_repository = Arc::new(database::auth::AuthRepository::new(database.clone()));
|
||||||
|
|
||||||
|
// Or create from pool
|
||||||
|
let auth_repository = Arc::new(database::auth::AuthRepository::from_pool(&database_pool));
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Replace Direct SQL Queries
|
||||||
|
|
||||||
|
**Before:**
|
||||||
|
```rust
|
||||||
|
pub async fn create_user(&self, user: &User) -> Result<()> {
|
||||||
|
sqlx::query!(
|
||||||
|
"INSERT INTO users (id, email, username) VALUES ($1, $2, $3)",
|
||||||
|
user.id,
|
||||||
|
user.email,
|
||||||
|
user.username
|
||||||
|
)
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**After:**
|
||||||
|
```rust
|
||||||
|
pub async fn create_user(&self, user: &User) -> Result<()> {
|
||||||
|
match self.database.database_type() {
|
||||||
|
DatabaseType::PostgreSQL => self.create_user_postgres(user).await,
|
||||||
|
DatabaseType::SQLite => self.create_user_sqlite(user).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create_user_postgres(&self, user: &User) -> Result<()> {
|
||||||
|
self.database
|
||||||
|
.execute(
|
||||||
|
"INSERT INTO users (id, email, username) VALUES ($1, $2, $3)",
|
||||||
|
&[
|
||||||
|
user.id.into(),
|
||||||
|
user.email.clone().into(),
|
||||||
|
user.username.clone().into(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create_user_sqlite(&self, user: &User) -> Result<()> {
|
||||||
|
self.database
|
||||||
|
.execute(
|
||||||
|
"INSERT INTO users (id, email, username) VALUES (?, ?, ?)",
|
||||||
|
&[
|
||||||
|
user.id.to_string().into(),
|
||||||
|
user.email.clone().into(),
|
||||||
|
user.username.clone().into(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Update Row Processing
|
||||||
|
|
||||||
|
**Before:**
|
||||||
|
```rust
|
||||||
|
let row = sqlx::query_as::<_, UserRow>("SELECT * FROM users WHERE id = $1")
|
||||||
|
.bind(id)
|
||||||
|
.fetch_optional(&self.pool)
|
||||||
|
.await?;
|
||||||
|
```
|
||||||
|
|
||||||
|
**After:**
|
||||||
|
```rust
|
||||||
|
let row = self.database
|
||||||
|
.fetch_optional(
|
||||||
|
"SELECT * FROM users WHERE id = $1", // PostgreSQL
|
||||||
|
&[id.into()],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if let Some(row) = row {
|
||||||
|
let user = User {
|
||||||
|
id: row.get_uuid("id")?,
|
||||||
|
email: row.get_string("email")?,
|
||||||
|
username: row.get_string("username")?,
|
||||||
|
created_at: row.get_datetime("created_at")?,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Database Initialization
|
||||||
|
|
||||||
|
**Before:**
|
||||||
|
```rust
|
||||||
|
let pool = PgPool::connect(&database_url).await?;
|
||||||
|
let auth_repository = AuthRepository::new(pool);
|
||||||
|
```
|
||||||
|
|
||||||
|
**After:**
|
||||||
|
```rust
|
||||||
|
let database_config = DatabaseConfig {
|
||||||
|
url: database_url.to_string(),
|
||||||
|
max_connections: 10,
|
||||||
|
min_connections: 1,
|
||||||
|
connect_timeout: Duration::from_secs(30),
|
||||||
|
idle_timeout: Duration::from_secs(600),
|
||||||
|
max_lifetime: Duration::from_secs(3600),
|
||||||
|
};
|
||||||
|
|
||||||
|
let database_pool = DatabasePool::new(&database_config).await?;
|
||||||
|
let database = Database::new(database_pool.clone());
|
||||||
|
let auth_repository = database::auth::AuthRepository::new(database.create_connection());
|
||||||
|
```
|
||||||
|
|
||||||
|
## Database-Specific Considerations
|
||||||
|
|
||||||
|
### PostgreSQL vs SQLite Differences
|
||||||
|
|
||||||
|
| Feature | PostgreSQL | SQLite |
|
||||||
|
|---------|------------|--------|
|
||||||
|
| **Parameter Binding** | `$1, $2, $3` | `?, ?, ?` |
|
||||||
|
| **UUID Storage** | Native `UUID` type | `TEXT` (string) |
|
||||||
|
| **Timestamps** | `TIMESTAMP WITH TIME ZONE` | `TEXT` (ISO 8601) |
|
||||||
|
| **JSON** | `JSONB` | `TEXT` (JSON string) |
|
||||||
|
| **Arrays** | Native arrays | `TEXT` (JSON array) |
|
||||||
|
| **Boolean** | `BOOLEAN` | `INTEGER` (0/1) |
|
||||||
|
|
||||||
|
### Handling Data Type Differences
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// UUID handling
|
||||||
|
match self.database.database_type() {
|
||||||
|
DatabaseType::PostgreSQL => {
|
||||||
|
// PostgreSQL stores UUIDs natively
|
||||||
|
params.push(user_id.into());
|
||||||
|
}
|
||||||
|
DatabaseType::SQLite => {
|
||||||
|
// SQLite stores UUIDs as strings
|
||||||
|
params.push(user_id.to_string().into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timestamp handling
|
||||||
|
match self.database.database_type() {
|
||||||
|
DatabaseType::PostgreSQL => {
|
||||||
|
// PostgreSQL stores timestamps natively
|
||||||
|
params.push(created_at.into());
|
||||||
|
}
|
||||||
|
DatabaseType::SQLite => {
|
||||||
|
// SQLite stores timestamps as ISO strings
|
||||||
|
params.push(created_at.to_rfc3339().into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSON handling
|
||||||
|
match self.database.database_type() {
|
||||||
|
DatabaseType::PostgreSQL => {
|
||||||
|
// PostgreSQL supports native JSONB
|
||||||
|
params.push(serde_json::to_value(&data)?.into());
|
||||||
|
}
|
||||||
|
DatabaseType::SQLite => {
|
||||||
|
// SQLite stores JSON as text
|
||||||
|
params.push(serde_json::to_string(&data)?.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Database Migration Files
|
||||||
|
|
||||||
|
### Migration File Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
migrations/
|
||||||
|
├── 001_create_users/
|
||||||
|
│ ├── up_postgres.sql
|
||||||
|
│ ├── down_postgres.sql
|
||||||
|
│ ├── up_sqlite.sql
|
||||||
|
│ └── down_sqlite.sql
|
||||||
|
├── 002_add_2fa_support/
|
||||||
|
│ ├── up_postgres.sql
|
||||||
|
│ ├── down_postgres.sql
|
||||||
|
│ ├── up_sqlite.sql
|
||||||
|
│ └── down_sqlite.sql
|
||||||
|
└── 003_create_posts/
|
||||||
|
├── up_postgres.sql
|
||||||
|
├── down_postgres.sql
|
||||||
|
├── up_sqlite.sql
|
||||||
|
└── down_sqlite.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example Migration Files
|
||||||
|
|
||||||
|
**PostgreSQL Migration (001_create_users/up_postgres.sql):**
|
||||||
|
```sql
|
||||||
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||||
|
|
||||||
|
CREATE TABLE users (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
email VARCHAR(255) UNIQUE NOT NULL,
|
||||||
|
username VARCHAR(100) UNIQUE NOT NULL,
|
||||||
|
password_hash VARCHAR(255) NOT NULL,
|
||||||
|
email_verified BOOLEAN DEFAULT FALSE,
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_users_email ON users(email);
|
||||||
|
CREATE INDEX idx_users_username ON users(username);
|
||||||
|
```
|
||||||
|
|
||||||
|
**SQLite Migration (001_create_users/up_sqlite.sql):**
|
||||||
|
```sql
|
||||||
|
CREATE TABLE users (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
email TEXT UNIQUE NOT NULL,
|
||||||
|
username TEXT UNIQUE NOT NULL,
|
||||||
|
password_hash TEXT NOT NULL,
|
||||||
|
email_verified INTEGER DEFAULT 0,
|
||||||
|
created_at TEXT DEFAULT (datetime('now')),
|
||||||
|
updated_at TEXT DEFAULT (datetime('now'))
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_users_email ON users(email);
|
||||||
|
CREATE INDEX idx_users_username ON users(username);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Running Migrations
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run migrations for PostgreSQL
|
||||||
|
cargo run --bin migrate -- --database-url "postgresql://user:pass@localhost/db"
|
||||||
|
|
||||||
|
# Run migrations for SQLite
|
||||||
|
cargo run --bin migrate -- --database-url "sqlite//:database.db"
|
||||||
|
|
||||||
|
# Roll back migrations
|
||||||
|
cargo run --bin migrate -- --database-url "sqlite//:database.db" --rollback
|
||||||
|
|
||||||
|
# Check migration status
|
||||||
|
cargo run --bin migrate -- --database-url "sqlite//:database.db" --status
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration Patterns
|
||||||
|
|
||||||
|
### Pattern 1: Simple Repository Migration
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Old
|
||||||
|
pub struct MyRepository {
|
||||||
|
pool: PgPool,
|
||||||
|
}
|
||||||
|
|
||||||
|
// New
|
||||||
|
pub struct MyRepository {
|
||||||
|
database: DatabaseConnection,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MyRepository {
|
||||||
|
pub fn new(database: DatabaseConnection) -> Self {
|
||||||
|
Self { database }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add convenience constructor
|
||||||
|
pub fn from_pool(pool: &DatabasePool) -> Self {
|
||||||
|
let connection = DatabaseConnection::from_pool(pool);
|
||||||
|
Self::new(connection)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pattern 2: Complex Query Migration
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Old
|
||||||
|
pub async fn complex_query(&self) -> Result<Vec<Item>> {
|
||||||
|
sqlx::query_as!(
|
||||||
|
Item,
|
||||||
|
r#"
|
||||||
|
SELECT i.*, u.username
|
||||||
|
FROM items i
|
||||||
|
JOIN users u ON i.user_id = u.id
|
||||||
|
WHERE i.created_at > $1
|
||||||
|
ORDER BY i.created_at DESC
|
||||||
|
"#,
|
||||||
|
since
|
||||||
|
)
|
||||||
|
.fetch_all(&self.pool)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
// New
|
||||||
|
pub async fn complex_query(&self, since: DateTime<Utc>) -> Result<Vec<Item>> {
|
||||||
|
match self.database.database_type() {
|
||||||
|
DatabaseType::PostgreSQL => self.complex_query_postgres(since).await,
|
||||||
|
DatabaseType::SQLite => self.complex_query_sqlite(since).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn complex_query_postgres(&self, since: DateTime<Utc>) -> Result<Vec<Item>> {
|
||||||
|
let rows = self.database
|
||||||
|
.fetch_all(
|
||||||
|
r#"
|
||||||
|
SELECT i.id, i.name, i.user_id, i.created_at, u.username
|
||||||
|
FROM items i
|
||||||
|
JOIN users u ON i.user_id = u.id
|
||||||
|
WHERE i.created_at > $1
|
||||||
|
ORDER BY i.created_at DESC
|
||||||
|
"#,
|
||||||
|
&[since.into()],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
self.rows_to_items(rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn complex_query_sqlite(&self, since: DateTime<Utc>) -> Result<Vec<Item>> {
|
||||||
|
let rows = self.database
|
||||||
|
.fetch_all(
|
||||||
|
r#"
|
||||||
|
SELECT i.id, i.name, i.user_id, i.created_at, u.username
|
||||||
|
FROM items i
|
||||||
|
JOIN users u ON i.user_id = u.id
|
||||||
|
WHERE i.created_at > ?
|
||||||
|
ORDER BY i.created_at DESC
|
||||||
|
"#,
|
||||||
|
&[since.to_rfc3339().into()],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
self.rows_to_items(rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rows_to_items(&self, rows: Vec<DatabaseRow>) -> Result<Vec<Item>> {
|
||||||
|
let mut items = Vec::new();
|
||||||
|
for row in rows {
|
||||||
|
items.push(Item {
|
||||||
|
id: row.get_uuid("id")?,
|
||||||
|
name: row.get_string("name")?,
|
||||||
|
user_id: row.get_uuid("user_id")?,
|
||||||
|
username: row.get_string("username")?,
|
||||||
|
created_at: row.get_datetime("created_at")?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(items)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pattern 3: Transaction Handling
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub async fn create_user_with_profile(&self, user: &User, profile: &Profile) -> Result<()> {
|
||||||
|
match self.database.database_type() {
|
||||||
|
DatabaseType::PostgreSQL => {
|
||||||
|
self.create_user_with_profile_postgres(user, profile).await
|
||||||
|
}
|
||||||
|
DatabaseType::SQLite => {
|
||||||
|
self.create_user_with_profile_sqlite(user, profile).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create_user_with_profile_postgres(&self, user: &User, profile: &Profile) -> Result<()> {
|
||||||
|
let mut tx = self.database.begin().await?;
|
||||||
|
|
||||||
|
// Create user
|
||||||
|
tx.execute(
|
||||||
|
"INSERT INTO users (id, email, username) VALUES ($1, $2, $3)",
|
||||||
|
&[user.id.into(), user.email.clone().into(), user.username.clone().into()],
|
||||||
|
).await?;
|
||||||
|
|
||||||
|
// Create profile
|
||||||
|
tx.execute(
|
||||||
|
"INSERT INTO profiles (user_id, first_name, last_name) VALUES ($1, $2, $3)",
|
||||||
|
&[profile.user_id.into(), profile.first_name.clone().into(), profile.last_name.clone().into()],
|
||||||
|
).await?;
|
||||||
|
|
||||||
|
tx.commit().await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create_user_with_profile_sqlite(&self, user: &User, profile: &Profile) -> Result<()> {
|
||||||
|
let mut tx = self.database.begin().await?;
|
||||||
|
|
||||||
|
// Create user
|
||||||
|
tx.execute(
|
||||||
|
"INSERT INTO users (id, email, username) VALUES (?, ?, ?)",
|
||||||
|
&[user.id.to_string().into(), user.email.clone().into(), user.username.clone().into()],
|
||||||
|
).await?;
|
||||||
|
|
||||||
|
// Create profile
|
||||||
|
tx.execute(
|
||||||
|
"INSERT INTO profiles (user_id, first_name, last_name) VALUES (?, ?, ?)",
|
||||||
|
&[profile.user_id.to_string().into(), profile.first_name.clone().into(), profile.last_name.clone().into()],
|
||||||
|
).await?;
|
||||||
|
|
||||||
|
tx.commit().await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration Checklist
|
||||||
|
|
||||||
|
### Code Migration
|
||||||
|
|
||||||
|
- [ ] Replace `PgPool` with `DatabaseConnection`
|
||||||
|
- [ ] Update repository constructors
|
||||||
|
- [ ] Split database operations into database-specific methods
|
||||||
|
- [ ] Handle parameter binding differences (`$1` vs `?`)
|
||||||
|
- [ ] Handle data type differences (UUID, timestamps, etc.)
|
||||||
|
- [ ] Update imports to use new database modules
|
||||||
|
- [ ] Add convenience constructors (`from_pool`)
|
||||||
|
- [ ] Update error handling
|
||||||
|
|
||||||
|
### Database Migration Files
|
||||||
|
|
||||||
|
- [ ] Create separate migration files for PostgreSQL (`*_postgres.sql`)
|
||||||
|
- [ ] Create separate migration files for SQLite (`*_sqlite.sql`)
|
||||||
|
- [ ] Update migration runner configuration
|
||||||
|
- [ ] Test migrations on both database types
|
||||||
|
- [ ] Add rollback migrations
|
||||||
|
- [ ] Document migration dependencies
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
- [ ] Update environment variables
|
||||||
|
- [ ] Test with different database URLs
|
||||||
|
- [ ] Update deployment scripts
|
||||||
|
- [ ] Update documentation
|
||||||
|
- [ ] Configure connection pooling
|
||||||
|
- [ ] Set appropriate timeouts
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
- [ ] Update unit tests to use new abstractions
|
||||||
|
- [ ] Add integration tests for both database types
|
||||||
|
- [ ] Test migration path from old to new architecture
|
||||||
|
- [ ] Performance testing on both databases
|
||||||
|
- [ ] Test rollback scenarios
|
||||||
|
- [ ] Add database-specific test fixtures
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues and Solutions
|
||||||
|
|
||||||
|
#### 1. UUID Conversion Errors
|
||||||
|
**Problem:** SQLite doesn't support UUID natively
|
||||||
|
**Solution:** Convert UUIDs to strings for SQLite
|
||||||
|
|
||||||
|
```rust
|
||||||
|
match self.database.database_type() {
|
||||||
|
DatabaseType::PostgreSQL => params.push(uuid.into()),
|
||||||
|
DatabaseType::SQLite => params.push(uuid.to_string().into()),
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. Parameter Binding Mismatch
|
||||||
|
**Problem:** Using PostgreSQL syntax (`$1`) with SQLite
|
||||||
|
**Solution:** Use database-specific query strings
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let query = match self.database.database_type() {
|
||||||
|
DatabaseType::PostgreSQL => "SELECT * FROM users WHERE id = $1",
|
||||||
|
DatabaseType::SQLite => "SELECT * FROM users WHERE id = ?",
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. Migration File Not Found
|
||||||
|
**Problem:** Missing database-specific migration files
|
||||||
|
**Solution:** Ensure both `*_postgres.sql` and `*_sqlite.sql` files exist
|
||||||
|
|
||||||
|
#### 4. Type Conversion Errors
|
||||||
|
**Problem:** Data type mismatches between databases
|
||||||
|
**Solution:** Use the `DatabaseRow` trait methods consistently
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Always use the trait methods
|
||||||
|
let user_id = row.get_uuid("user_id")?; // Handles conversion automatically
|
||||||
|
let created_at = row.get_datetime("created_at")?; // Handles conversion automatically
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 5. Connection Pool Issues
|
||||||
|
**Problem:** Connection pool exhaustion or configuration issues
|
||||||
|
**Solution:** Properly configure connection pool settings
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let database_config = DatabaseConfig {
|
||||||
|
url: database_url.to_string(),
|
||||||
|
max_connections: 10,
|
||||||
|
min_connections: 1,
|
||||||
|
connect_timeout: Duration::from_secs(30),
|
||||||
|
idle_timeout: Duration::from_secs(600),
|
||||||
|
max_lifetime: Duration::from_secs(3600),
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### 1. Database-Agnostic Design
|
||||||
|
- Write repositories that work with both databases
|
||||||
|
- Use the database abstraction layer consistently
|
||||||
|
- Avoid database-specific features when possible
|
||||||
|
- Test with both databases regularly
|
||||||
|
|
||||||
|
### 2. Migration Strategy
|
||||||
|
- Migrate one module at a time
|
||||||
|
- Test thoroughly with both database types
|
||||||
|
- Keep the old code until migration is complete
|
||||||
|
- Document the migration process
|
||||||
|
|
||||||
|
### 3. Performance Considerations
|
||||||
|
- PostgreSQL: Better for complex queries and large datasets
|
||||||
|
- SQLite: Better for simple queries and small datasets
|
||||||
|
- Use appropriate database features for your use case
|
||||||
|
- Monitor query performance on both databases
|
||||||
|
|
||||||
|
### 4. Testing Strategy
|
||||||
|
- Test all code paths with both databases
|
||||||
|
- Use SQLite for fast unit tests
|
||||||
|
- Use PostgreSQL for integration tests
|
||||||
|
- Test migration rollbacks
|
||||||
|
- Use database-specific test fixtures
|
||||||
|
|
||||||
|
### 5. Error Handling
|
||||||
|
- Handle database-specific errors appropriately
|
||||||
|
- Use consistent error types across databases
|
||||||
|
- Log database operations for debugging
|
||||||
|
- Provide meaningful error messages
|
||||||
|
|
||||||
|
## Example: Complete Repository Migration
|
||||||
|
|
||||||
|
Here's a complete example of migrating a repository from PostgreSQL-only to database-agnostic:
|
||||||
|
|
||||||
|
### Before (PostgreSQL-Only)
|
||||||
|
```rust
|
||||||
|
use sqlx::PgPool;
|
||||||
|
use uuid::Uuid;
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
|
||||||
|
pub struct PostRepository {
|
||||||
|
pool: PgPool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PostRepository {
|
||||||
|
pub fn new(pool: PgPool) -> Self {
|
||||||
|
Self { pool }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create_post(&self, post: &Post) -> Result<()> {
|
||||||
|
sqlx::query!(
|
||||||
|
"INSERT INTO posts (id, title, content, author_id, published) VALUES ($1, $2, $3, $4, $5)",
|
||||||
|
post.id,
|
||||||
|
post.title,
|
||||||
|
post.content,
|
||||||
|
post.author_id,
|
||||||
|
post.published
|
||||||
|
)
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn find_post(&self, id: Uuid) -> Result<Option<Post>> {
|
||||||
|
let row = sqlx::query_as!(
|
||||||
|
Post,
|
||||||
|
"SELECT id, title, content, author_id, published, created_at FROM posts WHERE id = $1",
|
||||||
|
id
|
||||||
|
)
|
||||||
|
.fetch_optional(&self.pool)
|
||||||
|
.await?;
|
||||||
|
Ok(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn find_posts_by_author(&self, author_id: Uuid) -> Result<Vec<Post>> {
|
||||||
|
let rows = sqlx::query_as!(
|
||||||
|
Post,
|
||||||
|
"SELECT id, title, content, author_id, published, created_at FROM posts WHERE author_id = $1 ORDER BY created_at DESC",
|
||||||
|
author_id
|
||||||
|
)
|
||||||
|
.fetch_all(&self.pool)
|
||||||
|
.await?;
|
||||||
|
Ok(rows)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### After (Database-Agnostic)
|
||||||
|
```rust
|
||||||
|
use crate::database::{DatabaseConnection, DatabaseType, DatabaseRow};
|
||||||
|
use uuid::Uuid;
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
|
||||||
|
pub struct PostRepository {
|
||||||
|
database: DatabaseConnection,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PostRepository {
|
||||||
|
pub fn new(database: DatabaseConnection) -> Self {
|
||||||
|
Self { database }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_pool(pool: &crate::database::DatabasePool) -> Self {
|
||||||
|
let connection = DatabaseConnection::from_pool(pool);
|
||||||
|
Self::new(connection)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create_post(&self, post: &Post) -> Result<()> {
|
||||||
|
match self.database.database_type() {
|
||||||
|
DatabaseType::PostgreSQL => self.create_post_postgres(post).await,
|
||||||
|
DatabaseType::SQLite => self.create_post_sqlite(post).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create_post_postgres(&self, post: &Post) -> Result<()> {
|
||||||
|
self.database
|
||||||
|
.execute(
|
||||||
|
"INSERT INTO posts (id, title, content, author_id, published) VALUES ($1, $2, $3, $4, $5)",
|
||||||
|
&[
|
||||||
|
post.id.into(),
|
||||||
|
post.title.clone().into(),
|
||||||
|
post.content.clone().into(),
|
||||||
|
post.author_id.into(),
|
||||||
|
post.published.into(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create_post_sqlite(&self, post: &Post) -> Result<()> {
|
||||||
|
self.database
|
||||||
|
.execute(
|
||||||
|
"INSERT INTO posts (id, title, content, author_id, published) VALUES (?, ?, ?, ?, ?)",
|
||||||
|
&[
|
||||||
|
post.id.to_string().into(),
|
||||||
|
post.title.clone().into(),
|
||||||
|
post.content.clone().into(),
|
||||||
|
post.author_id.to_string().into(),
|
||||||
|
(post.published as i32).into(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn find_post(&self, id: Uuid) -> Result<Option<Post>> {
|
||||||
|
match self.database.database_type() {
|
||||||
|
DatabaseType::PostgreSQL => self.find_post_postgres(id).await,
|
||||||
|
DatabaseType::SQLite => self.find_post_sqlite(id).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn find_post_postgres(&self, id: Uuid) -> Result<Option<Post>> {
|
||||||
|
let row = self
|
||||||
|
.database
|
||||||
|
.fetch_optional(
|
||||||
|
"SELECT id, title, content, author_id, published, created_at FROM posts WHERE id = $1",
|
||||||
|
&[id.into()],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
self.row_to_post(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn find_post_sqlite(&self, id: Uuid) -> Result<Option<Post>> {
|
||||||
|
let row = self
|
||||||
|
.database
|
||||||
|
.fetch_optional(
|
||||||
|
"SELECT id, title, content, author_id, published, created_at FROM posts WHERE id = ?",
|
||||||
|
&[id.to_string().into()],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
self.row_to_post(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn find_posts_by_author(&self, author_id: Uuid) -> Result<Vec<Post>> {
|
||||||
|
match self.database.database_type() {
|
||||||
|
DatabaseType::PostgreSQL => self.find_posts_by_author_postgres(author_id).await,
|
||||||
|
DatabaseType::SQLite => self.find_posts_by_author_sqlite(author_id).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn find_posts_by_author_postgres(&self, author_id: Uuid) -> Result<Vec<Post>> {
|
||||||
|
let rows = self
|
||||||
|
.database
|
||||||
|
.fetch_all(
|
||||||
|
"SELECT id, title, content, author_id, published, created_at FROM posts WHERE author_id = $1 ORDER BY created_at DESC",
|
||||||
|
&[author_id.into()],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
self.rows_to_posts(rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn find_posts_by_author_sqlite(&self, author_id: Uuid) -> Result<Vec<Post>> {
|
||||||
|
let rows = self
|
||||||
|
.database
|
||||||
|
.fetch_all(
|
||||||
|
"SELECT id, title, content, author_id, published, created_at FROM posts WHERE author_id = ? ORDER BY created_at DESC",
|
||||||
|
&[author_id.to_string().into()],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
self.rows_to_posts(rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn row_to_post(&self, row: Option<DatabaseRow>) -> Result<Option<Post>> {
|
||||||
|
if let Some(row) = row {
|
||||||
|
Ok(Some(Post {
|
||||||
|
id: row.get_uuid("id")?,
|
||||||
|
title: row.get_string("title")?,
|
||||||
|
content: row.get_string("content")?,
|
||||||
|
author_id: row.get_uuid("author_id")?,
|
||||||
|
published: row.get_bool("published")?,
|
||||||
|
created_at: row.get_datetime("created_at")?,
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rows_to_posts(&self, rows: Vec<DatabaseRow>) -> Result<Vec<Post>> {
|
||||||
|
let mut posts = Vec::new();
|
||||||
|
for row in rows {
|
||||||
|
posts.push(Post {
|
||||||
|
id: row.get_uuid("id")?,
|
||||||
|
title: row.get_string("title")?,
|
||||||
|
content: row.get_string("content")?,
|
||||||
|
author_id: row.get_uuid("author_id")?,
|
||||||
|
published: row.get_bool("published")?,
|
||||||
|
created_at: row.get_datetime("created_at")?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(posts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- [Database Configuration](../../configuration/database.md)
|
||||||
|
- [Performance Optimization](../../performance/database.md)
|
||||||
|
- [Testing Strategies](../testing/strategy.md)
|
||||||
|
- [Deployment Guide](../../deployment/production.md)
|
||||||
|
|
||||||
|
This migration guide provides a comprehensive approach to transitioning from PostgreSQL-only to database-agnostic architecture while maintaining functionality and performance across both database systems.
|
||||||
1
book/developers/setup/build.md
Normal file
1
book/developers/setup/build.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Build System & Tools
|
||||||
1
book/developers/setup/environment.md
Normal file
1
book/developers/setup/environment.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Development Environment
|
||||||
1
book/developers/setup/structure.md
Normal file
1
book/developers/setup/structure.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Project Structure
|
||||||
1
book/developers/setup/workflow.md
Normal file
1
book/developers/setup/workflow.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Development Workflow
|
||||||
1
book/developers/testing/e2e.md
Normal file
1
book/developers/testing/e2e.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# End-to-End Testing
|
||||||
1
book/developers/testing/integration.md
Normal file
1
book/developers/testing/integration.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Integration Testing
|
||||||
1
book/developers/testing/performance.md
Normal file
1
book/developers/testing/performance.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Performance Testing
|
||||||
1
book/developers/testing/strategy.md
Normal file
1
book/developers/testing/strategy.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Testing Strategy
|
||||||
1
book/developers/testing/unit.md
Normal file
1
book/developers/testing/unit.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Unit Testing
|
||||||
0
book/development/debugging.md
Normal file
0
book/development/debugging.md
Normal file
0
book/development/hot-reloading.md
Normal file
0
book/development/hot-reloading.md
Normal file
0
book/development/setup.md
Normal file
0
book/development/setup.md
Normal file
0
book/development/structure.md
Normal file
0
book/development/structure.md
Normal file
0
book/development/testing.md
Normal file
0
book/development/testing.md
Normal file
0
book/development/workflow.md
Normal file
0
book/development/workflow.md
Normal file
361
book/features/auth/2fa.md
Normal file
361
book/features/auth/2fa.md
Normal file
@ -0,0 +1,361 @@
|
|||||||
|
# Two-Factor Authentication (2FA) Implementation
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<img src="../logos/rustelo_dev-logo-h.svg" alt="RUSTELO" width="300" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
This document describes the implementation of Time-based One-Time Password (TOTP) two-factor authentication in the Rustelo application.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The 2FA implementation provides an additional layer of security for user accounts by requiring a second form of authentication beyond username and password. This implementation uses TOTP (Time-based One-Time Password) compatible with popular authenticator apps like Google Authenticator, Authy, and Microsoft Authenticator.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **TOTP Authentication**: Standards-compliant TOTP implementation (RFC 6238)
|
||||||
|
- **QR Code Generation**: Automatic QR code generation for easy setup
|
||||||
|
- **Backup Codes**: Recovery codes for account access if authenticator device is lost
|
||||||
|
- **Rate Limiting**: Protection against brute force attacks
|
||||||
|
- **Audit Trail**: Logging of 2FA attempts for security monitoring
|
||||||
|
- **Graceful Degradation**: Existing users can continue using the system without 2FA until they opt-in
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Backend Components
|
||||||
|
|
||||||
|
#### Database Schema
|
||||||
|
- `user_2fa`: Stores TOTP secrets and configuration
|
||||||
|
- `user_2fa_recovery_codes`: Individual recovery codes for better tracking
|
||||||
|
- `user_2fa_attempts`: Audit trail of authentication attempts
|
||||||
|
- `users`: Extended with `two_factor_required` flag
|
||||||
|
- `sessions`: Extended with `two_factor_verified` flag
|
||||||
|
|
||||||
|
#### Core Services
|
||||||
|
- `TwoFactorService`: Main 2FA business logic
|
||||||
|
- `AuthService`: Extended to handle 2FA login flow
|
||||||
|
- `AuthRepository`: Database operations for user management
|
||||||
|
|
||||||
|
#### API Endpoints
|
||||||
|
- `POST /api/auth/login`: First step login (returns 2FA requirement)
|
||||||
|
- `POST /api/auth/login/2fa`: Second step login with 2FA code
|
||||||
|
- `POST /api/auth/2fa/setup`: Initialize 2FA setup
|
||||||
|
- `POST /api/auth/2fa/verify`: Verify and enable 2FA
|
||||||
|
- `GET /api/auth/2fa/status`: Get current 2FA status
|
||||||
|
- `POST /api/auth/2fa/disable`: Disable 2FA
|
||||||
|
- `POST /api/auth/2fa/backup-codes`: Generate new backup codes
|
||||||
|
|
||||||
|
### Frontend Components
|
||||||
|
|
||||||
|
#### React Components
|
||||||
|
- `TwoFactorSetup`: Complete 2FA setup flow
|
||||||
|
- `TwoFactorLoginForm`: 2FA code input during login
|
||||||
|
- `TwoFactorLoginPage`: Full page 2FA login
|
||||||
|
- `GenerateBackupCodesComponent`: Backup code management
|
||||||
|
- `DisableTwoFactorComponent`: 2FA disabling interface
|
||||||
|
|
||||||
|
#### Auth Context
|
||||||
|
- Extended `AuthContext` to handle 2FA states
|
||||||
|
- `requires_2fa` flag to track 2FA requirement
|
||||||
|
- `pending_2fa_email` to store email during 2FA flow
|
||||||
|
|
||||||
|
## Setup Process
|
||||||
|
|
||||||
|
### 1. User Initiates 2FA Setup
|
||||||
|
```rust
|
||||||
|
POST /api/auth/2fa/setup
|
||||||
|
{
|
||||||
|
"password": "current_password"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Server Response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"secret": "BASE32_ENCODED_SECRET",
|
||||||
|
"qr_code_url": "data:image/svg+xml;base64,QR_CODE_DATA",
|
||||||
|
"backup_codes": ["12345678", "87654321", ...]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. User Scans QR Code
|
||||||
|
- User scans QR code with authenticator app
|
||||||
|
- Alternatively, manually enters the secret key
|
||||||
|
|
||||||
|
### 4. User Verifies Setup
|
||||||
|
```rust
|
||||||
|
POST /api/auth/2fa/verify
|
||||||
|
{
|
||||||
|
"code": "123456"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 2FA Enabled
|
||||||
|
- TOTP verification successful
|
||||||
|
- 2FA is now enabled for the account
|
||||||
|
- Backup codes are active
|
||||||
|
|
||||||
|
## Login Flow
|
||||||
|
|
||||||
|
### 1. Standard Login
|
||||||
|
```rust
|
||||||
|
POST /api/auth/login
|
||||||
|
{
|
||||||
|
"email": "user@example.com",
|
||||||
|
"password": "password",
|
||||||
|
"remember_me": false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 2FA Required Response
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"user": { ... },
|
||||||
|
"access_token": "",
|
||||||
|
"requires_2fa": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 2FA Code Submission
|
||||||
|
```rust
|
||||||
|
POST /api/auth/login/2fa
|
||||||
|
{
|
||||||
|
"email": "user@example.com",
|
||||||
|
"code": "123456",
|
||||||
|
"remember_me": false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Complete Authentication
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"user": { ... },
|
||||||
|
"access_token": "JWT_TOKEN",
|
||||||
|
"refresh_token": "REFRESH_TOKEN",
|
||||||
|
"requires_2fa": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Features
|
||||||
|
|
||||||
|
### Rate Limiting
|
||||||
|
- Maximum 5 failed attempts per 15-minute window
|
||||||
|
- Prevents brute force attacks on 2FA codes
|
||||||
|
|
||||||
|
### Backup Codes
|
||||||
|
- 8-digit recovery codes
|
||||||
|
- Hashed storage in database
|
||||||
|
- Single-use only
|
||||||
|
- Can be regenerated
|
||||||
|
|
||||||
|
### Audit Trail
|
||||||
|
- All 2FA attempts are logged
|
||||||
|
- Includes IP address, user agent, and timestamp
|
||||||
|
- Distinguishes between TOTP and backup code usage
|
||||||
|
|
||||||
|
### Secret Management
|
||||||
|
- TOTP secrets are Base32 encoded
|
||||||
|
- Secrets are unique per user
|
||||||
|
- Secrets are generated using cryptographically secure random number generation
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
```env
|
||||||
|
# Database connection
|
||||||
|
DATABASE_URL=postgresql://localhost/rustelo_dev
|
||||||
|
|
||||||
|
# JWT configuration
|
||||||
|
JWT_SECRET=your_jwt_secret_key
|
||||||
|
JWT_EXPIRATION=3600
|
||||||
|
|
||||||
|
# Application settings
|
||||||
|
APP_NAME=Rustelo
|
||||||
|
ISSUER_NAME=Rustelo Authentication
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
# 2FA specific
|
||||||
|
totp-rs = "5.6"
|
||||||
|
qrcode = { version = "0.15", features = ["svg"] }
|
||||||
|
base32 = "0.5"
|
||||||
|
sha2 = "0.10"
|
||||||
|
base64 = "0.22"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
### Enable 2FA for a User
|
||||||
|
```rust
|
||||||
|
// Setup 2FA
|
||||||
|
let request = Setup2FARequest {
|
||||||
|
password: "user_password".to_string(),
|
||||||
|
};
|
||||||
|
let response = auth_service.setup_2fa(user_id, request).await?;
|
||||||
|
|
||||||
|
// Verify and enable
|
||||||
|
let verify_request = Verify2FARequest {
|
||||||
|
code: "123456".to_string(),
|
||||||
|
};
|
||||||
|
auth_service.verify_2fa_setup(user_id, verify_request, None, None).await?;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Login with 2FA
|
||||||
|
```rust
|
||||||
|
// First step: regular login
|
||||||
|
let login_request = LoginCredentials {
|
||||||
|
email: "user@example.com".to_string(),
|
||||||
|
password: "password".to_string(),
|
||||||
|
remember_me: false,
|
||||||
|
};
|
||||||
|
let response = auth_service.login(login_request, None).await?;
|
||||||
|
|
||||||
|
if response.requires_2fa {
|
||||||
|
// Second step: 2FA verification
|
||||||
|
let twofa_request = Login2FARequest {
|
||||||
|
email: "user@example.com".to_string(),
|
||||||
|
code: "123456".to_string(),
|
||||||
|
remember_me: false,
|
||||||
|
};
|
||||||
|
let final_response = auth_service.login_with_2fa(twofa_request, None, None, None).await?;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
### Unit Tests
|
||||||
|
```rust
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_2fa_setup() {
|
||||||
|
let service = TwoFactorService::new(pool, "Test".to_string(), "Test".to_string());
|
||||||
|
let response = service.setup_2fa(user_id, "user@test.com", request).await;
|
||||||
|
assert!(response.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_totp_verification() {
|
||||||
|
// Test TOTP code verification
|
||||||
|
let service = TwoFactorService::new(pool, "Test".to_string(), "Test".to_string());
|
||||||
|
let result = service.verify_2fa_for_login(user_id, "123456", None, None).await;
|
||||||
|
// Assert based on test conditions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Integration Tests
|
||||||
|
```rust
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_full_2fa_flow() {
|
||||||
|
// Test complete 2FA setup and login flow
|
||||||
|
// 1. Setup 2FA
|
||||||
|
// 2. Verify setup
|
||||||
|
// 3. Login with 2FA
|
||||||
|
// 4. Verify successful authentication
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration Guide
|
||||||
|
|
||||||
|
### Database Migration
|
||||||
|
```sql
|
||||||
|
-- Run migration 002_add_2fa_support.sql
|
||||||
|
-- This adds all necessary 2FA tables and columns
|
||||||
|
```
|
||||||
|
|
||||||
|
### Existing Users
|
||||||
|
- Existing users can continue using the system without 2FA
|
||||||
|
- 2FA is opt-in for existing users
|
||||||
|
- `two_factor_enabled` field defaults to `false`
|
||||||
|
|
||||||
|
### Deployment Steps
|
||||||
|
1. Deploy database migration
|
||||||
|
2. Deploy backend code with 2FA support
|
||||||
|
3. Deploy frontend code with 2FA components
|
||||||
|
4. Update documentation and user guides
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
#### QR Code Not Displaying
|
||||||
|
- Check that SVG rendering is enabled
|
||||||
|
- Verify QR code generation dependencies
|
||||||
|
- Check browser console for errors
|
||||||
|
|
||||||
|
#### Invalid 2FA Code
|
||||||
|
- Ensure device time is synchronized
|
||||||
|
- Verify secret key entry
|
||||||
|
- Check for typos in manual entry
|
||||||
|
|
||||||
|
#### Backup Code Not Working
|
||||||
|
- Verify code hasn't been used before
|
||||||
|
- Check for typing errors
|
||||||
|
- Ensure user has remaining backup codes
|
||||||
|
|
||||||
|
### Debug Commands
|
||||||
|
```bash
|
||||||
|
# Check 2FA status for user
|
||||||
|
psql -d rustelo_dev -c "SELECT * FROM user_2fa WHERE user_id = 'USER_ID';"
|
||||||
|
|
||||||
|
# View recent 2FA attempts
|
||||||
|
psql -d rustelo_dev -c "SELECT * FROM user_2fa_attempts WHERE user_id = 'USER_ID' ORDER BY created_at DESC LIMIT 10;"
|
||||||
|
|
||||||
|
# Check backup codes
|
||||||
|
psql -d rustelo_dev -c "SELECT code_hash, used_at FROM user_2fa_recovery_codes WHERE user_id = 'USER_ID';"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
### Best Practices
|
||||||
|
- Use HTTPS in production
|
||||||
|
- Implement proper session management
|
||||||
|
- Regular security audits
|
||||||
|
- Monitor 2FA attempt logs
|
||||||
|
- User education on 2FA security
|
||||||
|
|
||||||
|
### Compliance
|
||||||
|
- TOTP implementation follows RFC 6238
|
||||||
|
- Backup codes follow industry best practices
|
||||||
|
- Audit logging supports compliance requirements
|
||||||
|
|
||||||
|
## Future Enhancements
|
||||||
|
|
||||||
|
### Planned Features
|
||||||
|
- SMS-based 2FA as alternative
|
||||||
|
- Hardware security key support (WebAuthn)
|
||||||
|
- Admin-enforced 2FA policies
|
||||||
|
- Bulk 2FA management for organizations
|
||||||
|
- Advanced reporting and analytics
|
||||||
|
|
||||||
|
### Performance Optimizations
|
||||||
|
- Caching of 2FA status
|
||||||
|
- Async processing of audit logs
|
||||||
|
- Database query optimization
|
||||||
|
- CDN for QR code generation
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For issues or questions regarding 2FA implementation:
|
||||||
|
1. Check this documentation
|
||||||
|
2. Review server logs
|
||||||
|
3. Check database state
|
||||||
|
4. Contact development team
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Last Updated: 2024-01-XX
|
||||||
|
Version: 1.0.0
|
||||||
0
book/features/auth/jwt.md
Normal file
0
book/features/auth/jwt.md
Normal file
0
book/features/auth/oauth2.md
Normal file
0
book/features/auth/oauth2.md
Normal file
0
book/features/auth/sessions.md
Normal file
0
book/features/auth/sessions.md
Normal file
0
book/features/authentication.md
Normal file
0
book/features/authentication.md
Normal file
0
book/features/combinations.md
Normal file
0
book/features/combinations.md
Normal file
0
book/features/content-management.md
Normal file
0
book/features/content-management.md
Normal file
0
book/features/content/database.md
Normal file
0
book/features/content/database.md
Normal file
0
book/features/content/markdown.md
Normal file
0
book/features/content/markdown.md
Normal file
0
book/features/content/static.md
Normal file
0
book/features/content/static.md
Normal file
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user