# {{TOOL_NAME}} Architecture Complete system design and component documentation. ## High-Level Overview {{TOOL_NAME}} is a production-grade tool implementing a **3-tier architecture**: ``` ┌─────────────────────────────────────────────┐ │ Tier 3: CLI / User Interface │ │ crates/{{tool_name_kebab}}-cli/ │ │ - clap command parsing │ │ - Configuration discovery │ │ - User-friendly output │ └─────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ Tier 2: REST API (optional) │ │ crates/{{tool_name_kebab}}-api/ │ │ - axum HTTP server │ │ - JSON request/response │ │ - RESTful endpoints │ └─────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ Tier 1: Core Library │ │ crates/{{tool_name_kebab}}-core/ │ │ - Business logic │ │ - Domain types │ │ - Service layer │ │ - Error handling │ │ - Data persistence │ └─────────────────────────────────────────────┘ ``` ## Tier 1: Core Library **Location**: `crates/{{tool_name_kebab}}-core/` **Purpose**: Reusable, interface-agnostic business logic ### Components #### Error Handling **File**: `src/error.rs` Canonical error struct pattern: ```rust pub struct {{ToolName}}Error { pub kind: {{ToolName}}ErrorKind, pub context: String, pub source: Option>, pub backtrace: Backtrace, } ``` **Error Types** (customize for your domain): - `ConfigError` - Configuration issues - `ValidationError` - Input validation - `IoError` - File I/O failures - `DatabaseError` - Database operations - Custom domain errors as needed **Usage**: ```rust fn operation() -> Result { if condition { return Err({{ToolName}}Error::new( {{ToolName}}ErrorKind::ValidationError("message".into()), "context about what failed", )); } Ok(value) } ``` #### Domain Types **File**: `src/types.rs` Primary domain type and related structures: ```rust pub struct {{MainType}} { pub id: String, // UUID v4 pub name: String, // Human-readable name pub description: String, // Details pub metadata: serde_json::Value, // Extensibility pub created_at: DateTime, // Creation timestamp pub updated_at: DateTime, // Last modification } ``` **Additional Types**: - Enums for status, priority, categories - Configuration structures (serde + validation) - Query filters and responses - Transfer objects for APIs #### Service Layer **File**: `src/handlers/service.rs` Business logic implementation: ```rust pub struct {{MainType}}Service { items: Arc>>, } impl {{MainType}}Service { pub async fn create(...) -> Result<{{MainType}}> pub async fn get(&self, id: &str) -> Result<{{MainType}}> pub async fn list(&self) -> Result> pub async fn update(...) -> Result<{{MainType}}> pub async fn delete(&self, id: &str) -> Result<()> } ``` **Storage Options**: - **In-memory** (template default) - Dev/testing only - **SQLite** - Single-user, embedded - **PostgreSQL** - Production, concurrent access - **Custom** - Implement `Storage` trait **Pattern**: Async/await with tokio for all I/O operations #### Module Organization ``` src/ ├── lib.rs # Exports and documentation ├── error.rs # {{ToolName}}Error, {{ToolName}}ErrorKind ├── types.rs # {{MainType}} and related types └── handlers/ ├── mod.rs # Module organization └── service.rs # {{MainType}}Service, business logic ``` ### Testing **Unit Tests** (in each module file): ```rust #[cfg(test)] mod tests { #[tokio::test] async fn test_create() { ... } } ``` **Integration Tests** (`tests/` directory): ``` tests/ ├── common/ │ └── mod.rs # Shared test utilities └── integration_test.rs ``` **Requirements**: - Minimum 15 tests per module - Test success paths - Test error paths - Test edge cases - All tests must pass before commit ## Tier 2: REST API (Optional) **Location**: `crates/{{tool_name_kebab}}-api/` **Purpose**: HTTP interface to core library ### Components #### Web Server **Framework**: axum (Rust async web framework) ```rust #[tokio::main] async fn main() -> Result<()> { let app = Router::new() .route("/health", get(health_check)) .route("/{{main_type_plural}}", get(list).post(create)) .route("/{{main_type_plural}}/:id", get(get_one).put(update).delete(delete)) .with_state(Arc::new(state)); axum::serve(listener, app).await?; Ok(()) } ``` #### Request/Response Types **Request** (input from client): ```rust #[derive(Deserialize)] struct CreateRequest { name: String, description: String, } ``` **Response** (output to client): ```rust #[derive(Serialize)] struct {{MainType}}Response { id: String, name: String, created_at: DateTime, } ``` #### Endpoints Standard CRUD with HTTP semantics: | Method | Path | Description | Status | |--------|------|-------------|--------| | GET | `/health` | Health check | 200 OK | | GET | `/{{main_type_plural}}` | List all | 200 OK | | GET | `/{{main_type_plural}}/:id` | Get one | 200 OK or 404 | | POST | `/{{main_type_plural}}` | Create | 201 Created | | PUT | `/{{main_type_plural}}/:id` | Update | 200 OK or 404 | | DELETE | `/{{main_type_plural}}/:id` | Delete | 204 No Content or 404 | #### Error Handling Structured error responses: ```json { "error": "Validation error", "details": "Name is required", "code": "VALIDATION_ERROR" } ``` ### Deployment **Local Development**: ```bash cargo run -p {{tool_name_kebab}}-api # Server on http://127.0.0.1:3000 ``` **Production**: ```bash cargo build -p {{tool_name_kebab}}-api --release ./target/release/{{tool_name_kebab}}-api ``` **Docker**: ```dockerfile FROM rust:latest as builder WORKDIR /app COPY . . RUN cargo build --release FROM debian:bookworm-slim COPY --from=builder /app/target/release/{{tool_name_kebab}}-api /usr/bin/ ENTRYPOINT ["{{tool_name_kebab}}-api"] ``` ## Tier 3: CLI **Location**: `crates/{{tool_name_kebab}}-cli/` **Purpose**: User-friendly command-line interface ### Components #### Command Parser **Framework**: clap (derive macros for CLI parsing) ```rust #[derive(Parser)] #[command(name = "{{tool_name_kebab}}")] #[command(about = "{{TOOL_NAME}} - {{SHORT_DESCRIPTION}}")] struct Cli { #[arg(short, long)] config: Option, #[arg(short, long, global = true)] verbose: bool, #[command(subcommand)] command: Commands, } ``` #### Configuration Discovery **Implementation**: tools-shared library ```rust use tools_shared::find_config_path; let config_path = find_config_path("{{tool_name_kebab}}.toml") .unwrap_or_else(|| PathBuf::from(".project/{{tool_name_kebab}}.toml")); ``` **Search Order**: 1. `.project/{{tool_name_kebab}}.toml` - Tools ecosystem 2. `.vapora/{{tool_name_kebab}}.toml` - VAPORA projects 3. `.coder/{{tool_name_kebab}}.toml` - Doc tracking 4. `./{{tool_name_kebab}}.toml` - Current directory **Help Text**: ``` CONFIGURATION SEARCH: Looks for config in order (uses first found): 1. .project/{{tool_name_kebab}}.toml 2. .vapora/{{tool_name_kebab}}.toml 3. .coder/{{tool_name_kebab}}.toml 4. ./{{tool_name_kebab}}.toml ``` #### Commands Organized into subcommands: ```rust #[derive(Subcommand)] enum Commands { /// List items List { #[arg(short, long)] filter: Option, #[arg(short, long, default_value = "20")] limit: usize, }, /// Show summary Summary { #[arg(short, long)] group_by: Option, }, /// Create new item Create { name: String, #[arg(short, long)] description: Option, }, /// Show version Version, } ``` #### Logging Structured logging with tracing: ```rust // Initialize let log_level = if cli.verbose { "debug" } else { "info" }; tracing_subscriber::fmt() .with_env_filter(log_level) .init(); // Usage tracing::info!("Starting operation"); tracing::debug!("Debug info"); tracing::warn!("Warning message"); tracing::error!("Error occurred"); ``` ### Data Flow ``` User runs command ↓ clap parses arguments ↓ Config discovery (tools-shared) ↓ Load configuration (serde + TOML) ↓ Validate configuration ↓ Initialize service from core library ↓ Execute command (call service method) ↓ Format output (JSON, table, text) ↓ Display to user ``` ## Configuration System ### Configuration File (TOML) **Structure**: ```toml [{{tool_name_kebab}}] # Main settings setting1 = "value1" setting2 = 42 enable_feature = true [{{tool_name_kebab}}.advanced] # Advanced options max_items = 1000 timeout_seconds = 30 [database] # If using database type = "sqlite" path = ".project/{{tool_name_kebab}}.db" ``` ### Configuration Validation In CLI before execution: ```rust fn validate_config(config: &Config) -> Result<()> { if config.name.is_empty() { return Err(ConfigError::EmptyName); } if config.timeout < 0 { return Err(ConfigError::InvalidTimeout); } Ok(()) } ``` ### Environment Variable Overrides Support ENV vars for key settings: ```bash export {{TOOL_NAME}}_SETTING1=value1 export {{TOOL_NAME}}_TIMEOUT=60 {{tool_name_kebab}} list # Uses ENV values if set, otherwise config file ``` ## Data Persistence ### Storage Interface ```rust pub trait Storage { async fn create(&mut self, item: {{MainType}}) -> Result<()>; async fn get(&self, id: &str) -> Result<{{MainType}}>; async fn list(&self) -> Result async fn update(&mut self, item: {{MainType}}) -> Result<()>; async fn delete(&mut self, id: &str) -> Result<()>; } ``` ### Storage Implementations **In-Memory** (template default): - Fast for development - Data lost on restart - Thread-safe with Arc> **SQLite**: - File-based, embedded - Good for single-user tools - Use sqlx with async **PostgreSQL**: - Server-based - Multiple concurrent users - Use sqlx with connection pooling ## Error Propagation ``` Tier 3 (CLI) ↓ catches Tier 2 (API) ↓ catches Tier 1 (Core) ↓ propagates Result ↓ back up Format for user/response ``` ## Testing Strategy ### Unit Tests (Tier 1) - Test each service method - Mock storage - Test error conditions - Minimum 15 tests ### Integration Tests - Test with real storage - Test full workflows - Test configuration loading - Test CLI argument parsing ### End-to-End Tests - Test complete user workflows - Test all commands - Test error scenarios - Test configuration discovery ## Performance Considerations ### Optimization Points - Configuration caching - Lazy loading of items - Database connection pooling - Async/await for all I/O ### Bottlenecks to Avoid - Synchronous blocking I/O - Loading all items in memory - Repeated configuration parsing - Unnecessary cloning ### Monitoring - Structured logging (tracing) - Performance metrics - Error tracking - Resource usage ## Security Considerations ### Input Validation - Validate all user input - Sanitize configuration values - Validate file paths - Check for path traversal ### Error Handling - Don't expose internal paths - Don't leak sensitive data - Provide helpful error messages - Log with appropriate levels ### Dependencies - Audit external crates (cargo audit) - Keep dependencies updated - Minimize external unsafe code - Pin versions in production ## Extension Points ### Adding New Commands 1. Add variant to Commands enum 2. Implement handler 3. Add tests 4. Update help text 5. Update documentation ### Adding New Service Methods 1. Implement in {{MainType}}Service 2. Add error handling 3. Add tests (success and error paths) 4. Update documentation 5. Expose in CLI or API ### Adding New Storage Backend 1. Implement Storage trait 2. Add configuration option 3. Add feature flag 4. Add tests 5. Update documentation ## Deployment Checklist - ✅ All tests pass (cargo test --workspace) - ✅ No clippy warnings (cargo clippy) - ✅ Code formatted (cargo fmt) - ✅ No vulnerabilities (cargo audit) - ✅ Documentation complete - ✅ Help text clear and accurate - ✅ Configuration discoverable - ✅ Error messages helpful ## References - **Complete README**: [README.md](README.md) - **Quick Start**: [QUICKSTART.md](QUICKSTART.md) - **Configuration Guide**: [configuration.md](configuration.md) - **Code**: `crates/{{tool_name_kebab}}-*/src/`