Files
image-platform/docs/assets-delivery-platform.md
2026-05-12 07:54:32 +03:00

9.8 KiB
Raw Blame History

Assets Delivery Platform

Концепция

image-platform эволюционирует из платформы для изображений в Assets Delivery Platform.

Платформа должна быть control plane и delivery layer для загрузки, обработки, версионирования и доставки ассетов. Первый поддерживаемый тип ассетов - изображения. Текущие наработки по image pipeline остаются основой первого production-ready vertical slice.

Продуктовая цель

Пользователь должен иметь возможность управлять ассетами через кабинет и программно через API.

Клиентский backend должен уметь без участия UI:

  • загрузить изображение;
  • выбрать preset обработки;
  • запустить build;
  • получить статус обработки;
  • получить готовые delivery URL;
  • использовать публичные URL в приложении, CMS, магазине или любом другом сервисе.

Платформа должна быть не только оптимизатором изображений, а headless-сервисом доставки ассетов с UI для управления.

Первый vertical slice: Images

Первый модуль платформы - изображения.

В рамках images сохраняются текущие архитектурные решения:

  • Gateway как публичный image origin;
  • read-through delivery flow;
  • Backend как orchestration/control plane;
  • PostgreSQL как источник правды для metadata, statuses и variants;
  • S3/MinIO как хранилище originals и generated variants;
  • RabbitMQ как очередь задач;
  • Worker как исполнитель image processing;
  • внешний imgproxy как CPU-heavy image processor;
  • versioned immutable public URLs;
  • presets и variants;
  • f=auto с negotiation по Accept header.

Текущий публичный URL для managed images остаётся базовым delivery contract:

GET /images/{assetId}/v{version}/{preset}?w={width}&q={quality}&f=auto

Кабинет пользователя

На первом этапе кабинет показывает только раздел работы с изображениями.

Пользователь должен иметь возможность:

  • загружать изображения;
  • создавать и редактировать image presets;
  • смотреть список загруженных изображений;
  • смотреть версии, variants, статусы обработки и готовые URL;
  • выпускать API-ключи для проекта.

В будущем кабинет расширяется разделами:

  • Images;
  • Videos;
  • Sprites;
  • Fonts;
  • другие типы ассетов при появлении продуктовой необходимости.

Projects

Project становится основной областью изоляции.

К проекту должны относиться:

  • assets;
  • presets;
  • builds;
  • variants/results;
  • API keys;
  • лимиты;
  • настройки delivery;
  • allowlist источников;
  • usage/billing metrics, если они появятся.

На первом этапе можно развивать images внутри проекта, не создавая преждевременно универсальную модель для всех типов ассетов.

API Keys

Для каждого проекта пользователь может выпускать API-ключи.

API-ключ нужен для server-side интеграций, где backend клиента программно добавляет файлы, запускает обработку и получает результаты.

Ключ должен храниться безопасно:

  • secret показывается пользователю только при создании;
  • в базе хранится hash секрета;
  • в UI отображается только prefix/identifier;
  • ключ можно отозвать;
  • ключ может иметь scopes;
  • желательно хранить дату последнего использования.

Базовые scopes:

assets:read
assets:write
assets:delete
presets:read
presets:write
builds:read
builds:write

Delivery URLs остаются публичными и не требуют Authorization, если конкретный проект не включает приватный delivery mode.

Headless API

Платформа должна предоставлять публичный management API для backend-клиентов.

Минимальный image API первого этапа:

POST   /api/v1/images
GET    /api/v1/images
GET    /api/v1/images/{id}
DELETE /api/v1/images/{id}

POST   /api/v1/images/{id}/builds
GET    /api/v1/images/{id}/builds
GET    /api/v1/images/{id}/results

GET    /api/v1/image-presets

POST   /api/v1/project-api-keys
GET    /api/v1/project-api-keys
DELETE /api/v1/project-api-keys/{id}

API должен поддерживать загрузку файла напрямую, а не только регистрацию внешнего sourceUrl.

Пример server-side сценария:

1. Backend клиента отправляет изображение в API платформы с project API key.
2. Платформа сохраняет original, создаёт asset и version.
3. Backend клиента указывает preset или запускает build.
4. Worker генерирует variants/results.
5. Backend клиента получает готовые public delivery URL.

Builds и Results

Build описывает запуск обработки ассета по preset или transform config.

Result или Variant описывает готовый артефакт, который можно доставлять через public URL.

Для images текущая сущность image_variants уже выполняет роль результата обработки. При развитии API можно добавить explicit build layer, не ломая текущий read-through delivery flow.

Realtime transforms и cropping

Платформа должна поддерживать два режима обработки изображений:

  • preset builds - заранее заданные и ограниченные variants;
  • realtime transforms - динамические resize/crop/format/quality операции через delivery URL.

Realtime crop должен быть ограничен правилами проекта и preset/custom transform config, чтобы пользователь не мог бесконтрольно создавать произвольные дорогие трансформации.

Первый запрос на dynamic transform может генерировать результат через worker/imgproxy и сохранять его в storage/cache. Следующие запросы должны отдавать уже готовый артефакт.

Пример будущего dynamic transform URL:

GET /images/{assetId}/v{version}/custom?w=800&h=600&fit=fill&crop=center&f=auto&q=80

Параметры, влияющие на bytes, должны входить в deterministic variant hash и S3 key.

Workers

Для каждого типа ассетов предусматривается специализированный worker.

Общий orchestration остаётся в backend, database, queue и storage. Worker конкретного типа отвечает за инструменты обработки этого типа.

Планируемая модель:

image-worker  -> imgproxy / sharp / imagemagick
video-worker  -> ffmpeg
font-worker   -> fonttools / subset tools
sprite-worker -> svg/css sprite builder

На первом этапе реализуется и развивается image-worker. Остальные worker'ы добавляются только при появлении соответствующих продуктовых задач.

Архитектурный принцип

Не нужно преждевременно строить универсальный engine для всех возможных ассетов.

Правильное направление:

  • делать images как первый полноценный модуль;
  • общие сущности называть так, чтобы они не блокировали будущие типы ассетов;
  • выносить в общий слой только реально общие части: projects, API keys, queue orchestration, storage contract, statuses, delivery concepts;
  • типоспецифичную обработку держать внутри конкретного модуля.

Примеры naming direction:

Project              вместо ImageProject
ProjectApiKey        вместо ImageApiKey
ProcessingJob        вместо ImageWorkerJob
AssetBuild           вместо ImageBuild, если build станет общим понятием

При этом текущие image_assets, image_asset_versions и image_variants могут оставаться конкретными image-таблицами, пока images являются единственным реализованным типом ассетов.