Files
sta/backend/src/presentation/mod.rs

106 lines
3.7 KiB
Rust
Raw Normal View History

//! Presentation layer - API contracts and DTOs
//!
//! This module defines data transfer objects (DTOs) and API request/response types
//! that form the public API contract. It translates between domain types and wire
//! formats (JSON) for HTTP communication.
//!
//! # Current Status
//!
//! **Currently unused** - API handlers are currently in [`crate::route`] module using
//! legacy structure. This module is prepared for future migration to proper hexagonal
//! architecture with clear presentation layer separation.
//!
//! # Architecture Principles
//!
//! - **API-first design**: Define contracts before implementation
//! - **DTO pattern**: Separate domain entities from API representations
//! - **Validation at boundary**: Parse and validate input before domain layer
//! - **OpenAPI integration**: Generate documentation from code
//!
//! # Planned Submodules
//!
//! ## `dto` - Data Transfer Objects
//!
//! - `relay_dto`: RelayResponse, RelayStatusResponse, BulkControlRequest
//! - `label_dto`: UpdateLabelRequest, LabelResponse
//! - `health_dto`: HealthResponse, DeviceStatusResponse
//! - `error_dto`: ApiError, ValidationError (user-facing errors)
//!
//! ## `mapper` - Domain ↔ DTO Conversions
//!
//! - `relay_mapper`: Convert between Relay entity and RelayResponse
//! - `error_mapper`: Translate domain errors to HTTP status codes
//!
//! ## `validator` - Input Validation
//!
//! - Request validation before domain layer
//! - Parse DTOs into domain types (parse, don't validate principle)
//!
//! # DTO Design Pattern
//!
//! DTOs are separate from domain types to:
//! 1. **Prevent domain leakage**: Domain types stay internal
//! 2. **Enable versioning**: API can evolve without changing domain
//! 3. **Control serialization**: Explicit JSON representation
//! 4. **Validate at boundary**: Convert raw input to validated domain types
//!
//! # Example DTO Structure
//!
//! ```rust,ignore
//! /// API response for relay status
//! #[derive(Serialize, Deserialize, Object)]
//! pub struct RelayResponse {
//! /// Relay ID (1-8)
//! pub id: u8,
//! /// Current state ("on" or "off")
//! pub state: String,
//! /// Optional custom label
//! pub label: Option<String>,
//! }
//!
//! impl From<Relay> for RelayResponse {
//! fn from(relay: Relay) -> Self {
//! Self {
//! id: relay.id().value(),
//! state: relay.state().to_string(),
//! label: relay.label().map(|l| l.to_string()),
//! }
//! }
//! }
//!
//! impl TryFrom<RelayResponse> for Relay {
//! type Error = ValidationError;
//!
//! fn try_from(dto: RelayResponse) -> Result<Self, Self::Error> {
//! let id = RelayId::new(dto.id)?;
//! let state = RelayState::from_str(&dto.state)?;
//! let label = dto.label.map(RelayLabel::new).transpose()?;
//! Ok(Relay::new(id, state).with_label(label))
//! }
//! }
//! ```
//!
//! # Migration Plan
//!
//! Current API in [`crate::route`] will be migrated to this layer:
//! 1. Define DTOs for all API endpoints
//! 2. Implement domain <20> DTO mappers
//! 3. Move API handlers to use DTOs
//! 4. Generate OpenAPI specs from DTOs
//! 5. Remove direct domain type exposure
//!
//! # References
//!
//! - Architecture: `specs/constitution.md` - API-First Design principle
//! - API design: `specs/001-modbus-relay-control/plan.md` - Presentation layer tasks
//! - Domain types: [`crate::domain`] - Types to be wrapped in DTOs
/// Data Transfer Objects (DTOs) for API responses.
///
/// This module contains DTO structures that are used to serialize domain
/// objects for API responses, providing a clean separation between internal
/// domain models and external API contracts.
pub mod api;
pub mod dto;
pub mod error;