- Avoid unnecessary
clone()calls - prefer borrowing with&Tor&mut T - Use
&strinstead ofStringin function parameters unless ownership is required - Only clone
Arc<T>when spawning new tasks - Arc cloning is cheap but still unnecessary if not spawning PgPoolis already Arc-based internally - never clone it, just use&pool- Preallocate
Veccapacity withVec::with_capacity(n)when size is known - Use iterator adapters (
.map(),.filter(), etc.) instead of manual loops where possible - Prefer
&[T]over&Vec<T>in function parameters - Use
Cow<str>when you might need to own or borrow strings conditionally - Avoid
to_string()andto_owned()unless actually transferring ownership - Use
query_asorquery_as!for type-safe database queries - Batch database operations - avoid N+1 queries by using
ANY($1)orINclauses - Use database transactions for multi-step operations that must be atomic
- Return
Result<T, E>instead of unwrapping - never panic in production code - Use
async moveblocks only when necessary - prefer borrowing in async functions
src/main.rs- Application entry point, sets up Axum server and database poolsrc/i18n.rs- Global i18n translation service (singleton pattern)src/jobs.rs- Background job scheduler using tokio taskssrc/types/- Shared request/response DTOs and domain typessrc/tests/- Unit tests organized by module (e.g.,i18n.rs,base.rs)src/routes/- HTTP route handlers (handlers only, no type definitions)migrations/- SQLx database migrationsJobStatestruct contains shared application state (database pool)- Wrap
JobStateinArc<JobState>for sharing across async tasks - Job scheduler spawns independent tokio tasks for each scheduled job
- Each job is a function returning
JobFuture(pinned boxed future) - Jobs share state via
Arc<JobState>- clone the Arc when spawning, not the pool
- All request/response structs live in
src/types/, not in the code files files - Organized by domain:
i18n.rs,base.rs, etc. mod.rsre-exports all types for easy importing:use crate::types::*;- Each file uses section comments for clarity:
- Request Types (structs with
Deserialize) - Response Types (structs with
Serialize) - Internal Types (DB row structs, helpers)
- Request Types (structs with
- Unit tests live in
src/tests/, not inline in route files - One test file per module:
i18n.rs,base.rs - Use
#[cfg(test)]wrapper for all test code - Group related tests in submodules:
mod types { ... } - Import types via
crate::types::*
- Contain only handler functions, no struct definitions
- Import types from
crate::types::{...} - Keep handlers thin: validate → delegate → respond
- Structure: Locate domain models and their
implblocks insrc/types/(e.g.,user.rs). - Logic: Use associated functions (
::) for queries/constructors and instance methods (.) for operations on specific records. - State: Pass
&PgPoolexplicitly as a parameter; never rely on global database state. - Mapping: Implement
to_responsemethods within the model to handle DTO transformations. - Encapsulation: Keep all SQL logic and business rules for a type within its dedicated file.
- Clippy lints are enforced:
correctnessandsuspiciousare denied,perfandstyleare warnings - Cognitive complexity threshold: 15
- Max function arguments: 5 (use structs for more)
- Max function lines: 100
- Document public APIs with
///doc comments - Include
# Errorsand# Panicssections in documentation where applicable - Use
#[must_use]for functions whose return value should not be ignored - Prefer explicit types over
_in public APIs - Use
thiserroror similar for custom error types - Do not use static strings, use the i18n system instead
- Use
#[sqlx::test]for database tests - provides isolated test database - Use
#[tokio::test]for async tests - Tests live in
src/tests/with one file per module - Group related tests in submodules:
mod types { },mod handlers { } - Clean up test data or use transactions that rollback
- Test error cases, not just happy paths
- Use
Result<(), Error>return type in tests for cleaner error propagation
- Use Tailwind classes for styling
- Use
useMainStore()for global state management - Use Shadcn UI for components (shad-vue)
- All ShadCN components are prefixed with
Shad, e.g.,ShadButtonorShadSelect, they are auto injected - Use the store.getTranslation() function for translations, always use them, no static strings
- Use customizable Tailwind classes like bg-primary, text-primary, etc. and not use fixed colors
- Always use parameterized queries (
$1,$2) to prevent SQL injection - Never use
unwrap()orexpect()in production code paths - Job scheduler runs indefinitely - ensure jobs handle errors gracefully
- Database URL must be set in
.envfile asDATABASE_URL - Migrations run automatically on startup
- Keep the code as simple as possible so beginners can also understand it
- Do not add comments to the code itself
- When writing axum routes, please use the response "module" to create responses
- NO SQL statements in route handlers, please add a function to the specific type's module for database operations (check if a smilar function already exists)
- Update this file when adding new modules or restructuring code
- Update when introducing new shared state patterns
- Update when adding performance-critical patterns
- Update when changing error handling strategies
- Update when modifying the job scheduler or testing approach