# Архитектура ## Назначение `image-platform` - отдельный control plane для своего Cloudinary-like image pipeline. Проект отвечает за metadata, S3 artifacts, variants, allowlist, presets и генерацию изображений через внешний `imgproxy`. ## Компоненты | Компонент | Статус | Роль | |---|---|---| | PostgreSQL | сейчас | Источник правды для assets, variants, hosts, statuses | | S3/MinIO | сейчас | Хранилище originals и generated variants | | API | позже | JSON API, admin operations, validation, orchestration | | Worker | позже | Генерация variants, upload в S3, update PostgreSQL | | Admin UI | позже | Управление hosts/assets/variants/presets | | Gateway | позже | Caddy/Souin hot cache и delivery layer | | imgproxy | external | CPU-heavy image processing | ## Целевая delivery схема ```text client -> CDN optional -> gateway Caddy/Souin -> S3 ready variant -> generator fallback -> external imgproxy -> source image ``` ## Разделение ответственности PostgreSQL отвечает на вопросы: - какие assets зарегистрированы; - какие variants созданы; - где variants лежат в S3; - какие variants `pending`, `processing`, `ready`, `failed`; - сколько bytes занимает asset/project/user; - какие source hosts разрешены. S3 хранит байты: - original images, если решим сохранять originals; - generated variants; - metadata объектов на уровне storage, но не бизнес-логику. Gateway отдаёт картинки: - hot cache HIT - сразу из Souin; - cache MISS - из S3; - S3 MISS - через generator fallback. Backend не должен проксировать картинки на каждый обычный запрос. Он отдаёт JSON, статусы и URLs. ## URL модель Публичные URL должны быть стабильными и не раскрывать source URL: ```text /images/{assetId}/{variantHash}.{format} ``` Примеры: ```text /images/asset_123/w640_q80_cfill.avif /images/asset_123/w640_q80_cfill.webp /images/asset_123/w640_q80_cfill.jpg ``` Формат лучше делать явным в URL и отдавать через ``/`srcset`, а не выбирать по `Accept` header. Так CDN/S3/Gateway cache остаётся предсказуемым. ## External imgproxy `imgproxy` не входит в этот проект и не деплоится вместе с ним. Он подключается через env: ```env IMGPROXY_UPSTREAM=http://external-imgproxy.internal:8080 ``` Это позволяет держать image processing на отдельной мощной машине и не рисковать основным сервером.