refactor: migrate monolithic crate to Cargo Workspace with Clean Architecture

Transform the single binary crate into a 9-crate workspace monorepo:

- Root Cargo.toml as [workspace] manager with resolver = "2"
- zesdex-entities: Domain entity types (session, settings, store, message, etc.)
- zesdex-utils: Pure utility functions (error, logger, pagination, slug, clipboard)
- zesdex-dto: Data Transfer Objects for LLM provider API communication
- zesdex-ipc: Unix-socket IPC layer (client/server/framing/protocol)
- zesdex-iam: Identity & Access Management (Clean Architecture: domain/application/infrastructure)
- zesdex-cms: Content Management (Clean Architecture: domain/application/infrastructure)
- zesdex-middleware: HTTP middleware (Auth, CORS, Rate Limiting)
- zesdex-libs: Composition root (AppContext, DB init, JWT, Argon2)
- zesdex-backend: Main binary entry point + seed/migrate binaries
- DevOps: Dockerfile, docker-compose, Nix (flake/shell/default), CI/CD updates
- Remove dead root src/ and src-misc/ directories

All crate re-exports maintain backward compatibility with original
crate::model::*, crate::dto::*, crate::ipc::* module paths.
Feature crates enforce strict layer separation: domain -> application
-> infrastructure with generic trait-based dependency injection.
This commit is contained in:
asepharyana
2026-07-17 09:08:41 +07:00
parent 86cc412395
commit be0a9582bb
248 changed files with 7901 additions and 1505 deletions
@@ -0,0 +1,66 @@
#![allow(
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
clippy::cast_precision_loss,
clippy::cast_possible_wrap
)]
//! Session management use-cases.
//!
//! `SessionServiceImpl` implements `SessionService` by delegating to
//! injected repository implementations, keeping the orchestration logic
//! independent of any concrete persistence mechanism.
use std::path::PathBuf;
use uuid::Uuid;
use crate::domain::repository::{SessionLockRepository, SessionRepository};
use crate::domain::service::SessionService;
use crate::domain::session::Session;
/// Concrete session service backed by generic repository implementations.
pub struct SessionServiceImpl<R: SessionRepository, L: SessionLockRepository> {
pub session_repo: R,
pub lock_repo: L,
pub base_dir: PathBuf,
}
impl<R: SessionRepository, L: SessionLockRepository> SessionServiceImpl<R, L> {
/// Create a new session service with the given repositories and base
/// data directory.
pub fn new(session_repo: R, lock_repo: L, base_dir: PathBuf) -> Self {
SessionServiceImpl {
session_repo,
lock_repo,
base_dir,
}
}
}
impl<R: SessionRepository, L: SessionLockRepository> SessionService for SessionServiceImpl<R, L> {
fn create_session(&self, title: &str) -> anyhow::Result<Session> {
let id = Uuid::new_v4().to_string();
let title_owned = if title.is_empty() {
"New Session".to_string()
} else {
title.to_string()
};
let session = Session::new(id, title_owned);
self.session_repo.save_session(&self.base_dir, &session)?;
Ok(session)
}
fn list_all(&self) -> anyhow::Result<Vec<Session>> {
self.session_repo.list_sessions(&self.base_dir)
}
fn archive_session(&self, id: &str) -> anyhow::Result<()> {
let mut session = self.session_repo.load_session(&self.base_dir, id)?;
session.archived = true;
session.updated_at = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as i64;
self.session_repo.save_session(&self.base_dir, &session)?;
Ok(())
}
}