mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-02-15 10:53:18 +08:00
Commands enhanced with multi-language support, error recovery strategies, and structured step-by-step workflows: - build-fix: build system detection table, fix loop, recovery strategies - test-coverage: framework detection, test generation rules, before/after report - refactor-clean: safety tiers (SAFE/CAUTION/DANGER), multi-language tools - update-codemaps: codemap format spec, diff detection, metadata headers - update-docs: source-of-truth mapping, staleness checks, generated markers New example: - rust-api-CLAUDE.md: Axum + SQLx + PostgreSQL with layered architecture, thiserror patterns, compile-time SQL verification, integration test examples
8.0 KiB
8.0 KiB
Rust API Service — Project CLAUDE.md
Real-world example for a Rust API service with Axum, PostgreSQL, and Docker. Copy this to your project root and customize for your service.
Project Overview
Stack: Rust 1.78+, Axum (web framework), SQLx (async database), PostgreSQL, Tokio (async runtime), Docker
Architecture: Layered architecture with handler → service → repository separation. Axum for HTTP, SQLx for type-checked SQL at compile time, Tower middleware for cross-cutting concerns.
Critical Rules
Rust Conventions
- Use
thiserrorfor library errors,anyhowonly in binary crates or tests - No
.unwrap()or.expect()in production code — propagate errors with? - Prefer
&stroverStringin function parameters; returnStringwhen ownership transfers - Use
clippywith#![deny(clippy::all, clippy::pedantic)]— fix all warnings - Derive
Debugon all public types; deriveClone,PartialEqonly when needed - No
unsafeblocks unless justified with a// SAFETY:comment
Database
- All queries use SQLx
query!orquery_as!macros — compile-time verified against the schema - Migrations in
migrations/usingsqlx migrate— never alter the database directly - Use
sqlx::Pool<Postgres>as shared state — never create connections per request - All queries use parameterized placeholders (
$1,$2) — never string formatting
// BAD: String interpolation (SQL injection risk)
let q = format!("SELECT * FROM users WHERE id = '{}'", id);
// GOOD: Parameterized query, compile-time checked
let user = sqlx::query_as!(User, "SELECT * FROM users WHERE id = $1", id)
.fetch_optional(&pool)
.await?;
Error Handling
- Define a domain error enum per module with
thiserror - Map errors to HTTP responses via
IntoResponse— never expose internal details - Use
tracingfor structured logging — neverprintln!oreprintln!
use thiserror::Error;
#[derive(Debug, Error)]
pub enum AppError {
#[error("Resource not found")]
NotFound,
#[error("Validation failed: {0}")]
Validation(String),
#[error("Unauthorized")]
Unauthorized,
#[error(transparent)]
Internal(#[from] anyhow::Error),
}
impl IntoResponse for AppError {
fn into_response(self) -> Response {
let (status, message) = match &self {
Self::NotFound => (StatusCode::NOT_FOUND, self.to_string()),
Self::Validation(msg) => (StatusCode::BAD_REQUEST, msg.clone()),
Self::Unauthorized => (StatusCode::UNAUTHORIZED, self.to_string()),
Self::Internal(err) => {
tracing::error!(?err, "internal error");
(StatusCode::INTERNAL_SERVER_ERROR, "Internal error".into())
}
};
(status, Json(json!({ "error": message }))).into_response()
}
}
Testing
- Unit tests in
#[cfg(test)]modules within each source file - Integration tests in
tests/directory using a real PostgreSQL (Testcontainers or Docker) - Use
#[sqlx::test]for database tests with automatic migration and rollback - Mock external services with
mockallorwiremock
Code Style
- Max line length: 100 characters (enforced by rustfmt)
- Group imports:
std, external crates,crate/super— separated by blank lines - Modules: one file per module,
mod.rsonly for re-exports - Types: PascalCase, functions/variables: snake_case, constants: UPPER_SNAKE_CASE
File Structure
src/
main.rs # Entrypoint, server setup, graceful shutdown
lib.rs # Re-exports for integration tests
config.rs # Environment config with envy or figment
router.rs # Axum router with all routes
middleware/
auth.rs # JWT extraction and validation
logging.rs # Request/response tracing
handlers/
mod.rs # Route handlers (thin — delegate to services)
users.rs
orders.rs
services/
mod.rs # Business logic
users.rs
orders.rs
repositories/
mod.rs # Database access (SQLx queries)
users.rs
orders.rs
domain/
mod.rs # Domain types, error enums
user.rs
order.rs
migrations/
001_create_users.sql
002_create_orders.sql
tests/
common/mod.rs # Shared test helpers, test server setup
api_users.rs # Integration tests for user endpoints
api_orders.rs # Integration tests for order endpoints
Key Patterns
Handler (Thin)
async fn create_user(
State(ctx): State<AppState>,
Json(payload): Json<CreateUserRequest>,
) -> Result<(StatusCode, Json<UserResponse>), AppError> {
let user = ctx.user_service.create(payload).await?;
Ok((StatusCode::CREATED, Json(UserResponse::from(user))))
}
Service (Business Logic)
impl UserService {
pub async fn create(&self, req: CreateUserRequest) -> Result<User, AppError> {
if self.repo.find_by_email(&req.email).await?.is_some() {
return Err(AppError::Validation("Email already registered".into()));
}
let password_hash = hash_password(&req.password)?;
let user = self.repo.insert(&req.email, &req.name, &password_hash).await?;
Ok(user)
}
}
Repository (Data Access)
impl UserRepository {
pub async fn find_by_email(&self, email: &str) -> Result<Option<User>, sqlx::Error> {
sqlx::query_as!(User, "SELECT * FROM users WHERE email = $1", email)
.fetch_optional(&self.pool)
.await
}
pub async fn insert(
&self,
email: &str,
name: &str,
password_hash: &str,
) -> Result<User, sqlx::Error> {
sqlx::query_as!(
User,
r#"INSERT INTO users (email, name, password_hash)
VALUES ($1, $2, $3) RETURNING *"#,
email, name, password_hash,
)
.fetch_one(&self.pool)
.await
}
}
Integration Test
#[tokio::test]
async fn test_create_user() {
let app = spawn_test_app().await;
let response = app
.client
.post(&format!("{}/api/v1/users", app.address))
.json(&json!({
"email": "alice@example.com",
"name": "Alice",
"password": "securepassword123"
}))
.send()
.await
.expect("Failed to send request");
assert_eq!(response.status(), StatusCode::CREATED);
let body: serde_json::Value = response.json().await.unwrap();
assert_eq!(body["email"], "alice@example.com");
}
#[tokio::test]
async fn test_create_user_duplicate_email() {
let app = spawn_test_app().await;
// Create first user
create_test_user(&app, "alice@example.com").await;
// Attempt duplicate
let response = create_user_request(&app, "alice@example.com").await;
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
}
Environment Variables
# Server
HOST=0.0.0.0
PORT=8080
RUST_LOG=info,tower_http=debug
# Database
DATABASE_URL=postgres://user:pass@localhost:5432/myapp
# Auth
JWT_SECRET=your-secret-key-min-32-chars
JWT_EXPIRY_HOURS=24
# Optional
CORS_ALLOWED_ORIGINS=http://localhost:3000
Testing Strategy
# Run all tests
cargo test
# Run with output
cargo test -- --nocapture
# Run specific test module
cargo test api_users
# Check coverage (requires cargo-llvm-cov)
cargo llvm-cov --html
open target/llvm-cov/html/index.html
# Lint
cargo clippy -- -D warnings
# Format check
cargo fmt -- --check
ECC Workflow
# Planning
/plan "Add order fulfillment with Stripe payment"
# Development with TDD
/tdd # cargo test-based TDD workflow
# Review
/code-review # Rust-specific code review
/security-scan # Dependency audit + unsafe scan
# Verification
/verify # Build, clippy, test, security scan
Git Workflow
feat:new features,fix:bug fixes,refactor:code changes- Feature branches from
main, PRs required - CI:
cargo fmt --check,cargo clippy,cargo test,cargo audit - Deploy: Docker multi-stage build with
scratchordistrolessbase