Files
vesti/openspec/changes/candidates-mail-ui/design.md
T

4.1 KiB
Raw Blame History

design.md — candidates-mail-ui

Текущая структура (из чтения кода)

  • web/app.py (FastAPI) — роуты:
    • GET /candidates — рендер candidates.html (список карточек).
    • POST /posts/{id}/approve — апрув (публикация через publisher).
    • POST /posts/{id}/reject (или аналогичный) — отклонение.
    • GET /media/{filename} — медиа (добавлен в web-media-preview).
  • Таблица posts: id, source_id (FK), text, direction, lang, views, reactions, media_path, status (new/published/rejected?), classified, created_at.
  • Таблица classifications: post_id, direction, relevance, interest, summary, model.

Архитектура нового UI

1. Левая панель: список + группировка + bulk

  • Один маршрут GET /candidates с query-параметрами:
    • group_by ∈ {source, date, status} (по умолчанию source)
    • filter (статус: new/published/rejected/all)
    • q (поиск по тексту)
  • Ответ: тот же HTML (серверный рендер, Jinja2), но layout — две колонки (Bootstrap 5 grid, уже подключён).
  • Список строится из постов (new/rejected), сгруппированных по выбранному признаку. Группы — сворачиваемые (<details>/<summary> — без JS).
  • Каждый пост имеет чекбокс <input type="checkbox" name="ids" value="{{ id }}">.
  • Форма bulk: POST /candidates/bulk с ids[] и action (approve/reject/reject-old).

2. Правая панель: детальный просмотр + действия

  • Выбранный пост: GET /candidates/{id} (или та же страница с ?selected=<id>).
  • Секции:
    • Кнопки действий: Опубликовать, Отклонить, Переклассифицировать, Переписать новость (LLM).
    • «Мой комментарий»: <textarea name="comment"> + POST /posts/{id}/comment.
    • Оригинальный пост: text (markdown), media (/media/<basename>), мета (source @channel, канал, время, views/reactions), direction badge.

3. Новые роуты/данные

  • posts.comment TEXT (nullable) — комментарий пользователя к посту.
  • POST /posts/{id}/comment — сохранить комментарий.
  • POST /candidates/bulk — bulk-одобрение/отклонение (транзакция).
  • POST /posts/{id}/reclassify — перезапуск классификатора (classifier.classify_text на посте, обновить direction/classifications).
  • POST /posts/{id}/rewrite — LLM-пересказ (qwen3:8b через Ollama): сгенерировать черновик текста от себя (без копипасты), сохранить в posts.rewritten_text, вернуть в текстовое поле для редактирования.

4. Минимум JS

  • Без JS: чекбоксы + form с method=post (multi-select через чекбоксы в одной форме).
  • Группировка/сворачивание: <details>.
  • Автоподсветка выбранного: сервер рендерит class="active" по selected id.

Реализация (по шагам)

  1. Миграция БД: ALTER TABLE posts ADD COLUMN comment TEXT.
  2. Роуты: GET /candidates (двухпанельный), POST /candidates/bulk, POST /posts/{id}/comment, POST /posts/{id}/reclassify, POST /posts/{id}/rewrite.
  3. Шаблоны: candidates.html переписать (двухколоночная), добавить new/reclassify/ comment/rewrite формы.
  4. Bulk-логика + группировка на сервере (Python).
  5. Тест: ручной сценарий (создать 2-3 поста, сгруппировать, bulk-отклонить, коммент, реклассификация).