← все проекты

Контент Завод (SaaS)

SaaS генерации контента: видео/карусели/посты, 40+ моделей, автопостинг. Прод 24contentzavod.ru, стейдж test.24contentzavod.ru.

repo: Logonchek/Contetn-fabric-site; local E:/…/Контент завод последняя версияserver: cfru. ПУТИ ПЕРЕПУТАНЫ: /var/www/content-factory = СТЕНД, /var/www/content-factory-prod = ПРОД. Выкладка ТОЛЬКО через /usr/local/bin/cf-deploy.sh — собирает в отдельную папку и подменяет за доли секунды (раньше сборка писала в рабочую папку и роняла сайт на 4 минуты, съедая вебхуки). Скрипт сам проверяет, поднялось ли, и откатывает. БЭКАПЫ базы: /usr/local/bin/cf-backup.sh, каждую ночь 3:15, хранится 14 суточных копий в /opt/backups/content-factory. До 01.08.2026 бэкапов не было вовсе. Очередь: Inngest (облако, ключи в .env), обработчик /api/inngest. Redis у проекта НЕТ.docs: ГЛАВНОЕ: docs/MAP.md — карта проекта, собирается автоматически на каждой выкладке скриптом scripts/build-map.mjs и ПЕРЕСОБИРАЕТСЯ ЦЕЛИКОМ (руками не править, затрётся; убрали что-то из проекта — из карты исчезает само). Внутри: где живут процессы, внешние сервисы, очереди и функции Inngest, свои таблицы-очереди, задачи по расписанию, таблицы базы, 292 маршрута, страницы, имена переменных окружения (значения маскируются). ПРАВИЛО: прежде чем искать «есть ли у нас X» и тем более писать своё — открыть карту. Один раз уже построили свою очередь, не заметив готовый Inngest с четырьмя функциями. Прочие доки: docs/ в корне (ACCEPTANCE, parallel-work и другие).память: content-factory-server-rules, content-factory-ledger-schema, content-factory-models-pricing-project
ревьюS1 · Спринт качества контента8/9

Цель: Голоса-пул, дизайнер+фон, Wan 2.7, Студия native

Голоса-пул 12 + дизайнер + фон
стейдж, ветка test/sprint-3-quality
feature
ИИ-критик ролика на вирусность (Gemini) + UI /studio/virality
Gemini 2.5 Flash через OpenRouter смотрит ролик, пораздельная оценка (хук/видео/озвучка/сабы/текст-хук/понятность/товар). Прайсинг 40р до 30с +1р/с. Ledger тип studio_virality_check.
Стейдж, e2e пройден (скрин). Gated в подписку Студии. Себестоимость ~0.33р/ролик.
feature
Агент текст-хуков + оверлей отдельным слоем + связка в пайплайн
hook-writer (gpt-4o, <=7 слов боль/желание). buildHookOverlayEvent (ASS, верх, дефолт жёлтый КАПС, хук с 00 сек). content_items.text_hook -> прожиг сабов.
Доказано на реальном ролике (фитнес): текст-хук в критике 0->4. Дефолт жёлтый КАПС, overridable.
feature
Фиксы качества: голос (audio-теги/эмоция/пунктуация) + регрессия сабов
generateSpeech срезает [теги] (баг Драматик) + маппинг эмоции в voice_settings. planAudio требует пунктуацию. Фикс self-call сабов мимо глобального NL-прокси (undici Agent).
Стейдж, сэмплы old/new у юзера. Инфра: OpenRouter гео-бан cfru -> ходим через AI_PROXY_URL (NL-прокси) в instrumentation.
fix
Настройка стиля текст-хука в визарде фабрики (hook_*)
Таб Текст-хук на странице редактирования фабрики: вкл/выкл, позиция, шрифт, размер, цвета, капс, пресеты, живое превью. Колонки factories.hook_*. Стиль проходит через пайплайн в прожиг оверлея.
Стейдж, e2e в браузере: таб рендерится, сохранение форма->PATCH->БД подтверждено (hook_color/caps/pos/font/size).
feature
ПРОД ЛЕЖАЛ: не работал вход, упал слой REST у Supabase
Владелец: «у контент завода на проде не работает кнопка войти». Вход был не при чём: страница входа открывалась, пароль проверялся, Яндекс и ВК редиректили. ПРИЧИНА: 24.08 в 02:25 перезапускалась база supabase-db, контейнер supabase-rest (PostgREST) получил SIGTERM, вышел с кодом 255 и больше не поднялся, два часа висел Exited. Весь /rest/v1 отдавал 503. Человек вводил пароль, GoTrue пускал, а кабинет не мог прочитать ни профиль, ни заводы, и выкидывал обратно на форму. Со стороны это выглядит как «кнопка не работает». Тем же объясняются ошибки планировщика «Failed to fetch factories: name resolution failed», которые сыпались всё это время. ПОЧИНЕНО: поднял supabase-rest, он подключился к базе, но снаружи всё ещё шёл 503: kong держал в кэше DNS мёртвый адрес, а контейнер поднялся с новым IP 172.19.0.14. Перезапустил supabase-kong. Сейчас rest 200, auth 200, планировщик без ошибок, /rest/v1 без ключа отвечает 401 как положено.
feature
Прод: поднимается ли REST сам после перезапуска базы
31.08 · сегодня
После инцидента 24.08 (rest лежал два часа, никто не заметил) проверить, что при перезапуске базы слой REST встаёт сам. КОМАНДА ПРОВЕРКИ: ssh cfru "docker ps -a --format '{{.Names}}\t{{.Status}}' | grep -E '^supabase-(rest|kong|auth|db)'" Все четыре должны быть Up, ни одного Exited. Затем снаружи: открыть https://24contentzavod.ru/auth/login, войти. Если выкидывает обратно на форму, значит REST снова лежит. ЕСЛИ ПОВТОРИЛОСЬ: docker start supabase-rest, затем docker restart supabase-kong (kong кэширует адрес и после подъёма rest продолжает отдавать 503). Дальше договориться с владельцем про depends_on с healthcheck в compose Supabase и про внешнюю проверку /rest/v1, которая шумит в Телеграм: сейчас падение видно только когда клиент не может войти.
check
Система качества видео (критик, банк хуков, viral_patterns)
стейдж, структуры is_active=false до прода
feature
Выкат спринта качества на прод
ждёт «да» владельца
Весь батч выкачен на прод (мерж test/sprint-3-quality -> fix/impersonate-on-v1.4, чистый; билд+рестарт content-factory-prod). Проверено: /studio/virality=200, /evaluate=401, debug-gen=404, прокси-инструментация активна.
feature
В РАБОТЕS2 · Взрослый редизайн СММ-Центра19/26

Цель: Не MVP. Хаб «Создать контент» (обёртка Студии), компания над фабрикой, честные Расходы/Дашборд/Аналитика по разрезам, Ролс-канвас. Спек: myvisionagency.ru/lab/smm-redesign. Согласовать до кода.

Схема прайса применена
feature
Фаза 0: фундамент данных (леджер модель/секунды/content_item + сбор аналитики по сетям + UTM-счётчик)
Без этого разрезы Расходов/Дашборда/Аналитики нельзя показать честно.
Роллап-леджер закрыт: tenant-метки transactions + триггер (сделано ранее), RPC smm_expense_rollup/smm_expense_items существуют и питают Расходы. Остаток фазы: UTM-счётчик и гранулярный сбор аналитики по сетям (появятся при подключении сбора).
feature
Фаза 1: быстрые баги и тексты (Ролс-обложка+долгая загрузка превью, убрать техтекст и тире, мёртвая кнопка политики, переходы из календаря)
Стейдж, проверено в браузере: (1) Ролс получает постер первого кадра при сборке (extractFirstFrame+upload, best-effort; ffmpeg-путь доказан на реальном mp4 бесплатно), Мои работы показывают видео обложкой-картинкой вместо загрузки mp4; (2) превью без медиа = кнопка Сгенерировать в Публикациях вместо тупика (скрин); (3) техтекст про не трогаем переписан; (4) Политика сетей проверена вживую end-to-end (открытие-тоггл-сохранение-БД network_policy записан) + ошибки сохранения теперь показываются; (5) вычищены длинные тире в ~35 видимых местах СММ-раздела. Существующих Ролсов без обложки в БД нет, бэкфилл не нужен.
bug
Фаза 2: Создать контент — пост и карусель (единый конструктор, обёртка Студии, канвас каруселей+пресеты)
Хаб /smm/create + студия поста + Konva-канвас карусели + ИИ-копирайт слайдов + полная ИИ-отрисовка Nano c i2i (e2e 2026-07-27, 2/2 слайда, леджер и кошелёк клиента ок). Осталось: пресеты канваса.
feature
Фаза 3: видео, ИИ-аватар, Ролс-канвас (режиссёрский, склейка, свои голос/музыка); Ролс переезжает в хаб
Сделано: полноэкранные студии Видео и ИИ-аватар (company-таргет), Ролс-канвас React Flow (сцены), Ролс в хабе. Осталось: модельная система видео per-item (Wan/Kling/Seedance/Veo), склейка-таймлайн, свои голос/музыка.
feature
Фаза 4: Расходы и Дашборд — честные разрезы (даты, по моделям с кол-вом/секундами, drill-down, виджеты)
Расходы с честными разрезами СДЕЛАНЫ (обнаружены готовыми при ревизии): даты-пресеты+кастом период, разрез по продуктам/моделям с кол-вом и секундами, по клиентам, история с drill-down к контенту (RPC smm_expense_rollup/items). Остаток: дашборд-виджеты добавляемые/убираемые с drill-down (отдельный кусок).
feature
Фаза 5: Аналитика-конструктор (метрики/разрезы/сравнение/экспорт) + Тренды по нише фабрики
Конструктор аналитики добит: метрика х разрез х даты + СРАВНЕНИЕ С ПРОШЛЫМ ПЕРИОДОМ (дельты по строкам и итогу) + экспорт CSV. Тренды по нише из брифа сделаны ранее. Проверено в браузере.
feature
Фаза 6: Компания над фабрикой (бриф/бренд/настройки на уровень компании, работа вне фабрики) — крупный сдвиг, отдельная миграция
Сделано: контент без завода на company (пост/карусель/видео/аватар), экран настроек компании (бриф+целевые сети), кошелёк клиента полный цикл. Осталось: Ролс на company, company-OAuth соцсетей + резолв публикации.
feature
Видео-Kie: модельная система per-item (Wan 2.7/Kling/Seedance/Veo, первый/последний кадр, аудио, вариация)
Протащить выбор модели per-item через generate-пайплайн (сейчас модель на уровне фабрики, завязана на 10+ мест: Inngest-воркеры + расчёт цены). Крупный кусок, отдельная сессия.
МОДЕЛЬНАЯ СИСТЕМА ГОТОВА ЦЕЛИКОМ (стейдж, проверено в браузере+БД, 6 коммитов): per-item модель/длительность/разрешение/кадры/референсы/звук. 4 модели: Veo 3.1 Lite (8/15/30с), Wan 2.7 (ползунок 3-30с, 720p 12р/с / 1080p 16р/с, r2v-референсы фото+видео до 5 + голос 1-10с, первый кадр совместим с рефами, видео-едит 12р/с до 10с), Seedance 2 (4-30с, 27/67/136 р/с по разрешению, референсы фото9/видео3/аудио3, ИИ-звук) и Seedance 2 Fast (22р/с). Свой звук = наша озвучка/сабы скипаются. >15с = 2 клипа со склейкой. Вариация + видео-едит в Моих работах. UI-иерархия по фидбэку владельца: модель компактным списком, возможности крупными дропзонами с превью. Цены = себестоимость Kie (фактчек по каталогу) + наценка. Осталось: Kling (по инфо владельца), платные тесты генераций перед продом.
feature
Company-OAuth: подключение соцсетей на аккаунт компании + резолв публикации
Без токенов аккаунтов компании публикация company-контента невозможна. Отдельная крупная фича.
Стейдж, проверено в браузере+БД: у companies сетевые поля симметрично фабрикам, publish резолвит company-подключения (can_publish_company), connect Upload-Post в режиме companyId, блок Подключение аккаунтов в настройках компании (Upload-Post + прямые TG/VK, сохранение проверено e2e в БД). Ролс принимает companyId с кошельком клиента и своими фото. Живая публикация company-поста в сеть = по outbound-гейту.
feature
Ролс на company + company-биллинг
chargeForCompany/refundForCompany уже в billing.ts (сделаны 2026-07-27). Осталось перевести Ролс-роуты на company-таргет.
Стейдж, проверено в браузере+БД: у companies сетевые поля симметрично фабрикам, publish резолвит company-подключения (can_publish_company), connect Upload-Post в режиме companyId, блок Подключение аккаунтов в настройках компании (Upload-Post + прямые TG/VK, сохранение проверено e2e в БД). Ролс принимает companyId с кошельком клиента и своими фото. Живая публикация company-поста в сеть = по outbound-гейту.
feature
Ассеты компании: аватар + голос ElevenLabs + локация
Настройки ассетов на уровне компании для студий (аватар/голос/локация съёмки).
Стейдж, проверено в браузере: блок Ассеты для контента в настройках компании (лицо аватара, голос из пула ElevenLabs с прослушиванием превью, фото товара/локаций до 8 в companies.product_images). Их читают студии аватара/видео и Ролс (авто-Ролс на company заработал через product_images).
feature
Пресеты канвас-каруселей
Готовые раскладки слайдов на Konva-канвасе.
Пресеты раскладки слайда в студии карусели: сверху/по центру/снизу с подстрокой/цитата. Проверено в браузере.
feature
Юзкейс: чип Компания (без завода) в хабе и студиях при наличии фабрик
Сейчас company-режим включается только когда фабрик нет. Нужен явный выбор компании как цели наравне с фабриками.
Стейдж, проверено в браузере: опция компании в селекторе цели всех студий (пост/карусель/видео/аватар/Ролс) даже при наличии фабрик; хаб показывает форматы company-only юзерам.
bug
Юзкейс: выбор движка полной отрисовки карусели (Nano 10р / GPT Image 2 15р за слайд)
Стейдж, проверено в браузере: переключатель движка в отрисовке карусели - Nano 10р/слайд или GPT Image 2 15р/слайд (3:4, i2i-чейнинг, леджер пишет модель), цена на кнопке пересчитывается.
feature
Юзкейс: свои референсы карусели (2-3 примера) + режим в-этом-стиле / точный-повтор-про-меня
Стейдж: блок Референсы стиля в студии (до 3 своих примеров, идут style-ref в обложку вместо системной базы). Режим точный-повтор-про-меня пока не отдельный: точность достигается своим промтом слайда + референсом.
feature
Юзкейс: перерисовать ОДИН слайд карусели с правкой текста/оффера (10-15р)
Стейдж: кнопка Отрисовать/Перерисовать у каждого слайда (10/15р за один), чейнинг от отрисованной обложки, возврат при сбое.
feature
Юзкейс: режиссёрский шаг - показать/править промт сцены каждого слайда перед отрисовкой
Стейдж: ИИ предложит визуал (designOnly, бесплатно) кладёт сцены дизайнера в редактируемые поля каждого слайда; свой промт уходит в модель как есть без переписывания агентами (directPrompt: сцена + точный кириллический заголовок + контраст + 4:5).
feature
Юзкейс: фото только на обложке карусели (тумблер, не на все слайды)
Стейдж: тумблер фото только на обложке - референс уходит только на обложку, остальные слайды рисуются без него.
feature
Креатив-канва студий (карусель, пост): композер задачи, агенты, референсы, пресеты
Новый UX по референсу Mage: ячейки по центру, композер снизу, агент-режиссёр+креативный директор, примеры из базы под формат, пресеты, публикация модалкой, переключалка форматов с сохранением черновика.
feature
РЕСЁРЧ: банк шаблонов постов и каруселей (чистая курация)
Собрать больше примеров и РАЗДЕЛИТЬ: в постах только одиночные посты-картинки с читаемым текстом (рус/англ), в каруселях только настоящие карусели. Выкинуть лендинги, баннеры, мокапы, инфографику маркетплейсов, мудборды. Разметить niche/type/style, залить в carousel_reference_templates с kind.
Собран инструмент вместо ручной курации: сбор примеров из Telegram (t.me/s, альбом = карусель) и VK (newsfeed.search в окне 14-90 дней), пороги по просмотрам и вовлечению, отсев рекламы, дедуп. На стейдже 564 кандидата (195 каруселей, 331 пост). Страница /admin/references для проверки глазами + ИИ-критик на vision, отделяющий живой пост от лендинга и баннера (платный, по кнопке). Осталось: пройти глазами и одобрить, потом прогнать критика.
feature
Видео-канва: клипы-ячейки, агенты раскадровки, кадры/аудио через композер
Стиль как у карусели/поста. Модель+длительность -> N ячеек-клипов (16с Veo = 2 куска, объединим при публикации), правка каждого куска отдельно, первый/последний кадр, аудио-дорожка, референсы, персонажи. Пайплайн: режиссёр раскадровки + арт-директор.
Стейдж, проверено: ячейки-куски по лимиту модели (Veo 8с -> 16с=2 части, Wan/Seedance 15с), пояснение про склейку, все 4 модели в селекторе, агент-режиссёр раскадровки, первый/последний кадр и аудио через плюсик, звук модели для Seedance, сцены сохраняются в video_scenes и используются генерацией. Осталось: платный тест сборки.
feature
Аватар-канва: персонажи (загрузить, сохранить, выбирать пресетом)
Канва как у поста + библиотека персонажей: загрузка лица, сохранение персонажа для будущих роликов, выбор внизу композера как пресет.
Канва /smm/create/avatar-canvas в стиле карусели и видео: ячейка речи, композер снизу, ползунок длины, 22 руб/сек. Персонажа можно загрузить через плюсик, сохранить в библиотеку (таблица smm_characters с RLS по владельцу) и выбирать пресетом внизу. Лицо, голос и длина из идеи перебивают настройки завода, раскадровка канвы уходит режиссёру аватара. Проверено на стейдже: загрузка лица, сохранение, выбор после перезагрузки, восстановление черновика.
feature
Пост: выбор формата картинки (1:1, 4:5, 9:16, 16:9)
Стейдж, проверено: 4:5/1:1/9:16/16:9, ячейка и промт подстраиваются, GPT Image получает корректный аспект.
feature
Контент без завода: скрытый рабочий завод компании
Раньше контент компании создавался с factory_id=null и сборка его не находила (inner join по заводу) - кейс был мёртвый. Теперь у компании есть один скрытый завод (is_company_default), поля тянутся из компании при каждом создании; кошелёк резолвится по company_id, скрытый завод не показывается там, где выбирают цель; собрать контент компании может любой с правом её редактировать.
feature
Слить 8 семейств + залить 203 варианта + 43 новых
feature
В РАБОТЕS3 · Леджер и платежи1/2

