Files
Deal/.superpowers/sdd/channel-discovery/task-9-report.md
T
Rustam Khalimov 27c7831910
ci / build-test (push) Canceled after 0s
Deal — единая кодовая база
SaaS-мониторинг Telegram: ядро (модули Cards/Kanban/Pipeline/Tenants/Settings/
Discovery, Api, Infrastructure), сервисы telegram/ai/ml/storage, фронт Vue,
контракты и grpc-hosting, деплой-конфиги (dev/prod/observability/CI-раннер),
Gitea Actions CI, документация (ТЗ, техдок, api-map, код-стайл, планы, бэклог).

Текущее состояние: все этапы роадмапа 0–12 закрыты, сборка 5 sln 0/0,
тесты 1340/130/52/38/9 зелёные.
2026-09-11 23:56:47 +03:00

50 lines
7.0 KiB
Markdown
Raw 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.
# Task 9 — Отчёт: Фронтенд — кандидаты, действия, чёрный список, история
## Статус
Выполнено. `cd /c/telbase/frontend && npm run build` — без ошибок (`✓ built`, 42 modules transformed).
`python -m py_compile backend/app/routers/settings_routes.py` — OK.
## Файлы
- Изменён: `frontend/src/views/DiscoveryView.vue` — табы кандидатов/истории/чёрного списка, карточки кандидатов, квоты.
- Изменён: `frontend/src/store.js``state.discCounts` + `loadDiscCounts(taskId)`; `loadDiscCandidates` обновляет счётчик текущего статуса.
- Изменён: `frontend/src/components/Icon.vue` — новые иконки `users`, `megaphone`, `list` (чипы вида источника, участники, темы).
- Изменён: `backend/app/routers/settings_routes.py``discPaused` добавлен в `_PUBLIC_BOOL` (одной строкой).
## Что сделано
### Табы панели задачи (DiscoveryView, правая колонка)
- Под «мастером» и действиями задачи — панель с табами: «В обработке» (`new`), «На рассмотрении» (`review`), «Вступили» (`joined`), «Отклонены» (`rejected`), «История» (лог), «Чёрный список».
- Бейджи-счётчики (`state.discCounts`) скрыты при 0; переключение таба вызывает `loadDiscCandidates(taskId, status)` / `loadDiscLog(taskId)` / `loadDiscBlacklist()`; смена активной задачи и повторный клик по ней — авто-загрузка панели (`loadPanel`).
- Счётчики всех четырёх статусов обновляет `loadDiscCounts` (4 параллельных GET по статусам). Защита от гонок при быстром переключении табов/задач — `panelSeq` (stale-ответ перезагружает актуальный таб).
- Пока задача `running` — список кандидатов/счётчики тихо обновляются каждый второй тик опроса (~9 c).
### Карточка кандидата
- Аватар по `hue` (как в ChannelsView), название, `@username`, чип вида (канал `megaphone`/brand, группа `users`/online, форум `list`/warn), участники (`N участник/а/ов`, «—» при None), метки `marks` чипами (важные — закрытая группа/история недоступна — подсвечиваются warn).
- Соответствие: для канала/группы — «подходит N%» (по `fitRatio`); для форума — «подходит тем: N из M» и раскрывающийся список тем «тема „{title}" — подходит {fitCount} из {total}» с passed-подсветкой (pass — online, нет — приглушённый).
- Кнопки «Вступить и мониторить» и «Отклонить» — только для `status === 'review'`; join без подтверждения, reject через `askConfirm` (уходит в чёрный список). Для `new` кнопок нет — подпись «воркер оценит источник». После join/reject счётчики перечитываются.
- Раскрытие тем форума — локальный `Set` `expanded` (chevron).
### Чёрный список
- Выбран отдельный таб «Чёрный список» в той же панели (читабельно и не спорит с макетом). Строка: иконка, имя, причина/дата, кнопка «Снять» (`removeDiscBlacklist`, guard от двойного клика `unbanId`).
### Квоты авто-вступлений
- Маленькая кнопка «Квоты» в шапке левой панели (рядом со списком задач) → inline-блок: суточный лимит `discJoinLimit`, паузы мин/макс `discJoinDelayMin/Max` (сек), стоп-кран-переключатель `discPaused`.
- Дефолты не хардкодятся: при первом открытии блока — `GET /api/settings` (локальная загрузка), сохранение чисел — `PATCH /api/settings` одним объектом (клампы 1–200 и 5–600 как на бэке, min ≤ max), стоп-кран патчится сразу при переключении.
- На бэке `discPaused` добавлен в `_PUBLIC_BOOL` — теперь принимается PATCH и отдаётся в GET.
### store.js
- `state.discCounts = { new:0, review:0, joined:0, rejected:0 }`.
- `loadDiscCandidates` дополнительно пишет `discCounts[status]`.
- `loadDiscCounts(taskId)` — Promise.all по 4 статусам, заполняет `discCounts` (не трогает `discCandidates`).
## Вывод проверок
1. `cd /c/telbase/frontend && npm run build``✓ built in 1.24s`, `42 modules transformed`, ошибок нет.
2. `diagnostics` по `DiscoveryView.vue`, `store.js`, `Icon.vue` — ошибок/предупреждений нет.
3. `python -m py_compile backend/app/routers/settings_routes.py` → OK.
## Concerns
1. Живой API/UI не гонялся (нет запущенного бэкенда/дев-сервера в этой сессии); поведение опирается на контракт Task 7. Визуальная проверка сценариев — за Task 10.
2. Кнопка «Квоты» дергает `GET/PATCH /api/settings` напрямую из вью (в store нет state-полей под диск-квоты, по брифу разрешена локальная загрузка/сохранение через `api.patch`). Это единственное место, где вью импортирует `api` напрямую — если захочется строгой «только через store», квоты стоит перевести в store-функции.
3. Счётчики табов получаются отдельными запросами по каждому статусу (у бэкенда нет эндпоинта counts); при активном воркере это ~4 лёгких GET каждые ~9 c — приемлемо для текущих объёмов, но при росте числа кандидатов можно добавить серверный `counts`.
4. «На рассмотрении» — таб по умолчанию для активной задачи (в `state.discCandidateStatus` изначально `review`); таб «История»/«Чёрный список» сохраняется при переключении задач.
5. `progress.md` не трогался.