Photo Studio Service
Ответственность
Генерация и улучшение фотографий блюд с помощью AI (Polza Nano Banana 2). Принимает входное изображение + style preset или текстовое описание, создаёт Job, выполняет генерацию асинхронно, возвращает результат через SSE или polling.
Нестандартный сервис
Написан на Go (не Java + Spring Boot). Подробнее — ADR-021.
Ключевые функции
- Генерация в стиле (
photo-studio) — style transfer через системный или личный пресет - Улучшение (
enhance) — text-guided transform с сохранением блюда - Постеры (
poster) — маркетинговый макет с заголовком на основе шаблона - Композиция (
composition) — 3 изображения: блюдо + посуда + фон - Асинхронная очередь — Job создаётся мгновенно (HTTP 202), обрабатывается воркером через Redis Streams
- Polza async polling —
async: trueна POST → pollGET /v1/media/{id}каждые 3 сек до 15 мин (см. ADR-022) - Smart fallback — fallback-модель только на «реальные» отказы Polza (не на сетевые ошибки), исключает двойное списание
- SSE real-time — клиент подписывается на
GET /jobs/{id}/stream, получаетpending → running → succeeded/failed(опционально; основной канал — polling/v1/jobsкаждые 5 сек на фронте) - Системные пресеты — управляемая библиотека стилей (CRUD через admin endpoints)
- Личные пресеты — per-user библиотека reference-изображений (до 50 штук, atomic-quota)
- Ассет-хранилище — входные и выходные файлы в MinIO, presigned URLs для доступа (TTL 1ч)
- Audit log — все админ-действия пишутся в
audit_log
Зависимости
| Зависимость | Роль | Примечание |
|---|---|---|
| Auth Service | Валидация JWT через POST /internal/auth/validate | Token introspection — см. ADR-021 |
PostgreSQL (gensvc_db) | Метаданные: jobs, presets, user_presets, assets, audit_log, job_outputs | |
| Redis | Очередь заданий (воркер) + кэш introspection-ответов (TTL 60 сек) | |
| MinIO | Хранилище бинарных файлов: входные фото и сгенерированные результаты | S3-совместимый API |
| Polza.ai | AI-провайдер — Nano Banana 2 (google/gemini-3.1-flash-image-preview) | Внешний API |
Авторизация
Token Introspection через Auth Service
Все запросы к
/api/v1/gensvc/*должны содержатьAuthorization: Bearer <JWT>. Сервис вызываетPOST /internal/auth/validateAuth Service с Redis-кэшем TTL 60 сек. Подробнее: ADR-021.
JWT claims, используемые сервисом:
| Поле | Источник | Использование |
|---|---|---|
user_id / sub | JWT | Фильтрация заданий, owner check |
franchise_id | JWT | Мультитенантная изоляция данных |
permissions | /internal/auth/validate response | Проверка прав на каждый endpoint |
URL-пути и API Gateway
Несоответствие URL-префикса
Текущий сервис использует пути
/v1/jobs/...без/api/префикса. При подключении через API Gateway пути будут переписаны:{gateway}/api/v1/gensvc/jobs/.... Задача по выравниванию — Декомпозиция: Photo Studio Service.
| Внешний путь (через Gateway) | Внутренний путь сервиса |
|---|---|
/api/v1/gensvc/jobs/photo | /v1/jobs/photo |
/api/v1/gensvc/jobs/{id} | /v1/jobs/{id} |
/api/v1/gensvc/presets | /v1/presets |
/api/v1/gensvc/admin/presets | /v1/admin/presets |
Конфигурация
База
| Variable | Description | Default |
|---|---|---|
DATABASE_URL | PostgreSQL connection string | — |
REDIS_URL | Redis connection string | — |
S3_ENDPOINT | MinIO endpoint | — |
S3_ACCESS_KEY | MinIO access key | — |
S3_SECRET_KEY | MinIO secret key | — |
S3_BUCKET_INPUTS | Bucket для входных фото | gensvc-inputs |
S3_BUCKET_OUTPUTS | Bucket для сгенерированных фото | gensvc-outputs |
S3_BUCKET_PRESETS | Bucket для системных пресетов | gensvc-presets |
S3_BUCKET_USER_PRESETS | Bucket для личных пресетов | gensvc-user-presets |
S3_BUCKET_POSTER_TEMPLATES | Bucket для шаблонов постеров | gensvc-poster-templates |
S3_BUCKET_COMPOSITION | Bucket для тарелок/фонов композиции | gensvc-composition |
CORS_ALLOWED_ORIGINS | Разрешённые CORS origins (через запятую) | http://localhost:5173 |
AI / Polza (см. ADR-022)
| Variable | Description | Default |
|---|---|---|
AI_API_KEY | Polza.ai API key (pza_...) | — |
AI_BASE_URL | Polza endpoint | https://polza.ai/api/v1 |
AI_MODEL | Primary модель (на момент 2026-05-08 — Nano Banana, быстрее GPT) | google/gemini-3.1-flash-image-preview |
AI_MODEL_FALLBACK | Fallback модель. Пустое = выключено. Включается только при isFallbackableError (см. ADR-022) | (пусто) |
Worker
| Variable | Description | Default |
|---|---|---|
WORKER_CONCURRENCY | Сколько jobs воркер обрабатывает параллельно | 5 |
WORKER_JOB_TIMEOUT_SEC | Жёсткий context-deadline на один job (включая 15-мин polling) | 1080 |
WORKER_MAX_RETRIES | Сколько раз worker пытается обработать один job; minimum effective 1 | 1 |
Авторизация (см. ADR-021)
| Variable | Description | Default |
|---|---|---|
AUTH_MODE | local (HS256) / jwks / introspection (целевой) | local |
JWT_LOCAL_SECRET | HS256 секрет (общий с auth-service) | — |
JWT_AUDIENCE | Если задан — обязательно совпадает с aud claim. ERP не выставляет — оставлять пустым | (пусто) |
JWT_ISSUER | Если задан — обязательно совпадает с iss claim. ERP не выставляет — оставлять пустым | (пусто) |
AUTH_USERINFO_URL | Базовый URL ERP API (/auth/me будет дёрнут после валидации JWT, чтобы получить permissions[]). Пустое значение = не обогащать | https://erp.nirbi.ru/api/v1 |
AUTH_USERINFO_TTL_SEC | TTL кеша permissions от /auth/me | 60 |
AUTH_SERVICE_URL | (целевой режим, когда выдан service-token) URL Auth Service для /internal/auth/validate | — |
AUTH_SERVICE_TOKEN | (целевой режим) Service token для X-Service-Token | — |
ERP_JWKS_URL | JWKS endpoint (только при AUTH_MODE=jwks) | https://erp-test.nirbi.ru/.well-known/jwks.json |