openspec: архив 14 завершённых change-ов (веб-фиксы, crawler-queue, own-content-hub, publisher-service); спеки влиты в openspec/specs

This commit is contained in:
kpa39l
2026-09-16 17:01:00 +00:00
parent 584582a48c
commit 771f6a8276
88 changed files with 1632 additions and 3 deletions
@@ -0,0 +1,69 @@
## Why
Пост #1017 (linux) опубликован без картинки: в Telegram ушёл только текст, хотя
у поста есть медиа (`media_path='media/linux_education_2772.jpg'`, файл на хосте
`/opt/vesti/media/linux_education_2772.jpg`, 151 КБ).
Причина: Docker-контейнер `vesti-publisher` монтирует
`../../media/media:/srv/publisher/media` — **внутренний** каталог `media/media/`.
С 2026-09-12 краулер качает медиа в `media/<file>` (внешний каталог), а не в
`media/media/<file>`. В контейнере (CWD `/srv/publisher`) путь `media/<file>`
резолвится в `/srv/publisher/media/<file>` = `/opt/vesti/media/media/<file>`,
которого для новых постов не существует.
В publisher (`services/publisher/app/main.py`):
```python
if req.card.media and Path(req.card.media).exists():
```
проверка проваливается → медиа молча пропускается, публикуется только текст.
Ошибки нет — файл «просто не найден».
Проверено в контейнере:
```
docker exec vesti-publisher python -c "import os; print(os.path.exists('media/linux_education_2772.jpg'))" # False
```
Затронуты все посты с медиа, скачанные с 2026-09-12 (новая раскладка). Старых
файлов в `media/media/` на диске нет (545 постов со старым путём вообще без
файлов — отдельная проблема, не этого change).
## What Changes
1. **`services/publisher/docker-compose.yml`**: монтировать весь каталог медиа
`../../media:/srv/publisher/media:ro` вместо `../../media/media`. Тогда в
контейнере видны ОБЕ раскладки:
- новые файлы: `/srv/publisher/media/<file>` = `media/<file>` ✓
- старые (если появятся/восстановятся): `/srv/publisher/media/media/<file>` = `media/media/<file>` ✓
2. **`services/publisher/app/main.py`**: устойчивый резолвинг медиа-файла в
контейнере. Вместо единственной проверки `Path(card.media).exists()` —
пробовать кандидатов в порядке приоритета (под контейнерный CWD):
- `card.media` как есть (заданный путь, напр. `media/<file>`,
резолвится от `/srv/publisher`),
- `media/<basename>` (если путь в БД содержал подкаталог),
- `media/media/<basename>` (старая раскладка).
Первый существующий путь идёт в `send_media`.
Это чинит и будущие случаи, когда веб пришлёт нормализованный путь, и
старые посты, файлы которых восстановят.
3. **`publisher/card.py`** — не меняем (нормализация путей на стороне веба уже
работает, publisher получает `media='media/<file>'`).
## Why Not
- Не переносить файлы из `media/` в `media/media/` и не править 12 строк БД:
новая раскладка правильная, старую не размножаем.
- Не отключать проверку существования файла: у 545 старых постов файла нет,
publisher должен молча пропускать отсутствующее медиа, а не падать.
- Не менять `media_path` в БД: веб (route `/media/{filename}`, MEDIA_DIRS)
и читает оба каталога, и publisher после фикса тоже.
## Impact
- Файлы: `services/publisher/docker-compose.yml`, `services/publisher/app/main.py`.
- Сервис: пересоздать контейнер publisher (`docker compose up -d` — volume
меняется), проверить healthz.
- Данные: без миграций БД.
- Rollback: вернуть монтирование `../../media/media` и старый код, пересоздать
контейнер.