feat: добавить генерацию image variants

- добавлен shared config presets, custom transforms и allowlist hosts
- реализованы Backend endpoints для assets, presets и variants
- добавлена orchestration через PostgreSQL, RabbitMQ, S3 и worker
- обновлён Gateway read-through flow с L1 cache и корректным Vary: Accept
- добавлена миграция resize_mode для variants lookup
- обновлены dev scripts, env template, lockfile и документация
This commit is contained in:
2026-05-05 13:25:28 +03:00
parent bcadb85a83
commit 1c0e8277a3
59 changed files with 3526 additions and 143 deletions

View File

@@ -1,21 +1,43 @@
import { ApiProperty } from "@nestjs/swagger"
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger"
import type { ActualImageFormat, RequestedImageFormat, ResizeMode } from "@image-platform/image-config"
export class EnsureImageVariantRequestDto {
@ApiProperty({ example: "asset_123" })
@ApiProperty({ description: "Публичный идентификатор asset из Gateway URL.", example: "asset_123" })
assetId!: string
@ApiProperty({ example: 4, minimum: 1 })
@ApiProperty({ description: "Версия source image из Gateway URL `v{version}`.", example: 4, minimum: 1 })
version!: number
@ApiProperty({ example: "card" })
@ApiProperty({ description: "Имя preset трансформации. Сейчас используется как часть variant key.", example: "card" })
preset!: string
@ApiProperty({ example: 640, minimum: 1 })
width!: number
@ApiPropertyOptional({ description: "Целевая ширина variant в пикселях. Обязательна для responsive presets и custom.", example: 640, minimum: 1 })
width?: number
@ApiProperty({ example: 80, minimum: 1 })
quality!: number
@ApiPropertyOptional({ description: "Целевая высота variant в пикселях. `0` или отсутствие означает auto height.", example: 420, minimum: 0 })
height?: number
@ApiProperty({ enum: ["auto", "avif", "webp", "jpg", "png"], example: "auto" })
format!: "auto" | "avif" | "jpg" | "png" | "webp"
@ApiPropertyOptional({ description: "Качество сжатия для imgproxy. Если не передано, берётся из preset.", example: 80, minimum: 1 })
quality?: number
@ApiPropertyOptional({
description: "Формат, который запросил клиент. Для `auto` Gateway выбирает фактический формат по `Accept` header.",
enum: ["auto", "avif", "webp", "jpg", "png"],
example: "auto",
})
requestedFormat?: RequestedImageFormat
@ApiPropertyOptional({
description: "Режим resize для custom transforms. Для обычных presets берётся из preset config.",
enum: ["fit", "fill"],
example: "fit",
})
resize?: ResizeMode
@ApiProperty({
description: "Фактический output format после negotiation. Именно этот формат попадает в S3 key и L1 cache key.",
enum: ["avif", "webp", "jpg", "png"],
example: "webp",
})
format!: ActualImageFormat
}