Цель: Единая таблица transactions, симметрия списаний

Инцидент ЮKassa (тестовый магазин) закрыт
боевой 1239397 + защита от повтора
feature
Леджер-починка: выкат на прод
стейдж a50546c готов
feature
планS4 · Качество видео — докрутка0/5

Цель: Динамика и подача роликов: промты, хук↔озвучка, мягкий бренд, банк структур

Динамика видео: докрутить промты (Veo/Kling), не модель
Ролики статичные — дело в промтах/подаче, а не в модели (подтвердить: прогнать 1 промт через 3-5 моделей и сравнить). Докрутить prompt-director: движение в кадре, смены планов, вау-моменты.
feature
Хук и озвучка — комплементарно (не разъединять)
avoidText сделал текст-хук и озвучку РАЗНЫМИ — критик ловит рассинхрон (текст на экране ≠ озвучка). Связать: хук цепляет, озвучка продолжает ту же мысль.
improvement
Смягчить вставку бренда (не в лоб)
Критик ставит товар 2/10: логотип+слоган сразу выдают рекламу и режут вирусность. Бренд вплетать вторым слоем, задача №1 — вирусность.
improvement
Банк вирусных структур: пачки до ~100 + активация is_active
Догенерить вирусные структуры пачками 2-5 до ~100, проверить, активировать is_active на проде (сейчас часть выключена).
feature
Пунктуация/паузы озвучки — добить если слабо
Промт planAudio теперь требует пунктуацию, но ИИ ставит её не всегда. Если на роликах паузы слабые — усилить правило/пост-обработку текста перед TTS.
improvement
ревьюS5 · СММ-Центр: Каркас + Дашборд + Бриф6/6

Цель: Отдельный раздел со своим layout, дашборд-домашняя с ИИ-рекомендациями, единый бриф компании

Каркас раздела СММ-Центр
Блок на главной + пункт в левом меню → отдельный layout: та же шапка + кнопка «назад», СВОЙ боковой сайдбар, свои блоки справа. Роутинг/навигация раздела.
Каркас /smm: своя шапка+сайдбар (9 разделов), на staging
feature
Дашборд-домашняя раздела
Общие метрики: подключено N сетей, суммарный охват/подписчики + дельты роста ↑↓, топ-посты, вовлечение, входящие без ответа. Health-score по сети/компании. Алерты (фейл публикации, негатив, отписки, токен истекает). Свитчер компаний (агентство).
Дашборд: реальные метрики (подключённые сети+видео из завода), company switcher
feature
ИИ-рекомендации на дашборде
«Мало рилсов — сделай N», «лучшее время постить», «VK проседает», «3 коммента ждут ответа», «подключи ещё сети». Реюз аналитики + factory_soul.
Контекстные ИИ-рекомендации на дашборде (нет сетей/мало видео/бриф/тайминг)
feature
Единый Бриф компании
Консолидировать разрозненные поля завода + factory_soul/insights в одну сущность: айдентика (лого/цвета/шрифт), tone of voice, можно/нельзя, ниша/рубрика, ЦА, ссылки. Кормит ИИ (тексты) и тренды (ниша).
Бриф: консолидация полей завода+soul, индикатор заполненности, подсветка пустых→ссылка правки
feature
🔴 Мультитенант: организация/компания + участники + роли (foundation прав)
Сейчас всё владеется user_id, команд/оргов НЕТ (только is_admin + manager_access_tokens для нашей поддержки). Ввести сущность организация/компания + membership (участники) + роли. Переключить владение (заводы/контент/подключения) на организацию. Архитектурная развилка — согласовать подход до кода.
Аддитивный слой: таблицы organizations/org_members + RLS (owner_user_id). Не трогает существующее user_id-владение
feature
Светлая/тёмная тема (механика) + миграция приложения
Люди, кому тяжело на тёмном → переключатель light/dark. Приложение сейчас тёмное намертво (фикс dark-* + общий тёмный Header). Механика заложена в СММ-Центре через CSS-переменные scoped (.smm-root+data-theme, localStorage-переключатель). Отдельно: миграция всего приложения на тему + тема общего Header.
Light/dark через CSS-переменные .smm-root, переключатель, localStorage; проверено обе темы
feature
ревьюS6 · СММ-Центр: Календарь + Публикации + Загрузка-как-есть7/7

Цель: Пульт: редакционный календарь, согласование, загрузка своего медиа, per-network времена/превью

Страница-Календарь (неделя/месяц) + drag-перенос
Поднять контент-план+планировщик из модалки в полноценную редакционную страницу-календарь. Кросс-компания.
Календарь: месячная сетка из content_items.scheduled_date, фильтр компаний, детали дня
feature
Рубрикатор
Постоянные рубрики-столпы («Кейс-понедельник» и т.п.), ИИ наполняет по расписанию.
Стейдж: smm_rubrics (6 системных + свои, RLS) + content_items.rubric_id + RPC smm_set_item_rubric. Селектор рубрики у поста + фильтр по рубрике + менеджер (создать/удалить свою). Проверено e2e скриншотом (назначил Аналитику, цвет применился) + БД (RPC/RLS).
feature
Согласование draft→review→approved + клиентский доступ
Флоу апрува: черновик → на проверку → одобрено → в план. Клиент (компания) заходит и апрувит ДО публикации — критично для агентств.
Стейдж: Согласовать/Вернуть/Опубликовать по правам (canApprove/canPublish) + RPC smm_set_item_status/can_approve_factory/can_publish_factory (SECURITY DEFINER). Клиентский доступ = 4 уровня (view/approve/edit/publish). Проверено на БД.
feature
Загрузка своего медиа → опубликовать как есть
Залил готовый пост/видео → опубликовать как есть по расписанию или быстро обработать, без обязательной ИИ-генерации. Медиатека (DAM) переиспользуемых ассетов.
Стейдж: кнопка «Загрузить своё» → /api/smm/upload-media (can_edit_factory) → готовый content_item (status=ready, media_url). Проверено e2e скриншотом (загрузил PNG → пост в очереди), почищено.
feature
Per-network: отдельные времена + превью + варианты текста
Своё время публикации под каждую сеть, превью «как выглядит» под сеть, варианты текста под сеть (VK длиннее, IG короче).
Стейдж, e2e проверено скриншотами+БД+шедулером: smm_network_posts (RLS can_edit_factory), редактор Расписание-по-сетям (время+текст+превью как в сети, матрица тип↔сеть), /api/smm/publish-network (одна сеть своим текстом, reuse postToSMM), шаг шедулера processDueNetworkPosts (публикует due каждый тик). Живой пост в сеть — по outbound-гейту.
feature
Поэлементный таргетинг сетей (Фазы 1/2a/2b)
Чипы сетей у каждого поста (очередь+календарь). Матрица тип<->сеть many-to-many (карусель=VK/TG/IG, клип=+YouTube/RuTube). Пресеты: 4 системных + свои + скрыть наш в своей учётке (smm_network_presets/smm_preset_dismissals, RLS). Bulk-применение к выделенным. Авто-политика по типу (factories.network_policy + BEFORE INSERT триггер, ловит Лию/планы/ручное). RPC smm_set_item_networks/smm_set_factory_policy (can_edit_factory). Колонка content_items.target_networks.
Стейдж test/sprint-3-quality. Проверено скриншотами (вошёл тест-юзером viral.critic.test) + БД (RPC/триггер/RLS). Модалки через портал в .smm-root.
feature
Реальная публикация: «Опубликовать» -> сеть + агентская авторизация
Кнопка публикует через существующий /api/content-item/[id]/publish. Авторизация can_publish_factory (владелец ИЛИ агентство с правом), атрибуция публикации владельцу фабрики (как планировщик), admin-клиент после явной проверки. Уважает per-item target_networks.
ДОКАЗАНО вживую 2026-07-20: реальный пост в Telegram-канал завода «Контент» (message 620, publication_logs success), ТОЛЬКО telegram — поэлементный таргетинг отфильтровал VK/IG/YT. Попутно 2 фикса прода: лимит подписи Telegram под медиа 1024 (было 4096), фолбэк sendPhoto скачать-и-загрузить-файлом при любой ошибке URL (RU-сторедж Telegram не достаёт).
feature
планS7 · СММ-Центр: Российский слой публикации0/4

Цель: Заменить/дополнить Upload-Post российским API: Rutube, VK органика рилсов, OK, Дзен

Ресёрч + выбор российского сервиса публикации с API
Upload-Post плохо под РФ. Найти тот сервис что находили ранее (адекватная цена): Rutube, нормальный VK (рилсы в органику), OK. Сравнить, выбрать.
feature
Интеграция российского сервиса публикации
Подключить как основной/доп канал рядом с Upload-Post/прямыми VK/TG. Кросс-пост через него.
feature
Фикс VK: рилсы в органику
Сейчас через прямой VK API рилсы НЕ идут в органику (минус охватов). Решить через новый сервис или иначе.
feature
Дзен: интеграция публикации
Придумать и сделать публикацию в Дзен.
feature
ревьюS8 · СММ-Центр: Входящие + автоответы6/6

Цель: Единый инбокс комменты+директ; 2 тира автоответов (канные дёшево / ИИ платно) + база знаний

