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

@@ -36,6 +36,13 @@ export function useAlbums() {
onSuccess: () => qc.invalidateQueries({ queryKey: ["albums"] }),
})
const deleteAlbum = useMutation({
mutationFn: async (id: string) => {
await api.delete(`/albums/${id}`)
},
onSuccess: () => qc.invalidateQueries({ queryKey: ["albums"] }),
})
const addEntry = useMutation({
mutationFn: async ({ albumId, assetId }: { albumId: string; assetId: string }) => {
await api.post(`/albums/${albumId}/entries`, { asset_id: assetId })
@@ -60,6 +67,7 @@ export function useAlbums() {
albums: query.data ?? [],
isLoading: query.isLoading,
createAlbum: create.mutateAsync,
deleteAlbum: deleteAlbum.mutateAsync,
updateAlbum: update.mutateAsync,
addEntry: addEntry.mutateAsync,
removeEntry: removeEntry.mutateAsync,