meta(tasks): create [migrate-gallery-originals-to-s3] in OpeItcLoc03/admin
This commit is contained in:
@@ -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 -->
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user