# ТЗ: Cutout — SaaS по удалению фона с изображений

Версия: 0.1 (M0) · Статус: согласовано · Дата: 2026-09-25

## 0. Зафиксированные решения

| Вопрос | Решение |
|---|---|
| Название / папка | `cutout`, `/home/skinenbayev/cutout` |
| Стек фронтенда | HTML5 + vanilla JS (ES modules), без фреймворков |
| CSS | TailwindCSS через локальную сборку Tailwind CLI (без CDN) |
| Бэкенд | Python FastAPI (проектируем контракт, реализация позже) |
| Платежи | Stripe, этап M5 (в MVP — только кредиты) |
| Деплой | Docker + Docker Swarm (Traefik как edge) |
| M1 | Лендинг + редактор, работающие на мок-API без бэкенда |

## 1. Продукт

Cutout — веб-сервис и публичный REST API, который по входному изображению
автоматически вырезает объект переднего плана и возвращает его на прозрачном
фоне (PNG с alpha). Аналоги: remove.bg, Photoroom, rembg.

Бизнес-модель: freemium → кредиты → подписка; API-ключи для разработчиков;
превью с водяным знаком для анонимных пользователей.

## 2. Цели и не-цели

**Цели MVP**
- Быстрый путь «загрузил → получил PNG без фона → скачал» (< 5 секунд).
- Публичный API с ключами, лимитами, вебхуками.
- Самообслуживание: регистрация, кредиты, история.
- Развёртывание одной командой в Docker Swarm.

**Не-цели MVP**
- Обучение собственной ML-модели (используем готовую).
- Мобильные приложения, десктоп-клиент.
- Обработка видео, полноценный фоторедактор.
- B2B-мультитенантность, SSO, on-prem.

## 3. Роли

| Роль | Возможности |
|---|---|
| Аноним | N бесплатных обработок в сутки, результат с водяным знаком, без истории |
| Пользователь | кредиты, полное разрешение, история, скачивание, сохранение фона |
| Разработчик / API-клиент | API-ключи, batch, вебхуки, usage-статистика |
| Админ | планы, лимиты, пользователи, метрики |

## 4. Пользовательские сценарии

1. Перетащил фото в редактор → через секунды вижу объект без фона → скачал PNG.
2. Сравниваю «до/после» слайдером, переключаю фон (прозрачный / цвет / своё изображение), кропаю, качаю PNG или JPG.
3. Закинул 50 файлов → они встают в очередь → скачиваю результаты.
4. Разработчик: создал ключ → `POST /v1/remove-background` → получил `result_url` → подписался на вебхук.
5. Пользователь: вижу баланс кредитов, историю, покупаю пакет (M5).

## 5. Функциональные требования

### 5.1 Frontend (M1 — реализуется в этой итерации)

**Страницы**
- `/` — лендинг: hero + CTA, интерактивная зона загрузки, «как это работает»,
  возможности, тарифы (тизер), FAQ, футер.
- `/app` — редактор (основной экран).
- `/pricing`, `/docs`, `/login`, `/signup`, `/account` — в M1 заглушки/ссылки,
  полноценно в M5.

**Редактор**
- Способы загрузки: drag&drop, вставка из буфера (`Ctrl+V`), URL, выбор файла.
- Валидация: допустимые форматы `image/jpeg, image/png, image/webp`;
  размер ≤ 20 МБ; разрешение ≤ 12 МП; понятные сообщения об ошибках.
- Просмотр: исходник и результат; слайдер «до/после»; шахматная подложка для
  прозрачности; зум и панорамирование.
- Управление фоном: прозрачный / сплошной цвет / собственное изображение.
- Экспорт: PNG (с alpha) и JPG; имя файла на основе исходного.
- Батч: несколько файлов, последовательная обработка, список со статусами,
  скачивание каждого результата.
- История сессии: миниатюра, имя, время, повторное скачивание.
- Водяной знак для анонимов (наложение на результат).
- Счётчик кредитов в шапке; списание за успешную обработку.

**Сквозные требования фронтенда**
- Только ES-модули, без сборщика JS и без фреймворков.
- Tailwind собирается локально (`npm run build:css`), итоговый CSS хешируется nginx-кешем.
- Мок-режим API (feature flag) — весь UI работает без бэкенда.
- Тёмная и светлая темы (`class`-стратегия), сохраняются в `localStorage`.
- Локализация ru/en через `data-i18n`, переключатель языка.
- Адаптивность 360–1920 px, доступность (фокус, aria, контраст), Lighthouse ≥ 90.
- Никаких внешних CDN в рантайме.

### 5.2 Backend API (дизайн, M3+)

Контракт — OpenAPI 3.1 (`docs/openapi.yaml`). Принципы:
- Ошибки `application/problem+json` (`type, title, status, detail, code, trace_id`).
- Аутентификация `Authorization: Bearer <api_key>`; для браузера — JWT access/refresh.
- Идемпотентность через заголовок `Idempotency-Key`.
- Rate limit: заголовки `X-RateLimit-Limit/Remaining/Reset`, `Retry-After`.

**Ключевые эндпоинты**
- `POST /v1/remove-background` — multipart (`image`) или JSON (`image_url`,
  `bg_color`, `crop`, `alpha_matting`, `format`), `200` синхронно для мелких
  изображений, иначе `202` + `poll_url`.