Единый инбокс
Комменты + директ по сетям (VK/TG/IG/…) в одном окне, статусы (без ответа/отвечено/эскалация), фильтры.
Страница Входящих: настройки автоответов + канные + база знаний + фид (пустой до подключения площадок)
feature
Тир 1 — готовые/канные автоответы (дёшево)
Автоответ по ключевым словам/правилам, без ИИ. Дешёвая альтернатива.
Тир 1 канные ответы: CRUD (название/ключевые слова/текст/вкл-выкл), проверено end-to-end
feature
Тир 2 — ИИ-автоответы (платно отдельно)
ИИ читает контекст диалога и отвечает. Списание отдельно, дороже.
Тир 2 ИИ-ответы: тумблер + тон; генерация ответа подключится после API площадок
feature
Настройка ИИ-автоответов + база знаний
Загрузка базы знаний: прайс/сколько что стоит, о компании, как отвечать, что НЕЛЬЗЯ говорить, куда вести (ссылка) + примеры бесед (few-shot). Тон из брифа.
Настройки автоответов (тон/задержка 15м/подтверждение) + база знаний CRUD (прайс/о компании/правила/FAQ/примеры)
feature
Модерация/эскалация/лиды
Негатив → человеку; спам → скрыть; preview перед отправкой, задержка; мониторинг упоминаний бренда; захват лидов из директа → в продажи.
Стейдж, e2e скрин: лента→очередь модерации (вкладки Новые/Лиды/На-человеке/Все со счётчиками), у сообщения предложенный ответ (suggest-reply), пометить отвеченным, тумблер Лид, Человеку, Закрыть. Колонки is_lead/handled_at, правки через RLS can_edit_factory.
feature
Инбокс-ingestion VK/TG (прямые API)
Подтянуть комменты (VK wall.getComments) + директ (VK messages / Telegram Bot API) в smm_inbox_messages + отправка ответа обратно. Токены VK/TG уже есть. Движок автоответов готов (/api/smm/inbox/suggest-reply, DeepSeek). Upload-Post комменты/директ = в осн. Instagram (в РФ заблок) -> для RU только прямые API.
Стейдж, e2e на РЕАЛЬНЫХ данных (профиль MyVIsion): 108 Instagram-директ + комменты по всем постам из history (IG+YouTube), лид-детект (8 из 108). Гибрид: Upload-Post даёт директ (только IG) + комменты (IG/FB/YT/LinkedIn) — проверено по всем 8 площадкам. VK/TG прямыми API — след.шаг. Кнопка Синхронизировать.
feature
ревьюS9 · СММ-Центр: Аналитика + Тренды + Расходы4/4

Цель: Кросс-сетевая аналитика всех типов, white-label отчёты, тренды по нише, журнал расходов

Кросс-сетевая аналитика по всем типам
Не только рилсы: посты/сторис/входящие. По компании/сети/рубрике, рост/вовлечение/лучшее. Реюз analytics.
Аналитика: content_performance — просмотры/вовлечённость/топ/по площадкам, честный пустой стейт
feature
White-label PDF-отчёты клиенту
Для агентства — отчёт клиенту с брендингом. Экспорт, KPI-цели.
Стейдж, e2e скрин: кнопка Скачать отчёт на аналитике → брендированный отчёт (лого/имя/акцент агентства из org_branding, не Контент Завод) → печать браузером в PDF. SmmReport портал .smm-print-root, KPI+площадки+топ-посты+период. Печатные стили в globals.css.
feature
Тренды по нише из брифа + кросс-сетевые конкуренты
Привязать нишу брифа к трендам (сейчас статичный дропдаун); конкуренты расширить с YouTube на все сети.
Стейдж, e2e скрин: /smm/trends на официальном YouTube Data API (бесплатно, без Apify). Ниша из брифа компании (дефолт product_name) + поиск, топ коротких видео за 30 дней по просмотрам, превью/канал/лайки/комменты/ссылка. Реальные данные (нейросети для бизнеса → 9325 просмотров топ). Apify (TikTok/IG) — опция на будущее.
feature
Журнал расходов по компаниям/действиям
Реюз transactions/recordSpend: раскидать расходы по клиентам (для агентства).
Расходы: transactions — баланс/за месяц/всего/пополнено, по категориям, история
feature
ревьюS10 · СММ-Центр: ИИ-копайлот + Команда4/4

Цель: Лия-для-СММ, роли/команда, мульти-компания, авто-правила

Лия-для-СММ
Чат: собери план под сеть, напиши посты по брифу, драфт ответов на входящие, дай инсайты. Реюз Лии+tools.
Стейдж, e2e скрин: плавающий ИИ-помощник на всех страницах СММ-Центра. Дала реальный контент-план по запросу, с контекстом из брифа компании (продукт Тестовый товар). Дешёвая модель deepseek-chat-v3 через OpenRouter (как автоответы), контекст=бриф, история диалога, быстрые подсказки. Портал в .smm-root.
feature
Роли/команда + мульти-компания
Роли (сммщик/клиент-апрувер/админ), свитчер 10 компаний, права.
Роли/команда: организация (компания/агентство), владелец=суперадмин, приглашение email+роль, смена/удаление, проверено
feature
Авто-правила
Коммент содержит X → ответ Y/эскалация; авто-наполнение рубрик; авто-реюз топ-постов.
Стейдж, e2e (БД+скрин): секция Автоматизация в инбоксе — авто-сбор входящих (шаг шедулера processAutoInboxSync, троттл 30мин; проверено: 0→109 сообщений авто) + авто-пометка лидов (sync уважает флаг). Флаги на smm_autoreply_config.
feature
Раздача прав и настройки (RBAC-раздел)
Раздел управления доступом. Суперадмин = первый зарегавшийся (или назначенный) настраивает. Роли: суперадмин, СММщик, руководитель маркетинга, директор по маркетингу, отдел продаж, клиент-viewer/approver. Сценарии: агентство (1 СММщик, 10 клиентов) даёт доступ/показывает клиенту; клиент со своей командой (разные права). Приглашения, роли на организацию/компанию.
RBAC-раздел Права и настройки: команда + матрица ролей/доступов (владелец/директор/руководитель/СММ/продажи)
feature
ревьюS11 · СММ-Центр: Бренд-ассеты и шаблоны3/3

Цель: Шаблоны постов (reference-driven) + интро/аутро видео (bumpers)

Шаблоны постов (reference-driven, GPT Image)
Клиент грузит примеры своих постов (аналитика/новости). При создании выбирает шаблон + данные -> ИИ делает похожий пост, меняя текст/цифры (2 режима: только текст / элементы+текст). Движок reference-driven уже есть (gpt-image-2 image-to-image, LeadForge creative-engine / КЗ карусель). Кнопка «создать шаблон через GPT Image (Kie)» -> сохранить/переделать. Хранить: таблица шаблонов (per factory/org + системные, как пресеты). 15р/генерация = money-гейт (списание с баланса клиента через ledger).
Банк шаблонов (загрузка своих + галерея, RLS per-user) + генерация gpt-image-2: t2i «Сгенерировать шаблон» (проверено, рус.текст читается, ~2.85 руб/1K) + i2i «применить к посту» (эндпоинт + кнопка в Создать). Осталось: биллинг списания.
feature
Интро/аутро видео (bumpers, FFmpeg)
Клиент грузит начало (лого) и конец (лого+подписаться) = бренд-ассеты завода (intro_url/outro_url). Флаги use_intro/use_outro у видео-элемента. При рендере FFmpeg: нормализовать res/fps/codec у intro+main+outro -> concat.
Стейдж: бренд-ассеты завода intro_url/outro_url (менеджер Заставки, загрузка /api/smm/bumpers), флаги use_intro/use_outro у видео (тумблеры в очереди, RPC smm_set_item_bumpers проверен owner/stranger), при публикации видео FFmpeg-склейка intro+main+outro (reuse concatenateVideos, кэш bumped_media_url). Полный рендер-тест — по outbound-гейту с реальными заставками.
feature
Биллинг генерации картинок (списание баланса)
gpt-image-2 тратит наши деньги Kie (1K~2.85/2K~4.75/4K~7.6 руб), но не списывает с баланса клиента. Обязательно закрыть до выката шаблонов на прод: списание + запись в леджер transactions.
Списание с баланса за gpt-image-2 (deductBalance→генерация→refund при сбое), i2i-картинку поста платит владелец агентства (resolveBillingUser). Проверено вживую: −15₽, запись в леджер. Цена 1K=15/2K=25/4K=40 руб, показана на кнопках.
feature
ревьюS12 · Обучение, онбординг и связь с клиентом26/30

Цель: Инструкции со скриншотами по СММ-Центру, Заводу и Студии; онбординг первого входа; регистрация с почтой и телефоном, письма и второй канал связи

