## Why Два бага при работе со списком кандидатов: 1. **Пустой список при `?status=rejected`.** После фикса `candidates-only-external-new` в `_fetch_candidates` жёстко добавлено `p.status='new'`. Когда пользователь явно выбирает `status=rejected` (или `published`), в WHERE попадают ОБА условия: `p.status='new' AND p.status='rejected'` → выборка всегда пустая, страница показывает «Нет кандидатов по фильтру». 2. **Сброс группировки после действия.** Роут `/posts/{id}/reject` редиректит на `/candidates?status=rejected` без сохранения `group_by` (и direction/own/q). Пользователь был в группировке «дата» → после отклонения его выбрасывает на `?status=rejected` с дефолтной группировкой «источник». Аналогично approve/reclassify/rewrite/comment редиректят на `?selected={id}` без сохранения группировки. ## What Changes 1. **`web/app.py`, `_fetch_candidates`:** жёсткое `p.status='new'` добавлять только когда параметр `status` пуст (значение по умолчанию = кандидаты new). Если `status` задан явно (`new`/`rejected`/`published`) — применять его как единственный фильтр статуса. `p.is_own=0` остаётся всегда (свои посты не кандидаты). 2. **Формы правой панели в `candidates.html`** (approve, reclassify, rewrite, reject, comment): добавить скрытые поля `group_by`, `direction`, `own`, `q` со значениями текущей страницы. 3. **Роуты POST-действий** (approve, reclassify, rewrite, reject, comment): читать `group_by`/`direction`/`own`/`q` из формы и строить редирект с этими параметрами, чтобы пользователь остался в той же группировке/фильтре. ## Why Not - Не парсить `Referer`: хрупко и небезопасно. - Не возвращать на `/published` после approve без сохранения контекста: пользователь работает в списке кандидатов и хочет остаться в нём. - Не менять SQL-структуру counts: counts считаются по внешним постам и уже корректны. ## Impact - Файлы: `web/app.py`, `web/templates/candidates.html`. - Данные: без миграций БД. - Сервис: `vesti-web` (:8400) — перезапуск. - Rollback: откатить правки, перезапустить.