feat: safe deletion, album/asset delete, trash, README update

- volume-aware deletion: read-only volumes remove DB only, writable
  volumes soft-delete to trash with configurable grace period
- trash page with restore, worker purge sweep (TRASH_RETENTION_DAYS)
- album delete endpoint + sidebar trash icon
- asset delete from timeline selection toolbar
- all listing queries exclude trashed assets (deleted_at IS NULL)
- timeline ordered by EXIF capture date, date-summary endpoint
- README rewritten with features, setup, full env var table
This commit is contained in:
2026-06-01 01:57:53 +02:00
parent 957737ac9b
commit 0077caa743
36 changed files with 752 additions and 125 deletions

View File

@@ -0,0 +1,34 @@
use domain::{
entities::Asset, errors::DomainError, ports::AssetRepository, value_objects::SystemId,
};
use std::sync::Arc;
pub struct ListTrashQuery {
pub owner_id: SystemId,
pub limit: u32,
pub offset: u32,
}
pub struct TrashResult {
pub assets: Vec<Asset>,
pub total: u64,
}
pub struct ListTrashHandler {
asset_repo: Arc<dyn AssetRepository>,
}
impl ListTrashHandler {
pub fn new(asset_repo: Arc<dyn AssetRepository>) -> Self {
Self { asset_repo }
}
pub async fn execute(&self, query: ListTrashQuery) -> Result<TrashResult, DomainError> {
let total = self.asset_repo.count_trashed(&query.owner_id).await?;
let assets = self
.asset_repo
.find_trashed_by_owner(&query.owner_id, query.limit, query.offset)
.await?;
Ok(TrashResult { assets, total })
}
}

View File

@@ -1,5 +1,6 @@
pub mod get_asset;
pub mod get_date_summary;
pub mod list_trash;
pub mod get_stack;
pub mod get_timeline;
pub mod list_stacks;