Files

130 lines
9.1 KiB
Markdown
Raw Permalink 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.
# TODO
Конкретные задачи на будущее, ранжированные по приоритету. Это не план
реализации (он — в [drafts/roadmap.md](drafts/roadmap.md)) и не свалка
идей ([drafts/ideas.md](drafts/ideas.md)): сюда попадает то, что уже решили
сделать, но ещё не сделали. Принятое и реализованное переезжает в
`docs/specs`/`docs/adr`.
Приоритет — грубая оценка «ценность / стоимость», не обязательство к
порядку.
## Высокий
### Проблема второго сезона
Если первый сезон сериала уже разложен, а мы добавляем второй/третий/…,
распознавание должно привязать новый сезон к **тому же** названию и папке,
а не завести рядом почти одинаковую вторую папку. Ключ — стабильный
`provider_id`: один и тот же `[tvdbid-…]` → одна папка сериала, новые
`Season NN` доливаются внутрь. Нужно: при матче учитывать уже существующие
в библиотеке сериалы (или прошлые распознавания с тем же провайдер-id) и
склонять LLM/выбор кандидата к согласованности с ними.
Связано: [recognition.md](specs/recognition.md) (модель уверенности,
матч в базе), [jellyfin-layout.md](specs/jellyfin-layout.md) (папка
сериала с провайдер-id).
### Название из контекста при добавлении в qBittorrent
При создании magnet-загрузки передавать в qBittorrent человекочитаемое имя
из контекста (если оно есть), чтобы в списке qBit не было безликих
`rutracker-topic-6852853`. Небольшая задача с заметной отдачей в
повседневной эксплуатации.
Связано: [architecture.md](specs/architecture.md) → «Транспорты», пакет
`ingest`/`qbt`.
### Рассинхрон состояния с реальностью (удалённый торрент / файлы)
Состояние jellybit может разойтись с тем, что реально лежит на диске.
Несколько сценариев разной остроты:
- **Жёсткий — удалён источник.** Раздачу удаляют (вручную или авто по
достижении seed limit), и qBittorrent стирает скачанные файлы. Тогда
хардлинк в библиотеке становится **последней** ссылкой на inode, и
обычный `undo` (`unlink` цели + чистка пустых каталогов) сотрёт
единственную копию насовсем — прямая потеря данных. Инвариант «источник
неприкосновенен» молчаливо перестаёт держаться: источника уже нет.
- **Мягкий — удалена цель.** Файлы убрали из библиотеки Jellyfin (вручную
или из самого Jellyfin), а jellybit по-прежнему числит загрузку в
`done`. Состояние врёт: ссылок уже нет, а сервис думает, что всё
разложено.
Нужно продумать сверку записанного состояния (`file_link`, состояние
загрузки) с фактом на ФС:
- как `worker` реагирует на исчезновение раздачи из qBittorrent
(состояние/пометка загрузки);
- как `undo` защищается, когда источник недоступен — например,
отказываться удалять, если у целевого файла счётчик ссылок == 1 (нет
второй копии) или исходный путь не существует, и явно об этом сообщать.
Откат снимает **лишний** хардлинк, а не последнюю копию файла;
- как ловить пропажу целевых файлов и отражать её в состоянии (напр.
периодическая сверка или проверка при показе — «разложено, но файлов
нет»), чтобы можно было осознанно перепривязать/переразложить.
Связано: [ADR-2026-06-13-hardlinks](adr/ADR-2026-06-13-hardlinks.md),
[architecture.md](specs/architecture.md) → «Раскладка файлов» (undo,
инвариант источника), [workflow.md](specs/workflow.md) (`done → reverted`).
## Средний
### Машина состояний на 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) →
«Транспорты».
### Добавление торрентов файлом/ссылкой — «единое окно»
Поддержать источники помимо magnet: `.torrent`-файл и URL (отдаём их в
qBittorrent, без исходящих запросов на пользовательский URL — SSRF
исключён). Идеал — одно поле «единого окна»: кидаем туда текст или файл, а
сервис сам разбирает, что это (magnet / ссылка / .torrent / сообщение
бота), и заводит загрузку.
Связано: [architecture.md](specs/architecture.md) → «Транспорты»
(`source_type = magnet|torrent|url` уже в схеме), пакет `ingest` (сейчас
поддержан только magnet).
## Низкий
### Многоступенчатая верификация привязки (тема для размышления)
Идея: несколько раз извлекать данные из раздачи и контекста разными
промптами, искать в метабазах, затем сводить результаты в общий вердикт
(голосование/консенсус) — выше точность ценой нескольких вызовов LLM и
запросов к базам. Требует проработки: когда включать, как мерджить
расхождения, стоимость/латентность.
Связано: [recognition.md](specs/recognition.md) (конвейер и модель
уверенности).
### Современный Web-UI как PWA
Переделать веб-интерфейс в современное PWA-приложение (устанавливаемое,
отзывчивое, удобное с телефона). Текущий server-rendered UI функционален,
поэтому это улучшение, а не блокер; большой объём работы.
Связано: [review-ux.md](specs/review-ux.md) (веб = точные правки),
пакет `httpapi`.