Files
vesti/openspec/changes/archive/2026-09-13-gotosocial-publisher/proposal.md
T

89 lines
6.6 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.
## 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) при частой публикации — допустимо (публикует человек,
не автопостинг).