chore(openspec): archive trash-permanent-delete-and-empty and sync main specs

This commit is contained in:
iu
2026-10-11 20:55:04 +03:00
parent 3b745fa737
commit a72d8876d6
8 changed files with 40 additions and 1 deletions
@@ -0,0 +1,28 @@
# Tasks
## 1. Fix permanent delete for albumless photos
- [x] 1.1 In `photos.Service.PermanentDelete`, when `p.AlbumID == ""`, authorize by `p.UploaderID == userID` instead of calling `albums.Access`; keep the album-role check when an album is present. Verify with a Go test that permanently deletes an albumless trashed photo (add to `backend/internal/e2e/sqlite_test.go`) and passes.
- [x] 1.2 Confirm object garbage collection still runs for albumless deletes (`PhotoObjectIDs` + `MarkObjectDeleting`); verify the test asserts the photo row is gone and an unbound object is marked deleting.
## 2. Add empty-trash operation
- [x] 2.1 Add a photos repository/store method that lists all accessible trashed photo identities (`id`, `album_id`, `uploader_id`) without the 200-item display cap; verify with a test that seeds more than 200 trashed photos and asserts all are returned.
- [x] 2.2 Add `Service.EmptyTrash(ctx, userID)` that authorizes each listed photo with the same rules as `PermanentDelete` (album role when bound, uploader when albumless), skips forbidden ones, and returns the deleted count; verify with a test where a shared album holds another user's trashed photo — the foreign photo remains, the caller's are removed, and the count matches.
- [x] 2.3 Add `Handler.EmptyTrash` and the `DELETE /trash` route returning `{ "deleted": n }`; verify with an HTTP-level test asserting the status code and response body.
- [x] 2.4 Add end-to-end coverage: emptying an empty trash returns `0`, and after emptying a non-empty trash `TrashCount` is `0`; verify with `make test`.
## 3. Trash screen action
- [x] 3.1 Add `photosApi.emptyTrash()` calling `DELETE /trash` in `frontend/src/lib/api.ts`; verify with `npm run check`.
- [x] 3.2 Add an «Очистить корзину» control to `frontend/src/routes/(app)/trash/+page.svelte`, enabled only when the list is non-empty, opening the existing `ConfirmDialog`; on confirm call `emptyTrash`, then reload the list and call `trash.load()`; verify by clearing a non-empty trash and observing the empty state and a busy state during the call.
- [x] 3.3 Verify the rail counter reflects the result: after clearing, the trash count in `AlbumRail` becomes `0` (observable in the running app).
## 4. Integration verification
- [x] 4.1 Run `make test` (backend) and `npm run check` plus `npm run build` (frontend); verify all pass with no regressions.
## Workflow follow-up
- Run `/opsx-apply` to implement this change.
- Archive the change after review and verification (sync delta specs into main specs).