← ClippyАдминкаБенчмаркТЗРефералы и WinWorkПарсерыПравила кампанийДокументы

ТЗ: Clippy · MVP биржи продвижения видео

Актуальный сценарий и статус реализации: закрытый MVP. Для запуска через команду этот документ имеет приоритет над описанием самостоятельного запуска ниже.

Версия 0.1 · 20.09.2026. Основание: исследование Vyro и запрос на самостоятельную биржу, независимую от Trendsee. Рынок: русскоязычный. Валюта MVP: RUB. Все тарифы и SLA ниже — предлагаемые параметры пилота, а не действующие обязательства Clippy.

1. Цель и критерий результата

Заказчик может передать исходный видеоконтент независимым клипперам и оплачивать проверенные просмотры опубликованных клипов. Клиппер видит условия до работы, подключает свой аккаунт, отправляет ссылку, отслеживает проверку и получает выплату. Оператор может объяснить и воспроизвести каждое начисление.

Готовность MVP: сквозная кампания от создания и фактического подтверждения пополнения до финальной сверки, выплаты исполнителю и возврата остатка. Наличие кликабельных экранов само по себе не является готовностью MVP. Прототип показывает интерфейс; финансовые операции и интеграции в нём имитируются.

2. Роли и права

Роль Доступ Запрет
Гость Каталог, открытый бриф, правила, FAQ Деньги, чужие персональные данные, исходники без лицензии
Клиппер Собственные аккаунты, участие, публикации, начисления, реквизиты, апелляции Чужие клипы/кошельки, изменение ставок кампании
Заказчик Кампании своей организации, бюджет, агрегаты, допустимые данные исполнителей Произвольное уменьшение зафиксированных начислений
Модератор Очередь контента, доказательства, причины решений Изменение платёжных реквизитов и выполнение выплат
Финансовый оператор Сверка, возвраты, выплаты с разделением полномочий Единоличное редактирование ledger или выдача себе денег
Администратор Управление доступами и настройками в пределах аудита Скрытые изменения финансовой истории

Один аккаунт имеет ровно одну роль: клиппер или рекламодатель. Роль выбирается при первом входе и после подтверждения не изменяется. Переключателя ролей нет ни в кабинете, ни в настройках; сервер должен запрещать изменение роли. Продакшен-авторизация проверяется на сервере по tenant/owner, не только скрытием кнопок.

3. Информационная архитектура

Клиппер: Главная → Кампании → Мои клипы → Кошелёк; аккаунты и настройки в профиле. Внутри кампании: обзор/экономика, бриф, исходники, правила, мои публикации. Главная — первый следующий шаг, текущие кампании и статус денег.

Заказчик: Обзор → Кампании → Проверка клипов → Аналитика → Финансы. Создание кампании: контент → условия/бюджет → предпросмотр. Оператор: кампании на проверке, клипы, спорные просмотры, апелляции, выплаты/сверка, инциденты.

Самостоятельный продукт: собственные регистрация, профиль, бренд, каталог и биллинг. Не зависит от аккаунтов, тарифов, библиотеки или инфраструктуры Trendsee. Clippy — рабочее название.

4. Сквозные сценарии

C1. Первый клип

  1. Гость открывает каталог и выбирает доступную кампанию по теме, языку, площадке, ставке и сроку.
  2. До регистрации видит бриф и условия денег; для скачивания защищённых исходников требуется участие.
  3. Вход → возраст/страна доступности → минимальный профиль. Соцподключение можно отложить до первой отправки.
  4. Подключить OAuth-аккаунт; сохранить внешний ID, тип верификации и scopes. Если OAuth не поддерживается, отдельный разрешённый метод подтверждения владельца. Никакой автоматической «проверки» по совпадению username.
  5. Вступление фиксирует версию правил и ставку. Показать статус кампании и предупреждение, что Join не резервирует весь её бюджет под пользователя.
  6. Скачать материалы, смонтировать и опубликовать в своём канале, выполнить обязательную маркировку.
  7. Отправить URL. Сервер нормализует ссылку, проверяет владельца, площадку, публикацию, дубликат и фиксирует baseline.
  8. Получить ID отправки, статус, время начала учёта и срок проверки. При ошибке baseline — статус «Ожидаем данные», начисление не выдумывать.
  9. Увидеть решение модерации; при отказе — причина и возможность исправления/апелляции.
  10. Наблюдать просмотры и предварительное вознаграждение. После settlement средства переходят в available.
  11. Пройти платёжную верификацию, запросить вывод и получить статус провайдера.

