Заархивировал review-source-selection: дельта web-ui влита в спеки (openspec)
Влил 3 ADDED (единый список источников, ручное добавление по id/URL, предпросмотр полей до фиксации) и 2 MODIFIED (превью для каждого источника; матч ссылкой в списке источников) требования в openspec/specs/web-ui. Change перенесён в changes/archive. Убрал реализованный пункт из беклога, перецелил ссылки на review-ux.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+4
-31
@@ -95,32 +95,6 @@ qBittorrent — осознанный выход за инвариант «ист
|
|||||||
[architecture.md](specs/architecture.md) → «Раскладка файлов»,
|
[architecture.md](specs/architecture.md) → «Раскладка файлов»,
|
||||||
[workflow.md](specs/workflow.md).
|
[workflow.md](specs/workflow.md).
|
||||||
|
|
||||||
### Ревью: выбор источника совпадения и предпросмотр
|
|
||||||
|
|
||||||
Переработать страницу ревью так, чтобы показывать **все** совпавшие
|
|
||||||
результаты по метабазам списком и дать выбрать из них. Принцип: совпадение
|
|
||||||
есть **всегда** — мы лишь выбираем источник. Поэтому матч нейронки — это
|
|
||||||
отдельная строка в том же списке (наравне с кандидатами TMDB/TVDB), а не
|
|
||||||
особый режим.
|
|
||||||
|
|
||||||
Возможности экрана:
|
|
||||||
|
|
||||||
- список кандидатов из баз + строка «распознано нейронкой»;
|
|
||||||
- выбрать один кандидат, переключиться на другой, отменить матч с базой в
|
|
||||||
пользу нейронки;
|
|
||||||
- добавить кандидат вручную (по id/url базы), когда автопоиск промахнулся;
|
|
||||||
- при выборе/переключении — **предпросмотр полей** (название, режиссёр,
|
|
||||||
год) и **предпросмотр раскладки** (целевые пути) до применения.
|
|
||||||
|
|
||||||
Развивает уже реализованный показ матча в вебе (страница загрузки и экран
|
|
||||||
ревью — провайдер, id, ссылка на запись) и детальный экран `/download/{id}`;
|
|
||||||
пересекается с быстрым выбором в Telegram. Веб остаётся точкой точных правок.
|
|
||||||
|
|
||||||
Связано: [review-ux.md](specs/review-ux.md) (выбор кандидата, «без базы»,
|
|
||||||
переключатель типа), [recognition.md](specs/recognition.md) (кандидаты
|
|
||||||
матча, провайдер-id), [«Улучшения UI: показывать матч»](#улучшения-ui-показывать-матч-с-записью-метабазы),
|
|
||||||
пакет `httpapi`.
|
|
||||||
|
|
||||||
### Ретеншн и очистка БД
|
### Ретеншн и очистка БД
|
||||||
|
|
||||||
Терминальные задачи (`done`/`cancelled`/`failed`/`reverted`), их попытки
|
Терминальные задачи (`done`/`cancelled`/`failed`/`reverted`), их попытки
|
||||||
@@ -233,7 +207,7 @@ LLM, и **сверку с внешними базами** — а «поиск в
|
|||||||
|
|
||||||
Связано: [recognition.md](specs/recognition.md) (модель уверенности),
|
Связано: [recognition.md](specs/recognition.md) (модель уверенности),
|
||||||
[ADR-2026-06-13-auto-link-requires-db-match](adr/ADR-2026-06-13-auto-link-requires-db-match.md),
|
[ADR-2026-06-13-auto-link-requires-db-match](adr/ADR-2026-06-13-auto-link-requires-db-match.md),
|
||||||
[«Ревью: выбор источника совпадения»](#ревью-выбор-источника-совпадения-и-предпросмотр),
|
[review-ux.md](specs/review-ux.md) (выбор источника в ревью, реализовано),
|
||||||
[«Пересмотр набора capabilities»](#пересмотр-набора-capabilities-и-рефакторинг-спек).
|
[«Пересмотр набора capabilities»](#пересмотр-набора-capabilities-и-рефакторинг-спек).
|
||||||
|
|
||||||
### История переходов загрузки
|
### История переходов загрузки
|
||||||
@@ -283,8 +257,8 @@ Web-сторона реализована: страница загрузки `/d
|
|||||||
загрузка — провайдер, id и ссылку на запись. Осталось довести то же в
|
загрузка — провайдер, id и ссылку на запись. Осталось довести то же в
|
||||||
**Telegram**: в уведомлениях/подтверждениях показывать запись матча (название,
|
**Telegram**: в уведомлениях/подтверждениях показывать запись матча (название,
|
||||||
год, провайдер-id, ссылку), чтобы ошибочную привязку было видно и из бота.
|
год, провайдер-id, ссылку), чтобы ошибочную привязку было видно и из бота.
|
||||||
Полный выбор источника в вебе — см. [«Ревью: выбор источника
|
Полный выбор источника в вебе уже реализован — см.
|
||||||
совпадения»](#ревью-выбор-источника-совпадения-и-предпросмотр).
|
[review-ux.md](specs/review-ux.md).
|
||||||
|
|
||||||
Связано: [review-ux.md](specs/review-ux.md), [recognition.md](specs/recognition.md)
|
Связано: [review-ux.md](specs/review-ux.md), [recognition.md](specs/recognition.md)
|
||||||
(матч в базе), [architecture.md](specs/architecture.md) → «Транспорты».
|
(матч в базе), [architecture.md](specs/architecture.md) → «Транспорты».
|
||||||
@@ -388,8 +362,7 @@ qBittorrent, без исходящих запросов на пользоват
|
|||||||
Когда распознавание даёт несколько подходящих кандидатов в метабазе,
|
Когда распознавание даёт несколько подходящих кандидатов в метабазе,
|
||||||
предлагать их в Telegram списком (кнопки) для ручного выбора, а не молча
|
предлагать их в Telegram списком (кнопки) для ручного выбора, а не молча
|
||||||
брать первый/лучший. Веб остаётся точкой точных правок (полный выбор
|
брать первый/лучший. Веб остаётся точкой точных правок (полный выбор
|
||||||
источника — см. [«Ревью: выбор источника
|
источника уже реализован — см. [review-ux.md](specs/review-ux.md)), бот —
|
||||||
совпадения»](#ревью-выбор-источника-совпадения-и-предпросмотр)), бот —
|
|
||||||
быстрый выбор из готового короткого списка.
|
быстрый выбор из готового короткого списка.
|
||||||
|
|
||||||
Связано: [review-ux.md](specs/review-ux.md) (боты — быстрые действия, веб —
|
Связано: [review-ux.md](specs/review-ux.md) (боты — быстрые действия, веб —
|
||||||
|
|||||||
+117
-11
@@ -178,9 +178,10 @@ jellybit (`created_at`). Порядок MUST быть согласован ме
|
|||||||
|
|
||||||
Веб-UI SHALL показывать подтверждённый матч с записью метабазы (TMDB/TVDB/IMDb)
|
Веб-UI SHALL показывать подтверждённый матч с записью метабазы (TMDB/TVDB/IMDb)
|
||||||
как ссылку на эту запись — на странице просмотра `/download/{id}` (блок
|
как ссылку на эту запись — на странице просмотра `/download/{id}` (блок
|
||||||
распознавания) и в блоке «Источник совпадения» экрана ревью. Ссылка SHALL
|
распознавания) и в едином списке источников совпадения экрана ревью (у
|
||||||
открываться в новой вкладке с `rel="noopener"`. Рядом со ссылкой SHALL быть
|
активного источника-кандидата). Ссылка SHALL открываться в новой вкладке с
|
||||||
видны провайдер, идентификатор записи и (при наличии) год.
|
`rel="noopener"`. Рядом со ссылкой SHALL быть видны провайдер, идентификатор
|
||||||
|
записи и (при наличии) год.
|
||||||
|
|
||||||
#### Scenario: Матч виден ссылкой на странице просмотра
|
#### Scenario: Матч виден ссылкой на странице просмотра
|
||||||
|
|
||||||
@@ -192,8 +193,8 @@ jellybit (`created_at`). Порядок MUST быть согласован ме
|
|||||||
|
|
||||||
- **WHEN** матч подтверждён (например, id задан вручную), но канонический URL
|
- **WHEN** матч подтверждён (например, id задан вручную), но канонический URL
|
||||||
записи построить нельзя
|
записи построить нельзя
|
||||||
- **THEN** матч показывается текстом (провайдер и id) без ссылки, страница не
|
- **THEN** матч показывается текстом (провайдер и id) без ссылки, строка списка
|
||||||
ломается
|
не ломается
|
||||||
|
|
||||||
### Requirement: Блок информации о торренте
|
### Requirement: Блок информации о торренте
|
||||||
|
|
||||||
@@ -227,16 +228,27 @@ jellybit (`created_at`). Порядок MUST быть согласован ме
|
|||||||
### Requirement: Превью раскладки через единую логику именования
|
### Requirement: Превью раскладки через единую логику именования
|
||||||
|
|
||||||
Превью целевых путей раскладки в веб-UI SHALL вычисляться той же логикой
|
Превью целевых путей раскладки в веб-UI SHALL вычисляться той же логикой
|
||||||
именования, что и реальная раскладка (`internal/naming`), а не дублировать
|
именования, что и реальная раскладка (`internal/naming`/`internal/layout`), а
|
||||||
правила в шаблоне. Показанные пути MUST совпадать с теми, что создались бы при
|
не дублировать правила в шаблоне. На экране ревью превью SHALL строиться **для
|
||||||
|
каждого источника в списке** (нейронка, кандидат базы, добавленный вручную) —
|
||||||
|
эфемерно на сервере, без записи сохранённого матча. Показанные для источника
|
||||||
|
пути MUST совпадать с теми, что создались бы при выборе этого источника и
|
||||||
применении.
|
применении.
|
||||||
|
|
||||||
#### Scenario: Превью совпадает с реальной раскладкой
|
#### Scenario: Превью совпадает с реальной раскладкой
|
||||||
|
|
||||||
- **WHEN** на экране ревью отображается превью целевых путей для текущей
|
- **WHEN** на экране ревью отображается превью целевых путей для источника
|
||||||
догадки
|
- **THEN** эти пути идентичны тем, что создаст применение при выборе этого
|
||||||
- **THEN** эти пути идентичны тем, что создаст применение (те же правила имён,
|
источника (те же правила имён, спецвыпусков, мультифайла, запрещённых
|
||||||
спецвыпусков, мультифайла, запрещённых символов и коллизий)
|
символов, тега провайдера и коллизий)
|
||||||
|
|
||||||
|
#### Scenario: Переключение источника не тянет чужие поля
|
||||||
|
|
||||||
|
- **GIVEN** активен кандидат с запиненными название/год, затем выбран
|
||||||
|
источник без собственных названия/года (нейронка или ручной кандидат)
|
||||||
|
- **WHEN** строится превью и затем выполняется применение выбранного источника
|
||||||
|
- **THEN** и превью, и применение используют название/год этого источника
|
||||||
|
(из плана распознавания), без унаследованных от прежнего кандидата
|
||||||
|
|
||||||
### Requirement: Клиентские взаимодействия без сборки
|
### Requirement: Клиентские взаимодействия без сборки
|
||||||
|
|
||||||
@@ -256,3 +268,97 @@ jellybit (`created_at`). Порядок MUST быть согласован ме
|
|||||||
- **WHEN** пользователь раскрывает спойлер переданного контекста
|
- **WHEN** пользователь раскрывает спойлер переданного контекста
|
||||||
- **THEN** контекст показывается нативным `<details>`, без скриптов
|
- **THEN** контекст показывается нативным `<details>`, без скриптов
|
||||||
|
|
||||||
|
### Requirement: Единый список источников совпадения на ревью
|
||||||
|
|
||||||
|
Экран ревью (`/review/{id}`) SHALL показывать совпавшие источники **единым
|
||||||
|
списком**, в котором распознавание нейронкой (без базы) — такая же строка,
|
||||||
|
как кандидаты метабаз (TMDB/TVDB/TVMaze), а не отдельный режим сверху.
|
||||||
|
Ровно один источник в списке SHALL быть отмечен активным (эффективный
|
||||||
|
матч). Экран SHALL позволять как операции над этим списком: выбрать
|
||||||
|
кандидата базы, переключиться на другого кандидата и снять матч с базой
|
||||||
|
обратно на нейронку («без базы»). Смена активного источника SHALL
|
||||||
|
выполняться через раундтрип на сервер (форма/htmx), без клиентского
|
||||||
|
пересчёта доменного состояния. Список источников SHALL показываться только
|
||||||
|
при наличии плана распознавания.
|
||||||
|
|
||||||
|
#### Scenario: Нейронка — строка в общем списке
|
||||||
|
|
||||||
|
- **GIVEN** загрузка в `review` с распознаванием нейронкой и одним или
|
||||||
|
несколькими кандидатами метабаз
|
||||||
|
- **WHEN** пользователь открывает `GET /review/{id}`
|
||||||
|
- **THEN** источники показаны единым списком, где строка «распознано
|
||||||
|
нейронкой» стоит наравне с кандидатами баз
|
||||||
|
- **AND** активным отмечен ровно один источник (текущий эффективный матч)
|
||||||
|
|
||||||
|
#### Scenario: Переключение между кандидатами
|
||||||
|
|
||||||
|
- **GIVEN** на экране ревью выбран один кандидат метабазы
|
||||||
|
- **WHEN** пользователь выбирает другого кандидата из списка
|
||||||
|
- **THEN** активным становится выбранный кандидат, прочие — неактивны
|
||||||
|
|
||||||
|
#### Scenario: Снятие матча в пользу нейронки
|
||||||
|
|
||||||
|
- **GIVEN** на экране ревью активен кандидат метабазы с названием «Fargo»
|
||||||
|
- **WHEN** пользователь выбирает строку «распознано нейронкой»
|
||||||
|
- **THEN** матч с базой снимается (источник — нейронка, «без базы»), тег
|
||||||
|
папки провайдера не проставляется
|
||||||
|
- **AND** поля источника — из распознавания нейронкой, без унаследованных
|
||||||
|
от прежнего кандидата название/год
|
||||||
|
|
||||||
|
### Requirement: Ручное добавление источника по id или URL
|
||||||
|
|
||||||
|
Когда автопоиск по базам промахнулся, экран ревью SHALL позволять добавить
|
||||||
|
источник вручную — по идентификатору записи метабазы или, где применимо, по
|
||||||
|
её URL. Ввод SHALL разбираться и валидироваться в пару
|
||||||
|
`(provider, provider_id)` на входной границе (`internal/httpapi`); допустимые
|
||||||
|
провайдеры — `tmdb`, `tvdb`, `imdb`. Добавленный источник SHALL появляться в
|
||||||
|
списке как выбираемая строка; при совпадении `provider:id` с уже присутствующим
|
||||||
|
источником новая строка NOT создаётся, а выбирается существующая.
|
||||||
|
Некорректный ввод SHALL отклоняться с сообщением, не меняя текущий активный
|
||||||
|
источник.
|
||||||
|
|
||||||
|
#### Scenario: Добавление кандидата по URL TMDB
|
||||||
|
|
||||||
|
- **GIVEN** загрузка в `review`, где нужной записи нет среди автокандидатов
|
||||||
|
- **WHEN** пользователь вводит URL записи TMDB и подтверждает добавление
|
||||||
|
- **THEN** из URL извлекаются провайдер и id, источник добавляется в список
|
||||||
|
выбираемой строкой
|
||||||
|
|
||||||
|
#### Scenario: Дубль id выбирает существующую строку
|
||||||
|
|
||||||
|
- **GIVEN** в списке уже есть кандидат с данным `provider:id`
|
||||||
|
- **WHEN** пользователь добавляет вручную тот же `provider:id`
|
||||||
|
- **THEN** новая строка не создаётся, активным становится существующий
|
||||||
|
кандидат
|
||||||
|
|
||||||
|
#### Scenario: Некорректный ввод отклонён
|
||||||
|
|
||||||
|
- **WHEN** пользователь вводит нераспознаваемый id/URL
|
||||||
|
- **THEN** экран показывает сообщение об ошибке и не меняет текущий активный
|
||||||
|
источник
|
||||||
|
|
||||||
|
### Requirement: Предпросмотр полей источника до фиксации выбора
|
||||||
|
|
||||||
|
Экран ревью SHALL показывать для рассматриваемого источника (нейронка,
|
||||||
|
кандидат базы или добавленный вручную) **поля** результата — тип, название,
|
||||||
|
год, с зарезервированным местом под режиссёра. Показ полей источника
|
||||||
|
MUST NOT менять сохранённый матч загрузки и MUST NOT создавать хардлинки:
|
||||||
|
сохранённый матч меняется только явным выбором источника, а раскладка —
|
||||||
|
только действием «Применить». Совпадение целевых путей предпросмотра с
|
||||||
|
результатом применения регулируется требованием «Превью раскладки через
|
||||||
|
единую логику именования».
|
||||||
|
|
||||||
|
#### Scenario: Предпросмотр полей без фиксации выбора
|
||||||
|
|
||||||
|
- **GIVEN** список источников на экране ревью
|
||||||
|
- **WHEN** пользователь рассматривает источник, ещё не выбрав его активным
|
||||||
|
- **THEN** показаны поля результата (тип, название, год) для этого источника
|
||||||
|
- **AND** сохранённый матч загрузки не меняется, хардлинки не создаются
|
||||||
|
|
||||||
|
#### Scenario: Зарезервированное место под режиссёра
|
||||||
|
|
||||||
|
- **GIVEN** режиссёр из метабазы пока не загружается
|
||||||
|
- **WHEN** отображается предпросмотр полей источника
|
||||||
|
- **THEN** в предпросмотре присутствует место под режиссёра, показанное
|
||||||
|
пустым (или прочерком), не ломая вёрстку
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user