Refactor error handling in IAM and CMS crates

- Introduced `RepositoryError` and `ServiceError` enums in both IAM and CMS domains for better error management.
- Updated domain traits and services to return specific error types instead of `anyhow::Result`.
- Enhanced session and OAuth repository implementations to handle errors more explicitly.
- Refactored session service methods to return `Result<T, ServiceError>` for improved error handling.
- Updated HTTP handlers to utilize the new error types.
- Modified password hashing functions to run in a blocking context using `tokio::task::spawn_blocking`.
- Added tests for new error handling mechanisms and async password functions.
This commit is contained in:
asepharyana
2026-07-20 06:14:23 +07:00
parent 5aaedbf787
commit ab1a54b72e
47 changed files with 630 additions and 347 deletions
@@ -12,10 +12,10 @@
use std::path::PathBuf;
use anyhow::{Context, Result};
use tracing;
use crate::domain::conversation::{ChatMessage, Conversation};
use crate::domain::error::ServiceError;
use crate::domain::repository::ConversationRepository;
use crate::domain::service::ConversationService;
@@ -59,25 +59,27 @@ impl<R: ConversationRepository> ConversationService for ConversationServiceImpl<
/// Load a conversation from disk for the given session.
///
/// Flow: resolve session dir → delegate to repo.load() → wrap error with context.
fn load_conversation(&self, session_id: &str) -> Result<Conversation> {
fn load_conversation(&self, session_id: &str) -> Result<Conversation, ServiceError> {
tracing::debug!("loading conversation for session {session_id}");
let dir = self.session_dir(session_id);
self.repo
.load(&dir)
.with_context(|| format!("failed to load conversation for session '{session_id}'"))
self.repo.load(&dir).map_err(|e| {
ServiceError::Other(format!(
"failed to load conversation for session '{session_id}': {e}"
))
})
}
/// Persist a conversation to disk.
///
/// Flow: resolve session dir from conv.session_id → delegate to repo.save() → wrap error.
fn save_conversation(&self, conv: &Conversation) -> Result<()> {
fn save_conversation(&self, conv: &Conversation) -> Result<(), ServiceError> {
tracing::debug!("saving conversation for session {}", conv.session_id);
let dir = self.session_dir(&conv.session_id);
self.repo.save(&dir, conv).with_context(|| {
format!(
"failed to save conversation for session '{}'",
self.repo.save(&dir, conv).map_err(|e| {
ServiceError::Other(format!(
"failed to save conversation for session '{}': {e}",
conv.session_id
)
))
})
}
@@ -88,15 +90,15 @@ impl<R: ConversationRepository> ConversationService for ConversationServiceImpl<
/// ## Note
/// This is a write-through operation: the message is appended to the
/// in-memory `Conversation` and then the full conversation is persisted.
fn add_message(&self, conv: &mut Conversation, msg: ChatMessage) -> Result<()> {
fn add_message(&self, conv: &mut Conversation, msg: ChatMessage) -> Result<(), ServiceError> {
tracing::debug!("adding message to session {}", conv.session_id);
conv.push(msg); // append message to in-memory conversation
let dir = self.session_dir(&conv.session_id);
self.repo.save(&dir, conv).with_context(|| {
format!(
"failed to persist conversation after adding message for session '{}'",
self.repo.save(&dir, conv).map_err(|e| {
ServiceError::Other(format!(
"failed to persist conversation after adding message for session '{}': {e}",
conv.session_id
)
))
})
}
}