B1. Первая кампания

  1. Указать организацию, исходник, правообладателя и цель распространения.
  2. Бриф: описание, обязательные элементы, запрещённое, допустимые типы постов, язык, площадка, disclosure, длина ролика.
  3. Условия: бюджет клипперов, ставка за 1 000, лимит на пост, сроки, окно учёта и период удержания публикации.
  4. Предпросмотр карточки как у клиппера; отдельно показать комиссию и общую сумму.
  5. Проверка кампании оператором, устранение замечаний; только затем разрешить пополнение.
  6. Подтверждённый платёжный webhook переводит её в active. Возврат пользователя из платёжной формы не подтверждает оплату.
  7. Модерация клипов, аналитика, пауза новых вступлений, пополнение бюджета. Изменение материальных условий требует новой версии или новой кампании.
  8. Завершение → финальный сбор → проверка → settlement → выплаты и возврат. Отчёт: расход, комиссия, оплаченные просмотры и причины исключения.

O1. Спор

Отказ содержит reason_code, ссылку на правило и evidence. Клиппер подаёт апелляцию в течение 7 дней (гипотеза), оператор отвечает до 3 рабочих дней. Повторная проверка не должна автоматически менять baseline. Финансовая корректировка оформляется отдельной операцией, а не изменением старой строки.

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

ID Требование Приёмка
FR-01 Авторизация и две роли Роль выбирается один раз; сервер запрещает её изменение; данные разных организаций изолированы
FR-02 Доступность Недоступная страна/площадка объяснена до создания клипа или оплаты
FR-03 Каталог Поиск, тема, язык, площадка, доступность, сортировка по новизне/ставке/остатку; пустое состояние со сбросом
FR-04 Карточка Ставка, бюджет, порог, лимит, время, язык, форматы и источник правил доступны до Join
FR-05 Подключение Проверен внешний account ID; истёкший доступ явно отмечен; повторное подключение не создаёт дубликат
FR-06 Участие Сохранены timestamp, версия брифа/лицензии/условий и ставка; повторный Join идемпотентен
FR-07 URL submission Разрешённые домены и типы постов, канонический ID, принадлежность, дубликаты, лимиты, понятные ошибки
FR-08 Модерация approve/reject/needs_changes с причиной и журналом; 48 ч — целевой SLA пилота
FR-09 Метрики Raw / eligible / payable отдельно, baseline, last_success_at и признак stale
FR-10 Начисление Серверный расчёт, целочисленные денежные единицы, атомарный бюджетный лимит
FR-11 Кошелёк pending, available, processing, paid, reversed; связь каждого движения с основанием
FR-12 Выплата Проверенные реквизиты, KYC/налоговый статус по выбранной модели, retry и защита от дубля
FR-13 Мастер кампании Черновик, validation, preview, модерация, подтверждение пополнения, запуск
FR-14 Контроль бюджета Пауза/дозаправка/завершение с понятными последствиями для действующих клипов
FR-15 Аналитика Период, площадка, клип, исполнитель, проверенные просмотры, расход и комиссия; экспорт
FR-16 Уведомления Join, решение, stale data, budget low, campaign ended, funds released, payout result; настройка согласий
FR-17 Апелляция Один открытый спор на решение, SLA и история; пересмотр с отдельной корректировкой
FR-18 Права Лицензия на исходники, разрешение на производные клипы и распространение, правила удаления

Ставка в MVP фиксируется для участника при Join. Изменение ставки задним числом запрещено. Вариант Vyro с live rate оставляется за пределами MVP; если понадобится, отдельная история ставок с effective_from и расчёт по каждому временному интервалу.

6. Машины состояний

Кампания: draft → under_review → awaiting_funding → scheduled/active → closing → verifying → settled. Из review возможен needs_changes. В active возможен intake_paused; это только остановка новых вступлений/отправок, начисления ранее принятым клипам продолжаются до указанного окна или исчерпания денег. Отдельный cancelled допустим до запуска; после запуска только завершение с расчётом обязательств.

Публикация: submitted → validating → pending_review → approved / needs_changes / rejected. После approved может возникнуть under_fraud_review, removed или settled. Статус модерации не равен статусу сбора данных. metrics_stale — флаг, а не отказ.

Деньги: estimated → reserved_pending → available → payout_processing → paid. Отклонение освобождает резерв. Fraud reversal идёт отдельной записью. Ошибка провайдера возвращает processing в available только при подтверждении, что перевод не состоялся. Timeout — reconciliation, а не новый перевод.

7. Учёт просмотров и денег

Правила пилота

