//! Shared domain error types for the entire domain layer. //! //! Provides [`DomainError`] — a unified repository-level error enum used //! by both the `auth` and `cms` modules (type-aliased as `RepositoryError` //! in each module). This avoids a dependency on `thiserror` while still //! giving callers distinct error variants to match on. //! //! # Flow //! //! Infrastructure adapters convert their native errors (I/O, serde, etc.) //! into `DomainError` via `From` impls. Domain service layers wrap //! `DomainError` in their own `ServiceError` enum via `From`. //! //! # Components //! //! - `DomainError` — 6 variants: `NotFound`, `Conflict`, `Io`, `Serde`, //! `InvalidId`, `Other` //! - `From` — converts I/O errors //! - `From` — converts serialisation errors use std::fmt; /// Unified repository-level error for domain operations. /// /// Covers the common failure modes across all persistence adapters: /// missing entities, conflicts, I/O failures, serialization errors, /// invalid identifiers, and a catch-all `Other` variant. #[derive(Debug)] pub enum DomainError { /// The requested entity was not found. NotFound(String), /// An operation failed due to a conflict (e.g. duplicate key). Conflict(String), /// An I/O error occurred during persistence. Io(std::io::Error), /// A serialization / deserialization error occurred. Serde(String), /// An identifier was rejected as invalid (e.g. path traversal). InvalidId(String), /// A generic / uncategorised error. Other(String), } impl fmt::Display for DomainError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { DomainError::NotFound(msg) => write!(f, "not found: {msg}"), DomainError::Conflict(msg) => write!(f, "conflict: {msg}"), DomainError::Io(err) => write!(f, "I/O error: {err}"), DomainError::Serde(msg) => write!(f, "serialization error: {msg}"), DomainError::InvalidId(msg) => write!(f, "invalid id: {msg}"), DomainError::Other(msg) => write!(f, "{msg}"), } } } impl std::error::Error for DomainError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { DomainError::Io(err) => Some(err), _ => None, } } } impl From for DomainError { fn from(err: std::io::Error) -> Self { DomainError::Io(err) } } impl From for DomainError { fn from(err: serde_json::Error) -> Self { DomainError::Serde(err.to_string()) } }