Веб-UI: основной идентификатор карточек — download.id вместо infohash
В карточке списка и шапке /download/{id} показываем и копируем download.id
(ULID) — тот же ключ, что в логах (download_id), удобно грепать. Infohash
остаётся в блоке «Информация о торренте». Поиск по списку расширен: матчит
любой идентификатор (download.id ИЛИ infohash), плюс название/контекст.
Удалены осиротевшие поля Infohash/InfohashShort и хелпер shortenHash.
Дельта web-ui влита в спеки, change заархивирован.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-07-04
|
||||
@@ -0,0 +1,38 @@
|
||||
## Context
|
||||
|
||||
Изменение презентационное и уже реализовано в коде (шаблоны, поиск, view-структуры).
|
||||
Дизайн-документ здесь короткий и нужен лишь как зависимость для `tasks` и чтобы
|
||||
зафиксировать одно продуктовое решение. Полноценного двухчекпоинтного ревью
|
||||
задача не требует (тривиальная — достаточно прохода по коду).
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Показывать и копировать в карточках `download.id` — тот же ключ, что в логах
|
||||
(`download_id`), чтобы «скопировал → нашёл в логах» работало без перекодировки.
|
||||
- Поиск по списку — по любому идентификатору загрузки (`download.id` ИЛИ infohash).
|
||||
|
||||
**Non-Goals:**
|
||||
- Не убираем infohash из UI совсем: он остаётся в блоке «Информация о торренте».
|
||||
- Не меняем модель данных, API-DTO и формат логов.
|
||||
|
||||
## Decisions
|
||||
|
||||
- **Идентификатор карточки — `download.id`, не infohash.** В логах основной ключ
|
||||
связывания — `download_id` (см. `internal/worker/*`), поэтому именно его нужно
|
||||
копировать и грепать. Infohash второстепенен и уместен только в детальном блоке
|
||||
о торренте. Альтернатива (оставить infohash в шапке) отвергнута: заставляет
|
||||
пользователя вручную сопоставлять хэш с id при чтении логов.
|
||||
- **Поиск матчит любой идентификатор.** В LIKE-условие `internal/store/list.go`
|
||||
добавлен `download.id` рядом с уже имевшимся infohash; название/контекст
|
||||
сохранены. Так скопированный из карточки id находится обратным поиском.
|
||||
- **Чистка мёртвого кода.** Поля `Infohash`/`InfohashShort` во view-структурах и
|
||||
хелпер `shortenHash` стали не нужны — удалены, чтобы не копить неиспользуемое.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [ULID менее узнаваем на глаз, чем hex-infohash] → показываем полностью (26
|
||||
символов помещаются в строку), рядом кнопка копирования; в детальном блоке
|
||||
infohash остаётся для тех, кому он нужен.
|
||||
- [Проза `## Purpose` в live-спеке упоминает «копирование infohash»] → правится
|
||||
прямой правкой live-спеки при archive (Purpose не покрывается дельта-операциями).
|
||||
@@ -0,0 +1,37 @@
|
||||
## Why
|
||||
|
||||
Веб-UI показывал в карточках (список + шапка страницы просмотра) infohash с
|
||||
кнопкой копирования. Но в логах основной ключ загрузки — `download_id` (ULID),
|
||||
именно по нему удобно грепать и связывать события; infohash в логах второстепенен.
|
||||
Пользователю нужно копировать из карточки то, что реально ищется в логах.
|
||||
|
||||
## What Changes
|
||||
|
||||
- В карточке списка и в шапке `/download/{id}` показываем и копируем
|
||||
`download.id` (ULID) вместо infohash — как основной идентификатор загрузки.
|
||||
- Infohash остаётся видимым только в блоке «Информация о торренте» (без
|
||||
изменений), где ему место рядом с сырым источником.
|
||||
- Поиск по списку расширяем: искать можно по **любому идентификатору**
|
||||
(`download.id` ИЛИ infohash), плюс прежние название/контекст. Плейсхолдер
|
||||
строки поиска обновлён.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
<!-- нет -->
|
||||
|
||||
### Modified Capabilities
|
||||
- `web-ui`: основной копируемый идентификатор карточек — `download.id`, а не
|
||||
infohash (Requirement «Клиентские взаимодействия без сборки» и Scenario
|
||||
копирования); поиск по списку матчит любой идентификатор загрузки (Scenario
|
||||
«Серверный фильтр и поиск»).
|
||||
|
||||
## Impact
|
||||
|
||||
- Шаблоны: `web/templates/index.html`, `web/templates/download.html`.
|
||||
- Поиск: `internal/store/list.go` (в LIKE-условие добавлен `download.id`).
|
||||
- View: `internal/httpapi/httpapi.go`, `internal/httpapi/download.go` (удалены
|
||||
осиротевшие поля `Infohash`/`InfohashShort` и хелпер `shortenHash`).
|
||||
- Клиент: `web/static/js/app.js` (комментарий — функция копирования теперь про
|
||||
идентификатор загрузки, не только infohash).
|
||||
- Совместимость: чисто презентационно; API-DTO и модель данных не меняются.
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Страницы веб-UI
|
||||
|
||||
Веб-UI SHALL предоставлять страницы: список загрузок с единым окном
|
||||
добавления, **серверными фильтром по группе состояний, поиском и постраничной
|
||||
выдачей (пагинацией)** (`/`), экран ревью одной загрузки (`/review/{id}`)
|
||||
и страницу просмотра одной загрузки (`/download/{id}`) с распознаванием,
|
||||
файлами→раскладкой, историей, блоком информации о торренте и — для сидирующих
|
||||
задач — секцией живой статистики раздачи. Карточки активных (downloading)
|
||||
загрузок в списке SHALL содержать индикатор прогресса. Фильтр, поиск и номер
|
||||
страницы SHALL передаваться GET-параметрами запроса (например `f`, `q`, `page`)
|
||||
и SHALL работать без клиентского JavaScript. Состояние `deleted` SHALL быть
|
||||
скрыто в списке по умолчанию (с переключателем «показать всё»). Механика живого
|
||||
обновления прогресса и наполнение секции раздачи определяются capability
|
||||
`live-status`.
|
||||
|
||||
#### Scenario: Просмотр одной загрузки
|
||||
|
||||
- **WHEN** клиент открывает `GET /download/{id}` существующей загрузки
|
||||
- **THEN** отрисовывается страница с её распознаванием, файлами, раскладкой и
|
||||
историей
|
||||
|
||||
#### Scenario: Прогресс активной загрузки в списке
|
||||
|
||||
- **WHEN** в списке есть загрузка в состоянии `downloading`
|
||||
- **THEN** её карточка содержит индикатор прогресса (прогресс-бар со скоростью
|
||||
и ETA)
|
||||
|
||||
#### Scenario: Удалённые скрыты по умолчанию
|
||||
|
||||
- **WHEN** в списке есть загрузки в состоянии `deleted` и фильтр «показать
|
||||
всё» не включён
|
||||
- **THEN** они не отображаются, но доступны при включённом переключателе
|
||||
|
||||
#### Scenario: Пагинация списка
|
||||
|
||||
- **WHEN** загрузок под текущим фильтром больше, чем помещается на одну
|
||||
страницу, и клиент запрашивает `GET /?page=N`
|
||||
- **THEN** возвращается N-я страница результатов и элементы навигации по
|
||||
страницам, сохраняющие текущие фильтр и поисковый запрос
|
||||
|
||||
#### Scenario: Серверный фильтр и поиск
|
||||
|
||||
- **WHEN** клиент запрашивает список с параметрами фильтра по состоянию и/или
|
||||
строкой поиска (`GET /?f=review&q=дюна`)
|
||||
- **THEN** сервер возвращает только подходящие загрузки (по группе состояний и
|
||||
совпадению строки в названии, любом идентификаторе загрузки — `download.id`
|
||||
ИЛИ infohash — и контексте), отфильтрованные на стороне БД, а не на клиенте
|
||||
|
||||
### Requirement: Клиентские взаимодействия без сборки
|
||||
|
||||
Веб-UI SHALL реализовывать клиентскую логику без шага сборки и без реактивных
|
||||
фреймворков: копирование идентификатора загрузки (vanilla JS) и раскрытие
|
||||
контекста нативным `<details>`. Основной копируемый идентификатор в карточке
|
||||
списка и в шапке страницы просмотра SHALL быть `download.id` (ULID) — тот же
|
||||
ключ, что пишется в логи (`download_id`). Все действия над загрузкой SHALL
|
||||
выполняться через формы/htmx (раундтрип на сервер), без клиентского пересчёта
|
||||
доменного состояния.
|
||||
|
||||
#### Scenario: Копирование идентификатора загрузки
|
||||
|
||||
- **WHEN** пользователь нажимает кнопку копирования рядом с идентификатором
|
||||
загрузки (`download.id`) в карточке списка или шапке страницы просмотра
|
||||
- **THEN** значение `download.id` копируется в буфер обмена без перезагрузки
|
||||
страницы
|
||||
@@ -0,0 +1,25 @@
|
||||
## 1. Карточки: идентификатор = download.id
|
||||
|
||||
- [x] 1.1 `web/templates/index.html` — в карточке списка показать и копировать
|
||||
`{{.ID}}` вместо infohash; убрать `{{if .Infohash}}`
|
||||
- [x] 1.2 `web/templates/download.html` — в шапке страницы просмотра показать и
|
||||
копировать `{{.ID}}` вместо infohash
|
||||
- [x] 1.3 `internal/httpapi/httpapi.go`, `internal/httpapi/download.go` — удалить
|
||||
осиротевшие поля `Infohash`/`InfohashShort` и хелпер `shortenHash`
|
||||
- [x] 1.4 `web/static/js/app.js` — комментарий: функция копирования теперь про
|
||||
идентификатор загрузки (не только infohash)
|
||||
|
||||
## 2. Поиск по любому идентификатору
|
||||
|
||||
- [x] 2.1 `internal/store/list.go` — добавить `download.id` в LIKE-условие
|
||||
поиска (рядом с infohash/названием/контекстом); обновить комментарий `Query`
|
||||
- [x] 2.2 `web/templates/index.html` — обновить плейсхолдер строки поиска
|
||||
|
||||
## 3. Спека и проверки
|
||||
|
||||
- [x] 3.1 Дельта-спека `web-ui`: MODIFIED «Страницы веб-UI» (поле поиска) и
|
||||
«Клиентские взаимодействия без сборки» (копирование идентификатора)
|
||||
- [x] 3.2 Обновить прозу `## Purpose` в live-спеке `openspec/specs/web-ui/spec.md`
|
||||
(упоминание «копирование infohash») — при archive
|
||||
- [x] 3.3 `openspec validate --strict` для change
|
||||
- [x] 3.4 `task test` / `task lint` — зелёные
|
||||
Reference in New Issue
Block a user