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

71
docs/imgproxy-contract.md Normal file
View File

@@ -0,0 +1,71 @@
# Контракт с imgproxy
`imgproxy` всегда внешний сервис для `image-platform`.
## Env
```env
IMGPROXY_UPSTREAM=http://external-imgproxy.internal:8080
IMGPROXY_SIGNING_ENABLED=false
IMGPROXY_KEY=
IMGPROXY_SALT=
```
## Dev режим
В dev можно использовать unsigned `/unsafe` URL, если внешний `imgproxy` запущен без key/salt.
Пример path:
```text
/unsafe/resize:fit:800:0:0/q:80/plain/https://example.com/photo.jpg
```
## Prod режим
В prod нужно перейти на signed URLs и закрыть `/unsafe`.
Path для подписи строится без `/unsafe`:
```text
/resize:fit:800:0:0/q:80/plain/https://example.com/photo.jpg
```
Signature:
```text
HMAC-SHA256(binary_key, binary_salt + path_bytes)
base64url without padding
```
Node implementation reference:
```ts
import crypto from "node:crypto"
export function signImgproxyPath(keyHex: string, saltHex: string, path: string) {
const key = Buffer.from(keyHex, "hex")
const salt = Buffer.from(saltHex, "hex")
const hmac = crypto.createHmac("sha256", key)
hmac.update(Buffer.concat([salt, Buffer.from(path)]))
return hmac.digest("base64url")
}
```
Final signed URL:
```text
{IMGPROXY_UPSTREAM}/{signature}{path}
```
## Security rules
- Не отдавать `IMGPROXY_KEY` и `IMGPROXY_SALT` в браузер.
- Source URL валидировать в API/worker.
- Разрешать только `http` и `https`.
- Запрещать localhost, private IP, loopback, link-local.
- Source host должен быть enabled в `allowed_image_hosts`.
- Не давать клиенту произвольные imgproxy options.
- Использовать presets и deterministic `variantHash`.