//! Infrastructure layer - External integrations and adapters //! //! This module implements the technical infrastructure required by the application, //! including external system integrations, persistence, and communication protocols. //! All infrastructure depends on domain/application layers through trait implementations. //! //! # Architecture Principles //! //! - **Implements domain traits**: Provides concrete implementations of domain interfaces //! - **Depends inward**: Depends on domain/application, never the reverse //! - **Substitutable**: Different implementations can be swapped without changing domain //! - **Framework-specific**: Contains framework and library dependencies (Modbus, SQLx, etc.) //! //! # Planned Submodules //! //! ## `modbus` - Modbus RTU over TCP Integration //! //! - `client`: ModbusRelayController implementation using tokio-modbus //! - `mock`: MockRelayController for testing without hardware //! - `config`: Modbus connection configuration //! - `connection`: Connection pool and health management //! //! Implements: [`domain::relay::controller::RelayController`](crate::domain) //! //! ## `persistence` - SQLite Database with SQLx //! //! - `sqlite_repository`: SqliteRelayLabelRepository implementation //! - `schema.sql`: Database schema with relay_labels table //! - `migrations`: Database migration scripts (if using sqlx-cli) //! //! Implements: [`domain::relay::repository::RelayLabelRepository`](crate::domain) //! //! # Technology Stack //! //! - **Modbus**: `tokio-modbus` 0.17.0 for async Modbus RTU over TCP //! - **Persistence**: `sqlx` 0.8 for compile-time verified SQLite queries //! - **Async Runtime**: `tokio` 1.48 (shared with main application) //! - **Testing**: `mockall` 0.13 for mock implementations //! //! # Implementation Pattern //! //! Each infrastructure adapter: //! 1. Implements domain-defined trait (e.g., `RelayController`) //! 2. Translates domain types to/from external formats //! 3. Handles connection management and retries //! 4. Provides error translation (external errors → domain errors) //! //! # Example: Modbus Controller //! //! ```rust,ignore //! pub struct ModbusRelayController { //! client: Arc>, //! config: ModbusConfig, //! } //! //! #[async_trait] //! impl RelayController for ModbusRelayController { //! async fn read_relay_state(&self, id: RelayId) -> Result { //! let address = self.config.base_address + id.value() as u16; //! let mut client = self.client.lock().await; //! //! // Read coil from Modbus device //! let result = client.read_coils(address, 1).await //! .map_err(|e| ControllerError::CommunicationError(e.to_string()))?; //! //! // Translate to domain type //! Ok(if result[0] { RelayState::On } else { RelayState::Off }) //! } //! } //! ``` //! //! # References //! //! - Architecture: `specs/constitution.md` - Dependency Inversion Principle //! - Implementation: `specs/001-modbus-relay-control/plan.md` - Infrastructure tasks //! - Modbus docs: `docs/Modbus_POE_ETH_Relay.md` - Hardware protocol specification