- `GET /v1/images/{id}`, `GET /v1/images/{id}/content?type=result|original|preview|mask`, `DELETE /v1/images/{id}`.
- `POST /v1/jobs` (батч), `GET /v1/jobs/{id}`, `GET /v1/jobs/{id}/items`.
- Auth: `POST /v1/auth/register|login|refresh|logout`, `GET /v1/me`.
- API-ключи: `GET/POST /v1/me/api-keys`, `DELETE /v1/me/api-keys/{id}`.
- Кредиты: `GET /v1/credits/balance`, `GET /v1/usage`, `POST /v1/credits/checkout`.
- Вебхуки: `GET/POST /v1/webhooks`, `DELETE /v1/webhooks/{id}`; события
  `image.completed`, `image.failed`, `job.completed`.
- Служебные: `GET /healthz`, `GET /readyz`, `GET /metrics`, `GET /v1/plans`.

**Коды ошибок**: `400`, `401`, `402` (недостаточно кредитов), `413`, `415`,
`422`, `429`, `500`, `503`.

### 5.3 Модель данных

`users`, `api_keys`, `images` (original/result/mask, S3-key, статус, TTL),
`jobs`, `job_items`, `credit_ledger`, `webhooks`, `webhook_deliveries`, `plans`.

### 5.4 ML-инференс

- Движок: `rembg` (модели U2Net / ISNet / BiRefNet), alpha-matting и
  доочистка краёв; CPU по умолчанию, GPU — опционально через placement-constraints.
- Вход: JPEG/PNG/WEBP ≤ 12 МП. Выход: RGBA PNG.
- Воркеры горизонтально масштабируются, задачи берутся из очереди Redis.

## 6. Нефункциональные требования

- Производительность: p95 ≤ 3 с для изображения ≤ 1 МП на CPU.
- Доступность: 99.9%, rolling update без даунтайма.
- Безопасность: проверка magic-bytes, удаление EXIF, защита от decompression
  bomb и SSRF (блок приватных IP при загрузке по URL), CORS/CSP/HSTS,
  rate limiting, non-root и read-only контейнеры, скан образов Trivy.
- Приватность/GDPR: авто-удаление файлов (free 1 ч, платные 30 дней),
  экспорт и удаление аккаунта, DPA.
- Наблюдаемость: Prometheus + Grafana, Loki, OpenTelemetry, Sentry.
- Бэкапы: `pg_dump` по расписанию + версионирование S3.

## 7. Архитектура и Docker Swarm

```
Internet → Traefik (edge, TLS) → web (nginx, статика)
                               → api (FastAPI) → redis (очередь) → worker-infer (rembg)
                                                               → worker-jobs (батчи)
                                 → postgres
                                 → minio / S3
                                 scheduler (cleanup, retry, delivery)
```

**Swarm-требования**
- Overlay-сети: `public` (edge↔web/api) и `internal` (api↔redis/db/minio/workers).
- `secrets`: `postgres_password`, `jwt_secret`, `api_key_pepper`, `s3_*`, `stripe_*`.
- `configs`: `traefik.yml`, конфиги приложения.
- `deploy`: replicas, `resources.limits/reservations`, `update_config`
  (`order: start-first`, `parallelism`, `delay`, `failure_action`),
  `restart_policy`, `placement` по labels (`tier=gpu`, `tier=storage`), healthcheck.
- Персистентность: named/bind volumes на storage-ноде или NFS.
- Деплой: `docker stack deploy -c stack.yaml cutout`.

## 8. Этапы

- **M0** — ТЗ и фиксация решений (этот документ).
- **M1** — фронтенд: лендинг + редактор на моках, темы, i18n, адаптив. Артефакт — статика.
- **M2** — докеризация web + Traefik, локальный compose, деплой статики в Swarm.
- **M3** — скелет API FastAPI (auth/upload/jobs/credits) с фейковым воркером + OpenAPI.
- **M4** — inference-сервис rembg, реальная очередь, метрики.
- **M5** — Auth UI, dashboard, Stripe, вебхуки.
- **M6** — hardening, observability, нагрузочные тесты, GDPR, документация.

## 9. Критерии приёмки M1

- [ ] Страницы `/` и `/app` полностью рабочие на мок-API.
- [ ] Загрузка: drag&drop, `Ctrl+V`, URL, file input; валидация формата/размера/разрешения.
- [ ] Слайдер «до/после», шахматная подложка, зум/pan.
- [ ] Выбор фона: прозрачный / цвет / изображение; экспорт PNG и JPG.
- [ ] Батч-очередь с прогрессом и скачиванием.
- [ ] Тёмная/светлая темы, ru/en, адаптив 360–1920.
- [ ] Нет JS-фреймворков; Tailwind собран локально; CDN в рантайме отсутствует.
- [ ] `docker compose up` отдаёт сайт; `stack.yaml` валиден и деплоится в Swarm.

## 10. Открытые вопросы (на потом)

- Точные тарифы, цены и размер бесплатной квоты.
- Выбор финальной ML-модели и требования к GPU.
- Домен и провайдер S3 (MinIO self-hosted vs облако).
- Юрисдикция и политика хранения данных.
