feat: add presentation layer + bootstrap wiring for vertical slice

This commit is contained in:
2026-05-31 05:51:09 +02:00
parent 8c1a0e4519
commit 201eff717d
21 changed files with 726 additions and 51 deletions

View File

@@ -4,8 +4,9 @@ version = "0.1.0"
edition = "2024"
[dependencies]
domain = { workspace = true }
serde = { workspace = true }
uuid = { workspace = true }
chrono = { workspace = true }
utoipa = { workspace = true }
domain = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
uuid = { workspace = true }
chrono = { workspace = true }
utoipa = { workspace = true }

View File

@@ -15,3 +15,28 @@ pub struct LoginRequest {
pub struct CreateAlbumRequest {
pub title: String,
}
#[derive(Debug, serde::Deserialize, utoipa::ToSchema)]
pub struct AlbumEntryRequest {
pub asset_id: uuid::Uuid,
}
#[derive(Debug, serde::Deserialize, utoipa::ToSchema)]
pub struct RegisterVolumeRequest {
pub volume_name: String,
pub uri_prefix: String,
pub is_writable: bool,
}
#[derive(Debug, serde::Deserialize, utoipa::ToSchema)]
pub struct RegisterLibraryPathRequest {
pub volume_id: uuid::Uuid,
pub relative_path: String,
pub owner_id: uuid::Uuid,
pub is_ingest_destination: bool,
}
#[derive(Debug, serde::Deserialize, utoipa::ToSchema)]
pub struct UpdateMetadataRequest {
pub data: std::collections::HashMap<String, serde_json::Value>,
}

View File

@@ -32,6 +32,7 @@ pub struct AlbumResponse {
pub title: String,
pub description: String,
pub creator_id: Uuid,
pub asset_count: usize,
pub created_at: DateTime<Utc>,
}
@@ -42,7 +43,109 @@ impl AlbumResponse {
title: album.title.clone(),
description: album.description.clone(),
creator_id: *album.creator_user_id.as_uuid(),
asset_count: album.asset_count(),
created_at: *album.created_at.as_datetime(),
}
}
}
#[derive(Debug, serde::Serialize, utoipa::ToSchema)]
pub struct AssetResponse {
pub id: Uuid,
pub asset_type: String,
pub mime_type: String,
pub file_size: u64,
pub is_processed: bool,
pub created_at: DateTime<Utc>,
pub metadata: std::collections::HashMap<String, serde_json::Value>,
}
impl AssetResponse {
pub fn from_domain(
asset: &domain::entities::Asset,
metadata: &domain::value_objects::StructuredData,
) -> Self {
let meta_map = metadata
.inner()
.iter()
.map(|(k, v)| {
let json_val = match v {
domain::value_objects::MetadataValue::String(s) => {
serde_json::Value::String(s.clone())
}
domain::value_objects::MetadataValue::Integer(i) => {
serde_json::json!(*i)
}
domain::value_objects::MetadataValue::Float(f) => {
serde_json::json!(*f)
}
domain::value_objects::MetadataValue::Boolean(b) => {
serde_json::Value::Bool(*b)
}
domain::value_objects::MetadataValue::Null => serde_json::Value::Null,
};
(k.clone(), json_val)
})
.collect();
Self {
id: *asset.asset_id.as_uuid(),
asset_type: format!("{:?}", asset.asset_type),
mime_type: asset.mime_type.clone(),
file_size: asset.file_size,
is_processed: asset.is_processed,
created_at: *asset.created_at.as_datetime(),
metadata: meta_map,
}
}
}
#[derive(Debug, serde::Serialize, utoipa::ToSchema)]
pub struct TimelineResponse {
pub assets: Vec<AssetResponse>,
pub total: usize,
}
#[derive(Debug, serde::Serialize, utoipa::ToSchema)]
pub struct VolumeResponse {
pub id: Uuid,
pub volume_name: String,
pub uri_prefix: String,
pub is_writable: bool,
}
impl VolumeResponse {
pub fn from_domain(volume: &domain::entities::StorageVolume) -> Self {
Self {
id: *volume.volume_id.as_uuid(),
volume_name: volume.volume_name.clone(),
uri_prefix: volume.uri_prefix.clone(),
is_writable: volume.is_writable,
}
}
}
#[derive(Debug, serde::Serialize, utoipa::ToSchema)]
pub struct LibraryPathResponse {
pub id: Uuid,
pub volume_id: Uuid,
pub relative_path: String,
pub is_ingest_destination: bool,
}
impl LibraryPathResponse {
pub fn from_domain(path: &domain::entities::LibraryPath) -> Self {
Self {
id: *path.path_id.as_uuid(),
volume_id: *path.volume_id.as_uuid(),
relative_path: path.relative_path.clone(),
is_ingest_destination: path.is_ingest_destination,
}
}
}
#[derive(Debug, serde::Serialize, utoipa::ToSchema)]
pub struct IngestResponse {
pub asset: AssetResponse,
pub session_id: Uuid,
}