Инструкции со скриншотами: СММ-Центр
Как создать карусель, пост, видео, аватар; как опубликовать и запланировать; где история и скачивание. Скриншоты снимаются браузером автоматически, нужные места подсвечиваются. Без внутренней кухни: ни агентов, ни моделей, ни промптов.
13 гайдов с экранами: шесть форматов (карусель, пост, видео, ИИ-аватар, Ролс, публикации) и семь разделов Центра (дашборд с календарём, тренды, входящие, аналитика, бриф, настройки компании, расходы и права). Переключение вкладками, липкая строка сверху, клик по экрану открывает крупно, блок частых вопросов. Подсветка целится в поле по содержимому, а не в первый список подряд.
feature
Инструкции со скриншотами: Контент Завод
Экраны кабинета уже сняты (public/docs/factory). Осталось написать шаги: создать завод, бриф, соцсети, расписание, расходы.
Раздел /docs/factory: два руководства (первый завод, как работает дальше), 4 экрана с подсветкой, частые вопросы. Старое текстовое полотно /docs заменено хабом на три инструкции.
feature
Инструкции со скриншотами: Студия
Экран Студии снят (public/docs/studio). Осталось написать шаги: разовая картинка и ролик, выбор модели и качества, цены.
Раздел /docs/studio: обзор, картинка, видео, библиотека — 4 экрана, вкладки, частые вопросы.
feature
Онбординг СММ-Центра
Первый вход: короткий тур, подсказка что делать первым, пустой кабинет ведёт за руку. Свои ветки для владельца агентства, сотрудника и клиента.
Четыре экрана знакомства при первом заходе (отметка в профиле, не в браузере) + чеклист первых шагов, который сам отмечается по факту: бриф, соцсеть, первый контент, публикация. Повторный показ — ссылкой «Как здесь всё устроено».
feature
Регистрация: почта и телефон с подтверждением
Брать два контакта, подтверждать почту письмом, валидировать телефон.
Телефон обязателен, нормализуется к +7XXXXXXXXXX, долетает в профиль через триггер. Кривой номер отсекается на форме. Подтверждение почты остаётся за GoTrue — включится вместе с боевым SMTP.
feature
Письма: приветствие, подтверждение, сброс пароля
Шаблоны и отправка, проверка доставляемости.
Почта поднята на Timeweb без сторонних сервисов: smtp.timeweb.ru:465, ящик no-reply@24contentzavod.ru. SMTP прописан и в приложении (наши письма), и в Supabase Auth (системные). Тестовое письмо доставлено, сброс пароля отработал без ошибок SMTP. SPF и DKIM у домена уже были. Осталось по решению заказчика включить подтверждение почты (ENABLE_EMAIL_AUTOCONFIRM=false).
feature
Второй канал связи: Telegram-бот или MAX
Сейчас с клиентом можно связаться только почтой, и это дыра. Привязка аккаунта к боту, уведомления и обратная связь.
Сделано в обе стороны и в обоих мессенджерах. Телеграм: вебхук отвечает за 50-120 мс вместо секунд (держали соединение — Телеграм не дожидался и слал повторы, отсюда была задержка). Ответ реплаем не работал вообще: ветку искали поиском по образцу прямо по uuid, база такое не выполняет — завели короткий код отдельным полем. Служебный чат больше не заводит переписку сам с собой. MAX: подписки на события не было вообще, подписали, приём вопросов проверен боевым запросом. Раздел «Поддержка» в админке: вся переписка целиком, ответ доходит и до тех, кто писал из чата на сайте.
feature
Счета по безналу: уведомления и раздел в админке
Оплата счёта проходила молча: деньги ушли, тариф включился, а человек об этом не узнавал ниоткуда — и мы тоже.
Письмо клиенту на выставление (со сроками: банк переводит не мгновенно) и на зачисление, обоим событиям — строчка нам в Телеграм. Раздел «Счета» в админке: кто запросил, плательщик с ИНН, за что, оплачен или ждёт, PDF. Счёт, висящий пятый день, подсвечивается.
feature
Публикация в MAX через бота
MAX как площадка публикации наравне с ВК и Телеграмом.
MAX не принимает картинку ссылкой — три шага: адрес загрузки, файл, сообщение с ключом. Формат сверен живым запросом к их API. Видео обрабатывается не мгновенно, отправку повторяем. Галочка в целях, поле канала в настройках компании, публикация из всех четырёх мест. ВЖИВУЮ НЕ ПРОВЕРЕНО: у бота пока нет ни одного канала.
feature
Картинки не пропадают при перезапуске сервера
Отрисовка идёт обычным запросом: браузер ждёт, сервер рисует. Перезапуск сервера (обновление) убивал запрос, а картинка у Kie дорисовывалась — деньги списаны, забрать некому. Так потерялись три оплаченных слайда. Для прода это значило: ночное обновление рушит работу любого клиента.
Номер задачи записываем сразу, до ожидания (таблица image_jobs). Фоновая задача раз в 2 минуты добирает повисшее в наше хранилище, канвас показывает плашку «нашлись картинки» и ставит их по номеру слайда или совпадению текста. Не влезло — заводим новую ячейку, оплаченное не выбрасываем. Три потерянных слайда достал вручную и вернул в очередь. Работает и при закрытой вкладке.
bug
Приложенный референс: правка картинки вместо рисования с нуля
На просьбу «замени на этом плакате надпись» рисовался новый плакат: любая приложенная картинка считалась образцом стиля, и модели прямо говорилось «повтори настроение, но НЕ копируй сюжет».
Роль приложенной картинки определяется по формулировке задачи: править её / это товар / это настроение. Однозначные слова («вместо», «замени», «убери») решают без ИИ, спорное разбирает Gemini, при сбое откат к прежнему поведению. ВЖИВУЮ НЕ ПРОВЕРЕНО (нужен платный прогон ~15 руб).
bug
Карусель: слайд знает концепцию всей серии
Обложка «6 новостей про ИИ» выдумала шесть заголовков вместо настоящих: каждый слайд рисовался в одиночку и видел только свой текст.
Каждому слайду передаётся список заголовков всей серии по порядку с прямым запретом сочинять свои; обложке отдельно — брать формулировки дословно. ВЖИВУЮ НЕ ПРОВЕРЕНО.
bug
Несколько черновиков в одном холсте
Холст помнит один черновик на тип контента: начал новый пост — предыдущий затёрся. Чтобы вести три поста одновременно, нужны вкладки или список черновиков. Вариант на памяти браузера — день работы, но черновики не переедут на другой компьютер. Вариант с таблицей и синхронизацией — два-три дня. Решили делать позже, после выкатки. Док: docs/parallel-work.md
feature
Несколько вариантов картинки по одной задаче
Одна задача — несколько попыток, чтобы выбрать лучшую. Не путать с параллельными задачами: там разные задачи, тут одна и несколько картинок. Выбор количества рядом с ценой, цена умножается и видна до запуска; варианты полоской под картинкой, переключаются кликом. Удобство, а не поломка — после выкатки. Док: docs/parallel-work.md
feature
Очередь отрисовки: работа не рвётся при уходе со страницы
Браузер сам перебирал слайды: ушёл на другую страницу — остаток серии не запускался, оплаченные результаты оставались ничьими. Для агентства это ежедневная потеря контента.
Задача ставится в очередь, доводит её сервер. Логику отрисовки не дублировали — работник зовёт тот же роут изнутри. Один упавший слайд не хоронит серию. Перезапуск сервера подбирается раз в 5 минут, уже нарисованное не оплачивается повторно. Панель «В работе» видна с любой страницы СММ-Центра.
bug
Списание не проходило через очередь
Деньги списывались клиентом с правами сессии, а у работника очереди сессии нет — база блокировала операцию. Человек видел «не удалось списать баланс» и не мог сделать ничего.
Списание, возврат и запись расхода переведены на тот же клиент, что и леджер. ВЖИВУЮ НЕ ПРОВЕРЕНО — нужен платный прогон ~17 руб.
bug
Публикация врала про успех в Инстаграм
Ответ Upload-Post разбирался только по коду HTTP: пришло 200 — успех всем площадкам. На деле у каждой свой итог внутри ответа. Карусель ушла в Телеграм, в Инстаграм не ушла, в журнале обе помечены успехом, у Инстаграма стоял идентификатор телеграмного поста. Хуже ошибки: человек уверен, что пост вышел, и не проверяет.
Опубликованной считается только подтверждённая площадка. Про остальные пишем, что не вышло и почему. Подхватываем настоящие ссылки на посты — раньше терялись.
bug
Цены: слайд карусели 7 руб, пост 10 руб
Карусель и пост стоили одинаково, потому что их рисует один код. Это разные покупки: карусель берут пачкой, пост поштучно.
Цена зависит от вида контента, канвас говорит его прямо (по числу картинок судить нельзя — карусель бывает из одного слайда). Одна таблица lib/billing/image-prices.ts: и списание, и подписи в интерфейсе. 2K/4K/Nano пересчитаны в тех же пропорциях, себестоимость Kie 2.85/4.75/7.6 — запас сохранён.
feature
Рабочее окно просмотра готовой работы
Одна колонка: картинка, лента миниатюр, текст, площадки — всё прокручивалось вместе, тёмный слайд сливался с тёмным фоном, листать было нечем.
Два блока: слева работа на своей подложке с листанием (стрелки, клавиши, точки), справа площадки со ссылками на живые посты, дата, текст (единственное прокручиваемое) и действия. Новое: доотправить в сети, где работы ещё не было (без повторной оплаты, с защитой от дубля), и «Сделать на основе» — холст открывается с картинками этой работы как образцом стиля. Окно уезжало за край экрана — рисуем в body.
feature
Ручной режим: промт уходит слово в слово
Усиление промта иногда мешает, и нужен способ его отключить, а не бороться формулировками.
Кнопка «С ИИ / Ручной» во всех четырёх канвасах, выбор запоминается. В ручном одиночная картинка вообще не ходит к разбору — промт становится задачей как есть; карусель зовёт разбор только при явной разметке слайдов; отрисовка ничего не дописывает. Заодно нашли: отрисовка не запускалась, если у ячейки нет текста для нанесения — в ручном его может не быть вовсе.
feature
Вечная загрузка после сбоя запроса
«Мои работы» и весь контекст СММ-Центра вешались навсегда, если один запрос не дошёл: обработки сбоя не было, выйти можно было только перезагрузкой.
Загрузка выключается в любом случае, человек видит причину и кнопку повторить.
bug
Подсказка у значка субтитров не появляется
Сжал подпись «с субтитрами» до значка, а подсказка при наведении не показывается — значок без объяснения непонятен. ПРИЧИНА НАЙДЕНА, ОБЩАЯ ДЛЯ ОБОИХ. Чтобы лента настроек не переносилась на второй этаж, я задал ей overflow-x: auto (класс smm-noscroll). Контейнер с прокруткой обрезает всё, что вылезает за его границы, — и подсказку над кнопкой, и выпадающий список истории. Формально они рисуются, но их не видно. ЧТО ДЕЛАТЬ: убрать обрезку — рисовать подсказку и список через портал в body с позицией по координатам кнопки (как уже сделано у модалок просмотра), либо отказаться от overflow на ленте и держать её в одну строку другим способом. Правка небольшая, но трогает Hint.tsx и TaskHistoryButton.tsx.
Причина была общая: прокрутка на ленте настроек обрезала всё, что вылезает за её границы. Прокрутку убрали, строка держится в одну линию за счёт сжатия субтитров и истории до значков. Проверено в браузере: подсказка показывается, список открывается.
bug
Список «что я писал» не открывается
Клик по значку истории задач не открывает список: он пытается вылезти и остаётся за кнопкой. ПРИЧИНА НАЙДЕНА, ОБЩАЯ ДЛЯ ОБОИХ. Чтобы лента настроек не переносилась на второй этаж, я задал ей overflow-x: auto (класс smm-noscroll). Контейнер с прокруткой обрезает всё, что вылезает за его границы, — и подсказку над кнопкой, и выпадающий список истории. Формально они рисуются, но их не видно. ЧТО ДЕЛАТЬ: убрать обрезку — рисовать подсказку и список через портал в body с позицией по координатам кнопки (как уже сделано у модалок просмотра), либо отказаться от overflow на ленте и держать её в одну строку другим способом. Правка небольшая, но трогает Hint.tsx и TaskHistoryButton.tsx.
Причина была общая: прокрутка на ленте настроек обрезала всё, что вылезает за её границы. Прокрутку убрали, строка держится в одну линию за счёт сжатия субтитров и истории до значков. Проверено в браузере: подсказка показывается, список открывается.
bug
Анимация ожидания дёргается на стыке цикла
Пока картинка рисуется, по кружку идёт волна заполнения. Дойдя до края, она обрывается и начинается заново — рывок хорошо виден и режет глаз. ГДЕ СМОТРЕТЬ: GENERATING_KEYFRAMES в канвасах (карусель, пост, видео, аватар, Ролс). ЧТО НЕ ТАК: у анимации нет бесшовного перехода — конец кадра не совпадает с началом. Нужен либо цикл, где последний кадр равен первому, либо непрерывное движение по кругу вместо заполнения из края в край. Заодно проверить, что при нескольких ячейках волны не идут вразнобой.
Сдвиг волны был в процентах от размера фигуры, а фигура шире одной волны — на стыке цикла прыжок. Сдвигаем ровно на длину волны.
bug
Анимация ожидания пропадает после перехода в другой раздел
Запустил пост, перешёл в карусель и вернулся — анимация в ячейке исчезла, хотя картинка ещё рисуется. Человек думает, что всё сорвалось. ПОЧЕМУ: пометка «рисуется» живёт в состоянии страницы (rendering/queued) и при уходе с холста теряется. Сама работа при этом идёт: она в очереди на сервере. ЧТО ДЕЛАТЬ: восстанавливать пометку из задачи очереди при возврате — hook useRenderQueue уже подключается к своей задаче по номеру из памяти браузера, осталось по её слотам заново пометить ячейки рисующимися, пока статус queued или running.
Пометка «рисуется» жила в состоянии страницы и терялась при уходе. Теперь при возврате восстанавливаем её из задачи очереди по слотам.
bug
В холсте нет кнопки скачать готовую картинку
Картинка готова прямо в холсте, а забрать её себе нельзя: под ячейкой есть перерисовать, текст, посмотреть, фото товара и меню, скачивания нет. Приходится идти в Публикации или тянуть правой кнопкой из браузера. ГДЕ: строка действий под ячейкой в канвасах поста и карусели (там же, где значок глаза и перерисовки). Скачивание уже написано в окне просмотра готовой работы (PublishedViewer, downloadAll) — можно взять оттуда, файлы забираются по одному с паузой, иначе браузер режет пачку.
Кнопка встала в строку действий под ячейкой в канвасах поста и карусели.
feature
Черновик сбрасывается при переходе между холстами
Отправил задачу в холсте аватара, переключился на видео и вернулся — отправка сброшена, черновик как был. Уходя со страницы, компонент размонтируется, и ответ агента приходить некуда. ПОЧЕМУ: черновик лежит в памяти браузера по ключу на каждый холст, но незавершённая отправка в нём не сохраняется. ЧТО ДЕЛАТЬ: это частный случай задачи «Несколько черновиков в одном холсте» — решать вместе с ней, отдельно чинить смысла нет. Минимальный шаг: держать признак «отправка идёт» в том же черновике и при возврате дожидаться ответа, как это сделано для очереди отрисовки в посте и карусели.
Запрос к агенту браузер не отменяет — терялся только результат, потому что компонент размонтирован. Теперь раскладка сразу пишется в черновик, а он читается при возврате. Сделано в холстах аватара и видео.
bug
Пул ключей Kie + ограничитель скорости
ОТЛОЖЕНО по решению заказчика: делаем, когда будут хотя бы десятки активных пользователей. Сейчас одного ключа хватает. СМЫСЛ: несколько учёток Kie, задачи распределяются между ними, свой ограничитель скорости перед провайдером — иначе при массовой генерации получим отказы пачками. ГДЕ: src/lib/kie-ai/client.ts и studio/kie-ai-studio.ts берут ключ из одной переменной KIE_AI_API_KEY. Нужен выбор ключа с учётом остатка и текущей нагрузки.
feature
Проверить ИИ-аватар живым прогоном после защит
Выкачено, но НЕ проверено на живой генерации — заказчик остановил после серии двойных списаний. Что проверять за один прогон: реплики из сценария звучат все (не только первая), кадр перерисовывается через GPT Image по английскому промту, повтор из очереди не создаёт вторую генерацию, списание сверяется с фактической длиной. ВАЖНО: сценарий заказчика ~480 знаков это ~40 секунд речи, при заказе 15 секунд спишется разница (~550 руб вместо 330) — предупредить до запуска.
task
OmniHuman отказывает: Volcengine CV API error
В логах три попытки подряд: «OmniHuman сегмент 1 task attempt 1/2/3 failed: Call Volcengine CV API error, action=CVSubmitTask». К повторам очереди отношения не имеет — это отказ на стороне провайдера. Проверить: доступность URL картинки и аудио снаружи, формат и размер кадра, остаток на счёте Kie, лимиты OmniHuman.
Причина найдена прогоном: отбивался не провайдер, а наш файл. gpt-image отдаёт PNG весом около двух мегабайт со стороной больше 1000 — такой кадр оживление не принимает ни как .jpg, ни как .png. Тот же кадр в JPEG 720x960 проходит, как и внешняя картинка. Кадр теперь пережимается перед отправкой (lib/storage/put-image.ts).
bug
В РАБОТЕS13 · Пайплайны: разбор, сценарии, починка26/38

Цель: Э0-Э3 плана docs/FIX-ROADMAP.md: мерки, ремонт контракта холст-сервер, деньги под контролем, Задание (TaskSpec) вместо догадок

