Files
vesti/openspec/changes/gotosocial-publisher/proposal.md
T
kpa39l bf176cc02b fediverse: публикация в GoToSocial (@vesti@dedinit.ru) из publisher-service
- gotosocial.py: клиент GtS (httpx): post_status (markdown), upload_media v2, verify_credentials, delete_status
- config.py: gt_social_url/token/visibility/format/channels
- channels.py: fediverse-каналы (VESTI_GTS_CHANNELS, префикс gt:), gt: уходит только в fediverse
- main.py: _publish_gotosocial + healthz-блок gotosocial + dry_run; status_id (ULID) в ответе
- .env.example: GT_SOCIAL_* и VESTI_GTS_CHANNELS
- STATUS.md/WALKTHROUGH.md: fediverse-раздел, хронология
- openspec: change gotosocial-publisher (proposal/design/tasks/specs), validate чисто
2026-09-13 20:19:52 +00:00

6.6 KiB
Raw Blame History

Why

У VESTI уже работает публикация в Telegram через изолированный publisher-service (POST /api/v1/publish, Docker-контейнер :8410, каналы @dedinit_vesti). Но у проекта есть вторая цель — «ленты ботов (Telegram, VK, fediverse)» (openspec/config.yaml, домен: медиа-конвейер → банк статей → дайджесты + ленты ботов). Fediverse-нода — собственный GoToSocial на social.dedinit.ru (bigbox, Docker-контейнер, :8082), аккаунт @vesti (@vesti@dedinit.ru) — обычный пользователь (admin=0), создан и подтверждён.

Сейчас при approve статьи веб зовёт publisher-service, и тот умеет публиковать только в Telegram. Чтобы публиковать одобренные карточки ещё и в свой GoToSocial-аккаунт (от имени vesti), publisher-service нужно расширить fediverse-каналом.

GtS 0.22.x реализует Mastodon-совместимый REST API (проверено: POST /api/v1/apps работает, возвращает client_id/client_secret; у ноды есть действующие OAuth-приложения Phanpy/Tusky/GoToSocial Settings). Значит, публикация в GtS идентична Mastodon: POST /api/v1/statuses с Bearer-токеном пользователя и опциональными медиа (POST /api/v2/media). Это стандарт, библиотек не требует — хватит httpx (уже есть в publisher).

What Changes

Расширяем publisher-service (FastAPI, :8410) мульти-канальной отправкой: помимо Telegram-каналов (@dedinit_vesti) появляется fediverse-канал @vesti@dedinit.ru — публикация в GoToSocial через Mastodon-совместимый API.

  • Новый модуль services/publisher/app/gotosocial.py — клиент GtS:
    • post_status(text, media_paths, visibility="public") → POST /api/v1/statuses (текст ≤5000, лимит GtS; разметка: markdown или plaintext);
    • upload_media(path) → POST /api/v2/media (multipart) до публикации, вернёт media_id; до 6 вложений (лимит GtS);
    • get_me() → GET /api/v1/accounts/verify_credentials (healthz);
    • delete_status(id) → DELETE /api/v1/statuses/{id} (для отмены тестовых);
    • все GET запросы к GtS напрямую (без прокси — social.dedinit.ru доступен из контейнера, проверено HTTP 200).
  • Конфиг (config.py + .env): GT_SOCIAL_URL=https://social.dedinit.ru, GT_SOCIAL_ACCESS_TOKEN=<токен @vesti> (Bearer, scope write), GT_SOCIAL_VISIBILITY=public (MAY: private/unlisted).
  • main.py: channels-список может содержать помимо @... (Telegram) ещё и fediverse-канал (например @vesti@dedinit.ru или префикс gt:); publisher умеет отправлять карточку в оба типа каналов, результаты — в results как обычно. dry_run также эмулирует fediverse-публикацию (не уходит наружу).
  • healthz: добавить gotosocial блок (url, аккаунт, токен задан?).
  • Документация: .env.example, README publisher, STATUS.md.

Не меняется

  • Telegram-путь (telegram.py, каналы @dedinit_vesti) — работает как раньше.
  • Веб :8400 (approve) — публикация по-прежнему через HTTP POST /api/v1/publish; веб-клиент не меняется (только конфиг каналов publisher).
  • Формат карточки (текст+медиа) — один и тот же для всех каналов.

Capabilities

New Capabilities

  • gotosocial-publisher: публикация карточки VESTI в собственный GoToSocial (Mastodon API, Bearer-токен @vesti), медиа-аплоад, healthz, dry_run, delete.

Modified Capabilities

  • tg-publisher-service: publisher-service теперь мульти-канальный (Telegram + fediverse); конфиг каналов расширяется.
  • vesti-web: без изменений кода (approve шлёт карточку publisher как раньше, но та уходит и в GtS если канал в конфиге).

Impact

  • Затронутые сервисы/порты: publisher-service :8410 (Docker-контейнер vesti-publisher) — только пересборка образа; GtS :8082/8443 (social.dedinit.ru) — читается по HTTPS.
  • Файлы:
    • новый: services/publisher/app/gotosocial.py
    • изменён: services/publisher/app/main.py, config.py, channels.py, services/publisher/Dockerfile (НЕ нужно — httpx уже есть), .env.example
  • Данные: без миграций БД.
  • Секреты: GT_SOCIAL_ACCESS_TOKEN (новый, в .env), URL GtS не секретен.
  • Прокси: Telegram — как раньше через SOCKS5; GoToSocial — НАПРЯМУЮ (внутренняя сеть WG → vps02 → bigbox; из контейнера publisher social.dedinit.ru отвечает 200).
  • Rollback: убрать канал @vesti@dedinit.ru из VESTI_BOT_CHANNELS (или вернуть конфиг) — Telegram-публикация не затронута; модуль gotosocial.py можно оставить невостребованным.

Risks

  • Токен @vesti (scope write) — если протухнет, publisher вернёт 401/403 в results с понятной ошибкой; healthz покажет token_set=false.
  • GtS недоступен → HTTP 502 в результатах канала; остальные каналы продолжают работать (fan-out не падает целиком — уже реализовано в main.py).
  • Лимиты GtS: 5000 символов, 6 вложений, MIME ограничен — текст обрезается до 5000, медиа до 6; неподдерживаемый тип → ошибка в результатах канала.
  • Спам-защита GtS (rate limit) при частой публикации — допустимо (публикует человек, не автопостинг).