# Черновик API Контракта Это не реализация API, а фиксация будущего контракта для NestJS backend. Backend отдаёт JSON, metadata, statuses и URLs. Он не должен проксировать image bytes на каждый обычный запрос. ## Allowed Hosts ```text GET /allowed-hosts POST /allowed-hosts PATCH /allowed-hosts/:id DELETE /allowed-hosts/:id ``` ## Assets ```text GET /assets POST /assets GET /assets/:id DELETE /assets/:id ``` `POST /assets` request: ```json { "sourceUrl": "https://example.com/photo.jpg" } ``` Responsibilities: - validate source URL; - check `allowed_image_hosts`; - create or reuse `image_assets` row; - optionally save original to S3 later. ## Variants ```text GET /assets/:id/variants POST /assets/:id/variants POST /variants/:id/regenerate DELETE /variants/:id ``` `POST /assets/:id/variants` request: ```json { "preset": "card", "format": "webp", "width": 640 } ``` Response if ready: ```json { "id": "variant_123", "status": "ready", "url": "http://localhost:8888/images/asset_123/w640_q80_card.webp" } ``` Response if generation is async: ```json { "id": "variant_123", "status": "pending", "url": null } ``` ## Image URLs For UI Для UI нужен endpoint, который возвращает готовый набор URLs для ``/`srcset`. ```text GET /assets/:id/picture?preset=card ``` Example response: ```json { "assetId": "asset_123", "preset": "card", "sources": [ { "type": "image/avif", "srcset": "http://localhost:8888/images/asset_123/w320_card.avif 320w, http://localhost:8888/images/asset_123/w640_card.avif 640w" }, { "type": "image/webp", "srcset": "http://localhost:8888/images/asset_123/w320_card.webp 320w, http://localhost:8888/images/asset_123/w640_card.webp 640w" } ], "fallback": { "src": "http://localhost:8888/images/asset_123/w640_card.jpg", "width": 640, "height": null } } ``` ## Worker Lifecycle Первый MVP может генерировать sync на request. Если генерация тяжёлая, variant создаётся как `pending`, а worker обрабатывает job. PostgreSQL может выступить первой очередью: ```text SELECT * FROM image_variants WHERE status = 'pending' FOR UPDATE SKIP LOCKED LIMIT 1 ``` Позже можно добавить Redis/Valkey или отдельную queue, если PostgreSQL станет узким местом.