А. Пайплайны выгружены и описаны
docs/PIPELINES.md переписан полностью: контракт полей холст→сервер, карта всех 15 вызовов моделей, карта всех списаний, отдельный раздел «где данные теряются» и реестр из 24 дефектов (Д1..Д24).
Второй, углублённый заход: 495 строк, каждое утверждение с файлом и строкой. Найдено 12 мест, где данные человека молча выбрасываются.
task
Б. Матрица сценариев постановки задачи
docs/SCENARIOS.md: 115 сценариев (аватар 27, пост 24, карусель 22, видео 22, Ролс 20). Каждый со ссылкой на дефект из реестра.
Было 63, стало 115. Добавлены сценарии с ролями вложений, противоречиями между выбором и текстом, невозможными просьбами.
task
В. Отчёт: где результата не будет
docs/PIPELINES-REPORT.md: 41 из 115 не дадут результата, 33 дадут половину. Девять дефектов ранжированы по ущербу, три системные причины, что уже хорошо и ломать нельзя.
Отчёт переписан под новую матрицу. Добавлен раздел «почему напрямую в Kie работает, а у нас нет»: между человеком и моделью стоят от двух до шести переписывающих агентов.
task
🔴 Г1. Разбор намерения: один вход вместо россыпи догадок
Один вызов модели на входе холста → Задание (TaskSpec): intent, verbatim (что дословно), invent (что можно придумать), attachments с ролями, constraints, missing, impossible, summary_for_human. Контракт в docs/PIPELINES-FIX-PLAN.md. Убирает decideRefRole и decideScene как отдельные догадки. Дефекты Д1, Д12.
Приёмщик lib/task: схема Задания, пять профилей, structured output, температура 0. 108 из 110 постановок разбираются верно. Задание доведено до генератора: пост и карусель рисуют по нему напрямую, аватар и видео получают его в карточке.
feature
🔴 Г2. Роли у приложенных картинок
Роли: base_to_edit, product, person, location, style_ref, logo, frame_first, frame_last, audio_voice, audio_music. Роль предлагает разбор, человек правит одним нажатием. В промте картинки подписаны ролью, а не «Image 1». Дефекты Д2, Д3.
Роли задаются в холсте (лицо, место, товар, озвучка) и определяются зрением, когда человек их не задал. Выбор человека всегда сильнее.
feature
Г3. Проверка достаточности до списания
Правила кодом (нет лица, нет голоса, нет фото, длина вне сетки, сценарий длиннее заказа) + зрение там, где нужно (видно ли лицо, один ли человек, не обрезан ли товар). Плюс экран «понял так: …, N ₽» с подтверждением: сейчас у аватара одна кнопка делает всё сразу (avatar-canvas/page.tsx:313). Дефекты Д4, Д19.
Окно «понял так» со сметой во всех пяти холстах; без лица и без фото кнопка запуска заблокирована. Проверено: аватар без лица даёт no_face и no_voice.
feature
Г4. Заказ побеждает догадку: длина, тайминги, порядок
constraints из Задания жёсткие: длина, тайминги, порядок кадров, число слайдов, обязательные строки (цена, телефон). Что не влезает — отказ с объяснением ДО денег, а не молчаливое обрезание (сейчас молча режутся 15 слайдов до 10 и 6 кадров Ролса до 4). Дефекты Д5, Д14.
feature
Г5. Готовый промт не переписывается даже в режиме «С ИИ»
Готовый режиссёрский промт и готовая речь уходят в verbatim и вставляются кодом дословно: ни стиля серии, ни служебных хвостов. Приёмка: один и тот же промт напрямую в Kie и через холст в режиме «С ИИ» дают сопоставимый результат. Дефекты Д1, Д7.
Задание с verbatim уходит в отрисовку без агента. Приписки из промтов вычищены: тот же промт, что давал рекламный плакат, теперь даёт заказанное фото.
feature
Г6. Память задач: «сделай как в прошлый раз»
Хранить последнее Задание по компании и формату, подставлять по просьбе «как в прошлый раз». Пересекается со «Скиллами» — делать вместе. Дефект Д16.
feature
🔴 Г7. Вложения аватара доходят до генератора
create-content/route.ts:183-186 принимает referenceImages/Videos/Audios только для Wan и Seedance → у avatar_video они превращаются в null. Первый/последний кадр сохраняются, но пайплайн аватара их не читает. Фото локации и товара из чата ролями не становятся, своя озвучка игнорируется (всё равно TTS). Дефект Д8.
Приняли referenceImages/Audios для avatar_video и Veo; роли вложений в новой колонке attachment_roles; фото места и товара из чата доходят до кадра, своя озвучка заменяет синтез. Проверено контрактом на карточке a5c3af8c (без генерации).
fix
🔴 Г8. Видео на Veo использует раскадровку холста
video_scenes читаются только в премиум-ветке (Wan/Seedance). На Veo — модели по умолчанию — сценарий пишется заново от item.idea, а холст обрезает idea до 300 знаков (video-canvas/page.tsx:286). То есть согласованная человеком раскадровка до генератора не доходит. Дефект Д9.
video-build-multi-clip берёт сцены холста как промты клипов и как сценарий; idea в холсте больше не режется до 300 знаков (2000).
fix
Г9. Честная сетка длин аватара
numSegments максимум 3 по 15 секунд речи, поэтому заказ 16-29 и 46-60 секунд структурно невыполним: 25 с даёт 15 с, 60 с даёт 45 с (дальше возврат разницы). Ползунок при этом предлагает 5-60. Либо снять предел в три сегмента, либо ограничить ползунок реальными значениями. Дефект Д6.
Снят потолок в три сегмента (60с давали 45). Отдельно найдено и починено: заказ длины сохранялся только для 8/15/30, всё остальное превращалось в null ещё до генерации. Живьём не прогонялось — за владельцем.
fix
Г10. Авто-Ролс слышит задачу человека
lib/rols/jobs.ts:80 зовёт runDirector(product, factory, template) без brief: текст задачи попадает только в idea и script карточки, на кадры не влияет. Дефект Д13.
runDirector получил бриф, в промте он выше шаблона. Живой прогон: задача «скидка 30% до воскресенья» попала в бейдж, в подписи и в озвучку (job d40f4027).
fix
Г11. Карусель снова чейнится от обложки
Очередь рисует слайды по одному с onlyIndex и берёт обложку из payload.coverRefUrl, который фронт заполняет из УЖЕ отрисованной обложки (carousel-chat/page.tsx:455). На первом прогоне обложки нет → слайды 2..N рисуются без неё, единство серии держится только текстом seriesStyle. Дефект Д11.
Работник очереди рисует обложку первой и подставляет её результат остальным слайдам. Живой прогон: серия из 4 слайдов в единой манере (job 3bb9bed6), плюс 3 слайда на Nano (job f2e7413e).
fix
Г12. До шестнадцати картинок вместо четырёх
carousel/render/route.ts:444,476,495 режет референсы до 4, хотя gpt-image-2 принимает 16 (kie-ai/client.ts:561), nano-banana-2-lite — 10, а холст даёт приложить 16. Пятая и дальше выбрасываются молча. Дефект Д3.
Лимит по движку: GPT Image 16, Nano 10, дубли отсеиваются, лишнее пишется в лог. Живой прогон: коллаж из 5 приложенных картинок собрался со всеми пятью.
fix
Г13. Сверка результата с заказом
Сейчас единственная проверка результата — длина ролика аватара. Добавить: обязательные строки на картинке (цена, телефон), тот ли товар, читается ли текст. Не сошлось — пересборка за наш счёт или честный возврат. Дефект Д15.
feature
Г14. Режиссёр аватара через OpenRouter, не напрямую в OpenAI
lib/openai/avatar-director.ts ходит в OpenAI прямым ключом (gpt-4o-mini). Правило проекта: текст через OpenRouter, картинки и видео через Kie. Заодно поднять модель: речь ролика — не механическая задача. Дефект Д22.
avatar-director переведён на openrouterCompletion (deepseek-chat-v3). Прямых вызовов OpenAI в пути аватара не осталось.
fix
Г15. Честные отказы на невозможное
Снять водяной знак, два голоса в одном ролике, шесть кадров Ролса, две пропорции сразу, ссылка на чужой ролик как образец — говорить «нет» до списания, а не пробовать. Дефект Д24.
feature
Б2. Матрица сценариев по ролям (6 ролей x 5 форматов)
docs/SCENARIOS-ROLES.md: предприниматель без опыта в ИИ, предприниматель со знанием базы, маркетолог, СММщик компании, СММщик агентства, креатор. По 12 сценариев на каждый формат = 360. Итог: 136 работают, 125 наполовину, 99 не дадут результата. Вместе с матрицей по форматам — 475 разобранных способов поставить задачу, из них 140 провальных. Найдены дефекты Д25..Д36 (продуктовые пробелы).
Проверено по коду, какие функции реально есть (derive, video-edit, композер, шаблоны, пресеты, труппа, бумперы, сторис), чтобы оценки не были выдумкой.
research
Э0. Регресс-набор 40 сценариев
Отобрать по 8 сценариев на формат из 475 разобранных: те, что ломаются у трёх ролей и больше, плюс те, что уже работают (ловить регресс). Прогон руками после каждого этапа, запись в docs/REGRESSION-SET.md. Черновик набора — в docs/FIX-ROADMAP.md, раздел 6.
chore
Э0. Живой прогон аватара
Часть выводов по аватару сделана из кода, а не из наблюдения: длина, голос по умолчанию, решение по кадру, клип товара. Прогон 15 секунд = 330 ₽, нужно разрешение владельца. Висит с 12 спринта.
chore
Э0. Базовые метрики из БД
Снять по transactions за 30 дней: доля возвратов, доля повторных запусков того же задания в течение 30 минут, средний чек ошибки. Без этого нечем доказать, что стало лучше. Цели — в docs/FIX-ROADMAP.md, раздел 7.
chore
(служебная, игнорировать)
Осталась от синхронизации дашборда 02.08, удалить нечем: API не поддерживает DELETE задач.
feature
🔴 Цена «всё включено»: никаких доплат по ходу
Решение владельца 02.08: объявленная до старта цена не растёт. Убраны отдельные списания у аватара (ведущий 5 ₽, перерисовка кадра 10 ₽ в двух местах) и доплата за перебор длины — теперь это наш перерасход. Возврат остаётся только в пользу человека (вышло короче заказа). Себестоимость OmniHuman 0.135 $/с против цены 22 ₽/с, внутренние шаги помещаются в маржу. Осталось распространить правило на Ролс (дорисованные кадры, субтитры) и на видео.
Аватар — сделано. Ролс и видео — впереди.
fix
🔴 Г1а. Приёмщик задач: ядро и пять профилей
lib/task: схема Задания + разбор одним вызовом (Gemini 2.5 Flash, температура 0), профили на формат, эндпоинт /api/smm/task/parse. Раскладывает кадр, действие, речь, надписи, роли вложений; числа и лимиты считает код. Прогон: 108 из 110 постановок задачи (docs/PARSER-RUN.md, набор в scripts/parser-cases.py). Осталось: зрение для ролей картинок, названных списком.
Работает на стенде, генераций не трогает. Было 91/110 на первом прогоне, стало 108/110 после переноса количества, цен, ролей аудио и отличия темы от речи в код.
feature
🔴 Г1б. Подключить приёмщика к холстам + окно «понял так»
Холсты зовут /api/smm/task/parse перед постановкой задачи, показывают разбор и смету, списание только после подтверждения. Порядок включения: пост, карусель, Ролс, видео, аватар.
Все пять холстов зовут разбор перед работой, показывают «понял так» и смету; списание только после подтверждения. Смета считается кодом по тем же таблицам, что и касса.
feature
Г1в. Зрение для ролей картинок
Когда человек называет вложения списком («локация, человек, товар»), порядок файлов может не совпасть с порядком слов. Нужен дешёвый vision-проход: что на картинке. Единственный кейс из 110, где разбор ошибается.
Роли определяются взглядом на картинку, выбор идёт из ролей, которые человек назвал словами. Проверено: гостиная → локация, монтажник → человек, диван → товар.
feature
Г5а. Вычистить наши приписки из промтов генератора
«top-tier ad-agency creative», стиль серии поверх готового промта и прочие хвосты перебивают инструкцию человека: доказано прогоном (фото кружки превратилось в рекламный плакат). Убрать всё, что человек не просил.
Убран хвост «top-tier ad-agency creative»; текст на картинке требуется только когда его просили, иначе надписи прямо запрещены. Пруф: тот же промт, что давал рекламный плакат, теперь даёт заказанное фото кружки.
fix
Г13а. Слой качества: отбраковка кадра и сверка результата
lib/task/frame-check.ts — кадр в двух вариантах + чеклист зрением перед дорогим шагом (аватар: 3 руб против 200; видео: 3 против 60-100). lib/task/verify.ts — сверка готовой картинки с заданием: цена, телефон, товар, лишние надписи. Служебный /api/smm/task/check для отладки без генераций. Описание: docs/QUALITY-LAYER.md
Проверено на готовых картинках: подменённые цену и телефон находит, человека спиной для липсинка бракует 0/10, фото кружки принимает 9/10. Автоперерисовку пока не включаем.
feature
Качество ролика аватара: вертикаль, звук места, дыхание, стык
Кадр рисуется 9:16 (было 3:4 — видео 832x1120, в лентах поля или обрезанная голова). Атмосфера подбирается по описанию кадра и подмешивается тихо под голос; нейтральные места остаются без фона. В конце каждого куска речи пауза 0.45с. Следующий кусок стартует с последнего кадра предыдущего — на склейке нет рывка. Подключён словарь произношения завода (раньше не передавался factoryId, слой молча не работал). Текст-хук пишется только когда сценарий придумываем мы.
Проверено: механизм паузы удлиняет дорожку ровно на добавленное дыхание. Проверку готового ролика намеренно не делаем — решение владельца: переделывать за свой счёт не будем.
feature
Г16. Аватар: одна озвучка, один клип, звук места, единые кнопки
Нарезка речи на куски по 15 секунд убрана: OmniHuman принимает аудио до 60 секунд, весь текст идёт целиком одним вызовом. Раньше собственная защита обрезала 4 реплики до 2 и давала швы на склейке. Кадр рисуется 9:16 (было 3:4 — в лентах поля). Атмосфера места подбирается по описанию кадра и подмешивается под голос (громкость 0.28 + срез гула). Подключён словарь произношения завода. Текст-хук пишется только когда сценарий придумываем мы. Действия над готовой работой (опубликовать, скачать, начать новую) вынесены в общий компонент и стоят в одном месте во всех пяти холстах.
Проверено логами и файлами: атмосфера подбирается и подмешивается, кадр вертикальный, картинки сохраняются с настоящим типом. Живьём после упрощения ещё не гонялось — ждём прогона владельца.
fix
Г17. Звук ролика: слышный фон места и нормальная громкость
amix делил громкость на число дорожек: речь проседала вдвое, фон уходил в неразличимое (замер готового ролика -36 dB при норме -16). Добавлены normalize=0 и loudnorm=I=-16 — замер после правки -19.4 dB средняя, -3.9 пик. Фон 0.35 + highpass 120 Гц, чтобы не давил на голос. Нарезка звука выровнена: 29 секунд это две части по 14.4, а не три обрывка; точка реза учитывает, что в предел должна влезть и часть, и остаток. Кадр даёт место движению: при описанном действии просим план от колен.
Владелец послушал собранный образец: улица слышна, речь на нормальной громкости. Генерация звуковых эффектов пока годится, база готовых записей отложена.
fix
🔴 Г18. Настоящая причина отказов оживления: файл не успевал стать доступным
Те же кадр и озвучка, что упали в пайплайне, при отправке вручную минутой позже прошли успешно — дважды. Значит провайдер идёт за файлом сразу после createTask, а наше хранилище в этот момент его ещё не отдаёт. Прежние версии (тяжёлый PNG, длина 28 секунд) были следствием той же гонки. Теперь после загрузки кадра и озвучки ждём, пока ссылка реально отвечает (до 10 попыток), и только потом отправляем. Ролик снова уходит одним куском до 30 секунд, при отказе система один раз режет запись по паузам и повторяет сама.
Прогон владельца прошёл: ролик 30 секунд собрался. Осталось качество формата, а не техника.
fix
Г19. Приёмщик обрывался на длинном ответе
OpenRouter returned invalid JSON: Unterminated string — ответ не влезал в 3000 токенов, задание уходило пустым, и в сборку шла одна реплика из ячейки вместо четырёх. Лимит поднят до 8000, добавлен повтор при битом JSON, в промте просьба не дублировать длинные тексты. Плюс в карточку теперь уходит полный текст задачи, а не только подписи ячеек: описание кадра до сборки не доезжало.
fix
Г20. Нажатие видно сразу, второй клик невозможен
Между нажатием и первым сообщением было несколько секунд тишины — человек успевал нажать ещё раз, и это грозило второй сборкой за деньги. Теперь сразу «Читаю задачу…», кнопка гаснет и крутится, Enter в это время не срабатывает.
fix
🔴 Г21. Качество ролика аватара не оправдывает цену — решить судьбу формата
Владелец оценивает готовый ролик в 150 руб при цене 660 и себестоимости около 400 (13.5 руб/сек у Kie). Техника доведена: весь текст произносится, кадр вертикальный, атмосфера подбирается по месту, стык ровный. Дальше вопрос не в коде, а в подаче: голос (сейчас нейтральный из списка), постановка (без описания поведения уходит дежурная фраза), характер кадра (с предметом получалось ярче). Предложено: серия дешёвых прогонов по 5-8 секунд на разных голосах и постановках, чтобы понять потолок. Если потолок низкий — честнее убрать формат из витрины, чем продавать за 660.
research
Г22. Сабы: брать наш текст, а не расшифровку своей же озвучки
Роут /api/video/subtitles гонит Whisper по дорожке, которую мы сами и синтезировали. На ролике Брендосс 09.08 получили «Пустая комната ям», «Брэндес» вместо БРЕНДОСС и по 70 символов в одном сабе. Когда озвучка наша, текст известен: брать тайминги из ElevenLabs /with-timestamps (alignment по символам), резать на куски по 3-4 слова и рисовать наш текст (бренд капсом, числа цифрами). Плюс segmentsToStyledASS зашивает PlayRes 1080x1920 — на кадре другого размера саб мелкий и тянутый, ставить реальный размер кадра и кегль долей высоты. Рабочий образец: scratchpad oks-subs.mjs.
feature
Г23. Премиум-ролик уезжает в 3:4 и молчит: чинить кадр и просить речь
Wan 2.7 в режиме i2v игнорирует ratio и берёт пропорции первого кадра — ролик 08.08 вышел 830x1108 вместо 9:16, под Reels не годится. Чинить: первый кадр генерить вертикальным (nano-banana-pro/gpt-image-2, aspect 9:16) либо звать t2v. Второе: Wan УМЕЕТ русскую речь (проверено 09.08, Whisper снял с дорожки ровно заказанную реплику) — но пайплайн её не просит, поэтому дорожка приезжает пустой (-58 dB) и озвучку клеим сверху. Дать режиссёру промтов вариант со встроенной речью: реплики кириллицей в кавычках + строка про lip sync. Комментарий в kie-ai-studio.ts про No native speech ввёл в заблуждение — поправить.
feature
планS14 · Продуктовые пробелы по ролям0/10

