# web-ui Specification (delta) ## ADDED Requirements ### Requirement: Обзор жизненного цикла в карточке списка Карточка загрузки в списке SHALL показывать обзорную мета-строку для решения о судьбе раздачи: метку `ID:` перед копируемым идентификатором загрузки, дату добавления раздачи (всегда), размер раздачи и рейтинг отдачи. Контекст загрузки MUST NOT показываться в карточке списка — он доступен на странице `/download/{id}`. Дата добавления SHALL показываться всегда как абсолютная дата и относительная давность (например «`2026-06-30 · 5 дней назад`»); источником SHALL быть время добавления раздачи в источник (`source_added_at`, qBittorrent `added_on`) с фолбэком на время создания загрузки (`created_at`), согласованным с порядком списка. Рейтинг отдачи SHALL браться из живого снимка телеметрии; если торрента нет в снимке (источник ушёл из qBittorrent), рейтинг SHALL отображаться прочерком «—». Размер раздачи SHALL браться из живого снимка (общий размер торрента), а при отсутствии торрента в снимке — из суммарного размера разложенных файлов загрузки; если неизвестно ни то, ни другое — прочерк «—». #### Scenario: Метка идентификатора - **WHEN** рендерится карточка загрузки в списке - **THEN** перед значением `download.id` показана метка «ID:», а кнопка копирования копирует именно `download.id` #### Scenario: Дата добавления показана всегда - **WHEN** рендерится любая карточка списка - **THEN** в ней показана дата добавления раздачи абсолютной датой и относительной давностью - **AND** если `source_added_at` неизвестно, используется `created_at` #### Scenario: Рейтинг из живого снимка - **WHEN** торрент загрузки присутствует в живом снимке - **THEN** в карточке показан его рейтинг отдачи - **AND** если торрента в снимке нет, рейтинг показан прочерком «—» #### Scenario: Размер с фолбэком на разложенные файлы - **WHEN** торрент загрузки присутствует в живом снимке - **THEN** размер раздачи в карточке берётся из общего размера торрента - **AND** если торрента в снимке нет, но у загрузки есть разложенные файлы — размер берётся из суммарного размера этих файлов #### Scenario: Контекст не в карточке - **WHEN** у загрузки есть переданный контекст - **THEN** он не показывается в карточке списка, но доступен на странице `/download/{id}` ## MODIFIED Requirements ### Requirement: Клиентские взаимодействия без сборки Веб-UI SHALL реализовывать клиентскую логику без шага сборки и без реактивных фреймворков: копирование идентификатора загрузки (vanilla JS). Основной копируемый идентификатор в карточке списка и в шапке страницы просмотра SHALL быть `download.id` (ULID) — тот же ключ, что пишется в логи (`download_id`). Все действия над загрузкой SHALL выполняться через формы/htmx (раундтрип на сервер), без клиентского пересчёта доменного состояния. #### Scenario: Копирование идентификатора загрузки - **WHEN** пользователь нажимает кнопку копирования рядом с идентификатором загрузки (`download.id`) в карточке списка или шапке страницы просмотра - **THEN** значение `download.id` копируется в буфер обмена без перезагрузки страницы #### Scenario: Действия только через раундтрип - **WHEN** пользователь выполняет действие над загрузкой - **THEN** оно исполняется формой/htmx-запросом на сервер, без клиентского пересчёта доменного состояния