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
This commit is contained in:
105
docs/next-image-provider.md
Normal file
105
docs/next-image-provider.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user