Цель: Э4-Э5 плана docs/FIX-ROADMAP.md: превью до денег, сверка результата, память задач, продуктовые пробелы по ролям

🔴 П1. Превью и согласование до списания
Дешёвая ступень «покажи, что получится» до полной оплаты и место, где заказчик утверждает макет. Просят пять ролей из шести: предприниматель, маркетолог, СММщик компании, агентство, креатор. Снимает половину боли «правка = полная переплата». Дефекты Д32, Д19.
feature
П2. Варианты одной задачи и A/B
«Дай три штуки, выберу», два хука на один ролик, две обложки карусели. Без этого маркетолог не может тестировать вообще. Дефект Д26.
feature
П3. Бренд-ассеты как правило + загрузка бренд-гайда
Логотип, шрифты, палитра, интро/аутро, стиль субтитров сейчас живут в разных местах и до холстов не доходят; бренд-гайд клиента (pdf) загрузить некуда. Агентство без этого не масштабируется. Дефекты Д27, Д30.
feature
П4. Пакетная работа
Карусели, Ролсы, аватары и видео запускаются по одному; композер планирует идеи, но сборку не запускает. Тридцать роликов вручную никто делать не станет. Дефект Д25.
feature
П5. Разъезд по площадкам и лимиты площадок
Один аспект на задачу: второй формат = отдельный платный запуск. Лимиты по длине текста и числу слайдов не проверяются. Дефекты Д36, Д29.
feature
П6. Повторяемость: сид и воспроизведение удачного кадра
«Тот же кадр, другой ракурс», «тот же сид, поменяй свет» — невозможно. Бьёт по креатору и по предпринимателю со знанием ИИ. Дефект Д34.
feature
П7. Свои материалы: музыка, съёмка, шрифты
Своя музыка не поддержана нигде, своё видео как основу не приложить, шрифты и вёрстка субтитров зашиты. Правка готового видео ограничена 15 секундами и 25 ₽/с. Дефекты Д17, Д33.
feature
П8. Сторис как формат в холстах
Сейчас сторис есть только в фабрике историй (премиум), в СММ-холстах формата нет. Дефект Д28.
feature
П9. Мультиязычность
Язык задаётся только словами в промте, служебные хвосты промтов на английском, субтитров на двух языках нет. Нужно агентствам с филиалами и экспортом. Дефект Д31.
feature
П10. Перенос стиля между форматами
Пресет карусели не применить к посту или видео: единый вид ленты приходится держать руками. Дефект Д35.
feature
В РАБОТЕS15 · Фундамент: стабильность под нагрузкой12/23

Цель: Убрать причины внезапных отказов и подготовить систему к росту числа клиентов. Основание: docs/STABILITY-AUDIT.md, снят с прода 05.08.2026.

🔴 Р2. Права проверялись перебором всей таблицы
org_members перебиралась целиком 2 552 782 раза против 228 обращений по индексу; organizations 780 964; companies 768 457. Индексов на user_id, owner_user_id и org_id не было вовсе. При 317 строках это незаметно, на тысяче компаний ложится каждый запрос к любой таблице. Добавлены индексы org_members(user_id), org_members(org_id,user_id), organizations(owner_user_id), companies(org_id), content_items(factory_id,status,created_at). Проверено: функция политики фильтрует ровно по org_id+user_id, индекс ей подходит.
fix
🔴 Р8. Журнал ошибок сам не писался
«Failed to log error: new row violates row-level security policy» 59 раз за сутки: журнал писался от имени человека, а ошибки чаще случаются там, где сессии нет (фоновая сборка, очередь, вебхук). Мы теряли ровно те ошибки, ради которых журнал заводили, и узнавали о сбоях только от клиента. Переведён на служебный ключ.
fix
🔴 Р4. Внешние вызовы без предела ожидания
240 вызовов наружу, из них с таймаутом 4. Процесс один на всех: подвисший провайдер держит наше соединение и память, остальные клиенты ждут. Появилась общая обёртка lib/net/fetch-safe.ts: предел ожидания, один повтор на сетевую осечку и коды 429/502/503/504, повтор для POST только по флагу. Переведены клиенты Kie (19 вызовов). Осталось перевести ElevenLabs, Suno, Upload-Post, VK, Telegram.
fix
Р1. Выкладка обрывает работу в открытых вкладках
«Failed to find Server Action» 62 раза и «Cannot read properties of null (reading digest)» 74 раза за сутки. Вкладка, открытая до выката, шлёт устаревший идентификатор и получает ошибку посреди работы. У агентства, которое держит кабинет открытым весь день, это происходит на каждом выкате. Плашка о новой версии есть, но она не ловит саму ошибку. Нужно: перехват такой ошибки на клиенте с предложением обновиться и сохранением набранного.
fix
Р6. Гонки состояния на холстах
Список ячеек собирался внутри обновления состояния, а команда на отрисовку читала его снаружи через 100 мс. Когда React не успевал, список приходил пустым и задача в очередь не уходила вовсе: человек видел восемь ячеек с текстами и ни одной картинки, в базе ноль задач. Переписаны карусель и агентская ветка. Осталось пять таких мест в холстах поста и карусели. Правило: посчитать значение и передать параметром, из состояния в обработчике не читать.
fix
Р5. Долгие генерации живут внутри HTTP-запроса
27 мест с циклом «спим пять секунд, спрашиваем статус», до десяти минут в одном запросе, при этом предел времени задан лишь у пяти роутов из 298. Запрос держит соединение и память всю генерацию; сеть моргнула, работа осиротела, деньги списаны. Довести до конца начатое очередью: ставим задачу, сразу отвечаем, результат забираем фоном.
feature
🔴 Р7. Списание денег не атомарно
Баланс читается, вычитается и пишется обратно с проверкой «не изменился» плюс повторы; запись в журнал операций идёт отдельным запросом. При сбое между ними баланс уменьшится без записи в журнал. Для корпоративного клиента расхождение в деньгах недопустимо. В базе уже есть функции charge и increment_balance, перевести списание на одну транзакцию.
fix
Р3. Картинки лежат в базе целиком
content_items весит 503 МБ при 4544 строках, из них 261 МБ в carousel_slides: 121 запись хранит data:image/png;base64 прямо в ячейке, самая тяжёлая 3,4 МБ. Раздувает бэкапы и память базы. Перелить в хранилище, оставить ссылки, запретить запись base64 на уровне кода.
fix
Р10. Очереди на кроне вместо воркера
Разбор писем и сбор картинок висят на crontab с шагом 2-5 минут: задержка на каждом шаге и никаких приоритетов. При росте крон запускает следующий проход, не дождавшись предыдущего. Нужен один постоянный воркер с ограничением параллельности.
feature
Р9. Публикации молча не уходят
VK Error 5 invalid access_token 16 раз, «message caption is too long», плюс 16 отказов отправки событий в Inngest. Клиент считает, что пост вышел, а он не вышел. Нужна проверка токенов по расписанию с предупреждением до публикации и обрезка подписи по правилам сети до отправки.
fix
🔴 Регресс-прогон перед выкладкой
Сейчас перед деплоем проверяются только типы и то, что сайт отвечает 200. Это не ловит ровно то, на чём мы горим: уехавшее окно, тяжёлые картинки, потерянный контекст, незапущенную отрисовку. Нужен сценарий, который логинится тестовым аккаунтом и проходит путь клиента на двух ширинах, проверяя факты: кнопка подтверждения видна, горизонтального скролла нет, вес картинок в списке ниже порога, задача в очереди появилась. Красный прогон блокирует выкладку.
feature
🔴 Смоук-прогон перед выкладкой: сделан и включён в деплой
Playwright, 14 проверок на двух ширинах: вход, дашборд, пять холстов, работы, публикации. Проверяет факты, а не «страница открылась»: кнопка подтверждения видна целиком, горизонтального скролла нет, картинки целы и легче 600 КБ, реакция на нажатие приходит за три секунды. Денег не тратит: доходит до окна подтверждения и жмёт «Не так». Красный прогон возвращает предыдущую сборку. Первый же запуск нашёл настоящий баг: холст поста был шире экрана на 23 пикселя.
feature
🔴 Окна поверх страницы уезжали за экран
В «Моих работах» клик по видео давал пустое затемнение: карточка открывалась за пределами экрана. Причина общая для Центра: анимация появления стояла в режиме both и навсегда удерживала transform, а он делает position: fixed относительным себе. Режим backwards снял ловушку и починил все 23 окна раздела разом.
fix
🔴 Карусель зависала с текстами без картинок
Список затронутых ячеек собирался внутри обновления состояния, а команда на отрисовку читала его снаружи через сто миллисекунд. Когда React не успевал, список приходил пустым и задача в очередь не уходила вовсе: восемь ячеек с текстами и ни одной картинки, в базе ноль задач.
fix
🔴 Работа шла только при открытой вкладке
Задачу доводила внешняя служба событий, она роняла её на первом шаге, наш возврат в очередь отправлял туда же: у одной работы было два хозяина. Закрыл вкладку — работа стояла. Теперь очередь тянет наш воркер по расписанию раз в минуту, брошенное подхватывается через три минуты, отметка живости пишется после каждого слайда.
fix
Показ хода работы врал
Все ячейки разом помечались «рисуется», хотя сервер делал обложку: от неё берётся стиль серии, остальные физически не могли начаться. Теперь крутится только то, что делается: сначала обложка, остальные пишут «ждёт обложку», дальше по три за раз.
fix
Пресет перерисовывал те же слайды
Пресет хранит все слайды прошлой карусели, и все десять уходили в модель как входные картинки в режиме «переделай картинку». Она брала готовый слайд и меняла надпись. Теперь от пресета берётся не больше двух образцов, а правило сказано прямо: брать палитру, шрифты, свет и фактуру, не брать предметы, героев, фон и композицию.
fix
На слайде рисовался весь план карусели
План серии уходил в промт каждого слайда со словами «используй только эти заголовки». Модель поняла буквально и печатала на картинке весь список. Теперь план видит только обложка и помечен как контекст, рисовать его нельзя. Плюс запрет на одинаковый текст у разных слайдов.
fix
Отметки доставки в поддержке
Ответ писался в базу и уходил в мессенджер, а результат отправки нигде не сохранялся: если мессенджер не принял, в переписке ответ всё равно выглядел отправленным. Теперь у каждого ответа отметка: доставлено, не дошло, ждёт в кабинете. «Прочитано» только у веб-чата: мессенджеры о прочтении ботам не сообщают.
feature
Работа без завода невидима в «Моих работах»
Список работ фильтруется по заводам, и контент, созданный с привязкой только к компании, не показывается ни при каком выборе, хотя деньги за него списаны. Поймано на живом контенте для клиента.
fix
Ролс нельзя поставить служебным ключом
У раздела вход только через интерфейс: задачу нельзя создать ни кроном, ни скриптом, ни помощником. Для остальных форматов служебный вход есть.
feature
Проверка: ключ очереди и авто-сборка на проде живы
09.08 прод три недели жил без INNGEST_EVENT_KEY: сайт отвечал 200, посты и карусели собирались, а видео, очередь картинок СММ, публикация через очередь и аналитика молча не работали. Ключ восстановлен, событие проверено живым вызовом (200 + Inngest вызвал функцию, 206). Тогда же в логе замечены две ошибки автосборки 'fetch failed' при вызове https://24contentzavod.ru/api/content-item/<id>/generate — не повторялись. КОМАНДА ПРОВЕРКИ: ssh cfru "grep -c '^INNGEST_' /var/www/content-factory-prod/.next/standalone/.env" → должно быть 2 ssh cfru "curl -s -o /dev/null -w '%{http_code}' https://24contentzavod.ru/api/inngest" → 401 (не 500) ssh cfru "grep -c 'couldn.t find an event key' /root/.pm2/logs/content-factory-prod-error-2.log" → не должно расти ssh cfru "grep -c 'Failed to generate item' /root/.pm2/logs/content-factory-prod-error-2.log" → было 2 В базе: SELECT count(*) FROM render_queue WHERE status='failed' AND error_message LIKE '%event%'; → не должно расти
Проверено 16.08: ключей INNGEST два, /api/inngest отвечает 401 (не 500), жалоб «couldn t find an event key» в логе ноль, сбоев автосборки ноль. Очередь и авто-сборка на проде живы.
check
Проверка: очередь прода работает своим кодом, а не стендовым
17.08 выяснилось, что внутренние вызовы прода шли на 127.0.0.1:3001 — это стенд. Очередь картинок, публикация и аналитика выполнялись кодом стенда. Задано INTERNAL_BASE_URL=http://127.0.0.1:3002. КОМАНДА ПРОВЕРКИ: ssh cfru "grep -c '^INTERNAL_BASE_URL=http://127.0.0.1:3002' /var/www/content-factory-prod/.next/standalone/.env" → 1 ssh cfru "pm2 logs content-factory --lines 300 --nostream | grep -c 'content-item'" → не должно расти (стенд больше не обслуживает прод) ssh cfru "pm2 logs content-factory-prod --lines 300 --nostream | grep -c 'content-item'" → должно появиться В базе: SELECT count(*) FROM render_queue WHERE status='failed' AND updated_at > now() - interval '3 days'; → не должно расти
ПРОВЕРЕНО 21.08, всё чисто. INTERNAL_BASE_URL=http://127.0.0.1:3002 в проде стоит (1). Стенд content-item больше не обслуживает: 0 упоминаний в последних 300 строках лога. Прод обслуживает: 19. В render_queue за трое суток 5 работ, все done, ни одного failed. То есть прод работает своим кодом, а не стендовым.
check

