Форма добавления не имела поля channel, валидатор требует его для
crawler=telegram → 'telegram-источнику нужен channel'.
Добавлено поле в add-форму (required для telegram через JS), показ channel
в таблице у telegram-источников. Backend не менялся.
web/templates/sources.html ранее отсутствовал в git — добавлен.
- новый статус selected; в кандидатах только «⭐ Отобрать» (single+bulk)
- /selected — отдельный список: вся обработка (классификация/переписывание/комментарий/публикация)
- классификация только по кнопке (токены на кандидатов не тратятся)
- рядом с оригиналом — поле «✍️ Мой пост» (rewritten_text всегда виден), туда ложится черновик «Переписать»
- все обработчики учитывают src (candidates|selected) для редиректов
- reject/reject-old (single + bulk): редирект на /candidates с текущей
группировкой вместо /candidates?status=rejected — не прерываем отбор.
Отклонённые доступны через фильтр статуса.
- candidates.html: Обработать/Переписать/Отклонить — один ряд над полем
комментария (после переноса Опубликовать в approve-форму кнопки съехали).
changes: candidates-buttons-order, reject-stay-candidates (skip_specs, валидны).
- _fetch_candidates: жёсткое status='new' только при пустом status; явный
статус (rejected/published) — единственный фильтр статуса → ?status=rejected
больше не даёт пустой список
- формы approve/reclassify/rewrite/reject/comment: скрытые поля
group_by/direction/own/q — контекст страницы
- POST-роуты: редирект через _cand_back() сохраняет группировку и фильтры
(reject → ?status=rejected&group_by=...; approve → ?status=published&...)
- _fetch_candidates: статус группы = доминирующий (new>rejected>published),
а не первого поста → при group_by=date группа «Ранее на этой неделе»
больше не выглядит опубликованной (openchange fix-date-group-status)
- base.html: padding-top 1.5rem→4.5rem — заголовок не перекрывается fixed-top меню
- published.html: ID поста на карточках (#N · направление)
- AGENT.MD: бэкапы автоматические по крону, вручную не запускать
- base.html: container -> container-fluid (nav and content full width)
- Right pane: large buttons Publish / Process with local model /
Rewrite / Reject (for new candidates)
- Left pane bottom: bulk operations panel with 4 visible buttons
(Publish / Process / Reject / Stale) instead of hidden select
- bulk: action 'process' reclassifies selected with local model
(impl_reclassify extracted); ids optional (empty selection ->
no_selection redirect instead of 422); redirect preserves filters
- Tests: full width, buttons present, bulk empty/process, published/metrics — green
- Группировка вынесена из onchange-сабмита bulk-формы в GET-ссылки
(/candidates?group_by=...&filters...&selected=...)
- Чекбоксы bulk привязаны к форме атрибутом form='bulk-form' (без JS,
HTML5) — устранены вложенные формы (невалидный HTML)
- Выбор поста — ссылкой GET (selected=id) вместо POST /candidates/select
- app.py: добавлен filters_qs (query-string фильтров для ссылок),
импорт urllib.parse.quote; /candidates/select оставлен для обратной
совместимости (сабмит старых форм)
- Тест: смена группировки, bulk reject, выбор поста, фильтры — зелёные