chore: добавить каркас image-platform

- добавлен базовый pnpm workspace для будущих приложений

- добавлена dev-инфраструктура PostgreSQL и MinIO

- добавлены env-пример и базовые правила репозитория

- зафиксированы архитектура, data model и API-контракт

- описан контракт с внешним imgproxy
This commit is contained in:
2026-05-04 22:53:55 +03:00
commit 37592c8b81
13 changed files with 675 additions and 0 deletions

84
docs/architecture.md Normal file
View File

@@ -0,0 +1,84 @@
# Архитектура
## Назначение
`image-platform` - отдельный control plane для своего Cloudinary-like image pipeline.
Проект отвечает за metadata, S3 artifacts, variants, allowlist, presets и генерацию изображений через внешний `imgproxy`.
## Компоненты
| Компонент | Статус | Роль |
|---|---|---|
| PostgreSQL | сейчас | Источник правды для assets, variants, hosts, statuses |
| S3/MinIO | сейчас | Хранилище originals и generated variants |
| API | позже | JSON API, admin operations, validation, orchestration |
| Worker | позже | Генерация variants, upload в S3, update PostgreSQL |
| Admin UI | позже | Управление hosts/assets/variants/presets |
| Gateway | позже | Caddy/Souin hot cache и delivery layer |
| imgproxy | external | CPU-heavy image processing |
## Целевая delivery схема
```text
client
-> CDN optional
-> gateway Caddy/Souin
-> S3 ready variant
-> generator fallback
-> external imgproxy
-> source image
```
## Разделение ответственности
PostgreSQL отвечает на вопросы:
- какие assets зарегистрированы;
- какие variants созданы;
- где variants лежат в S3;
- какие variants `pending`, `processing`, `ready`, `failed`;
- сколько bytes занимает asset/project/user;
- какие source hosts разрешены.
S3 хранит байты:
- original images, если решим сохранять originals;
- generated variants;
- metadata объектов на уровне storage, но не бизнес-логику.
Gateway отдаёт картинки:
- hot cache HIT - сразу из Souin;
- cache MISS - из S3;
- S3 MISS - через generator fallback.
Backend не должен проксировать картинки на каждый обычный запрос. Он отдаёт JSON, статусы и URLs.
## URL модель
Публичные URL должны быть стабильными и не раскрывать source URL:
```text
/images/{assetId}/{variantHash}.{format}
```
Примеры:
```text
/images/asset_123/w640_q80_cfill.avif
/images/asset_123/w640_q80_cfill.webp
/images/asset_123/w640_q80_cfill.jpg
```
Формат лучше делать явным в URL и отдавать через `<picture>`/`srcset`, а не выбирать по `Accept` header. Так CDN/S3/Gateway cache остаётся предсказуемым.
## External imgproxy
`imgproxy` не входит в этот проект и не деплоится вместе с ним. Он подключается через env:
```env
IMGPROXY_UPSTREAM=http://external-imgproxy.internal:8080
```
Это позволяет держать image processing на отдельной мощной машине и не рисковать основным сервером.