torrust_tracker_deployer_lib/application/command_handlers/create/mod.rs
1//! Create Command Module
2//!
3//! This module implements the delivery-agnostic `CreateCommandHandler` for orchestrating
4//! environment creation business logic. The command is synchronous and follows
5//! existing patterns from `ProvisionCommandHandler`.
6//!
7//! ## Architecture
8//!
9//! The `CreateCommandHandler` implements the Command Pattern and uses Dependency Injection
10//! to interact with infrastructure services through interfaces:
11//!
12//! - **Repository Pattern**: Persists environment state via `EnvironmentRepository`
13//! - **Clock Abstraction**: Provides deterministic time for testing via `Clock` trait
14//! - **Domain-Driven Design**: Uses domain objects from `domain::environment`
15//!
16//! ## Design Principles
17//!
18//! - **Delivery-Agnostic**: Works with CLI, REST API, or any delivery mechanism
19//! - **Synchronous**: Follows existing patterns (no async/await)
20//! - **Repository Responsibility**: Lets repository handle directory creation atomically
21//! - **Explicit Errors**: All errors implement `.help()` with actionable guidance
22//!
23//! ## Usage Example
24//!
25//! ```rust,no_run
26//! use std::sync::Arc;
27//! use torrust_tracker_deployer_lib::application::command_handlers::create::CreateCommandHandler;
28//! use torrust_tracker_deployer_lib::application::command_handlers::create::config::{
29//! EnvironmentCreationConfig, EnvironmentSection, LxdProviderSection, ProviderSection,
30//! SshCredentialsConfig,
31//! };
32//! use torrust_tracker_deployer_lib::application::command_handlers::create::config::tracker::TrackerSection;
33//! use torrust_tracker_deployer_lib::infrastructure::persistence::file_repository_factory::FileRepositoryFactory;
34//! use torrust_tracker_deployer_lib::shared::{SystemClock, Clock};
35//!
36//! // Setup dependencies
37//! let file_repository_factory = FileRepositoryFactory::new(std::time::Duration::from_secs(30));
38//! let repository = file_repository_factory.create(std::path::PathBuf::from("."));
39//! let clock: Arc<dyn Clock> = Arc::new(SystemClock);
40//!
41//! // Create command
42//! let command = CreateCommandHandler::new(repository, clock);
43//!
44//! // Prepare configuration
45//! let config = EnvironmentCreationConfig::new(
46//! EnvironmentSection {
47//! name: "production".to_string(),
48//! description: None,
49//! instance_name: None, // Auto-generate from environment name
50//! },
51//! SshCredentialsConfig::new(
52//! "keys/prod_key".to_string(),
53//! "keys/prod_key.pub".to_string(),
54//! "torrust".to_string(),
55//! 22,
56//! ),
57//! ProviderSection::Lxd(LxdProviderSection {
58//! profile_name: "lxd-production".to_string(),
59//! }),
60//! TrackerSection::default(),
61//! None, // prometheus
62//! None, // grafana
63//! None, // https
64//! None, // backup
65//! );
66//!
67//! // Execute command with working directory
68//! let working_dir = std::path::Path::new(".");
69//! match command.execute(config, working_dir) {
70//! Ok(environment) => {
71//! println!("Created environment: {}", environment.name());
72//! }
73//! Err(error) => {
74//! eprintln!("Error: {}", error);
75//! eprintln!("\n{}", error.help());
76//! }
77//! }
78//! ```
79
80pub mod config;
81pub mod errors;
82pub mod handler;
83pub mod schema;
84
85#[cfg(test)]
86mod tests;
87
88// Re-export main types for convenience
89pub use errors::CreateCommandHandlerError;
90pub use handler::CreateCommandHandler;