@@ -1,484 +0,0 @@
# Беклог
Единый список будущих задач по проекту: то, что уже решили сделать, и
идеи, которые ещё надо обдумать. Это не план реализации (он — в
[drafts/roadmap.md ](drafts/roadmap.md )) и не источник истины: принятое и
реализованное переезжает в `docs/specs` /`docs/adr` .
Приоритет — грубая оценка «ценность / стоимость», не обязательство к
порядку. Спекулятивные пункты (ещё без решения «делаем») помечены
_ (идея) _ — их сперва надо проработать.
## Высокий
### Проблема второго сезона
Если первый сезон сериала уже разложен, а мы добавляем второй/третий/…,
новый сезон должен лечь в **ту же ** папку сериала, а не завести рядом почти
одинаковую вторую. Разбор ([drafts/logical-title-model.md ](drafts/logical-title-model.md ))
показал: проблема не в группировке, а в **сходимости папки ** — папка каждый
раз печатается заново из выхода LLM, и совпадение `provider_id` не
гарантирует совпадение строки («Fargo» vs «Фарго», год сезона vs год
сериала). Отдельная сущность «тайтл» **не вводится ** ; решение — правило
сходимости при построении плана: при подтверждённом матче наследовать базу
папки от живых `file_link` 'ов загрузок с тем же `(provider, provider_id)` ,
игнорируя LLM-выход; якоря нет — папка из распознавания, как сейчас (первая
загрузка «печатает» имя).
- [ ] lookup живых ссылок по `(provider, provider_id)` через current recognition
- [ ] наследование базы папки (имя + год) при построении плана раскладки
- [ ] рассинхрон (несколько живых папок с одним матчем) → review, не молча
- [ ] тесты: сходимость, отсутствие якоря (свежая папка), смена провайдера
Связано: [drafts/logical-title-model.md ](drafts/logical-title-model.md ) §5.2,
[recognition.md ](specs/recognition.md ) (модель уверенности,
матч в базе), [jellyfin-layout.md ](specs/jellyfin-layout.md ) (папка
сериала с провайдер-id).
### Раздачи с докачиванием (слияние при повторном добавлении)
Свежий сериал раздают по мере выхода: торрент содержит 5 эпизодов из 10,
позже его перезаливают целиком, и пользователь добавляет раздачу повторно.
Решение проработано ([drafts/logical-title-model.md ](drafts/logical-title-model.md )
§6.2): новая загрузка приходит в ту же папку за счёт правила сходимости, а
раскладка становится **merge ** — доложить только недостающее. Существующие
пути не трогаем (never-overwrite, владение остаётся у старой загрузки),
новые кладём (владеет новая). Split-ownership сезона (серии поделены между
загрузками) принят как норма per-path модели; обе раздачи сидируют
независимо.
- [ ] в плане раскладки отличать «путь занят живой ссылкой того же матча»
(→ пропустить) от настоящей коллизии (→ review, как сейчас)
- [ ] merge-раскладка: существующее пропустить, недостающее доложить
- [ ] показать итог в карточке: сколько доложено, сколько уже было
- [ ] решить «слияние загрузок» при перезаливе той же вещи (одна строка
`download` + новый infohash vs новая загрузка) — открытый вопрос
черновика §10
Зависит от правила сходимости ([«Проблема второго
сезона» ](#проблема-второго-сезона )) и выигрывает от ULID-идентичности.
Связано: [jellyfin-layout.md ](specs/jellyfin-layout.md ) (раскладка,
идемпотентность), [workflow.md ](specs/workflow.md ) (повторный прогон
загрузки).
### Удаление средствами jellybit («единое окно», path 2)
Распознавание **ручного ** удаления (источник из qBittorrent / цель из
Jellyfin) и пометка рассинхрона уже сделаны: фоновая сверка по матрице
«источник × цель» → состояния `target_missing` /`orphaned` /`deleted` ,
безопасный `undo` (не снимает последнюю копию, `nlink <= 1` ), синхронный
preflight перед действиями. См. `openspec/specs/state-reconciliation/` ,
[workflow.md ](specs/workflow.md ) → «Сверка с реальностью».
Осталось (path 2) — продолжение «единого окна»: удалять просмотренное
**из самого jellybit ** , не идя руками в qBittorrent/Jellyfin. Решения из
разбора ([drafts/logical-title-model.md ](drafts/logical-title-model.md )
§5.3, §6.4): «тайтл» — вычисляемая группа загрузок по
`(provider, provider_id)` / общей папке, без новой сущности; удаление
целиком — обход загрузок группы штатным undo; удаление раздачи из
qBittorrent — осознанный выход за инвариант «источник неприкосновенен»,
только по явному подтверждению (не случайному клику).
- [ ] удаление одной загрузки: снять её живые хардлинки (штатный undo,
`superseded` пропускаем, `nlink` -гард) + опц. удалить раздачу из
qBittorrent с файлами — с осознанным подтверждением
- [ ] вычисляемая группа «тайтл» в UI: состав сериала/фильма (загрузки,
сезоны, файлы) одним экраном
- [ ] удаление тайтла целиком: обход загрузок группы + опц. снос
опустевшей папки
- [ ] после полного удаления память о тайтле не остаётся (линза без
содержимого не нужна)
Связано: [drafts/logical-title-model.md ](drafts/logical-title-model.md ),
[ADR-2026-06-13-hardlinks ](adr/ADR-2026-06-13-hardlinks.md ),
[architecture.md ](specs/architecture.md ) → «Раскладка файлов»,
[workflow.md ](specs/workflow.md ).
### Ретеншн и очистка БД
Терминальные задачи (`done` /`cancelled` /`failed` /`reverted` ), их попытки
`recognition` с сырыми ответами LLM и `metadata_candidate` копятся вечно —
со временем БД и список загрузок распухают и становятся нечитаемыми. Нужна
авточистка старше N дней (с настройкой в `[storage]` или `[worker]` ) и/или
ручное удаление. Маленькая задача, но без неё интерфейс деградирует по мере
эксплуатации.
Связано: [architecture.md ](specs/architecture.md ) → «Хранилище» (таблицы
`download` /`recognition` /`metadata_candidate` /`file_link` ), пакет `store` .
### Eval-харнес распознавания (корпус кейсов + метрика точности)
Распознавание — ядро продукта, но смена модели или правка промпта сейчас
вслепую: регрессий не видно. Нужен корпус размеченных кейсов (русские
релизы, аниме, сезон-паки, репаки, спецвыпуски) и прогон распознавания по
нему с метрикой точности (тип/название/год/нумерация). Тогда можно
сравнивать LLM-провайдеры и версии промпта по числам, а не на ощупь.
Прогон — отдельной командой (`jellybit eval` или тестом), на фикстурах, без
реального qBittorrent.
Связано: [recognition.md ](specs/recognition.md ) (конвейер, модель
уверенности), пакет `recognize` .
### НФТ: масштаб до 100 одновременных загрузок (потолок — 1000)
Сейчас потолок по нагрузке нигде не зафиксирован: воркер, поллинг
qBittorrent, пул LLM-вызовов и запись в SQLite спроектированы «на глаз».
Записать в **нефункциональные требования ** целевой ориентир — архитектура
держит до **100 одновременных загрузок ** в работе (приём → распознавание →
раскладка), план-максимум — **1000 ** . Сама запись требования дешева и
высокоценна: она задаёт рамку для решений ниже по списку. Отдельно (уже
дороже) — аудит узких мест под эту цифру: одиночное соединение SQLite и
сериализация записи, конкурентность воркера и лимит параллельных
распознаваний, частота/стоимость поллинга и дедуп при наплыве.
Связано: [architecture.md ](specs/architecture.md ) → «Отслеживание
загрузки»/«Хранилище», пакеты `worker` , `store` , `qbt` , `llm` .
## Средний
### Словарь единого языка (ubiquitous language)
Свести термины домена в один глоссарий, чтобы пользователь, документация,
код и агент говорили на одном языке: загрузка, раздача, распознавание, матч,
кандидат, раскладка, источник/цель, хардлинк, ревью, переход состояния и
т.д. — русский термин, английский идентификатор в коде, краткое определение.
Сейчас наименования расходятся между спеками, UI и кодом, и в диалоге с
агентом приходится каждый раз сверять понятия. Глоссарий — источник истины
по именам; на нём же строится агент-ревьювер наименований (см.
[«Агенты-ревьюверы качества» ](#агенты-ревьюверы-качества-наименования-архитектура-конвенции-стиль )).
Связано: [docs/conventions ](conventions/README.md ) (кросс-каттинг),
[architecture.md ](specs/architecture.md ) (домен), новый файл-глоссарий.
### Агенты-ревьюверы качества (наименования, архитектура, конвенции, стиль)
Набор узких сабагентов-ревьюверов поверх ревью-процесса из `CLAUDE.md` ,
каждый со своей оптикой: соответствие наименований словарю единого языка,
соблюдение архитектурных границ (единое ядро/тонкие транспорты, инварианты
безопасности данных), конвенций (ошибки, логирование, конфиг, TZ), стиля
кода на высоком уровне и поиск дублирования. Запускаются как чекпоинт перед
`archive` /коммитом. Развивает ревью-процесс OpenSpec в сторону
воспроизводимых автоматических проверок, не заменяя человеческое ревью.
Связано: `CLAUDE.md` (ревью-процесс, конвенции),
[docs/conventions ](conventions/README.md ),
[«Словарь единого языка» ](#словарь-единого-языка-ubiquitous-language ).
### Сила совпадения кандидата и пересмотр распознавания/матчинга _(идея)_
Сейчас у кандидата метабазы нет метрики силы совпадения (`metadata_candidate`
хранит provider/id/title/year/url), а решение «авто vs review» — по правилу
«единственный сильный матч + валидация», не по числовой уверенности. Для
ревью это значит: список кандидатов нечем отсортировать/подсветить по
уверенности — берём порядок сбора. Идея — ввести на этапе матча **силу
совпадения кандидата** (точное совпадение названия+года vs частичное) для
сортировки и подсказки в UI. Шире — отдельно продумать **сам процесс
распознавания и матчинга**: границы «разбор LLM / поиск в базе / сверка»,
что храним у кандидата, как считаем и показываем уверенность. Требует
проработки перед реализацией.
Связано: [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 ),
[review-ux.md ](specs/review-ux.md ) (выбор источника в ревью, реализовано),
[«Пересмотр набора capabilities» ](#пересмотр-набора-capabilities-и-рефакторинг-спек ).
### История переходов загрузки
Сохранять полную историю переходов состояний загрузки (что/когда/почему/кто
инициировал — воркер, человек, сверка), а не только текущее состояние.
Сейчас по задаче виден лишь актуальный статус, а разбор «как мы сюда попали»
идёт по логам сервера. Отдельная таблица истории даёт лог переходов в
карточке/расширенной информации и фундамент для метрик длительности стадий.
Естественно ложится на собственный идентификатор загрузки.
Связано: детальный экран загрузки (`/download/{id}` ) уже реализован — лог
переходов ложится в него;
[drafts/logical-title-model.md ](drafts/logical-title-model.md ) §5.4 (схема
`state_transition` , actor `worker|human|reconcile` ),
[workflow.md ](specs/workflow.md ) (граф состояний),
[database.md ](specs/database.md ), пакеты `worker` , `store` .
### Машина состояний на go-библиотеке
Сейчас FSM реализована вручную в `worker` . Выбрать подходящую go-библиотеку
для описания воркфлоу/машины состояний и перевести переходы на неё — ради
декларативности, проверяемости переходов и единого места правды. Кандидаты
для оценки: `looplab/fsm` , `qmuntal/stateless` (и аналоги). Граф и переходы
уже формализованы — переносим один в один.
Связано: [workflow.md ](specs/workflow.md ) (текущий граф состояний).
### Привязка уведомлений к источнику в ботах (мульти-бот)
Уведомления и запросы подтверждения должен получать тот, кто прислал
загрузку: автор сообщения о новой раздаче — адресат пингов и ревью по ней.
Транспортов-ботов может быть несколько (Telegram, в перспективе Matrix и
др.); каждый адресует «своему» отправителю. Веб-интерфейс остаётся
**единым для всех ** и точкой правды по функциональности (боты — тонкие
адаптеры над тем же ядром). Нужно: хранить у загрузки источник/транспорт и
идентификатор отправителя, маршрутизировать пинги по нему.
Связано: [review-ux.md ](specs/review-ux.md ) (разделение труда транспортов,
веб = точные правки), [architecture.md ](specs/architecture.md ) →
«Транспорты».
### Улучшения UI: показывать матч с записью метабазы
Web-сторона реализована: страница загрузки `/download/{id}` и экран ревью
показывают, **с какой именно записью ** метабазы (TMDB/TVDB/IMDb) сматчилась
загрузка — провайдер, id и ссылку на запись. Осталось довести то же в
**Telegram ** : в уведомлениях/подтверждениях показывать запись матча (название,
год, провайдер-id, ссылку), чтобы ошибочную привязку было видно и из бота.
Полный выбор источника в вебе уже реализован — см.
[review-ux.md ](specs/review-ux.md ).
Связано: [review-ux.md ](specs/review-ux.md ), [recognition.md ](specs/recognition.md )
(матч в базе), [architecture.md ](specs/architecture.md ) → «Транспорты».
### Сложные сериальные раздачи: все сезоны разом, паки, спецраскладки _(идея)_
Обычный случай сериальной раздачи — один сезон (его номер надо сразу видеть
глазами и сверять на ревью — под это сделана сводка сезонов в инфо-части, см.
`openspec/specs/review` ). Но в редких заказах раздача бывает сложнее: **все
сезоны сериала разом**, **пак нескольких сезонов ** , смешанная нумерация, вложенные
папки сезонов, разнобойные имена файлов. Сейчас `PlanFile.Season` задаётся на
каждом файле (мультисезон в принципе выразим), но целостно эти сценарии не
проработаны: как надёжно распознать многосезонную раздачу, как показать её на
ревью (сводка — лишь страховка, не полноценный разбор по сезонам), как разложить
и как это стыкуется со сходимостью папки и merge-докачиванием. Проработать
крайние случаи и решить, что поддерживаем явно, а что уводим в ревью как «сложную
раскладку».
Связано: [recognition.md ](specs/recognition.md ) (сезон-паки, нумерация),
[jellyfin-layout.md ](specs/jellyfin-layout.md ) (раскладка сезонов),
[review-ux.md ](specs/review-ux.md ) (крайние сценарии, сводка сезонов),
[«Проблема второго сезона» ](#проблема-второго-сезона ),
[«Раздачи с докачиванием» ](#раздачи-с-докачиванием-слияние-при-повторном-добавлении ).
### Аниме с абсолютной нумерацией
Релизы аниме часто нумеруют серии сквозным числом (`#137` ) без сезонов, а
Jellyfin ждёт `SxxEyy` . Нужен пересчёт абсолютной нумерации в сезон/серию —
надёжнее всего через TVDB (там есть absolute order). Отдельный крайний
случай распознавания; на стороне ревью — веб-хелпер «absolute → S·E».
Связано: [recognition.md ](specs/recognition.md ) (конвейер, сезон-паки),
[jellyfin-layout.md ](specs/jellyfin-layout.md ) (нумерация серий),
[review-ux.md ](specs/review-ux.md ) (крайние сценарии).
### Добавление торрентов файлом/ссылкой — «единое окно»
Поддержать источники помимо magnet: `.torrent` -файл и URL (отдаём их в
qBittorrent, без исходящих запросов на пользовательский URL — SSRF
исключён). Идеал — одно поле «единого окна»: кидаем туда текст или файл, а
сервис сам разбирает, что это (magnet / ссылка / .torrent / сообщение
бота), и заводит загрузку.
Связано: [architecture.md ](specs/architecture.md ) → «Транспорты»
(`source_type = magnet|torrent|url` уже в схеме), пакет `ingest` (сейчас
поддержан только magnet).
### Бэкап SQLite
`architecture.md` требует «бекапить data-том», но * как * — не описано. Без
понятной стратегии сбой или редеплой стирают всё in-flight состояние.
Зафиксировать решение и реализовать: периодический `VACUUM INTO` в
`/data/backups` по расписанию (с ротацией) либо потоковая репликация
(litestream). Лучше сделать, пока БД маленькая.
Связано: [architecture.md ](specs/architecture.md ) → «Деплой» (data-том,
«бекапить-и-не-терять»), пакет `store` .
### Глубокий healthcheck и статус зависимостей
`/healthz` проверяет только сам сервис. Если qBittorrent, LLM или метабаза
недоступны — узнаёшь лишь по застрявшим задачам. Нужна readiness-проверка
ключевых зависимостей и отражение их состояния в UI (бейдж «qBittorrent
недоступен»), чтобы причина простоя была видна сразу.
Связано: [architecture.md ](specs/architecture.md ) → «Деплой» (healthcheck),
пакеты `qbt` , `llm` , `metadata` , `httpapi` .
### Обучение на правках человека (few-shot из прошлых ревью)
Когда человек поправил матч, тип или нумерацию — сохранять это как пример и
подмешивать похожие в будущие промпты. Системно повышает точность на «твоих»
трекерах и форматах имён без смены модели. Развитие идеи многоступенчатой
верификации, но дешевле: учимся на уже собранных `hint` /`override` .
Связано: [recognition.md ](specs/recognition.md ) (конвейер, промпт),
[«Многоступенчатая верификация» ](#многоступенчатая-верификация-привязки-идея ),
[architecture.md ](specs/architecture.md ) → «Хранилище» (`hint` , `override` ).
### Гейт авто-раскладки по `confidence`: спека vs код
Аудит спек↔код (2026-07-03) нашёл расхождение в модели уверенности.
Спека `recognition` (унаследовано из `recognition.md` ) утверждает, что
самооценка LLM `confidence` — **вспомогательный сигнал, НЕ единственный гейт ** :
при подтверждённом матче в базе + чистой структурной валидации + согласованности
сигналов авто-раскладка допускается. Код же (`internal/recognize/validate.go` ,
`confidence < AutoThreshold` , дефолт 0.85) делает `confidence` **жёстким
блокирующим условием**: план с матчем и чистой валидацией, но `confidence` 0.5
уйдёт в review вопреки сценарию спеки. Нужно определиться, что правда: либо
признать порог `AutoThreshold` в спеке как легитимный гейт (скорее так — код его
осознанно ввёл конфигом), либо ослабить код. Заодно `AutoThreshold` как
конфигурируемый гейт спекой не описан.
Связано: `openspec/specs/recognition` (требование «Модель уверенности и решение
auto/review»),
[ADR-2026-06-13-auto-link-requires-db-match ](adr/ADR-2026-06-13-auto-link-requires-db-match.md ),
пакет `recognize` .
### Привязка внешних субтитров к серии (сериалы)
Аудит спек↔код (2026-07-03): спека `recognition` требует «внешние субтитры SHALL
привязываться к соответствующему видео». Для **фильма ** это работает — раскладка
именует субтитр по базе видеофайла. Для **сериала ** связь субтитр→конкретная
серия не выражена: в `PlanFile` (`internal/recognize` ) нет поля привязки, и нет
логики спаривания VobSub `.idx` +`.sub` . Нужно смоделировать привязку субтитра к
эпизоду (поле на `PlanFile` или роль с указанием `season` /`episode` ) и спаривание
`.idx` +`.sub` , либо — если поддержку откладываем — сузить формулировку спеки до
реального поведения.
Связано: `openspec/specs/recognition` (требование «Роли файлов на краях»),
[jellyfin-layout.md ](specs/jellyfin-layout.md ) (имена субтитров), пакеты
`recognize` , `layout` .
### Раздачи-копии диска (DVD/BluRay: VIDEO_TS/BDMV)
Иногда для очень редких фильмов скачивается не один видеофайл, а **полная копия
диска** — структура `VIDEO_TS/` (DVD: `VIDEO_TS.IFO` , `VTS_01_1.VOB` …) или
`BDMV/` (BluRay: `BDMV/STREAM/*.m2ts` , `index.bdmv` ). Сейчас распознавание и
раскладка заточены под пофайловый разбор (один main-видеофайл фильма / серии
сериала), а тут «фильм» — это **каталог целиком ** . Jellyfin такие раскладки
поддерживает (папка фильма с вложенным `VIDEO_TS` /`BDMV` ), нам нужно: распознать,
что раздача — это образ диска (по наличию `VIDEO_TS` /`BDMV` ), не пытаться
разбирать её по отдельным VOB/m2ts как серии, и разложить весь каталог диска
хардлинками в папку фильма Jellyfin (`Название (Год)/VIDEO_TS/…` ). Крайний, но
реальный случай для редких изданий; частота низкая, поэтому в «Среднем».
Связано: [recognition.md ](specs/recognition.md ) (роли файлов, что игнорируем),
[jellyfin-layout.md ](specs/jellyfin-layout.md ) (раскладка фильма, крайние
случаи), пакеты `recognize` , `layout` .
## Низкий
### Панель действий ревью вне htmx-свопа блока источника
При выборе источника одним кликом обновляется только блок источника
(`#source-block` ) htmx-свопом, а нижняя панель действий (кнопка «Применить»,
завязанная на `HasLinks` ) — вне блока и не обновляется до полной перезагрузки.
Практически не мешает (хардлинки только по явному «Применить»,
`Apply` без плана вернёт ошибку), но в краевом случае (источник с пустым
предпросмотром из-за коллизии) кнопка «Применить» может остаться/пропасть не
синхронно. Решение намечено в дизайне `review-unified-source-block`
(Risks/Trade-offs): обновлять панель `hx-swap-oob` из того же партиала.
Связано: `openspec/specs/review` , `openspec/specs/web-ui` , пакет `httpapi` .
### Мгновенные обновления через SSE
Живые обновления прогресса сейчас на htmx-поллинге (фаза 2 веб-UI) — просто
и работает, но с задержкой в интервал опроса и холостыми запросами.
Перевести динамический контент (прогресс загрузки, смена статуса, раздача)
на Server-Sent Events, чтобы обновления приходили почти мгновенно и без
лишнего поллинга. Поллинг работает, поэтому это улучшение, а не блокер; SSE —
один долгоживущий ответ на соединение, ложится на server-rendered UI без
тяжёлого фронтенда.
Связано: [architecture.md ](specs/architecture.md ) → «Транспорты»,
[review-ux.md ](specs/review-ux.md ), пакет `httpapi` .
### Версии/качество одного тайтла (репаки, апгрейд 1080p → 2160p)
По калибровке болей (2026-07-02,
[drafts/logical-title-model.md ](drafts/logical-title-model.md ) §6.3) —
**не боль ** , из приоритета выпало. Сосуществование версий доступно уже
сейчас (Jellyfin multi-version, другой целевой путь), коллизия на тот же
путь штатно уходит в review. Явный replace (undo старого хардлинка → lay
нового → супересид владения путём) — отдельный change, если/когда станет
болью.
Связано: [«Раздачи с докачиванием» ](#раздачи-с-докачиванием-слияние-при-повторном-добавлении ),
[jellyfin-layout.md ](specs/jellyfin-layout.md ) (never-overwrite, коллизия).
### Многоступенчатая верификация привязки _(идея)_
Несколько раз извлекать данные из раздачи и контекста разными промптами,
искать в метабазах, затем сводить результаты в общий вердикт
(голосование/консенсус) — выше точность ценой нескольких вызовов LLM и
запросов к базам. Требует проработки: когда включать, как мерджить
расхождения, стоимость/латентность.
Связано: [recognition.md ](specs/recognition.md ) (конвейер и модель
уверенности).
### Выбор из нескольких находок метабазы в Telegram
Когда распознавание даёт несколько подходящих кандидатов в метабазе,
предлагать их в Telegram списком (кнопки) для ручного выбора, а не молча
брать первый/лучший. Веб остаётся точкой точных правок (полный выбор
источника уже реализован — см. [review-ux.md ](specs/review-ux.md )), бот —
быстрый выбор из готового короткого списка.
Связано: [review-ux.md ](specs/review-ux.md ) (боты — быстрые действия, веб —
точные правки), [recognition.md ](specs/recognition.md ) (кандидаты матча).
### Проверка свободного места перед copy-fallback
Когда хардлинк невозможен (`EXDEV` /`ENOTSUP` /…), `layout` копирует файл,
дублируя место на диске. На забитом диске это упрётся в полку посреди
раскладки. Перед копированием проверять доступное место и при нехватке
внятно уходить в `failed` с понятной причиной, а не падать на полпути.
Связано: [architecture.md ](specs/architecture.md ) → «Раскладка файлов»
(фолбэк-копирование), пакет `layout` .
### Кэш метабаз (и опционально LLM)
Повторные и ретраящиеся прогоны распознавания бьют TMDB/TVDB/TVMaze одним и
тем же запросом. Кэш ответов с TTL экономит лимиты API и ускоряет «Распознать
заново»/«Уточнить». При желании — кэш ответов LLM по хешу входа (но он менее
полезен, т.к. вход меняется подсказками).
Связано: [recognition.md ](specs/recognition.md ) (сверка с базой), пакеты
`metadata` , `llm` .
### guessit как сервис-спутник _(идея)_
`go-ptn` слабее питоновского `guessit` . Если точности пред-парса не
хватит — завернуть `guessit` в крошечный HTTP-сервис (один файл,
поставляется рядом с бинарём jellybit) и спрашивать его на шаге
пред-парса. Сохраняет «доставку копированием»: два файла вместо одного.
Связано: [recognition.md ](specs/recognition.md ) → «На будущее» (пред-парс).
### Завершение загрузки через webhook _(идея)_
Сейчас завершение ловим поллингом qBittorrent раз в несколько секунд.
Альтернатива: «Run external program on torrent completion» в qBittorrent
дёргает эндпоинт jellybit. Реагирует быстрее, но связывает нас с конфигом
qBittorrent. Решим по опыту эксплуатации.
Связано: [architecture.md ](specs/architecture.md ) → «Отслеживание загрузки»,
пакет `worker` .
### Авторизация веб-UI (на будущее)
Решено для v1: без авторизации в доверенной LAN, опц. allowlist подсетей
(`http.trusted_subnets` ) — как умеет qBittorrent. Если понадобится защита:
токен/Basic в самом приложении или вынос за reverse-proxy с
аутентификацией.
Связано: [architecture.md ](specs/architecture.md ) → «Транспорты» (доступ к
веб-UI), пакет `httpapi` .
### Современный Web-UI как PWA
Переделать веб-интерфейс в современное PWA-приложение (устанавливаемое,
отзывчивое, удобное с телефона). Текущий server-rendered UI функционален,
поэтому это улучшение, а не блокер; большой объём работы.
Связано: [review-ux.md ](specs/review-ux.md ) (веб = точные правки),
пакет `httpapi` .