meta(tasks): create [migrate-gallery-originals-to-s3] in OpeItcLoc03/admin

This commit is contained in:
2026-06-12 11:09:50 +00:00
parent e001b8e331
commit 4c640dec65

View File

@@ -361,3 +361,62 @@ vehicles-loader (stostayer) деплоится в Docker у клиента (lite
<!-- created-by: OpeItcLoc03@DESKTOP-NSEF0UK / from: OpeItcLoc03/workshop / 2026-06-08T10:10:16.420Z -->
---
## ⚪ [migrate-gallery-originals-to-s3] — Галерейные (blog/gallery) картинки не отдаются ни на dev (imgproxy 404 "Source image is unreachable"), ни на prod (legacy-ресайз 404). Диагностика проведена в victor/snolla против живого pilorama98 + кода MoreThenCms. Нужен доступ к БОЕВОМУ серверу (локальный диск IIS + MinIO/S3), которого нет у snolla-агента — поэтому задача на admin.
## Диагноз (доказан, не гипотеза)
Корень: **галерейные оригиналы лежат ТОЛЬКО на локальном диске legacy-IIS** (`App_Data\galleries\<siteId:N>\<storageFilename-guid>.<ext>`). В S3/MinIO их нет. Продукты — мигрированы (`s3://pilorama98/products/...` отдаёт 200), галереи — нет.
Три независимых следствия одного корня:
1. **Prod не отдаёт картинки блога.** Legacy-роут `/galleries/<galleryId:N>/images/<size>/<seq>.jpg` — ресайзер на лету. Распиновка живого pilorama98 (2 галереи, 98078b74… и c1b53362…):
- `original/001.jpg` → **200** (235KB / 735KB) — оригинал жив, читается с локального диска;
- `800x450`, `default`, `thumbnail`, `100x100`, `600x400` → **404** всегда.
→ ресайз-пайплайн legacy-хоста мёртв глобально (System.Drawing / image-cache storage). Это отдельная legacy-поломка; целевая архитектура — отдавать через imgproxy, не чинить legacy-ресайз.
2. **Превью в админке видно.** Админка рендерит ОРИГИНАЛ (passthrough по imageId → `GetGalleryImageById`, без ресайза), читает локальный диск. Тот же путь, что `original/001.jpg`=200. Сломанную ресайз-ветку не трогает.
3. **Dev imgproxy 404.** snolla строит source `s3://${storageClient}/${siteId}/${storageFilename}` (packages/snolla/middleware/galleries.js:47 и lib/viewModels/index.js:289). Ключ-форма КОРРЕКТНА (реальный StorageFilename guid + siteId, ровно legacy-раскладка). Но imgproxy читает S3, а объекта там нет → "Source unreachable". Код билдера менять НЕ надо.
## Развилка, которую закрыть на боевом (нужен доступ к MinIO)
Имя бакета. Продукты: бакет `pilorama98`, prefix `products/`. snolla для галерей берёт `image.storageClient` («galleries») как ИМЯ БАКЕТА → `s3://galleries/...`. Проверить в MinIO:
- (A) целевой бакет реально `galleries` (отдельный) → достаточно залить файлы, код snolla без изменений;
- (B) всё в бакете `pilorama98`, галереи должны быть под prefix `galleries/` → тогда + маленький код-фикс на стороне snolla (storageClient как prefix, а не bucket) — в этом случае ЗАВЕСТИ follow-up таску обратно на victor/snolla через notify, НЕ чинить snolla из admin.
## Acceptance criteria
1. Определено фактическое состояние MinIO: какие бакеты есть, как лежат рабочие продукты, отсутствуют ли галерейные объекты — зафиксировано в close-note.
2. Развилка A/B закрыта явно (какой бакет/prefix — целевой).
3. Если A: legacy-оригиналы залиты в S3 под ключи, которые snolla уже ждёт (`<siteId>/<storageFilename>`); проверена доступность через imgproxy (хотя бы одна картинка → 200).
4. Если B: создана follow-up таска на victor/snolla с точной целевой формой ключа (bucket + prefix), миграция файлов под этот prefix выполнена.
5. В inbox victor/snolla при close: итоговая форма source (bucket/prefix/key), какие галереи/сколько файлов мигрировано, и нужен ли код-фикс на snolla.
## Контекст-источники (для воспроизведения)
- Живой prod: `https://www.pilorama98.ru/galleries/98078b74e062443ba0708476e031b6b0/images/original/001.jpg` (200) vs `/800x450/001.jpg` (404).
- Legacy-код: MoreThenCms/Galleries/GalleryImage.cs (Path/StorageFilename), GalleriesAppFunc.cs (resolve по galleryId+seq, 404 при null/mime-mismatch), Services/GalleryImagesService.cs:135 (StorageClient="galleries", filename=Guid.NewGuid():N), FileStorage.Local/GalleriesStorage.cs (BasePath App_Data\\galleries\\<siteId>\\).
- snolla-консьюмер: packages/snolla/middleware/galleries.js, lib/viewModels/index.js:289.
- siteId pilorama98: 37e67fc4… (бакет-сегмент в source).
## Обязательные скилы — вызвать до начала работы
- invoke `systematic-debugging` — закрыть развилку A/B по фактам MinIO до любых действий
- invoke `using-tasks` — управление статусом задачи
- invoke `project-discipline` — дисциплина коммитов/пушей
- invoke `using-vds-ops` — если MinIO/imgproxy крутятся на VDS (docker-диагностика)
- invoke `using-projects-meta` — кросс-проектный отчёт/ follow-up в victor/snolla
**TDD:** нет — ops/migration задача (нет тестируемого кодового ядра; если всплывёт код-фикс на snolla — он уйдёт отдельной impl-таской на victor/snolla с TDD).
**Разрешения:** интерны: нет | автопуш: да
**weight:** needs-human
**notify:** victor/snolla
**Status:** ready
**Where I stopped:** (not started) — диагностика выполнена в victor/snolla, см. тело
**Next action:** 1) В MinIO/S3 проверить: существует ли бакет `galleries` и есть ли в нём объекты `<siteId>/<storageFilename>`; сверить с тем, как лежат рабочие продукты (`s3://pilorama98/products/...`). 2) Залить legacy-оригиналы `App_Data\galleries\<siteId>\*` в целевой бакет под ключи `<siteId>/<storageFilename>`. 3) Re-smoke imgproxy на одной картинке.
**Branch:** master
**Notify:** victor/snolla
<!-- created-by: OpeItcLoc03@DESKTOP-NSEF0UK / from: victor/snolla / 2026-06-12T11:09:50.425Z -->
---