This is a Rust web service using Actix-web with async/await and SQLx for database access. All code must compile without warnings. Clippy must pass with no exceptions. Production code must never panic. Test code may panic only in test assertions.
- File names:
snake_case.rsonly. NocamelCaseorPascalCasefiles. - Module names:
snake_casematching file names exactly. - Public struct names:
PascalCase. Private struct names:snake_casewith leading underscore if unused. - Function names:
snake_casefor all functions, including async handlers. - Constant names:
SCREAMING_SNAKE_CASEfor module-level constants only. - Type parameters: Single uppercase letter (
T,E) or descriptivePascalCase(Handler,Request). - Lifetime parameters:
'a,'b,'staticonly. Never'lifetime_name. - Error enum variants:
PascalCasewithErrorsuffix on enum name (e.g.,ValidationError::InvalidEmail).
- Never use
astype assertions in non-test code. UseTryFrom,TryInto, or type guards instead. - Never use
_as a catch-all type. Explicitly name all types in function signatures. - Generic bounds must be on the function signature, never in the function body.
- All public function parameters must have explicit types. No type inference for public APIs.
- Return types must be explicit for all public functions. Use
-> Result<T, E>not-> impl Future.
- Run
cargo fmtbefore every commit. Non-formatted code is rejected. - Run
cargo clippy -- -D warningsand fix all warnings. No#[allow(...)]without justification in a comment. - Line length: 100 characters maximum. Break long lines at logical boundaries.
- Imports: Group in three sections (std, external crates, internal modules) separated by blank lines.
- No trailing whitespace. No multiple blank lines in sequence.
src/
main.rs # Entry point only. Calls run() from lib.rs
lib.rs # Public API exports and run() function
config.rs # Configuration loading and validation
error.rs # AppError enum and error handling utilities
handlers/
mod.rs # Handler module exports
health.rs # Health check endpoints
users.rs # User-related endpoints
items.rs # Item-related endpoints
models/
mod.rs # Model exports
user.rs # User struct and validation
item.rs # Item struct and validation
db/
mod.rs # Database module exports
pool.rs # Connection pool initialization
queries.rs # Raw SQL query functions
migrations.rs # Migration runner
middleware/
mod.rs # Middleware exports
auth.rs # Authentication middleware
logging.rs # Request logging middleware
utils/
mod.rs # Utility exports
validation.rs # Input validation functions
crypto.rs # Hashing and encryption utilities
tests/
integration/
mod.rs
health_test.rs
users_test.rs
- Every
mod.rsmust explicitly re-export public items:pub use self::submodule::*; - Never use glob imports in public APIs. Always name specific imports.
- Private modules use
mod submodule;withoutpub. - Public modules use
pub mod submodule;only if re-exporting frommod.rs.
Cargo.toml: Pinned versions for all dependencies. No wildcard versions (*)..env.example: Template with all required variables. No actual secrets.CLAUDE.md: This ruleset. Must be kept in sync with actual rules.
- All fallible operations return
Result<T, AppError>. AppErrorenum must have variants for:Database,Validation,NotFound,Unauthorized,Internal.- Each variant must include a
Stringmessage field and optionalsource: Box<dyn std::error::Error>. - Never use
.unwrap(),.expect(), or.panic!()in non-test code. Use?operator instead. - Every
Resultfrom external crates must be mapped toAppErrorat the boundary:.map_err(|e| AppError::Database(e.to_string()))? - Error responses must use
actix_web::error::ErrorResponsewith appropriate HTTP status codes. - Validation errors return
400 Bad Request. Database errors return500 Internal Server Error. Missing resources return404 Not Found.
- All I/O operations must use async/await. No blocking calls in async context.
- Database queries must use
sqlx::query!(compile-time checked) orsqlx::query_as!, neversqlx::query(). - Connection pool must be created once in
main()and passed viaweb::Data<PgPool>. - Tokio tasks spawned with
tokio::spawn()must have explicitSend + Syncbounds if capturing variables. - Never use
std::thread::spawn(). Usetokio::task::spawn_blocking()for CPU-bound work only. - Timeouts must be explicit: wrap all external calls with
tokio::time::timeout(Duration::from_secs(N), future).
- All handlers must be
async fnwith signature:async fn handler_name(req: web::Json<Request>, pool: web::Data<PgPool>) -> Result<web::Json<Response>, AppError> - Handlers must validate input immediately: call
validate_request(&req)?before any business logic. - Handlers must return
web::Json<T>for success, never rawT. - Handlers must never directly access database. Call functions from
db::queriesmodule. - Handlers must log all errors before returning:
log::error!("Handler failed: {}", err);
- All SQL queries must be in
db/queries.rsas standalone functions. - Query functions must accept
&PgPoolas first parameter. - Query functions must return
Result<T, AppError>withAppError::Databaseon failure. - Use
sqlx::query!for all queries. Compile-time checking is mandatory. - Migrations must be in
db/migrations/directory as numbered SQL files:001_initial_schema.sql. - Run migrations on startup in
main()before starting the server. - No raw SQL strings in handler code. All queries must be abstracted to
db/queries.rs.
- All user input must be validated in
utils/validation.rsfunctions. - Validation functions must return
Result<(), String>with descriptive error messages. - Call validation functions in handlers before any database operations.
- Validation must check: type correctness, length bounds, format (email, URL, etc.), and business rules.
- Never trust
Content-Typeheaders. Validate actual data structure.
- Load configuration from environment variables in
config.rsusingstd::env::var(). - Configuration struct must implement
Debugbut never print secrets. - Secrets (database passwords, API keys) must never be logged or included in error messages.
- Configuration must be validated on startup. Missing required variables must cause immediate panic in
main()only. - Use
.envfile for local development only. Never commit.envto version control.
- Authentication middleware must extract and validate JWT tokens from
Authorization: Bearer <token>header. - Middleware must return
401 Unauthorizedfor missing or invalid tokens. - Logging middleware must log: method, path, status code, and duration. Never log request/response bodies.
- Middleware must not modify request/response bodies. Use extractors for data access.
- All password hashing must use
argon2crate with default parameters. - Never store plaintext passwords. Hash on creation and verify on login.
- All external API calls must validate SSL certificates. Never use
danger_accept_invalid_certs(). - SQL injection prevention: use parameterized queries only.
sqlx::query!enforces this. - CORS headers must be explicitly configured. Never use
Access-Control-Allow-Origin: *in production. - Rate limiting must be implemented for authentication endpoints: max 5 attempts per minute per IP.
- Integration tests in
tests/integration/directory only. - Unit tests in same file as code with
#[cfg(test)]module at end of file. - Test file names:
{module}_test.rsfor integration tests,testsmodule for unit tests. - Test function names:
test_{scenario}_{expected_outcome}(e.g.,test_create_user_returns_201).
- Every public function must have at least one happy-path test and one error-case test.
- Database tests must use a test database with migrations run before each test.
- Handlers must be tested with
actix_web::test::TestServeroractix_web::test::call_service(). - Mock external services using
mockitocrate. Never make real HTTP calls in tests. - Tests must be deterministic. No random data without seeding. No time-dependent assertions.
- All tests must complete in under 5 seconds. Slow tests must be marked
#[ignore].
- Use
assert_eq!()for equality checks, neverassert!(a == b). - Use
assert!(condition, "message")for boolean checks with descriptive messages. - Use
Result::expect()in tests only:result.expect("test setup failed"). - Test error cases explicitly:
assert!(result.is_err(), "expected error"). - Never use
.unwrap()in test setup. Use.expect()with descriptive message instead.
- Create fixtures in
tests/fixtures/directory as JSON or SQL files. - Use builder pattern for complex test objects:
UserBuilder::new().with_email("test@example.com").build(). - Test database must be isolated per test. Use transactions that rollback after each test.
- Never commit test data with real user information. Use placeholder values only.
Source: Codelibrium — the marketplace for AI behaviour files. Browse multiple rulesets at codelibrium.com or install via CLI:
npx codelibrium-cli install <ruleset-name>