Files
vesti/openspec/changes/publisher-service/tasks.md
T

51 lines
5.4 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.
# Tasks: publisher-service
## 1. Скелет сервиса
- [x] 1.1 Создать services/publisher/ (app/, requirements.txt, .env.example, README.md)
Проверка: `ls services/publisher/app/` → main.py, config.py, telegram.py, channels.py
- [x] 1.2 requirements.txt: fastapi, uvicorn, httpx[socks], pydantic, python-dotenv
Проверка: `.venv/bin/pip install -r services/publisher/requirements.txt` без ошибок
- [x] 1.3 config.py: env VESTI_BOT_TOKEN, TG_PROXY, VESTI_BOT_CHANNELS, PUBLISHER_PORT
Проверка: `python -c "from services.publisher.app.config import Settings; print(Settings().channels)"` → ['@dedinit_vesti']
- Замечание: токен не читался из-за порядка (os.getenv при ClassVar, до load_dotenv) и неверного пути BASE (3x parent → /opt/vesti/services, нужно parents[3] → /opt/vesti). Исправлено: Settings → @dataclass + __post_init__, load_dotenv(override=True), BASE=parents[3].
## 2. Telegram-клиент (Bot API через SOCKS5)
- [x] 2.1 telegram.py: клиент httpx с proxy=socks5://127.0.0.1:1080, методы sendMessage/sendPhoto/getMessage
- [x] 2.2 channels.py: разбор VESTI_BOT_CHANNELS ("@a,@b" → ["@a","@b"])
- [x] 2.3 Обработка ошибок: 403 (бот не админ), сеть (прокси) → 502
## 3. FastAPI-эндпоинты
- [x] 3.1 main.py: GET /healthz (status, bot, proxy, channels)
Проверка: `curl -s :8410/healthz` → ok + бот + каналы. Реальное: {"status":"ok","bot":"dedinit_controller_bot","token_set":true,"proxy":"socks5://127.0.0.1:1080","channels":["@dedinit_vesti"]}
- [x] 3.2 main.py: POST /api/v1/publish (card {text, media?, direction, lang}, channels?) → results по каналам
Проверка: `curl -X POST :8410/api/v1/publish -d '{"card":{"text":"тест","direction":"linux","lang":"ru"}}'` → ok, message_id в @dedinit_vesti. Реальное: {"ok":true,"results":{"@dedinit_vesti":{"message_id":2,...}}}
- [x] 3.3 views: эндпоинт GET /api/v1/views/{channel}/{mid} (в main.py) + поле views в ответе publish (get_views при публикации)
## 4. Контейнеризация
- [x] 4.1 Dockerfile: python:slim, non-root, read-only fs, expose 8410
- [x] 4.2 docker-compose.yml: сервис publisher, порт 127.0.0.1:8410, env из .env, healthcheck curl /healthz
- Проверено 2026-09-09: `docker compose up -d --build` → vesti-publisher Up (healthy), 127.0.0.1:8410, healthz: bot=dedinit_controller_bot, proxy=host.docker.internal.
- Питфолы Docker: (1) пути в compose отсчитываются от services/publisher/ → .env надо `../../.env`, media `../../media`; (2) TG_PROXY=127.0.0.1 в контейнере = сам контейнер → заменить на socks5://host.docker.internal:1080 + extra_hosts host-gateway; (3) load_dotenv(override=True) перебивал env контейнера → override=False (env окружения приоритетнее .env); (4) dataclass-дефолт tg_proxy="socks5://127.0.0.1:1080" был truthy → os.getenv не срабатывал → дефолт сделан пустым.
## 5. Интеграция с вебом
- [x] 5.1 web/app.py: убрать `from publisher.bot import publish_multi/get_views_multi`; вместо них web/publisher_client.py (HTTP POST на PUBLISHER_URL, default http://127.0.0.1:8410)
- Проверка: grep — импорт publisher.bot убран; карточка шлёт card{direction,lang}, сервис берёт каналы из VESTI_BOT_CHANNELS.
- [x] 5.2 Обновить .env.example (VESTI_BOT_CHANNELS, TG_PROXY, PUBLISHER_URL)
- [x] 5.3 Реальный approve через веб: сквозной путь веб → HTTP → publisher(Docker) → канал.
- Проверено 2026-09-09: approve постов 136 и 137 через POST /posts/<id>/approve — 302 → /published, статус published, бандл, tg_message_id=3 и 4 в @dedinit_vesti.
- Веб-баги, найденные при проверке: (1) `raise RedirectResponse(...)` в _require_auth → TypeError (исключение не BaseException) → 500 на /candidates; фикс: HTTPException(303, headers={"Location": "/login"}); (2) tg_message_id для внешних постов искался по направлению (results["linux"]), а ключи results — каналы (@dedinit_vesti) → 0; фикс: брать первый message_id из results.values().
## 6. Проверка и документация
- [x] 6.1 `openspec validate publisher-service` → 0 ошибок (valid)
- [x] 6.2 Реальная публикация тестовой карточки в @dedinit_vesti (бот админ) → message_id в ответе. Реальное: message_id=2, ok.
- Бот добавлен админом канала (подтверждено пользователем).
- [x] 6.3 Обновить STATUS.md / TODO.md — сделано; WALKTHROUGH/PRD — обновлено (см. PRD.md)
## Открытые пункты
- [ ] publisher: медиа из card.media — путь в БД /opt/vesti/media/... не совпадает с монтированием в контейнере (/srv/publisher/media) → send_photo не уходит при Docker-запуске (нужен маппинг путей или передача имени файла)