Files
jellybit/openspec/changes/review-source-selection/specs/web-ui/spec.md
T
avandClaude Opus 4.8 e7fe88a986 Завёл change review-source-selection: выбор источника и предпросмотр в ревью (openspec)
Переработка экрана ревью: единый список источников (нейронка наравне с
кандидатами баз), выбор/переключение/снятие в пользу нейронки, ручное
добавление по id/URL, предпросмотр полей и целевых путей до применения.
Дизайн отревьюен: единая деривация «источник → overrides» (preview==apply,
чинит залипший override title/year). Ограничились существующими capabilities.

Беклог: добавил две идеи — «Пересмотр набора capabilities и рефакторинг спек»
и «Сила совпадения кандидата / пересмотр распознавания и матчинга».

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 09:52:48 +03:00

145 lines
11 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.
## ADDED Requirements
### 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** в предпросмотре присутствует место под режиссёра, показанное
пустым (или прочерком), не ломая вёрстку
## MODIFIED Requirements
### Requirement: Превью раскладки через единую логику именования
Превью целевых путей раскладки в веб-UI SHALL вычисляться той же логикой
именования, что и реальная раскладка (`internal/naming`/`internal/layout`), а
не дублировать правила в шаблоне. На экране ревью превью SHALL строиться **для
каждого источника в списке** (нейронка, кандидат базы, добавленный вручную) —
эфемерно на сервере, без записи сохранённого матча. Показанные для источника
пути MUST совпадать с теми, что создались бы при выборе этого источника и
применении.
#### Scenario: Превью совпадает с реальной раскладкой
- **WHEN** на экране ревью отображается превью целевых путей для источника
- **THEN** эти пути идентичны тем, что создаст применение при выборе этого
источника (те же правила имён, спецвыпусков, мультифайла, запрещённых
символов, тега провайдера и коллизий)
#### Scenario: Переключение источника не тянет чужие поля
- **GIVEN** активен кандидат с запиненными название/год, затем выбран
источник без собственных названия/года (нейронка или ручной кандидат)
- **WHEN** строится превью и затем выполняется применение выбранного источника
- **THEN** и превью, и применение используют название/год этого источника
(из плана распознавания), без унаследованных от прежнего кандидата
### Requirement: Матч с записью метабазы ссылкой
Веб-UI SHALL показывать подтверждённый матч с записью метабазы (TMDB/TVDB/IMDb)
как ссылку на эту запись — на странице просмотра `/download/{id}` (блок
распознавания) и в едином списке источников совпадения экрана ревью (у
активного источника-кандидата). Ссылка SHALL открываться в новой вкладке с
`rel="noopener"`. Рядом со ссылкой SHALL быть видны провайдер, идентификатор
записи и (при наличии) год.
#### Scenario: Матч виден ссылкой на странице просмотра
- **WHEN** у загрузки подтверждён матч с записью метабазы и известен URL записи
- **THEN** в блоке распознавания на `/download/{id}` матч показан ссылкой на
запись с провайдером и id
#### Scenario: URL записи неизвестен
- **WHEN** матч подтверждён (например, id задан вручную), но канонический URL
записи построить нельзя
- **THEN** матч показывается текстом (провайдер и id) без ссылки, строка списка
не ломается