# Spec — candidates-mail-ui ## ADDED Requirements ### Requirement: Двухпанельный интерфейс кандидатов Страница кандидатов разделена на две панели: слева список кандидатов (с группировкой), справа — детальный просмотр выбранного кандидата с меню действий. #### Scenario: Пользователь открывает список кандидатов Given на странице `GET /candidates` When страница загружается Then левая панель показывает список кандидатов, правая — детали первого/последнего выбранного And активный кандидат подсвечивается #### Scenario: Группировка списка по источнику Given список кандидатов When пользователь выбирает группировку «по источнику» Then кандидаты сгруппированы по источнику (канал/сайт) And каждая группа сворачивается/разворачивается (без JS, через `
`) #### Scenario: Группировка по дате поступления When пользователь выбирает группировку «по дате поступления» Then кандидаты сгруппированы по дате поступления (сегодня, вчера, ранее) And порядок: новые сверху, старые ниже ### Requirement: Bulk-операции над выбранными кандидатами Пользователь может выбрать несколько кандидатов (чекбоксы) и выполнить массовое действие: одобрить все выбранные / отклонить все выбранные. #### Scenario: Массовое отклонение выбранных Given на левой панели несколько кандидатов с отмеченными чекбоксами When пользователь нажимает «Отклонить выбранные» Then все отмеченные кандидаты получают статус «отклонён» And действие выполняется транзакционно (все или ни одного) #### Scenario: Массовое одобрение выбранных When пользователь нажимает «Одобрить выбранные» Then каждый отмеченный кандидат публикуется (вызывается approve-логика) #### Scenario: Отклонение всех старых постов группы Given группа «ранее» (старые посты) When пользователь выбирает «отклонить все в группе» Then все посты группы получают статус «отклонён» ### Requirement: Действия над конкретным кандидатом Правая панель содержит меню действий: Опубликовать, Отклонить, Переклассифицировать, Переписать новость под себя, блок «Мой комментарий», оригинальный пост со всеми медиа. #### Scenario: Опубликовать кандидата Given выбран кандидат в правой панели When пользователь нажимает «Опубликовать» Then пост публикуется (существующая логика approve, publisher) #### Scenario: Отклонить кандидата When пользователь нажимает «Отклонить» Then пост получает статус «отклонён» и исчезает из активных кандидатов #### Scenario: Переклассифицировать кандидата When пользователь нажимает «Переклассифицировать» Then запускается классификатор для данного поста And направление/relevance/interest обновляются, изменения видны на карточке #### Scenario: Переписать новость под себя When пользователь нажимает «Переписать новость» Then LLM генерирует черновик пересказа от первого лица (без копипасты) And черновик отображается в текстовом поле для редактирования And пользователь может отредактировать и затем опубликовать #### Scenario: Комментарий к кандидату Given в правой панели блок «Мой комментарий» When пользователь вводит текст и сохраняет Then комментарий сохраняется и отображается при повторном открытии кандидата #### Scenario: Оригинальный пост со всеми медиа Given выбран кандидат с медиа Then правая панель показывает оригинальный текст поста, все изображения/видео (через роут /media/), мета источника (канал, время, views/reactions) ### Requirement: Фильтрация и поиск по списку Список кандидатов можно фильтровать по статусу (новые/одобренные/отклонённые) и искать по тексту. #### Scenario: Фильтр по статусу Given на странице кандидатов When пользователь выбирает фильтр «новые» Then в списке остаются только новые кандидаты #### Scenario: Поиск по тексту When пользователь вводит текст в поиск Then список фильтруется по вхождению в текст поста