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

106 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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`:
```js
// next.config.js
module.exports = {
images: {
loader: "custom",
loaderFile: "./src/image-platform-loader.js",
qualities: [60, 75, 80, 90],
},
}
```
Пример loader:
```js
"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`
}
```
Пример использования:
```tsx
import Image from "next/image"
export function ProductCard() {
return <Image src="asset_123/v4/card" width={640} height={420} alt="Product" />
}
```
## Public URL
```text
GET /images/{assetId}/v{version}/{preset}?w={width}&q={quality}&f=auto
```
Сейчас route уже зарезервирован в Fastify Gateway, но возвращает placeholder `501`, пока не реализованы PostgreSQL/S3/imgproxy read-through операции.
Пример:
```text
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:
```http
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
```text
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.