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 pollingasync: true на POST → poll GET /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/validateToken introspection — см. ADR-021
PostgreSQL (gensvc_db)Метаданные: jobs, presets, user_presets, assets, audit_log, job_outputs
RedisОчередь заданий (воркер) + кэш introspection-ответов (TTL 60 сек)
MinIOХранилище бинарных файлов: входные фото и сгенерированные результатыS3-совместимый API
Polza.aiAI-провайдер — Nano Banana 2 (google/gemini-3.1-flash-image-preview)Внешний API

Авторизация

Token Introspection через Auth Service

Все запросы к /api/v1/gensvc/* должны содержать Authorization: Bearer <JWT>. Сервис вызывает POST /internal/auth/validate Auth Service с Redis-кэшем TTL 60 сек. Подробнее: ADR-021.

JWT claims, используемые сервисом:

ПолеИсточникИспользование
user_id / subJWTФильтрация заданий, owner check
franchise_idJWTМультитенантная изоляция данных
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

Конфигурация

База

VariableDescriptionDefault
DATABASE_URLPostgreSQL connection string
REDIS_URLRedis connection string
S3_ENDPOINTMinIO endpoint
S3_ACCESS_KEYMinIO access key
S3_SECRET_KEYMinIO secret key
S3_BUCKET_INPUTSBucket для входных фотоgensvc-inputs
S3_BUCKET_OUTPUTSBucket для сгенерированных фотоgensvc-outputs
S3_BUCKET_PRESETSBucket для системных пресетовgensvc-presets
S3_BUCKET_USER_PRESETSBucket для личных пресетовgensvc-user-presets
S3_BUCKET_POSTER_TEMPLATESBucket для шаблонов постеровgensvc-poster-templates
S3_BUCKET_COMPOSITIONBucket для тарелок/фонов композицииgensvc-composition
CORS_ALLOWED_ORIGINSРазрешённые CORS origins (через запятую)http://localhost:5173

AI / Polza (см. ADR-022)

VariableDescriptionDefault
AI_API_KEYPolza.ai API key (pza_...)
AI_BASE_URLPolza endpointhttps://polza.ai/api/v1
AI_MODELPrimary модель (на момент 2026-05-08 — Nano Banana, быстрее GPT)google/gemini-3.1-flash-image-preview
AI_MODEL_FALLBACKFallback модель. Пустое = выключено. Включается только при isFallbackableError (см. ADR-022)(пусто)

Worker

VariableDescriptionDefault
WORKER_CONCURRENCYСколько jobs воркер обрабатывает параллельно5
WORKER_JOB_TIMEOUT_SECЖёсткий context-deadline на один job (включая 15-мин polling)1080
WORKER_MAX_RETRIESСколько раз worker пытается обработать один job; minimum effective 11

Авторизация (см. ADR-021)

VariableDescriptionDefault
AUTH_MODElocal (HS256) / jwks / introspection (целевой)local
JWT_LOCAL_SECRETHS256 секрет (общий с 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_SECTTL кеша permissions от /auth/me60
AUTH_SERVICE_URL(целевой режим, когда выдан service-token) URL Auth Service для /internal/auth/validate
AUTH_SERVICE_TOKEN(целевой режим) Service token для X-Service-Token
ERP_JWKS_URLJWKS endpoint (только при AUTH_MODE=jwks)https://erp-test.nirbi.ru/.well-known/jwks.json

Ссылки