## 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/` (внешний каталог), а не в `media/media/`. В контейнере (CWD `/srv/publisher`) путь `media/` резолвится в `/srv/publisher/media/` = `/opt/vesti/media/media/`, которого для новых постов не существует. В 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/` = `media/` ✓ - старые (если появятся/восстановятся): `/srv/publisher/media/media/` = `media/media/` ✓ 2. **`services/publisher/app/main.py`**: устойчивый резолвинг медиа-файла в контейнере. Вместо единственной проверки `Path(card.media).exists()` — пробовать кандидатов в порядке приоритета (под контейнерный CWD): - `card.media` как есть (заданный путь, напр. `media/`, резолвится от `/srv/publisher`), - `media/` (если путь в БД содержал подкаталог), - `media/media/` (старая раскладка). Первый существующий путь идёт в `send_media`. Это чинит и будущие случаи, когда веб пришлёт нормализованный путь, и старые посты, файлы которых восстановят. 3. **`publisher/card.py`** — не меняем (нормализация путей на стороне веба уже работает, publisher получает `media='media/'`). ## 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` и старый код, пересоздать контейнер.