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
+16 -39
View File
@@ -19,11 +19,10 @@
use std::path::Path;
use anyhow::Result;
use super::app_config::AppConfig;
use super::conversation::Conversation;
use super::edit_log::{EditLog, EditLogEntry};
use super::error::RepositoryError;
use super::memory::Memory;
use super::settings::Settings;
@@ -32,14 +31,10 @@ use super::settings::Settings;
/// Implementors provide the actual I/O logic (e.g. file-based JSON storage).
pub trait SettingsRepository {
/// Load `Settings` from the given base directory.
///
/// Flow: read and deserialize `settings.json` from `base_dir`.
fn load(&self, base_dir: &Path) -> Result<Settings>;
fn load(&self, base_dir: &Path) -> Result<Settings, RepositoryError>;
/// Persist `Settings` to the given base directory.
///
/// Flow: serialize and write `settings.json` to `base_dir`.
fn save(&self, base_dir: &Path, settings: &Settings) -> Result<()>;
fn save(&self, base_dir: &Path, settings: &Settings) -> Result<(), RepositoryError>;
}
/// Persistence contract for `AppConfig` (provider and model configuration).
@@ -47,14 +42,10 @@ pub trait SettingsRepository {
/// Implementors provide the actual I/O logic (e.g. file-based JSON storage).
pub trait AppConfigRepository {
/// Load `AppConfig` from the given base directory.
///
/// Flow: read and deserialize `app_config.json` from `base_dir`.
fn load(&self, base_dir: &Path) -> Result<AppConfig>;
fn load(&self, base_dir: &Path) -> Result<AppConfig, RepositoryError>;
/// Persist `AppConfig` to the given base directory.
///
/// Flow: serialize and write `app_config.json` to `base_dir`.
fn save(&self, base_dir: &Path, config: &AppConfig) -> Result<()>;
fn save(&self, base_dir: &Path, config: &AppConfig) -> Result<(), RepositoryError>;
}
/// Persistence contract for `Conversation` (session conversation data).
@@ -62,14 +53,10 @@ pub trait AppConfigRepository {
/// Implementors provide the actual I/O logic (e.g. file-based JSON storage).
pub trait ConversationRepository {
/// Load a `Conversation` from the given session directory.
///
/// Flow: read and deserialize `conversation.json` from `session_dir`.
fn load(&self, session_dir: &Path) -> Result<Conversation>;
fn load(&self, session_dir: &Path) -> Result<Conversation, RepositoryError>;
/// Persist a `Conversation` to the given session directory.
///
/// Flow: serialize and write `conversation.json` to `session_dir`.
fn save(&self, session_dir: &Path, conversation: &Conversation) -> Result<()>;
fn save(&self, session_dir: &Path, conversation: &Conversation) -> Result<(), RepositoryError>;
}
/// Persistence contract for `Memory` (long-term agent memory entries).
@@ -77,16 +64,16 @@ pub trait ConversationRepository {
/// Implementors provide the actual I/O logic (e.g. per-memory markdown files).
pub trait MemoryRepository {
/// List all memory slugs (filenames without extension) in the memory directory.
fn list(&self, memory_dir: &Path) -> Result<Vec<String>>;
fn list(&self, memory_dir: &Path) -> Result<Vec<String>, RepositoryError>;
/// Load a single `Memory` by name from the memory directory.
fn load(&self, memory_dir: &Path, name: &str) -> Result<Memory>;
fn load(&self, memory_dir: &Path, name: &str) -> Result<Memory, RepositoryError>;
/// Save (create or overwrite) a `Memory` in the memory directory.
fn save(&self, memory_dir: &Path, memory: &Memory) -> Result<()>;
fn save(&self, memory_dir: &Path, memory: &Memory) -> Result<(), RepositoryError>;
/// Delete a `Memory` by name from the memory directory.
fn delete(&self, memory_dir: &Path, name: &str) -> Result<()>;
fn delete(&self, memory_dir: &Path, name: &str) -> Result<(), RepositoryError>;
}
/// Persistence contract for rewind-snapshot binary blobs.
@@ -95,25 +82,19 @@ pub trait MemoryRepository {
/// within a session. They capture file snapshots for the "rewind" feature.
pub trait RewindBlobRepository {
/// Store (or overwrite) a binary blob under `blob_key` for this session.
///
/// ## Parameters
/// - `session_dir` — the session directory to store the blob in
/// - `blob_key` — arbitrary caller-supplied key (e.g. tool-call ID)
/// - `data` — raw byte content of the blob
/// - `mime_type` — optional MIME type hint
fn store_blob(
&self,
session_dir: &Path,
blob_key: &str,
data: &[u8],
mime_type: Option<&str>,
) -> anyhow::Result<()>;
) -> Result<(), RepositoryError>;
/// Retrieve a blob's raw bytes by key, or `None` if not found.
fn retrieve_blob(&self, session_dir: &Path, blob_key: &str) -> anyhow::Result<Option<Vec<u8>>>;
fn retrieve_blob(&self, session_dir: &Path, blob_key: &str) -> Result<Option<Vec<u8>>, RepositoryError>;
/// List all blob keys for this session, ordered oldest-first.
fn list_blob_keys(&self, session_dir: &Path) -> anyhow::Result<Vec<String>>;
fn list_blob_keys(&self, session_dir: &Path) -> Result<Vec<String>, RepositoryError>;
}
/// Persistence contract for `EditLog` (append-only file mutation log).
@@ -122,14 +103,10 @@ pub trait RewindBlobRepository {
/// typically persisted to a file for audit and potential undo.
pub trait EditLogRepository {
/// Open (or initialise) the edit log for a session directory.
///
/// Flow: load existing log file if present, or create an empty log.
fn open(&self, session_dir: &Path) -> Result<EditLog>;
fn open(&self, session_dir: &Path) -> Result<EditLog, RepositoryError>;
/// Append one entry to the log and persist immediately (write-through).
///
/// Flow: push entry to in-memory log → append to disk file.
fn append(&self, session_dir: &Path, log: &mut EditLog, entry: EditLogEntry) -> Result<()>;
fn append(&self, session_dir: &Path, log: &mut EditLog, entry: EditLogEntry) -> Result<(), RepositoryError>;
/// Return a cloned copy of all in-memory entries for inspection.
fn entries(&self, log: &EditLog) -> Vec<EditLogEntry>;