Ворклог (места остановки)

27.08.2026, 01:44:44 · S13 · claude

Переделка двух работ для «Фабрики Брендосс» после разбора от владельца: обе прошлые версии были сделаны правдоподобно, а не правильно. КАРУСЕЛЬ «Механизмы диванов» v2: тексты переписаны на проверенные факты (клик-кляк 7-10 лет и 120-140 кг, убивает незащёлкнутый затвор; у еврокнижки ломаться нечему, срок жизни определяет обивка, ролики лечатся силиконовым спреем раз в полгода; аккордеон тяжелеет и метит пол; дельфин самый нагруженный — рычаги, крепления, люфт; книжка живучая, но усилие и стык). Прошлый текст был набором очевидностей вида «нужен метр перед диваном». Схемы перерисованы: строго боковая проекция вместо изометрии, ДВЕ фазы вместо трёх, обе на одной линии пола, фиксированный ракурс и явный запрет поворачивать диван между фазами — механика на всех шести слайдах вышла верной, перерисовывать не пришлось ни одного. РОЛИК «Он бежал к тебе» v2: снят ОДНИМ непрерывным планом, камера за спинкой дивана как в гоночной игре. Погоня, гигантские руки слева и справа, подворотня, лестница, дверь. Музыка и шумы родные от Wan, три реплики свои (ElevenLabs, голос Антон), дорожка модели приглушена до 0.62, наличие речи подтверждено обратной транскрипцией Whisper.

Три приёма, которые пора зашивать в завод, а не собирать руками скриптом. 1) Схемы механики: боковая проекция + две фазы + жёстко зафиксированный ракурс; изометрия с тремя фазами наложением даёт кашу и разные пропорции. 2) Один непрерывный план: оба опорных кадра обязаны быть сняты ИЗ ОДНОЙ ТОЧКИ — при разных ракурсах модель мирит их и разворачивает объект (так диван побежал назад в первом дубле). 3) Речь: Wan даёт русскую речь в кадре с человеком, но не даёт говорящей мебели — там кладём свою озвучку и проверяем обратной транскрипцией, а не на слух. Открытое: тип ткани 304 клиент так и не подтвердил; в заводе лежат две карусели про механизмы, старую кривую (4456618f) предложено снести; владельцу описана следующая карусель «Пять минут у двери» про приёмку дивана у курьера, ждёт решения.

24.08.2026, 04:49:11 · · claude

Разбор жалобы «не работает кнопка войти» на боевом сервисе. Вход оказался исправен, лежал слой данных: PostgREST упал при перезапуске базы в 02:25 и не поднялся, два часа весь /rest/v1 отдавал 503. Кабинет не мог прочитать профиль и заводы, поэтому после верного пароля человека возвращало на форму. Заводы всё это время ничего не выпускали. Поднял supabase-rest и перезапустил kong, который держал в кэше мёртвый адрес. Проверено снаружи: rest 200, auth 200, планировщик без ошибок.

Владельцу на решение: падение такого слоя сейчас видно только тогда, когда клиент не может войти, то есть два часа простоя вслепую. Предложено добавить в compose Supabase зависимость rest от базы с проверкой здоровья и внешнюю проверку /rest/v1 с оповещением в Телеграм. Это правка боевого стека, жду «да». Заведена проверка по сроку на 31.08: встаёт ли REST сам после перезапуска базы, с командой и порядком починки (docker start supabase-rest, затем docker restart supabase-kong). По ядру cz-core работа не двигалась: вся сессия ушла на прод.

19.08.2026, 02:32:04 · S13 · claude

Продакшн для «Фабрики Брендосс», заход в новом креативном регистре: владелец забраковал бытовые идеи и попросил концепты, пробивающие баннерную слепоту. Ролик «Он бежал к тебе»: ночной мультяшно-кинематографичный город, диван удирает на своих ножках от гигантских рук, которые расхватывают чужие диваны, добегает до своей комнаты и раскладывается в кровать. Собран ДВУМЯ клипами Wan 2.7 (8 с погоня + 7 с прибытие) вместо одного пятнадцатисекундного: разные сцены, в одном i2v модель половину действия придумывает сама, а по деньгам одинаково, Wan тарифицируется посекундно. Четыре кадра gpt-image-2 цепочкой image-to-image от фото товара, каждый клип ведётся первым и последним кадром, склейка встык на действии. Карусель «Механизмы диванов»: клик-кляк, еврокнижка, аккордеон, дельфин, выкатной — у каждого не только плюс, но и честный минус (метр пола спереди, два стыка, нагруженный узел, сон почти у пола). Слайды сделаны как дорогие инженерные изометрии с фазами раскладывания, стрелками движения и выносками, палитра серии сохранена. 49 ₽.

Приём, который теперь работает стабильно и стоит перенести в пайплайн: сложное действие резать на два клипа по первому и последнему кадру вместо одного длинного, кадры генерить цепочкой i2i от фото товара. Тип ткани 304 всё ещё не подтверждён клиентом — на CTA новых каруселей утверждение про велюр не ставим.

17.08.2026, 11:06:51 · · claude

Разбор «на проде затёрли выставление счетов» — и нашлось кое-что похуже. 1. ТОЧКА. Никто ничего не затирал: ключей на проде НЕ БЫЛО НИКОГДА, в бэкапе от 30.07 их тоже ноль. Они всегда стояли только на стенде. А счета от 30.07 видны в базе потому, что стенд и прод пишут в ОДНУ базу — выставлены они со стенда. Ключи перенесены на прод (.env и .next/standalone/.env, оба с бэкапом), проверены напрямую у банка: запрос состояния счёта вернул 200 и «payment_waiting». Доступы рабочие. 2. ГЛАВНОЕ: ВНУТРЕННИЕ ВЫЗОВЫ ПРОДА ШЛИ НА СТЕНД. Прод слушает 3002, стенд — 3001. У прода не была задана INTERNAL_BASE_URL, а значение по умолчанию в коде — http://127.0.0.1:3001. То есть очередь картинок СММ, публикация и сбор аналитики прода выполнялись КОДОМ СТЕНДА: другой версией, с другими ключами, с логами в чужом файле. База одна, поэтому со стороны всё выглядело работающим. Задано INTERNAL_BASE_URL и INNGEST_INTERNAL_BASE_URL на 3002. 3. СЕКРЕТ ВЕБХУКА MAX. На проде не задан, а проверка в коде пропускается, когда секрет пуст: обработчик принимал ЛЮБОЙ запрос. Открытая дверь, не поломка. Секрет перенесён. Прод перезапущен, отвечает 200, /api/inngest — 401 (не 500) и по внутреннему адресу, и по публичному. Копировать со стенда всё подряд не стал: остальные четыре настройки (KZ_OPS_TOKEN, PROMPT_ENV, DEBUG_CRITIC_KEY, BACKOFFICE_LIA_CHAT_URL) стендовые по смыслу.

Проверить руками то, что нельзя проверить отсюда: выставить счёт юрлицу из кабинета прода (это боевой банковский счёт, без спроса документ не создаю). Присмотреть за очередью пару дней: теперь она работает своим кодом, а не стендовым — если где-то была зависимость от стенда, она вылезет.

12.08.2026, 03:10:31 · S13 · claude

Ещё один продакшн-заход для завода «Фабрика Брендосс». Ролик «Диван-победитель»: турнир, соперников давят грузами и греют лампой, они оседают, наш 304 берёт медаль под 3D-надписью БРЕНДОСС. Первый и последний кадр нарисованы gpt-image-2 (последний — image-to-image от первого, иначе сцены не совпадают), Wan 2.7 i2v по обоим кадрам. Камеру удержали статичной через промт плюс negative_prompt (zoom, push in, close-up, human face) — после случая с макро-портретом в прошлом ролике это теперь обязательная часть промта. Кириллица в 3D-надписи собралась без ошибок. Реплику «Ура! Я победил!» модель не проговорила (Whisper с дорожки снял типовую галлюцинацию на музыке) — положили свою озвучку ElevenLabs на 11.2 с поверх фанфар, проверено обратной транскрипцией. Карусель «Какая ткань от какой беды»: дети и пролитый сок, кот и когти, выгорание у окна, аллергия и пыль, велюр ради удовольствия — 7 слайдов gpt-image-2, стиль серии подхвачен через styleRefUrls, 49 ₽.

Тип ткани 304 по-прежнему не подтверждён — на CTA новой карусели специально написано «состав обивки смотрите в карточке», чтобы не давать непроверенное утверждение. У прошлой карусели на CTA стоит «велюр на металлокаркасе»: как только клиент подтвердит состав, либо оставляем, либо перерисовываем слайд за 7 ₽. Наблюдение в копилку Г23: Wan проговаривает реплику не всегда — в кадре без людей (говорящая мебель) речи не дал, в кадре с человеком дал обе фразы.

09.08.2026, 16:05:38 · S13 · claude

Продакшн для клиента Оксана Яхина (завод «Фабрика Брендосс») плюс два дефекта пайплайна, найденных по ходу. Вчерашний премиум-ролик «Диван приезжает домой» приехал с пустой дорожкой (-58 dB) — озвучили: ElevenLabs, голос Виктория, текст через словарь произношения завода (Брэ́ндос, Ва́йлдберриз, велю́р), сведение -16 LUFS. Сабы продуктовый роут собрал негодные: Whisper по нашей же озвучке дал «комната ям» и «Брэндес», куски по 70 символов — пересобрал по таймингам ElevenLabs with-timestamps, 11 коротких фраз, PlayRes по реальному кадру. Собрана карусель «Ткани для дивана», 7 слайдов gpt-image-2 3:4, стиль подхвачен с прошлой серии через styleRefUrls, копирайт свой (Мартиндейл, рогожка, шенилл, флок, велюр) — 49 ₽. Снят вирусный ролик «Готовь сани летом»: первый кадр gpt-image-2 i2i от фото товара, Wan 2.7 720p 15 с. Первый дубль забраковал (камера ушла в макро-портрет, товара не видно 11 из 15 с), во втором задал negative_prompt против крупных планов и отъезд камеры — вышли обе русские реплики нативно от модели, финал с оленями над лесом, титр наложен своим ffmpeg. Обе работы и карусель лежат в заводе, две работы перенесены из служебного «Без завода» в «Фабрику Брендосс».

Открытый вопрос: на CTA-слайде карусели написано «велюр на металлокаркасе», а тип ткани в карточке товара не указан — подтвердить у клиента, иначе перерисовать слайд (7 ₽). Заведены Г22 (сабы должны брать наш текст, а не расшифровку) и Г23 (Wan i2v уезжает в 3:4 и не просит речь) — оба воспроизводимы, в деталях лежат рецепты.

07.08.2026, 14:33:56 · S15 · claude

Собран аудит стабильности с доказательствами из живого прода (docs/STABILITY-AUDIT.md) и закрыты первые зоны: индексы под проверку прав, журнал ошибок служебным ключом, таймауты и повторы для Kie. Появился смоук-прогон на Playwright, встроенный в выкладку: 14 проверок на двух ширинах, красный прогон возвращает сборку. Он сразу нашёл реальный баг с шириной холста. Починены: уезжающие за экран окна (общая причина для 23 окон раздела), гонка с незапущенной отрисовкой, зависимость работы от открытой вкладки, врущий показ хода, пресет-копировальщик, весь план карусели на одном слайде. В поддержке появились отметки доставки. Мобильный Центр пересобран: две строки вместо шести плашек, голосовой ввод, лёгкие превью в списках.

Открыто: работа без завода не видна в «Моих работах» (поймано на клиентском контенте); у Ролса нет служебного входа; из аудита ждут атомарное списание, генерации в фон, чистка базы от base64, воркер вместо крона, контроль публикаций. По клиенту Брендосс: карусель из семи слайдов готова и лежит в кабинете, АСМР-ролик забракован владельцем (нарезался на четыре клипа вместо одного пятнадцатисекундного и не показывал товар), переделка по правильной схеме ждёт разрешения на трату.

