title: Navius Architectural Principles description: Core architectural principles and patterns guiding the design of the Navius framework category: reference tags:
- architecture
- design
- principles
- patterns related:
- directory-organization.md
- ../../guides/development/project-navigation.md
- ../standards/naming-conventions.md last_updated: March 27, 2025 version: 1.0
Navius Architectural Principles
Overview
This reference document outlines the core architectural principles and design patterns that guide the development of the Navius framework. These principles ensure the framework remains maintainable, extensible, and performant as it evolves.
Core Principles
1. Modular Design
Navius is built around a modular architecture that separates concerns and enables components to evolve independently.
Key aspects:
- Self-contained modules with clearly defined responsibilities
- Minimal dependencies between modules
- Ability to replace or upgrade individual components without affecting others
- Configuration-driven composition of modules
2. Explicit Over Implicit
Navius favors explicit, clear code over "magic" behavior or hidden conventions.
Key aspects:
- Explicit type declarations and function signatures
- Clear error handling paths
- Minimal use of macros except for well-defined, documented purposes
- No "convention over configuration" that hides important behavior
3. Compile-Time Safety
Navius leverages Rust's type system to catch errors at compile time rather than runtime.
Key aspects:
- Strong typing for all API interfaces
- Use of enums for representing states and variants
- Avoiding dynamic typing except when necessary for interoperability
- Proper error type design for comprehensive error handling
4. Performance First
Performance is a primary design goal, not an afterthought.
Key aspects:
- Minimal runtime overhead
- Efficient memory usage
- Asynchronous by default
- Careful consideration of allocations and copying
- Benchmarking as part of the development process
5. Developer Experience
The framework prioritizes developer experience and productivity.
Key aspects:
- Intuitive API design
- Comprehensive documentation
- Helpful error messages
- Testing utilities and patterns
- Minimal boilerplate code
Architectural Patterns
Clean Architecture
Navius follows a modified Clean Architecture pattern with distinct layers:
┌─────────────────┐
│ Controllers │
│ (HTTP Layer) │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Services │
│ (Business Logic)│
└────────┬────────┘
│
▼
┌─────────────────┐
│ Repositories │
│ (Data Access) │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Data Store │
│ (DB, Cache, etc)│
└─────────────────┘
Principles applied:
- Dependencies point inward
- Inner layers know nothing about outer layers
- Domain models are independent of persistence models
- Business logic is isolated from I/O concerns
Dependency Injection
Navius uses a trait-based dependency injection pattern to enable testability and flexibility:
#![allow(unused)] fn main() { // Define a service that depends on a repository trait pub struct UserService<R: UserRepository> { repository: R, } impl<R: UserRepository> UserService<R> { pub fn new(repository: R) -> Self { Self { repository } } pub async fn get_user(&self, id: Uuid) -> Result<User, Error> { self.repository.find_by_id(id).await } } // In production code let db_repository = PostgresUserRepository::new(db_pool); let service = UserService::new(db_repository); // In test code let mock_repository = MockUserRepository::new(); let service = UserService::new(mock_repository); }
Error Handling
Navius uses a centralized error handling approach:
#![allow(unused)] fn main() { // Core error type pub enum AppError { NotFound, Unauthorized, BadRequest(String), Validation(Vec<ValidationError>), Internal(anyhow::Error), } // Converting from domain errors impl From<DatabaseError> for AppError { fn from(error: DatabaseError) -> Self { match error { DatabaseError::NotFound => AppError::NotFound, DatabaseError::ConnectionFailed(e) => AppError::Internal(e.into()), // Other conversions... } } } // Converting to HTTP responses impl IntoResponse for AppError { fn into_response(self) -> Response { let (status, error_message) = match self { AppError::NotFound => (StatusCode::NOT_FOUND, "Resource not found"), AppError::Unauthorized => (StatusCode::UNAUTHORIZED, "Unauthorized"), // Other mappings... }; // Create response (status, Json(ErrorResponse { message: error_message.to_string() })).into_response() } } }
Middleware Pipeline
Navius uses a middleware-based pipeline for processing HTTP requests:
#![allow(unused)] fn main() { let app = Router::new() .route("/api/users", get(list_users).post(create_user)) .layer(TracingLayer::new_for_http()) .layer(CorsLayer::permissive()) .layer(AuthenticationLayer::new()) .layer(CompressionLayer::new()) .layer(TimeoutLayer::new(Duration::from_secs(30))); }
Configuration Management
Navius uses a layered configuration system:
- Default values
- Configuration files
- Environment variables
- Command-line arguments
This ensures flexibility while maintaining sensible defaults:
#![allow(unused)] fn main() { // Configuration loading order let config = ConfigBuilder::new() .add_defaults() .add_file("config/default.toml") .add_file(format!("config/{}.toml", environment)) .add_environment_variables() .add_command_line_args() .build()?; }
API Design Principles
Resource-Oriented
APIs are structured around resources and their representations.
Consistent Error Handling
A standardized error response format is used across all API endpoints.
Proper HTTP Method Usage
HTTP methods match their semantic meaning (GET, POST, PUT, DELETE, etc.).
Versioning Support
APIs support versioning to maintain backward compatibility.
Database Access Principles
Repository Pattern
Data access is encapsulated behind repository interfaces.
Transaction Management
Explicit transaction boundaries with proper error handling.
Migration-Based Schema Evolution
Database schemas evolve through explicit migrations.
Testing Principles
Test Pyramid
Balance between unit, integration, and end-to-end tests.
Test Isolation
Tests should not depend on each other or external state.
Mocking External Dependencies
External dependencies are mocked for deterministic testing.
Related Documents
- Directory Organization - Detailed directory structure
- Project Navigation - Navigating the project
- Naming Conventions - Naming conventions reference