Предлагается отсутствие минимального порога начисления: первые подтверждённые просмотры оплачиваются, вывод имеет отдельный минимум. Лимит по умолчанию 100 000 просмотров на клип; ставка в прототипе 90–150 ₽/1 000 — иллюстрация, не рыночный бенчмарк. Минимальный бюджет в демо 30 000 ₽ — гипотеза для пилота. Никакой гарантии доставки.

На submit фиксировать baseline_count и baseline_observed_at. Если счётчик недоступен, сообщить, что учёт начнётся с первой успешной фиксации, и дать отменить отправку; не принимать нулевой baseline. Время на сервере UTC, интерфейс показывает часовой пояс кампании.

candidate_views = max(0, latest_count − baseline_count), ограниченные концом окна и cap. Из candidate исключаются только классифицированные просмотры с reason code; часть, которую нельзя надёжно классифицировать, отправляется на проверку, а не автоматически считается ботами. Изменение public count вниз не приводит к повторной оплате при обратном росте: вести high-water mark и отдельные corrections.

Если счётчик пересекает конец окна без точного снимка, не выдавать все поздние просмотры за произошедшие раньше. Использовать последний подтверждённый снимок до cutoff; разницу держать в unresolved до доступного доказательства и показывать ограничение. Статистика не доказывает органичность сама по себе.

Расчёт в интервале

Пусть r_i — рубли за тысячу, dv_i — новые допустимые просмотры, R_i — неиспользованный денежный cap. Сначала получить demand_i = min(dv_i × r_i / 1000, R_i). Далее сравнить сумму demand всех допустимых заявок интервала с атомарно доступным остатком B.

Если сумма ≤ B, начислить полную сумму. Иначе выделить B × demand_i / Σ demand каждой заявке этого интервала. Округлять к копейкам методом наибольших остатков с детерминированным tie-breaker по submission_id. Зафиксировать effective CPM и reason budget_exhausted. Прошлые интервалы не пересчитывать из-за новых публикаций.

При ожидании модерации сумма интервала резервируется и показана как предварительная. Reject освобождает резерв. Освобождённый резерв проходит отдельный reconciliation batch для недооплаченного хвоста того же окна согласно документированному порядку; никогда не уменьшает уже выданное. Просмотры без бюджета отображать отдельно, не как долг платформы.

Сумма reserved + payable + paid не превышает профинансированного бюджета кампании. Комиссия платформы учитывается на отдельных ledger accounts. Никаких float для денег: integer minor units и decimal/rational для промежуточных ставок.

Примеры для обязательных тестов

Случай Вход Ожидаемый результат
Обычный baseline 10 000, count 22 000, rate 120 12 000 кандидатных просмотров, 1 440 ₽ до иных исключений
Повторный снимок Тот же count и timestamp Ноль новых начислений
Cap 120 000 новых, cap 100 000, rate 120 Не более 12 000 ₽
Нехватка demand A 800 ₽, B 400 ₽, остаток 600 ₽ A 400 ₽, B 200 ₽; остаток 0
Baseline недоступен API timeout Нет начисления, ожидаем данные, visible reason
Rollback счётчика 22 000 → 20 000 → 22 000 Уже обработанный рост не оплачивается второй раз
Дубликат URL Shorts URL и альтернативный URL одного ID Одна публикация
Payout retry Один idempotency key, два webhook Один перевод и одна финальная запись
Пауза набора Intake paused при активных клипах Новые не принимаются; старые считают в пределах условий
Конец кампании Рост после cutoff Не начислять поздние просмотры без подтверждения времени

8. Интеграции и ограничения

Перед обещанием площадки сделать proof of access на реальных тестовых аккаунтах: OAuth и проверка владельца; список постов и canonical ID; нужный счётчик; задержки; отозванный токен; удалённое/скрытое видео; лимиты; допустимость хранения и производного расчёта.

YouTube Data API предоставляет statistics и идентификатор канала; определение viewCount нельзя подменять уникальным охватом или удержанием. TikTok Display API и Query Videos требуют отдельной проверки доступов и допустимого use case. Наличие endpoint не означает право строить на нём коммерческий биллинг. TikTok и Instagram не обязательны для первого рублёвого пилота.

Для VK API и рублёвых выплат в этой работе не подтверждены коммерческие права, точные scopes и SLA. Это release blockers, а не задачи «добавить потом». Выбрать провайдера после определения юрлица, географии получателей, договорной модели и требований к документам. Не использовать скриншоты статистики как единственное автоматическое основание выплаты.

9. Архитектура и данные

Рекомендуемая граница: самостоятельное веб-приложение; API приложения; PostgreSQL; очередь задач; object storage для исходников; изолированные adapters соцсетей и платёжного провайдера. Стек выбирается под отдельный продукт; интеграция с существующим сервисом не требуется.