03.08.2026, 16:31:25 · S13 · claude

Аватар доведён технически. Найдена настоящая причина серии отказов: не кадр, не формат и не длина аудио, а гонка — провайдер шёл за файлом раньше, чем хранилище начинало его отдавать (доказано: те же файлы вручную минутой позже прошли дважды). Теперь ждём доступности ссылки перед отправкой. Приёмщик обрывался на длинном ответе и отдавал пустое задание — лимит поднят, добавлен повтор; в карточку уходит полный текст задачи. Ролик идёт одним куском до 30 секунд с автонарезкой только при отказе. Починена обратная связь при нажатии. Прогон владельца: ролик на 30 секунд собрался целиком.

Открыт вопрос ценности формата: владелец оценивает результат в 150 руб при цене 660 и себестоимости 400. Следующий шаг не в коде, а в подборе голоса и постановки на коротких дешёвых прогонах; по итогу решить, остаётся ли ИИ-аватар в витрине. Отдельно ждёт своей очереди пересборка интерфейса холста единым макетом для пяти форматов.

03.08.2026, 14:17:06 · S13 · claude

Разобрана настоящая причина отказов оживления: не кадр и не формат, а длина аудио — 28 секунд провайдер отбивает, 10 перекодированных принимает (падающие задачи бесплатны, поэтому границу искали прогонами). Режем теперь звук по паузам на равные части до 15 секунд, текст при этом цел. Починен звук: amix делил громкость на число дорожек, из-за чего ролик выходил на -36 dB и фон был неразличим; после normalize=0 и loudnorm стало -19.4 dB, владелец подтвердил, что улица слышна. Кадр при описанном движении рисуется планом от колен. Действия над готовой работой сведены в общий компонент и стоят одинаково во всех холстах.

Живой прогон 30 секунд: ждём две части по 14.4, склеенные в один ролик, весь текст, вертикаль, слышный фон. Если фон покажется петлёй — заводим базу готовых записей вместо генерации.

03.08.2026, 11:05:11 · S13 · claude

Аватар упрощён до прямого пути: весь текст одной озвучкой, одно оживление, никакой нарезки. Раньше моя же защита от перерасхода резала речь (из четырёх реплик озвучивались две) и плодила швы. Кадр теперь 9:16, а не 3:4. Атмосфера места слышна (0.28 вместо 0.12 плюс срез гула). Подключён словарь произношения. Текст-хук только когда сценарий пишем мы. Отдельно: действия над готовой работой сведены в общий компонент и стоят в одном месте во всех холстах — раньше в карусели были кнопки, в видео и аватаре не было ничего.

Прогон владельца на 30 секунд: ожидаем один ролик целиком, все реплики, вертикаль, слышный фон улицы. Дальше — пересборка интерфейса холста единым макетом для пяти форматов.

03.08.2026, 08:15:12 · S13 · claude

Разобрана и устранена причина отказов OmniHuman (висела с 12 спринта): не провайдер, а наш файл — тяжёлый PNG от gpt-image, кадр теперь пережимается в JPEG до 1280. Починена доставка задания в сборку: ролик выходил на 5 секунд с одной репликой из четырёх, потому что задание передавалось через состояние React и не успевало, а речь бралась из ячейки холста. Теперь задание идёт параметром, речь берётся из него целиком. Ролик стал вертикальным 9:16. Добавлены: атмосфера места по описанию кадра, пауза в конце каждого куска речи, стык через последний кадр предыдущего клипа, словарь произношения, текст-хук только когда сценарий пишем мы. Из интерфейса убрана внутренняя кухня: окно перед запуском говорит человеческим языком, в ошибках нет названий провайдеров.

Контролируемый прогон аватара владельцем: ждём ролик на 30 секунд двумя кусками с полным текстом. Дальше по его решению: разрешение оживления (сейчас 720p) и пересборка интерфейса холста.

03.08.2026, 06:22:23 · S13 · claude

Найдена и устранена причина отказов OmniHuman, висевшая с 12 спринта: не провайдер, а наш файл кадра — тяжёлый PNG от gpt-image. Диагностика прогоном на двухсекундном аудио: PNG 1.9 МБ отбивается и как .jpg, и как .png; JPEG 720x960 с нашего же домена проходит, внешняя картинка тоже. Кадр теперь пережимается в JPEG до 1280 по длинной стороне, картинки сохраняются с настоящим типом. Отдельно: клиенту больше не показывается внутренняя кухня — окно подтверждения говорит человеческим языком, из ошибок убраны названия провайдеров.

Контролируемый прогон аватара владельцем — должен пройти до конца. Дальше: пересборка интерфейса холста (сейчас накопились слои), превью до денег, память задач.

03.08.2026, 03:45:21 · S13 / Э3 · claude

Задание доведено до генератора. Пост и карусель рисуют прямо по разобранному заданию, минуя агента-переписчика. Аватар и видео получают задание в карточке (task_spec) и берут из него речь дословно, действие в кадре и описание кадра; decideScene больше не вызывается, когда кадр описан человеком. Режиссёр аватара переведён с прямого ключа OpenAI на OpenRouter. Окно подтверждения блокирует запуск без лица и без фото. Проверено без генераций: задание сохраняется в карточке целиком, аватар без лица не запускается, полное задание разбирается чисто и даёт смету 330 рублей всё включено.

Ждём контролируемого прогона аватара владельцем: один ролик под наблюдением логов и кабинета Kie. Дальше Э4 — превью до денег, память задач, автоперерисовка при расхождении результата с заданием.

02.08.2026, 08:04:27 · S13 / Э2-Э3 · claude

Приёмщик подключён ко всем пяти холстам: перед работой показывается «понял так» и смета, списание только после подтверждения. Роли приложенных картинок определяются зрением из ролей, названных человеком. Вычищены приписки из промтов генератора: тот же промт, что раньше давал рекламный плакат с выдуманными лозунгами, теперь даёт ровно заказанное фото. Добавлен слой качества: кадр перед дорогим шагом рисуется в двух вариантах и проверяется по чеклисту (аватар 3 руб против 200), результат сверяется с заданием по цене и телефону. Проверки прогнаны на готовых картинках без генераций; из платного — один пост 10 руб.

Довести Задание до генератора (сейчас спека показывается человеку, но в генерацию уходит по-старому), снести старые догадки decideRefRole и decideScene, перевести режиссёра аватара на OpenRouter. Контролируемый прогон аватара — по слову владельца. Отдельно: Kie трижды не уложился в 240 секунд на посте с длинным текстом, поднять ожидание до 300.

02.08.2026, 06:05:24 · S13 / Э3 · claude

Собран и выложен приёмщик задач: одно ядро, пять профилей форматов, строгая схема ответа, температура 0, эндпоинт /api/smm/task/parse (ничего не генерит и не списывает). Прогон на 110 постановках задачи по всем пяти форматам без единой генерации: было 91 верно, стало 108 после того, как количество единиц, цены и телефоны, роль звукового файла и отличие темы от речи забрали у модели в код. Аватар, видео, карусель и Ролс разбираются чисто 22 из 22. Отчёт docs/PARSER-RUN.md, набор кейсов scripts/parser-cases.py.

Подключить приёмщика к холстам с окном «понял так» и сметой (порядок: пост, карусель, Ролс, видео, аватар), добавить зрение для ролей картинок, вычистить наши приписки из промтов генератора.

01.08.2026, 20:05:22 · S13 / Э1 · claude

Ночная сессия: этап Э1 «перестать терять данные» сделан и выложен на стенд (коммит 08e699a8). Вложения аватара (место, товар, своя озвучка) доезжают до генератора; роли вложений записываются в attachment_roles; ручной режим кладёт речь в task_verbatim и она произносится дословно; заказ длины аватара сохраняется целиком (нашли: сохранялись только 8/15/30, остальное превращалось в null); снят потолок в три сегмента; Veo взял раскадровку холста; авто-Ролс получил бриф; карусель чейнится от свежей обложки; в генератор уходит до 16 картинок вместо 4; подхват сборки фильтруется по компании. Отдельно: цена «всё включено» — сняты доплаты по ходу у аватара. Прогон 9 генераций (5 постов, 2 карусели, 2 Ролса), 73 ₽ по кассе, результаты и картинки — docs/REGRESSION-SET.md. Эталонный пруф проблемы Э3: один и тот же промт в ручном режиме даёт ровно заказанное фото, а в режиме «С ИИ» — рекламный макет с выдуманными надписями.

Владельцу утром: прогнать аватар (готова карточка a5c3af8c — 25 секунд, фото места и товара, дословная речь) и видео. Дальше по плану Э2: гейт достаточности, экран «понял так» со сметой, честные отказы. Открытые вопросы прежние: вид экрана подтверждения и поднимать ли превью из Э4 в Э2.

01.08.2026, 18:37:58 · S13/S14 · claude

Собран сквозной план починки: docs/FIX-ROADMAP.md (целевая архитектура со слоем Задания, контракт TaskSpec v1, схема данных task_specs/brand_kits, пять этапов с приёмкой, регресс-набор из 40 сценариев, метрики и деградация) и docs/ACCEPTANCE-PIPELINES.md (39 поведенческих критериев в формате делаю-ожидаю). Порядок: Э0 мерки, Э1 перестать терять данные, Э2 деньги под контролем, Э3 ядро (Задание вместо догадок), Э4 превью и сверка, Э5 продуктовые пробелы. Спринты 13 и 14 размечены по этапам, добавлены три задачи Э0.

Пять решений владельца из раздела 10 FIX-ROADMAP: порядок этапов, сетка длин аватара, вид экрана подтверждения, разрешение на живой прогон (330 ₽), поднимать ли превью из Э4 в Э2. После ответов — старт Э1.

01.08.2026, 18:20:35 · S13/S14 · claude

Ролевой проход: 6 ролей (предприниматель без опыта в ИИ, предприниматель со знанием базы, маркетолог, СММщик компании, СММщик агентства, креатор) x 5 форматов x 12 сценариев = 360 (docs/SCENARIOS-ROLES.md). Перед оценкой проверил по коду, какие функции реально есть: derive, video-edit, композер, шаблоны, пресеты, труппа, бумперы, сторис, upload-media. Итог: 136 работают, 125 наполовину, 99 провальных. Вместе с матрицей по форматам — 475 способов поставить задачу, 140 из них провальные. Найдены 12 новых дефектов Д25..Д36 — это уже не баги, а продуктовые пробелы: нет превью до денег, вариантов, бренд-гайда, пакетной работы, повторяемости, разъезда по площадкам. Заведён спринт 14.

Спринт 13 (починка пайплайнов) ждёт четырёх решений владельца из FIX-PLAN. Спринт 14 (продуктовые пробелы) нужно приоритизировать по ролям, на которых зарабатываем: превью до денег и варианты — самые частые запросы, бренд-ассеты и пакетная работа — условие масштабирования агентств.

01.08.2026, 18:05:17 · S13 · claude

Второй, углублённый заход по пайплайнам — по коду, а не по памяти. PIPELINES.md переписан (контракт полей холст→сервер, 15 вызовов моделей, все списания, 12 мест где данные молча теряются, реестр Д1..Д24). SCENARIOS.md расширен с 63 до 115 сценариев: 41 работает, 33 наполовину, 41 не даст результата со списанием. Добавлены REPORT и FIX-PLAN с контрактом Задания (TaskSpec). Найдено сверх прошлого разбора: вложения аватара выбрасываются в create-content; Veo игнорирует раскадровку холста и видит idea обрезанной до 300 знаков; длины аватара 16-29 и 46-60 секунд структурно недостижимы; бриф не доходит до режиссёра авто-Ролса; карусель не чейнится от обложки при первом прогоне через очередь; в генератор уходит 4 картинки вместо 16.

Ждём решения владельца по четырём вопросам из FIX-PLAN: порядок волн, сетка длин аватара, где живёт подтверждение перед списанием, разрешение на живой прогон аватара (15 с = 330 ₽). Дальше волна 1 (Г7, Г8, Г10, Г11, Г12) — это починка контракта, архитектуру не трогает.

01.08.2026, 15:33:36 · · claude

Тяжёлый день с деньгами. Заказчик поймал двойные и тройные списания за ИИ-аватар. Причина: очередь ходила к самой себе через внешний адрес, упиралась в таймаут веб-сервера, считала это сбоем и повторяла задачу — а защита от повторного запуска была написана с оговоркой «кроме внутренних вызовов», то есть не действовала ровно на очередь. Каждый повтор списывал полную цену и слал провайдеру новую задачу. Останавливал генерацию аварийно (снял ключи очереди и перезапустил). Поставлены три заслона: очередь ходит к себе напрямую; повтор в идущую сборку отклоняется даже изнутри (кроме остывшей дольше 45 минут); повтор в уже готовую работу отклоняется тоже. Плюс сверка списания с фактической длиной ролика: короче заказа — возврат, длиннее — доплата. Из 990 руб автоматически вернулось 748. Разобраны и две содержательные жалобы: ролик выходил на 6 секунд, потому что режиссёру велено писать СВОЙ текст с бюджетом 195 знаков, а сценарий клиента шёл справкой — теперь реплики достаются из кавычек кодом и произносятся дословно; кадр не перерисовывался, потому что роутер судил по короткой идее, а режиссёрский промт лежал в описании кадра — теперь роутер видит то, что человек написал. Отдельная мина: приложение читает СВОЙ .env внутри сборки, а не корневой. Правка корневого не действует, сайт при этом работает как ни в чём не бывало — так мы потеряли доступ к очереди и не заметили. Копирование добавлено в cf-deploy.sh.

Очередь включена, ничего само не запускается — проверено. ГЛАВНОЕ: живой прогон аватара не сделан, заведена отдельная задача. Перед ним предупредить заказчика про длину сценария и цену. Отдельно заведён отказ провайдера OmniHuman (Volcengine CV API error) — к повторам отношения не имеет. Не забыть при выкатке на прод: вебхуки обоих ботов и адрес приложения в облаке Inngest сейчас указывают на стенд.