Files
image-platform/docs/data-model.md
S.Gromov bcadb85a83 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
2026-05-05 09:59:21 +03:00

169 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Data Model
Текущая PostgreSQL модель описана в `packages/database/src/schema.ts` и миграциях Drizzle в `packages/database/drizzle`.
## allowed_image_hosts
```text
id uuid pk default gen_random_uuid()
hostname text not null unique
enabled boolean not null default true
description text nullable
created_at timestamptz not null default now()
updated_at timestamptz not null default now()
```
Правила normalization:
- lowercase;
- без protocol;
- без path;
- без trailing slash;
- без wildcard на первом этапе;
- source URL должен быть `http` или `https`;
- запрещены localhost, private IP, loopback, link-local.
## image_assets
```text
id uuid pk default gen_random_uuid()
public_id text not null unique
current_version integer not null default 1
status asset_status not null default active
created_at timestamptz not null default now()
updated_at timestamptz not null default now()
```
`public_id` - стабильный идентификатор в public URL. `current_version` указывает активную версию source image и используется для cache invalidation без purge.
## image_asset_versions
```text
id uuid pk default gen_random_uuid()
asset_id uuid not null references image_assets(id) on delete cascade
version integer not null
source_url text not null
source_host text not null
source_hash text not null
original_s3_key text nullable
width integer nullable
height integer nullable
content_type text nullable
size_bytes bigint nullable
created_at timestamptz not null default now()
```
Каждое изменение source image создаёт новую версию. Старые versioned URLs остаются immutable, новые клиенты получают URL с новым `v{version}`.
## image_variants
```text
id uuid pk default gen_random_uuid()
asset_id uuid not null references image_assets(id) on delete cascade
asset_version_id uuid not null references image_asset_versions(id) on delete cascade
asset_version integer not null
preset text not null
variant_hash text not null unique
requested_format requested_format not null default auto
format variant_format not null
width integer not null
height integer nullable
quality integer not null
s3_key text not null unique
content_type text nullable
etag text nullable
status variant_status not null default pending
size_bytes bigint nullable
error text nullable
attempt_count integer not null default 0
last_accessed_at timestamptz nullable
created_at timestamptz not null default now()
updated_at timestamptz not null default now()
```
`requested_format` хранит то, что запросил клиент (`auto`, `avif`, `webp`, `jpg`, `png`). `format` хранит фактический output format после negotiation по `Accept`.
## Enums
```text
asset_status: active | disabled | deleted
requested_format: auto | avif | webp | jpg | png
variant_format: avif | webp | jpg | png
variant_status: pending | processing | ready | failed
```
## Unique constraints
```text
allowed_image_hosts(hostname)
image_assets(public_id)
image_asset_versions(asset_id, version)
image_variants(asset_id, asset_version, preset, width, quality, format)
image_variants(s3_key)
image_variants(variant_hash)
```
Индексы:
```text
image_asset_versions(source_hash)
image_variants(status)
```
## S3 layout
```text
originals/{assetId}/v{version}/source
variants/{assetId}/v{version}/{variantHash}.{format}
```
`variantHash` должен включать:
- `assetId`;
- `assetVersion`;
- `preset`;
- normalized width;
- normalized quality;
- фактический output format;
- параметры transform, влияющие на bytes.
Для `f=auto` в public URL в S3 всё равно пишется фактический формат:
```text
variants/asset_123/v4/card_w640_q80_avif.avif
variants/asset_123/v4/card_w640_q80_webp.webp
variants/asset_123/v4/card_w640_q80_jpg.jpg
```
Public URL также versioned:
```text
/images/{assetId}/v{version}/{preset}?w={width}&q={quality}&f=auto
```
## Presets
Клиент не должен передавать произвольные трансформации. Сначала нужны ограниченные presets.
Пример:
```text
avatar:
widths: 128, 256, 512
formats: avif, webp, jpg
quality: 80
resize: fill
card:
widths: 320, 640, 960
formats: avif, webp, jpg
quality: 80
resize: fit
hero:
widths: 1280, 1920
formats: avif, webp, jpg
quality: 80
resize: fit
```