Files
jellybit/openspec/changes/archive/2026-08-10-bulk-delete-page/proposal.md
T
av 288be8ec34 web-ui: добавлена страница группового удаления загрузок
- выбор → поимённое подтверждение → отчёт: пачка до 20 загрузок, гарды входа
  на обеих границах, потолок времени и остановка после трёх подряд отказов
  внешнего сервиса
- допуск полного удаления сведён в единую точку store.State.CanDelete() —
  worker, страница загрузки и Telegram больше не держат своих перечней
2026-08-10 17:43:36 +03:00

60 lines
4.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Why
Удалить раздачу вместе с файлами сегодня можно только со страницы одной
загрузки, из её danger-секции. Чтобы освободить место после десяти закрытых
раздач, человек десять раз проходит путь «список → карточка → подтверждение».
Работа механическая, а цена ошибки высокая: на каждом проходе он подтверждает
необратимое действие заново и легко теряет, какие раздачи уже снёс.
## What Changes
- Появляется отдельная страница веб-UI «Удаление», доступная из шапки. На ней
перечислены только те загрузки, для которых удаление с файлами разрешено
поштучно (`done`, `orphaned`, `target_missing`), у каждой строки — чекбокс.
- Одна кнопка «Удалить выбранные» ведёт на **страницу подтверждения**, где
выбранные раздачи названы поимённо. Удаление уходит только оттуда: POST без
признака подтверждения отклоняется, ни одного удаления не делает.
- Результат показывается поимённо: что удалено и что отказало, с причиной
каждого отказа. Отказ на одной загрузке не отменяет остальных.
- Групповой путь прав не расширяет: каждая выбранная загрузка проходит ту же
проверку состояния, что и поштучное удаление, и отклоняется тем же конфликтом.
- Условие «удаление разрешено» переезжает в единую точку домена
(`store.State`): сейчас оно записано дважды — в проверке воркера и в сборке
представления страницы загрузки, — а групповая страница была бы третьим
местом.
- Страница намеренно **не самообновляется**: живая перерисовка карточек стёрла
бы выбор человека. Это и есть причина, по которой режим выбора не вешается на
основной список.
Не входит: групповое закрытие без файлов (`Dismiss`), автоматическая чистка по
сроку хранения, изменение самой операции удаления одной загрузки.
## Capabilities
### New Capabilities
Новых нет: групповое удаление — это новая поверхность существующего поведения,
а не новое поведение системы.
### Modified Capabilities
- `web-ui`: добавляется страница группового удаления с обязательным поимённым
подтверждением и поимённым отчётом об исходе; ссылка на неё в шапке.
- `state-reconciliation`: требование «Полное удаление загрузки пользователем»
уточняется — подтверждение может быть одно на пачку, но остаётся обязательным
и поимённым, а условия допустимости у каждой загрузки прежние и проверяются
для каждой отдельно.
## Impact
- `internal/httpapi`: страница выбора, страница подтверждения, обработчик
группового удаления и страница результата; ссылка в шапке.
- `web/templates`: новый шаблон страницы и её партиалы,
`partials/header.html`.
- `internal/store`: единая точка «в этом состоянии удаление разрешено».
- `internal/worker`: `Reviewer.Delete` зовётся по каждой выбранной загрузке;
сама операция не меняется.
- qBittorrent `torrents/delete` с `deleteFiles=true` — внешний сервис,
необратимая операция; число вызовов за один запрос человека растёт с одного
до числа выбранных.