Quantum/CONTRIBUTING.md
RTSDA 85a4115a71 🚀 Initial release: Quantum Web Server v0.2.0
 Features:
• HTTP/1.1, HTTP/2, and HTTP/3 support with proper architecture
• Reverse proxy with advanced load balancing (round-robin, least-conn, etc.)
• Static file serving with content-type detection and security
• Revolutionary file sync system with WebSocket real-time updates
• Enterprise-grade health monitoring (active/passive checks)
• TLS/HTTPS with ACME/Let's Encrypt integration
• Dead simple JSON configuration + full Caddy v2 compatibility
• Comprehensive test suite (72 tests passing)

🏗️ Architecture:
• Rust-powered async performance with zero-cost abstractions
• HTTP/3 as first-class citizen with shared routing core
• Memory-safe design with input validation throughout
• Modular structure for easy extension and maintenance

📊 Status: 95% production-ready
🧪 Test Coverage: 72/72 tests passing (100% success rate)
🔒 Security: Memory safety + input validation + secure defaults

Built with ❤️ in Rust - Start simple, scale to enterprise!
2025-08-17 17:08:49 -04:00

489 lines
12 KiB
Markdown

# Contributing to Caddy-RS
Thank you for your interest in contributing to Caddy-RS! This document provides guidelines and information for contributors.
## Table of Contents
- [Code of Conduct](#code-of-conduct)
- [How to Contribute](#how-to-contribute)
- [Development Setup](#development-setup)
- [Making Changes](#making-changes)
- [Pull Request Process](#pull-request-process)
- [Coding Standards](#coding-standards)
- [Testing Guidelines](#testing-guidelines)
- [Documentation](#documentation)
- [Issue Reporting](#issue-reporting)
## Code of Conduct
This project adheres to a code of conduct adapted from the [Contributor Covenant](https://www.contributor-covenant.org/). By participating, you are expected to uphold this code.
### Our Pledge
- **Be welcoming and inclusive** to all contributors regardless of experience level
- **Be respectful** in all communications and code reviews
- **Be constructive** when providing feedback
- **Focus on what is best** for the community and the project
## How to Contribute
There are many ways to contribute to Caddy-RS:
### Types of Contributions
1. **Bug Reports**: Help identify and fix issues
2. **Feature Requests**: Suggest new functionality
3. **Code Contributions**: Implement features, fix bugs, improve performance
4. **Documentation**: Improve or add documentation
5. **Testing**: Write tests, perform manual testing
6. **Performance**: Optimize code, identify bottlenecks
7. **Security**: Identify and fix security issues
### Getting Started
1. **Look for good first issues**: Check issues labeled `good-first-issue` or `help-wanted`
2. **Check existing issues**: Avoid duplicate work by checking existing issues and PRs
3. **Join discussions**: Participate in issue discussions to understand requirements
4. **Start small**: Begin with small contributions to understand the codebase
## Development Setup
### Prerequisites
- Rust 1.75+ with 2024 edition support
- Git
- A code editor (VS Code with rust-analyzer recommended)
### Setup Steps
1. **Fork the repository** on GitHub
2. **Clone your fork**:
```bash
git clone https://github.com/your-username/caddy-rs.git
cd caddy-rs
```
3. **Add upstream remote**:
```bash
git remote add upstream https://github.com/original-owner/caddy-rs.git
```
4. **Install dependencies and build**:
```bash
cargo build
cargo test
```
### Development Tools
Install these tools for better development experience:
```bash
cargo install cargo-watch # Auto-reload during development
cargo install cargo-edit # Easy dependency management
cargo install cargo-audit # Security vulnerability scanning
cargo install cargo-tarpaulin # Code coverage
```
## Making Changes
### Before You Start
1. **Create an issue** if one doesn't exist for your change
2. **Discuss the approach** in the issue before implementing
3. **Check for existing work** to avoid duplication
### Development Workflow
1. **Create a feature branch**:
```bash
git checkout -b feature/your-feature-name
```
2. **Make your changes**:
- Follow the [coding standards](#coding-standards)
- Write tests for new functionality
- Update documentation as needed
3. **Test your changes**:
```bash
cargo test # Run all tests
cargo clippy -- -D warnings # Check for linting issues
cargo fmt # Format code
```
4. **Commit your changes**:
```bash
git add .
git commit -m "feat: add new feature description"
```
### Commit Message Convention
We use conventional commits for clear, semantic commit messages:
```
<type>(<scope>): <description>
[optional body]
[optional footer]
```
**Types:**
- `feat`: New feature
- `fix`: Bug fix
- `docs`: Documentation changes
- `style`: Code style changes (formatting, etc.)
- `refactor`: Code refactoring
- `test`: Adding or updating tests
- `chore`: Maintenance tasks
**Examples:**
```
feat(proxy): add health check support
fix(config): handle missing configuration file gracefully
docs(api): update reverse proxy configuration examples
test(middleware): add unit tests for CORS middleware
```
## Pull Request Process
### Before Submitting
Ensure your PR meets these criteria:
- [ ] **Tests pass**: `cargo test`
- [ ] **Code is formatted**: `cargo fmt`
- [ ] **No linting warnings**: `cargo clippy -- -D warnings`
- [ ] **Documentation updated**: If you changed APIs or added features
- [ ] **Changelog updated**: Add entry to `CHANGELOG.md` if needed
- [ ] **Performance impact considered**: No significant performance regression
### Submitting the PR
1. **Push to your fork**:
```bash
git push origin feature/your-feature-name
```
2. **Create pull request** on GitHub with:
- **Clear title** describing the change
- **Detailed description** explaining what and why
- **Reference to related issues** using `#issue-number`
- **Testing instructions** for reviewers
- **Screenshots or examples** if UI-related
### PR Review Process
1. **Automated checks** will run (tests, linting, etc.)
2. **Code review** by maintainers and other contributors
3. **Address feedback** by making additional commits
4. **Final approval** and merge by maintainers
### Review Guidelines for Contributors
When reviewing others' PRs:
- **Be kind and constructive** in feedback
- **Focus on the code**, not the person
- **Explain your suggestions** with reasoning
- **Approve when ready** or request changes with specific feedback
- **Test the changes** if possible
## Coding Standards
### Rust Style Guidelines
Follow standard Rust conventions:
```rust
// Use snake_case for functions and variables
fn handle_request() -> Result<()> { }
let response_body = String::new();
// Use PascalCase for types and traits
struct ProxyService;
trait Middleware;
enum HandlerType;
// Use SCREAMING_SNAKE_CASE for constants
const MAX_RETRY_COUNT: u32 = 3;
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
```
### Code Organization
```rust
// Order imports logically
use std::collections::HashMap;
use std::time::Duration;
use anyhow::Result;
use serde::{Deserialize, Serialize};
use tokio::net::TcpListener;
use crate::config::Config;
use crate::proxy::ProxyService;
// Group related functionality
impl ProxyService {
// Public methods first
pub async fn new(config: Config) -> Result<Self> { }
pub async fn handle_request(&self) -> Result<()> { }
// Private methods last
async fn select_upstream(&self) -> Result<()> { }
}
```
### Error Handling
Use `Result` types consistently:
```rust
use anyhow::{Context, Result};
// Good: Propagate errors with context
pub async fn load_config(path: &str) -> Result<Config> {
let content = tokio::fs::read_to_string(path)
.await
.context("Failed to read configuration file")?;
let config = serde_json::from_str(&content)
.context("Failed to parse configuration")?;
Ok(config)
}
// Avoid: Unwrapping or ignoring errors
let config = serde_json::from_str(&content).unwrap(); // Don't do this
```
### Async Code
Follow async best practices:
```rust
// Good: Use async/await throughout
pub async fn proxy_request(&self, req: Request) -> Result<Response> {
let upstream = self.select_upstream().await?;
let response = self.client.request(upstream, req).await?;
Ok(response)
}
// Avoid: Blocking calls in async context
std::thread::sleep(Duration::from_secs(1)); // Don't do this
tokio::time::sleep(Duration::from_secs(1)).await; // Do this instead
```
### Documentation
Document public APIs:
```rust
/// Selects an upstream server using the configured load balancing algorithm.
///
/// This method applies the load balancing policy to choose from available
/// upstream servers. It considers server health and current load when making
/// the selection.
///
/// # Arguments
///
/// * `upstreams` - A slice of available upstream servers
/// * `policy` - The load balancing policy to apply
///
/// # Returns
///
/// Returns a reference to the selected upstream server, or an error if
/// no healthy upstreams are available.
///
/// # Examples
///
/// ```rust
/// let upstream = load_balancer.select_upstream(&upstreams, &policy)?;
/// println!("Selected: {}", upstream.dial);
/// ```
pub fn select_upstream<'a>(
&self,
upstreams: &'a [Upstream],
policy: &LoadBalancingPolicy,
) -> Result<&'a Upstream> {
// Implementation
}
```
## Testing Guidelines
### Test Categories
1. **Unit Tests**: Test individual functions and modules
2. **Integration Tests**: Test component interactions
3. **End-to-End Tests**: Test complete workflows
### Unit Test Examples
```rust
#[cfg(test)]
mod tests {
use super::*;
use tokio_test;
#[tokio::test]
async fn test_round_robin_selection() {
let load_balancer = LoadBalancer::new();
let upstreams = vec![
Upstream { dial: "backend1:8080".to_string() },
Upstream { dial: "backend2:8080".to_string() },
];
let policy = LoadBalancingPolicy::RoundRobin;
let first = load_balancer.select_upstream(&upstreams, &policy).unwrap();
let second = load_balancer.select_upstream(&upstreams, &policy).unwrap();
assert_ne!(first.dial, second.dial);
}
#[test]
fn test_config_parsing() {
let config_json = r#"
{
"listen": [":8080"],
"routes": []
}
"#;
let config: ServerConfig = serde_json::from_str(config_json).unwrap();
assert_eq!(config.listen, vec![":8080"]);
}
}
```
### Testing Async Code
```rust
#[tokio::test]
async fn test_async_function() {
let service = ProxyService::new(test_config()).await.unwrap();
let request = test_request();
let response = service.handle_request(request).await;
assert!(response.is_ok());
}
```
### Test Organization
- Place unit tests in the same file using `#[cfg(test)]`
- Place integration tests in separate files in `tests/` directory
- Use descriptive test names that explain what is being tested
- Group related tests in modules
## Documentation
### Types of Documentation
1. **Code Documentation**: Rustdoc comments in source code
2. **API Documentation**: Configuration and usage reference
3. **Architecture Documentation**: System design and decisions
4. **User Documentation**: README, getting started guides
### Documentation Standards
- **Keep examples up to date** with the current API
- **Include error cases** in documentation
- **Use clear, concise language**
- **Provide complete examples** that work without modification
### Updating Documentation
When making changes, update relevant documentation:
- **Rustdoc comments** for new or changed APIs
- **API documentation** in `docs/api.md` for configuration changes
- **README.md** for new features or usage changes
- **Architecture documentation** for design changes
## Issue Reporting
### Before Reporting
1. **Search existing issues** to avoid duplicates
2. **Check the documentation** to ensure it's actually a bug
3. **Try the latest version** to see if it's already fixed
### Bug Reports
Include this information in bug reports:
```markdown
## Bug Description
A clear description of what the bug is.
## Steps to Reproduce
1. Create config file with...
2. Run caddy-rs with...
3. Send request to...
4. See error
## Expected Behavior
What you expected to happen.
## Actual Behavior
What actually happened.
## Environment
- OS: (e.g., Ubuntu 20.04)
- Rust version: (e.g., 1.75.0)
- Caddy-RS version: (e.g., 0.1.0)
## Configuration
```json
{
"your": "configuration",
"file": "here"
}
```
## Logs
```
Relevant log output here
```
```
### Feature Requests
Structure feature requests like this:
```markdown
## Feature Description
A clear description of the feature you'd like to see.
## Use Case
Describe the problem this feature would solve.
## Proposed Solution
Your ideas for how this could be implemented.
## Alternatives
Other ways this problem could be solved.
## Additional Context
Any other context, screenshots, or examples.
```
## Questions and Support
- **Check the documentation** first (README, docs/, etc.)
- **Search existing issues** for similar questions
- **Create a new issue** with the "question" label
- **Be specific** about what you're trying to achieve
## License
By contributing to Caddy-RS, you agree that your contributions will be licensed under the same license as the project (Apache License 2.0).
## Recognition
Contributors will be recognized in the project README and release notes. Significant contributors may be invited to become project maintainers.
Thank you for contributing to Caddy-RS! 🦀