Сущность Ключевые поля и ограничения
User / Organization / Membership id, role, org_id, country, locale, status; tenant isolation
SocialAccount user_id, platform, external_id, verification_method, scopes, encrypted_token_ref, expires_at; unique(platform, external_id)
Campaign org_id, status, currency, budget_minor, funded_minor, starts_at, ends_at, platform_policy, rule_version
CampaignRules version, brief, required_tags, disclosure, min_length, cap, minimum_views, source_license, effective_from
Participation user_id, campaign_id, joined_at, accepted_rule_version, rate_snapshot; unique(user,campaign)
Asset campaign_id, storage_key, sha256, license_version, access_policy, retention
Submission participation_id, social_account_id, platform_post_id, canonical_url, submitted_at, baseline; unique(platform,post_id)
MetricSnapshot post_id, source, source_timestamp, observed_at, raw_count, payload_hash, freshness
ModerationDecision submission_id, reviewer_id, outcome, reason_code, evidence, timestamp
AccrualBatch / Allocation campaign_id, interval, rule_version, demand, allocated_minor, eligible_views; deterministic key
LedgerEntry transaction_id, debit_account, credit_account, amount_minor, currency, reason, reference; append-only
Payout / Refund provider_id, idempotency_key, status, amount_minor, webhook_state
Appeal / AuditEvent actor, entity, reason, before/after refs, timestamp

Не помещать токены и банковские реквизиты в клиентский код. Реквизиты по возможности токенизируются у провайдера. В ledger не хранить исходные финансовые секреты. Персональные данные не попадут в публичный каталог.

10. API-контракт и фоновые процессы

Минимальные команды: GET /campaigns, GET /campaigns/:id, POST /campaigns, PATCH /campaigns/:id/draft, POST /campaigns/:id/submit-review, POST /campaigns/:id/funding-intents, POST /campaigns/:id/join, POST /submissions, GET /submissions/:id/metrics, POST /submissions/:id/decisions, POST /appeals, GET /wallet, POST /payouts, GET /reports.

Все изменяющие деньги/участие команды поддерживают idempotency key и возвращают operation_id/status. 401/403 не смешивать с 404/409/422/429. Ошибка содержит code, понятное сообщение и исправимое поле без внутренних секретов. Webhooks валидировать подписью, deduplicate по provider_event_id; обработка в транзакции.

Jobs: collect_metrics (целевой часовой цикл, адаптивное замедление завершённых постов), risk_review, allocate_interval, settle_campaign, process_payout, reconcile_provider, release_unused_budget, notifications. Backoff, rate limits, dead-letter queue и dashboard задержек обязательны. При недоступности API stop/freeze неопределённой части расчёта, а не «успешно, 0 просмотров».

11. Самостоятельный UI/UX

Визуальная структура следует проверенному кабинету Vyro: верхняя навигация, центральная колонка около 1042 px, светло-серый фон, белые скруглённые панели, чёрные кнопки и компактные карточки без фотообложек. Название Clippy и рублёвая экономика самостоятельные. Четыре основные задачи клиппера: Главная, Кампании, Добавить клип, Доход; аккаунты, свои клипы и справка доступны через профиль.

Токены прототипа: canvas #F7F8FA, surface #FFFFFF, text #17181B, muted #767B85, border #E9EBEE, action #101114. Голубой акцент #DCEAFF используется в блоке старта. Радиусы панелей 20–24 px, аватаров 12 px, кнопки округлые. У карточки автор и миниатюра сверху, заголовок ниже, площадка слева внизу, ставка справа. Мелкие подписи повторяют плотность референса; перед production проверить читаемость на целевых устройствах и увеличить финансовые пояснения минимум до 12 px. Фокус видим, состояние не определяется одним цветом.

Экраны и обязательные состояния

Экран Содержимое Состояния
Главная клиппера Прогресс первого результата, активные кампании, деньги, следующий шаг Новый / активный / нет кампаний
Каталог Карточки с экономикой и сортировками Loading / loaded / empty / error / locked
Кампания Бриф, экономический блок, lifecycle, материалы, Join/submit Active / joined / paused / exhausted / review / completed
Добавление Выбор кампании, URL, подключение, результаты валидации Invalid / duplicate / wrong owner / pending / success
Мои клипы Статус, raw/valid/payable, деньги, причина Review / approved / rejected / appeal / stale
Кошелёк Остатки и журнал Empty / pending / available / payout processing / failed
Создание кампании Три шага и preview Draft / validation / needs changes / funding / success
Модерация Материал, бриф, причины, история Pending / decision / appeal
Аналитика Просмотры, расход, платформа/период, свежесть No data / partial / stale / full
Аккаунты Метод проверки, scopes, состояние, тематики Connected / expired / unsupported

