Files
Deal/.superpowers/sdd/channel-discovery/task-3-brief.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

30 lines
2.9 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 3: Хранилище Discovery (задачи/кандидаты/чёрный список/лог)
**Files:**
- Create: `backend/app/services/discovery.py`
**Interfaces:**
- Consumes: `store` (таблицы Task 1).
- Produces (все синхронные):
- `list_tasks() -> list[dict]`, `get_task(id) -> dict | None` (keywords — список)
- `create_task(payload: dict) -> dict` — валидация: name непустое; `plan_joins` 1..limit; **правило бюджета**: `sum(plan_joins задач, где status NOT IN ('done','failed')) + plan_joins <= discJoinLimit`, иначе `raise ValueError(...)`.
- `patch_task(id, patch: dict) -> dict` (name/description/keywords/min_subscribers/lang/threshold/sample_size/plan_joins/auto_join; увеличение plan_joins — с той же проверкой)
- `delete_task(id) -> None` (удалить задачу и её кандидатов)
- `start_task(id) -> dict` — требует непустой keywords; status=running; `pause_task(id) -> dict` — paused
- `list_candidates(task_id, status: str | None) -> list[dict]` (декод marks/topics)
- `add_candidate(task_id, dialog_id, name, username, kind, hue) -> dict | None``None`, если: в `dialogs`, в `disc_blacklist`, либо уже есть `disc_candidates` со статусом new/review/joined. Лог `skip` с причиной.
- `bump_counter(task_id, field: str, n: int = 1)` — found/evaluated/joined/rejected
- `set_candidate(task_id, dialog_id, patch: dict)` — обновление полей кандидата
- `set_candidate_status(dialog_id, status)` + лог
- `delete_candidate(dialog_id) -> None` — удалить кандидата (skip-ветки)
- `advance_search(task_id) -> None``search_idx += 1`; когда индекс >= len(keywords) → `search_done=True`
- `mark_joined(dialog_id, auto: bool)` — статус joined + `bump_counter('joined')` + лог `join_auto`/`join_manual`
- `mark_rejected(dialog_id, reason="")` — статус rejected + `bump_counter('rejected')` + лог `reject` + `add_blacklist`
- `add_blacklist(dialog_id, name, reason) / remove_blacklist(dialog_id) / list_blacklist() -> list[dict]`
- `add_log(task_id, event, text="")`; `task_log(task_id, limit=100) -> list[dict]`
- [ ] **Step 1: Реализовать модуль** (json-поля по конвенции проекта; все `store.execute/query` с параметрами).
- [ ] **Step 2: Проверить на временной БД** (сценарий): создать задачу plan=25 → ок; создать вторую plan=30 → `ValueError`; кандидат, совпадающий с `dialogs``add_candidate` вернул None + лог skip; `mark_rejected` → в чёрном списке; повторный `add_candidate` того же источника → None.
---