Files
image-platform/docs/next-image-provider.md
S.Gromov bcadb85a83 feat: добавить базовые сервисы image-platform
- добавлены backend, admin, gateway и worker skeleton
- добавлены Drizzle schema, database package и initial migration
- добавлены shared packages для RabbitMQ topology и S3 helpers
- обновлены dev-инфраструктура, env example, scripts и dependencies
- обновлена документация под versioned image URLs и read-through flow
2026-05-05 09:59:21 +03:00

3.4 KiB
Raw Blame History

Next/image Provider

image-platform должен работать как custom image provider для next/image.

Next.js contract

Next.js custom loader получает только:

  • src;
  • width;
  • quality.

Поэтому public image URL должен принимать эти параметры напрямую и сам запускать read-through генерацию при miss.

Loader config

В Next.js приложении используется loaderFile:

// next.config.js
module.exports = {
  images: {
    loader: "custom",
    loaderFile: "./src/image-platform-loader.js",
    qualities: [60, 75, 80, 90],
  },
}

Пример loader:

"use client"

const imageBaseUrl = process.env.NEXT_PUBLIC_IMAGE_PLATFORM_URL

export default function imagePlatformLoader({ src, width, quality }) {
  const normalizedSrc = src.startsWith("/") ? src.slice(1) : src
  const q = quality || 80

  return `${imageBaseUrl}/images/${normalizedSrc}?w=${width}&q=${q}&f=auto`
}

Пример использования:

import Image from "next/image"

export function ProductCard() {
  return <Image src="asset_123/v4/card" width={640} height={420} alt="Product" />
}

Public URL

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

Сейчас route уже зарезервирован в Fastify Gateway, но возвращает placeholder 501, пока не реализованы PostgreSQL/S3/imgproxy read-through операции.

Пример:

https://img.example.com/images/asset_123/v4/card?w=640&q=80&f=auto

src не должен быть source URL. Это должен быть versioned platform identifier, например asset_123/v4/card. Source URL хранится в PostgreSQL и не раскрывается в public image URL.

v{version} меняется при обновлении source image. Старые URL можно кэшировать как immutable без purge.

Format auto

f=auto выбирает output format по Accept header:

  1. image/avif, если клиент поддерживает AVIF и preset разрешает AVIF.
  2. image/webp, если клиент поддерживает WebP и preset разрешает WebP.
  3. image/jpeg или original fallback.

Для auto format обязательны headers:

Vary: Accept
Cache-Control: public, max-age=31536000, immutable
Content-Type: image/avif | image/webp | image/jpeg

CDN и Gateway L1 cache должны учитывать Vary: Accept, иначе можно отдать AVIF клиенту без AVIF support.

Read-through behavior

client -> CDN -> Fastify gateway -> L1 memory -> Backend -> RabbitMQ -> Worker -> imgproxy -> S3

Поведение:

  • CDN HIT: backend не вызывается.
  • Gateway L1 HIT: backend не вызывается.
  • Gateway L1 MISS: Gateway вызывает Backend internal ensure endpoint.
  • S3 HIT: Backend отдаёт bytes Gateway, Gateway кладёт result в L1.
  • S3 MISS: Backend ставит RabbitMQ job, Worker генерирует variant через external imgproxy, сохраняет в S3, обновляет PostgreSQL, Backend возвращает bytes Gateway.

Так достигается Cloudinary-like поведение: первый запрос создаёт derived asset, следующие запросы отдаются из cache/storage.