2026-05-04 22:53:55 +03:00
# Локальная разработка
## Принцип
2026-05-05 09:59:21 +03:00
В Docker запускаем стабильную инфраструктуру. Кодовые сервисы запускаем нодой с hot reload.
2026-05-04 22:53:55 +03:00
Сейчас в Docker есть только:
- PostgreSQL;
- MinIO;
2026-05-05 09:59:21 +03:00
- MinIO bucket init;
- imgproxy dev instance;
- RabbitMQ.
2026-05-04 22:53:55 +03:00
2026-05-05 13:25:28 +03:00
`backend` уже умеет регистрировать assets и выполнять internal ensure. `gateway` уже ходит в Backend и держит L1 memory cache. `worker` уже читает RabbitMQ jobs, вызывает imgproxy и пишет variants в S3.
2026-05-05 09:59:21 +03:00
Gateway обязателен для Cloudinary-like поведения и интеграции с `next/image` .
2026-05-04 22:53:55 +03:00
## Запуск инфраструктуры
```bash
cp .env.example .env
pnpm install
pnpm infra:up
2026-05-05 13:25:28 +03:00
pnpm db:migrate
2026-05-04 22:53:55 +03:00
```
2026-05-05 13:25:28 +03:00
`.env` используется только локально и игнорируется git. Backend, Gateway, Worker и Drizzle scripts автоматически подхватывают е г о через Node `--env-file-if-exists` ; в production эти переменные должны приходить из окружения процесса.
2026-05-04 22:53:55 +03:00
Проверить compose config:
```bash
pnpm infra:config
```
Остановить:
```bash
pnpm infra:down
```
Логи:
```bash
pnpm infra:logs
```
## Порты
| Сервис | URL |
|---|---|
| PostgreSQL | `localhost:5433` |
| MinIO API | `http://localhost:9000` |
| MinIO Console | `http://localhost:9001` |
2026-05-05 09:59:21 +03:00
| imgproxy | `http://localhost:18080` |
| RabbitMQ | `amqp://localhost:5672` |
| RabbitMQ Management | `http://localhost:15672` |
| Backend API | `http://localhost:3001/api` |
| Swagger | `http://localhost:3001/docs` |
| Admin | `http://localhost:5173` |
| Gateway | `http://localhost:8888` |
Если `localhost:8888` занят старым `image-gateway` , остановите старый stack или задайте `GATEWAY_PORT=8890` в `.env` .
## Backend
Запустить NestJS backend:
```bash
pnpm backend:dev
```
Проверки:
```bash
curl http://localhost:3001/api/health
open http://localhost:3001/docs
```
2026-05-05 13:25:28 +03:00
Зарегистрировать source image в dev mode:
```bash
curl -sS -X POST http://localhost:3001/api/assets \
-H 'content-type: application/json' \
-d '{"sourceUrl":"https://storage.yandexcloud.net/shared1318/img/1.jpg","publicId":"asset_demo"}'
```
Посмотреть business API:
```bash
curl -sS http://localhost:3001/api/presets
curl -sS http://localhost:3001/api/assets
curl -sS http://localhost:3001/api/assets/asset_demo
2026-05-05 13:35:25 +03:00
curl -sS 'http://localhost:3001/api/assets/asset_demo/picture?preset=card& sizes=100vw'
2026-05-05 13:25:28 +03:00
curl -sS http://localhost:3001/api/assets/asset_demo/variants
```
2026-05-05 13:31:45 +03:00
Создать новую source version для asset:
```bash
curl -sS -X POST http://localhost:3001/api/assets/asset_demo/versions \
-H 'content-type: application/json' \
-d '{"sourceUrl":"https://storage.yandexcloud.net/shared1318/img/1.jpg"}'
```
2026-05-05 13:25:28 +03:00
Явно поставить jobs на генерацию family variants без Gateway lazy request:
```bash
curl -sS -X POST http://localhost:3001/api/assets/asset_demo/variants \
-H 'content-type: application/json' \
-d '{"preset":"card","mode":"family"}'
```
2026-05-05 09:59:21 +03:00
## Database
Drizzle schema живёт в `packages/database/src/schema.ts` , миграции - в `packages/database/drizzle` .
Сгенерировать миграцию после изменения schema:
```bash
pnpm db:generate
```
Применить миграции к локальному PostgreSQL:
```bash
pnpm db:migrate
```
Открыть Drizzle Studio из корня проекта:
```bash
pnpm db:studio
```
Проверить database package:
```bash
pnpm db:typecheck
pnpm db:build
```
## Admin
Запустить React/Vite admin:
```bash
pnpm admin:dev
```
Открыть:
```bash
open http://localhost:5173
```
## Gateway
Gateway запускается нодой:
```bash
pnpm gateway:dev
```
Проверить gateway health:
```bash
curl http://localhost:8888/health
```
2026-05-05 13:25:28 +03:00
Проверить image origin route после запуска Backend и Worker:
2026-05-05 09:59:21 +03:00
```bash
2026-05-05 13:25:28 +03:00
curl -i "http://localhost:8888/images/asset_demo/v1/card?w=640& q=80& f=auto"
curl -i "http://localhost:8888/images/asset_demo/v1/avatar?f=auto"
curl -i "http://localhost:8888/images/asset_demo/v1/custom?w=777& h=333& q=72& fit=fill& f=webp"
2026-05-05 09:59:21 +03:00
```
2026-05-05 13:25:28 +03:00
Первый запрос должен пройти через Backend/RabbitMQ/Worker/imgproxy/S3 и вернуться с `x-image-platform-l1: MISS` . Повторный запрос должен вернуться из gateway L1 с `x-image-platform-l1: HIT` .
Статические presets сейчас лежат в `packages/image-config` :
- `card` - responsive, widths `320` , `640` , `960` .
- `hero` - responsive, widths `1280` , `1920` .
- `avatar` - fixed `256x256` .
Mock allowlist source hosts задаётся через `SOURCE_ALLOWED_HOSTS` . В dev по умолчанию разрешён `storage.yandexcloud.net` .
2026-05-05 09:59:21 +03:00
## Worker
2026-05-05 13:25:28 +03:00
Worker запускается нодой, объявляет RabbitMQ topology, слушает `image.generate-variant` , вызывает `imgproxy` и пишет готовый variant в S3.
2026-05-05 09:59:21 +03:00
```bash
pnpm worker:dev
```
Проверить worker package без запуска consumer:
```bash
pnpm worker:typecheck
pnpm worker:build
```
2026-05-04 22:53:55 +03:00
## Будущий dev flow
2026-05-05 09:59:21 +03:00
Текущая и будущая схема:
2026-05-04 22:53:55 +03:00
```text
React/Vite admin localhost:5173
2026-05-05 09:59:21 +03:00
-> NestJS backend localhost:3001
2026-05-04 22:53:55 +03:00
-> PostgreSQL localhost:5433
-> MinIO localhost:9000
2026-05-05 09:59:21 +03:00
-> RabbitMQ localhost:5672
2026-05-04 22:53:55 +03:00
worker node process
-> PostgreSQL
-> MinIO
2026-05-05 09:59:21 +03:00
-> RabbitMQ
-> imgproxy localhost:18080
2026-05-04 22:53:55 +03:00
2026-05-05 09:59:21 +03:00
Fastify gateway localhost:8888
-> L1 memory cache
-> Backend internal ensure endpoint
2026-05-04 22:53:55 +03:00
```
2026-05-05 09:59:21 +03:00
## imgproxy для разработки
2026-05-04 22:53:55 +03:00
2026-05-05 09:59:21 +03:00
В dev compose поднимается локальный `imgproxy` , опубликованный только на `127.0.0.1:18080` :
2026-05-04 22:53:55 +03:00
```env
IMGPROXY_UPSTREAM=http://localhost:18080
```
2026-05-05 09:59:21 +03:00
Для production `imgproxy` всё равно рассматривается как внешняя зависимость и может жить на отдельном мощном сервере.