Rustelo/docs/root-path-config.md

365 lines
8.3 KiB
Markdown
Raw Normal View History

# ROOT_PATH Configuration Guide
This document explains how to use the `ROOT_PATH` configuration feature to manage absolute and relative paths in your Rust application.
## Overview
The `ROOT_PATH` configuration allows you to:
- Convert all relative paths in configuration files to absolute paths
- Set a base directory for your application
- Deploy your application anywhere without hardcoding paths
- Maintain consistent path resolution across different environments
## Configuration
### Setting ROOT_PATH
There are several ways to set the `ROOT_PATH`:
#### 1. Environment Variable (Recommended)
```bash
export ROOT_PATH=/path/to/your/application
```
#### 2. Configuration File
```toml
# config.toml
root_path = "/path/to/your/application"
```
#### 3. Default Behavior
If not set, `ROOT_PATH` defaults to the current working directory.
### Environment Variable Priority
The `ROOT_PATH` can be overridden using the `ROOT_PATH` environment variable:
```bash
# Override config file setting
ROOT_PATH=/custom/path ./target/release/server
```
## Path Resolution
### How It Works
1. **Absolute Paths**: Left unchanged
- Input: `/absolute/path/to/file`
- Output: `/absolute/path/to/file`
2. **Relative Paths**: Resolved against `ROOT_PATH`
- ROOT_PATH: `/app`
- Input: `public/assets`
- Output: `/app/public/assets`
3. **Current Directory References**: Resolved properly
- ROOT_PATH: `/app`
- Input: `./config`
- Output: `/app/config`
4. **Parent Directory References**: Resolved properly
- ROOT_PATH: `/app/server`
- Input: `../shared`
- Output: `/app/shared`
### Affected Configuration Sections
The following configuration sections have their paths resolved:
#### Static Files
```toml
[static]
assets_dir = "public" # -> /app/public
site_root = "target/site" # -> /app/target/site
site_pkg_dir = "pkg" # -> /app/pkg
```
#### Server Directories
```toml
[server_dirs]
public_dir = "public" # -> /app/public
uploads_dir = "uploads" # -> /app/uploads
logs_dir = "logs" # -> /app/logs
temp_dir = "tmp" # -> /app/tmp
cache_dir = "cache" # -> /app/cache
config_dir = "config" # -> /app/config
data_dir = "data" # -> /app/data
backup_dir = "backups" # -> /app/backups
```
#### TLS Configuration
```toml
[server.tls]
cert_path = "certs/server.crt" # -> /app/certs/server.crt
key_path = "certs/server.key" # -> /app/certs/server.key
```
#### Logging
```toml
[logging]
file_path = "logs/app.log" # -> /app/logs/app.log
```
#### Content Directory (if enabled)
```toml
[content]
content_dir = "content" # -> /app/content
```
## Usage Examples
### Development Environment
```bash
# Set ROOT_PATH to your project directory
export ROOT_PATH=/home/user/my-rust-app
cd /home/user/my-rust-app
cargo run
```
### Production Deployment
```bash
# Docker example
FROM rust:latest
WORKDIR /app
COPY . .
ENV ROOT_PATH=/app
ENV ENVIRONMENT=production
RUN cargo build --release
EXPOSE 3030
CMD ["./target/release/server"]
```
### Systemd Service
```ini
[Unit]
Description=My Rust Application
After=network.target
[Service]
Type=simple
User=myapp
WorkingDirectory=/opt/myapp
Environment=ROOT_PATH=/opt/myapp
Environment=ENVIRONMENT=production
ExecStart=/opt/myapp/target/release/server
Restart=always
[Install]
WantedBy=multi-user.target
```
## Directory Structure
### Recommended Layout
```
ROOT_PATH/
├── config.toml
├── config.dev.toml
├── config.prod.toml
├── target/
│ └── release/
│ └── server
├── public/ # Static assets
├── content/ # Content files
├── uploads/ # User uploads
├── logs/ # Application logs
├── cache/ # Temporary cache
├── data/ # Application data
├── backups/ # Backup files
└── certs/ # TLS certificates
├── server.crt
└── server.key
```
## API Reference
### Config Methods
#### `get_absolute_path(relative_path: &str) -> Result<String, ConfigError>`
Converts a relative path to an absolute path using the configured `ROOT_PATH`.
```rust
use server::config::Config;
let config = Config::load()?;
let absolute_path = config.get_absolute_path("uploads/images")?;
println!("Absolute path: {}", absolute_path);
// Output: /app/uploads/images
```
### Environment Variables
| Variable | Description | Default |
|----------|-------------|---------|
| `ROOT_PATH` | Base directory for path resolution | Current directory |
| `CONFIG_FILE` | Explicit path to config file | Auto-discovered |
| `ENVIRONMENT` | Runtime environment | `development` |
## Migration Guide
### Converting Hardcoded Paths
#### Before (Hardcoded)
```rust
// Don't do this
let config_path = "../../../config.toml";
let content_path = "../../content/menu.toml";
```
#### After (ROOT_PATH)
```rust
// Do this instead
let config = Config::load()?;
let uploads_path = config.get_absolute_path("uploads")?;
let content_path = config.get_absolute_path("content/menu.toml")?;
```
### Content Loading
#### Before
```rust
// Hardcoded relative path
let content = include_str!("../../content/menu.toml");
```
#### After
```rust
// Dynamic path resolution
use shared::get_content_path;
let menu_path = get_content_path("menu.toml")?;
let content = std::fs::read_to_string(menu_path)?;
```
## Best Practices
### 1. Use Environment Variables in Production
```bash
# Production
export ROOT_PATH=/opt/myapp
export ENVIRONMENT=production
export DATABASE_URL=postgresql://...
```
### 2. Keep Config Files Portable
```toml
# Use relative paths in config files
[server_dirs]
public_dir = "public" # Good
# public_dir = "/var/www" # Avoid hardcoded absolute paths
```
### 3. Document Your Directory Structure
```toml
# config.toml
# Directory structure:
# ROOT_PATH/
# ├── public/ -> static assets
# ├── uploads/ -> user uploads
# ├── logs/ -> application logs
# └── data/ -> application data
[server_dirs]
public_dir = "public"
uploads_dir = "uploads"
logs_dir = "logs"
data_dir = "data"
```
### 4. Use Consistent Naming
```toml
# Consistent directory naming
[server_dirs]
public_dir = "public" # Not "static" or "assets"
uploads_dir = "uploads" # Not "files" or "media"
logs_dir = "logs" # Not "log" or "logging"
```
## Troubleshooting
### Common Issues
#### 1. Path Not Found
```
Error: Root path '/invalid/path' does not exist
```
**Solution**: Ensure the `ROOT_PATH` directory exists and is accessible.
#### 2. Permission Denied
```
Error: Directory creation error: Permission denied
```
**Solution**: Check file permissions and ensure the application has write access.
#### 3. Config File Not Found
```
Error: Configuration file 'config.toml' not found
```
**Solution**: Ensure the config file exists in the `ROOT_PATH` directory.
### Debug Commands
```bash
# Check current configuration
cargo run --bin config_tool -- show
# Validate configuration
cargo run --bin config_tool -- validate
# Generate new config
cargo run --bin config_tool -- generate dev
```
## Testing
### Unit Tests
```rust
#[test]
fn test_path_resolution() {
use std::env;
// Set test ROOT_PATH
env::set_var("ROOT_PATH", "/tmp/test");
let config = Config::load().unwrap();
let absolute_path = config.get_absolute_path("uploads").unwrap();
assert!(absolute_path.starts_with("/tmp/test"));
assert!(absolute_path.ends_with("uploads"));
}
```
### Integration Tests
```bash
# Test with different ROOT_PATH values
ROOT_PATH=/tmp/test1 cargo test
ROOT_PATH=/var/tmp/test2 cargo test
```
## Security Considerations
1. **Path Traversal**: The system prevents `../` attacks by resolving paths properly
2. **Permissions**: Ensure the `ROOT_PATH` directory has appropriate permissions
3. **Validation**: All paths are validated before use
4. **Sandboxing**: Consider using chroot or containers for additional security
## Performance
- Path resolution is performed once at startup
- Resolved paths are cached in the configuration
- No runtime overhead for path lookups
- Canonical path resolution may involve filesystem access
## Related Documentation
- [Configuration Guide](./CONFIGURATION.md)
- [Deployment Guide](./DEPLOYMENT.md)
- [Environment Variables](./ENVIRONMENT.md)
- [Directory Structure](./DIRECTORY_STRUCTURE.md)