Мобильная версия: основной путь клиппера без горизонтального скролла страницы; финансовая таблица может иметь локальную прокрутку. Нажимаемые элементы 44×44 px или достаточная зона. Модальные окна закрываются Escape, возвращают фокус, доступны с клавиатуры. У длинного брифа полноценная страница или широкий drawer; ключевые деньги и CTA видимы без поиска в tooltip.

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

13. План реализации

Этап Результат Условие перехода
0. Discovery и legal/integration spike Страна/юрлицо, права, API, выплата, 5 брифов Реально доступные метрики и переводы, согласованные правила
1. Продуктовый каркас Две роли, каталог, профиль, мастер, asset access Сквозной dry-run без денег
2. Учёт и операции Метрики, очередь, ledger, budgets, idempotency Тесты гонок, replay, rounding, reconciling проходят
3. Выплаты и пилот Provider sandbox → ограниченный production Подтверждённая сверка, возврат и поддержка
4. Проверка спроса Повторные бюджеты, contribution margin, качество Ворота пилота из исследования

Ориентир разработки 8–12 недель командой с frontend, backend, product/design и выделенной QA/ops-поддержкой после закрытия внешних блокеров. Это оценка порядка, не обещание срока: OAuth review и платёжный onboarding могут занять дольше.

14. Что реализовано в прототипе

Кликабельные: однократный выбор роли, каталог, поиск/фильтры/сортировка/сохранение, бриф/исходники/правила, вступление, отправка демо-ссылки с валидацией, список клипов, approve/reject и апелляция, кошелёк/демо-вывод, подключение демо-аккаунта, три шага создания кампании, пауза, аналитический период, справка, лендинг, исследование и ТЗ.

Неподключённые: OAuth, видеофайлы, платёжный провайдер, реальные счётчики, серверная авторизация, ledger, durable storage, антифрод и настоящая рассылка. Роль сохраняется в браузере после первого выбора и не меняется в интерфейсе. Прочие изменения прототипа живут в памяти открытой страницы и сбрасываются при перезагрузке. Демо-данные не являются данными пользователя или партнёров.

15. Решения, требующие утверждения перед разработкой

Юрлицо и страны выплат; разрешённые площадки; definition of payable view и допустимость источников; минимальный бюджет/ставка/лимиты; комиссия и налоги; SLA; ответственность за маркировку; сроки сохранения опубликованного клипа и лицензий; финальная политика распределения остатка; кредитный риск/возвраты; кто модерирует; утверждение самостоятельного бренда и тарифов.

Дополнение: отправка клипа

Кабинет кампании содержит результаты, бриф, исходники и публикации. В форме есть выбор аккаунта, последние демо-видео и режим ссылки. Перед отправкой требуются подтверждение брифа и проверка данных. Новая публикация получает статус «На проверке».

Лимит в демо: 5 отправок на аккаунт площадки за 24 часа текущей сессии. Ссылки нормализуются для поиска дубликатов. Финальный экран подтверждения спроектирован для Clippy; в Vyro он не проверен. Соцсети не подключены: существование ролика, принадлежность аккаунту и содержание не проверяются. Публикации сбрасываются после перезагрузки, выбранная роль сохраняется.

Дополнения 0.2: рефералы, WinWork, админка и статистика

Выплаты в рублях только самозанятым и ИП через WinWork. ИП на НПД учитывается отдельно от ИП на других режимах. Спецификация профиля, договоров, реферальных событий и сверки: Рефералы и WinWork.

Актуальный статус реализации парсеров, проверки био и админки: Сбор статистики. Юридические тексты с полями для реквизитов и обязательных условий: Проект документов. Эти дополнения уточняют платёжные требования предыдущей версии.

Уточнение кампаний и расчёта каждые 6 часов

Актуальные правила модерации, порогов, лимитов и статусов реализации: Кампания и расчёт. Они заменяют прежний интервал обновления и отсутствие порога в демонстрационной кампании.

Отправка публикации и правила контента

Путь: Мои кампании → Добавить клип → кампания → аккаунт → публикация или ссылка → подтверждение правил → проверка данных → На проверке. Открытие правил не сбрасывает форму. Без аккаунта, корректной публикации и подтверждения продолжить нельзя. Дубли и дневная квота блокируют отправку. Аккаунты и последние посты в этом сценарии демонстрационные; реальный сбор находится в админке. Правила контента.

Лендинги и рекламодатель: обновление прототипа