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:
@@ -0,0 +1,168 @@
|
||||
//! CMS-specific DTOs (Data Transfer Objects) for the REST API.
|
||||
//!
|
||||
//! These types define the wire format accepted and returned by HTTP handlers.
|
||||
//! They are independent of the domain entities so the API contract can
|
||||
//! evolve without coupling to the domain model.
|
||||
|
||||
#![allow(
|
||||
clippy::cast_possible_truncation,
|
||||
clippy::cast_sign_loss,
|
||||
clippy::cast_precision_loss,
|
||||
clippy::cast_possible_wrap
|
||||
)]
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Settings
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Request body for updating settings (partial update — only specified fields
|
||||
/// are changed).
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SettingsUpdateRequest {
|
||||
pub internet_mode: Option<String>,
|
||||
pub provider: Option<String>,
|
||||
pub model: Option<String>,
|
||||
pub api_keys: Option<std::collections::HashMap<String, String>>,
|
||||
pub max_tokens: Option<Option<u32>>,
|
||||
pub temperature: Option<Option<f32>>,
|
||||
pub review_max_lessons_per_run: Option<usize>,
|
||||
pub adaptive_review_max_skip: Option<u32>,
|
||||
pub verify_command: Option<Option<String>>,
|
||||
pub verify_timeout_ms: Option<u64>,
|
||||
pub workflow_max_concurrency: Option<usize>,
|
||||
pub review_enabled: Option<bool>,
|
||||
pub session_archive_enabled: Option<bool>,
|
||||
pub lsp_auto_provision: Option<bool>,
|
||||
pub lsp_languages: Option<Vec<String>>,
|
||||
pub hive_mind_node_timeout_ms: Option<u64>,
|
||||
}
|
||||
|
||||
/// Response body for settings.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SettingsResponse {
|
||||
pub internet_mode: String,
|
||||
pub provider: String,
|
||||
pub model: String,
|
||||
pub api_keys: Vec<String>, // key names only, values redacted
|
||||
pub max_tokens: Option<u32>,
|
||||
pub temperature: Option<f32>,
|
||||
pub review_max_lessons_per_run: usize,
|
||||
pub adaptive_review_max_skip: u32,
|
||||
pub verify_command: Option<String>,
|
||||
pub verify_timeout_ms: u64,
|
||||
pub workflow_max_concurrency: usize,
|
||||
pub review_enabled: bool,
|
||||
pub session_archive_enabled: bool,
|
||||
pub lsp_auto_provision: bool,
|
||||
pub lsp_languages: Vec<String>,
|
||||
pub hive_mind_node_timeout_ms: u64,
|
||||
}
|
||||
|
||||
impl From<crate::domain::settings::Settings> for SettingsResponse {
|
||||
fn from(s: crate::domain::settings::Settings) -> Self {
|
||||
Self {
|
||||
internet_mode: format!("{:?}", s.internet_mode),
|
||||
provider: s.provider,
|
||||
model: s.model,
|
||||
api_keys: s.api_keys.keys().cloned().collect(),
|
||||
max_tokens: s.max_tokens,
|
||||
temperature: s.temperature,
|
||||
review_max_lessons_per_run: s.review_max_lessons_per_run,
|
||||
adaptive_review_max_skip: s.adaptive_review_max_skip,
|
||||
verify_command: s.verify_command,
|
||||
verify_timeout_ms: s.verify_timeout_ms,
|
||||
workflow_max_concurrency: s.workflow_max_concurrency,
|
||||
review_enabled: s.flags.review_enabled,
|
||||
session_archive_enabled: s.flags.session_archive_enabled,
|
||||
lsp_auto_provision: s.flags.lsp_auto_provision,
|
||||
lsp_languages: s.lsp_languages,
|
||||
hive_mind_node_timeout_ms: s.hive_mind_node_timeout_ms,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Memory
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Request body for creating or updating a memory.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct MemoryCreateRequest {
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub content: String,
|
||||
pub kind: Option<String>,
|
||||
pub outcome: Option<String>,
|
||||
pub lifecycle: Option<String>,
|
||||
pub scope: Option<String>,
|
||||
pub before_snippet: Option<String>,
|
||||
pub after_snippet: Option<String>,
|
||||
pub provenances: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
/// Response body for a memory.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct MemoryResponse {
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub content: String,
|
||||
pub kind: String,
|
||||
pub created_at: i64,
|
||||
pub updated_at: i64,
|
||||
pub outcome: Option<String>,
|
||||
pub lifecycle: String,
|
||||
pub scope: Option<String>,
|
||||
pub before_snippet: Option<String>,
|
||||
pub after_snippet: Option<String>,
|
||||
pub provenances: Vec<String>,
|
||||
}
|
||||
|
||||
impl From<crate::domain::memory::Memory> for MemoryResponse {
|
||||
fn from(m: crate::domain::memory::Memory) -> Self {
|
||||
Self {
|
||||
name: m.name,
|
||||
description: m.description,
|
||||
content: m.content,
|
||||
kind: m.kind,
|
||||
created_at: m.created_at,
|
||||
updated_at: m.updated_at,
|
||||
outcome: m.outcome,
|
||||
lifecycle: m.lifecycle,
|
||||
scope: m.scope,
|
||||
before_snippet: m.before_snippet,
|
||||
after_snippet: m.after_snippet,
|
||||
provenances: m.provenances,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Conversation
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Response body for a conversation.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ConversationResponse {
|
||||
pub session_id: String,
|
||||
pub message_count: usize,
|
||||
pub model: String,
|
||||
pub system_prompt: String,
|
||||
pub max_tokens: Option<u32>,
|
||||
pub temperature: Option<f32>,
|
||||
}
|
||||
|
||||
impl From<crate::domain::conversation::Conversation> for ConversationResponse {
|
||||
fn from(c: crate::domain::conversation::Conversation) -> Self {
|
||||
let message_count = c.len();
|
||||
Self {
|
||||
session_id: c.session_id,
|
||||
message_count,
|
||||
model: c.model,
|
||||
system_prompt: c.system_prompt,
|
||||
max_tokens: c.max_tokens,
|
||||
temperature: c.temperature,
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user