Перейти к содержимому

Разрешить сайту считать ваши посещения с помощью Яндекс Метрики? Для этого она сохранит в браузере файлы cookie. Как сайт использует cookie

VC
Кейс 19 из 22 · Разработка под ключ · полный цикл

Платформа для запуска рекламы: от приложения для себя до веб-сервиса

Эту платформу я сделал для управления кампаниями в собственных рекламных проектах. Началась она в 2024 году как десктопное приложение на Tkinter для себя. Потом выросла в полноценный продукт: больше 80 функций, Telegram-бот и рабочее веб-приложение на Next.js и FastAPI. В веб-версии есть права доступа по ролям и шифрованное хранилище токенов. С мая по сентябрь 2026 года в репозитории появилось 826 коммитов. Сейчас у десктопа 13 вкладок, у веб-версии 228 точек API. Расход двух рекламных сетей попадает в трекер по часовому поясу площадки. Отчёты прослеживают клик до конкретного объявления и сводят воронку «регистрация → первая оплата» по приложению, стране и офферу — предложению партнёрской сети.

Тип проекта
Платформа автоматизации маркетинга, три интерфейса
Технологии
Next.js 14 · FastAPI · PostgreSQL · Celery
Срок
2024 → 2026 · 826 коммитов с мая по сентябрь 2026
Масштаб
13 вкладок · 228 точек API · 221 автотест
01 · Проблема

Запуск одной кампании — 2 часа ручной работы

В закупке рекламы запуск одной кампании — это 9 связанных шагов: составить название по схеме (магазин, продукт, страна, специалист, ниша), подобрать посадочную страницу и офферы в трекере Keitaro, сделать короткую ссылку через Cutt.ly, прописать OG-теги для превью ссылки, привязать пиксель Facebook и токен доступа, создать пост на странице в Facebook, добавить первые комментарии.

На каждом шаге легко ошибиться: имя ссылки совпадает с прошлой кампанией, указан не тот пиксель, забыта UTM-метка — и учёт конверсий ломается, а бюджет тратится впустую. Когда в день запускается 5–10 рекламных наборов, на копирование и вставку уходит больше времени, чем на работу с креативами.

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

02 · Как рос проект

Четыре версии и три интерфейса

v1
ДЕСКТОП

Приложение на Tkinter для macOS, сначала для себя

Первая версия написана на Python и Tkinter, с родным меню правки macOS (отменить, вырезать, копировать, вставить). Это был личный рабочий инструмент: одна форма с автоподбором посадочных страниц и офферов, проверкой полей, сохранением шаблонов и локальной историей в SQLite. В нём было около 2000 строк на Python, и он собирался в приложение .app.

v2
TELEGRAM

Telegram-бот для команды: работа прямо в чате

Бот написан на python-telegram-bot 20 и ведёт пошаговый сценарий: задаёт вопросы по очереди, а ответы выбираются кнопками прямо в переписке. Бизнес-логика общая с десктопной версией. Специалист по рекламе создаёт кампанию с телефона, прямо из чата.

v3
ВЕБ

Рабочее веб-приложение с правами доступа по ролям

Веб-версия написана с нуля как полноценный сервис: Next.js 14 (App Router, TypeScript, Tailwind, shadcn/ui) + FastAPI (async SQLAlchemy 2 + Pydantic v2) + PostgreSQL 16 + Celery + Redis 7.

Шифрованное хранилище токенов на Fernet (AES-128-CBC + HMAC-SHA256): токен попадает в браузер, только если пользователь повторно ввёл пароль. Вход по JWT, пароли хранятся в виде хешей bcrypt. Каждое действие записывается в журнал в базе. Сервис развёрнут через Docker Compose на сервере Vultr, адрес сервера скрыт за Cloudflare.

v4
ДАННЫЕ

Лето 2026: версии выровнены, данные приведены в порядок

С июня по сентябрь — 178 коммитов. Первая часть работы — выровнять десктоп и веб-версию, чтобы в обеих были одинаковые возможности. Было шесть кругов проверки (с 38-го по 43-й), 24 коммита с 6 по 14 июня. Каждый круг устроен так: параллельная проверка по группам вкладок, сводный список расхождений, затем исправления. Правило для исправлений — «один файл — один исполнитель»: два параллельных редактора одного файла незаметно откатывают работу друг друга. Правки одного круга пришлось откатить. Проверка типов и сборка прошли, страница отдавала код 200, но в браузере падала каждая страница после входа. Причина: компонент кнопки передавал обёртке Radix двух потомков, а она принимает ровно одного. Через два дня правки вернули, и теперь перед каждой выкладкой все страницы заранее отрисовываются.

Вторая часть — данные. Расход рекламных сетей попадает в трекер по часовому поясу площадки: для Meta — по поясу каждого рекламного кабинета, для Unity Ads почасовые данные складываются в сутки по времени Лос-Анджелеса, по которым считает трекер. Поверх этого появились разметка клика до объявления по fbclid (идентификатору клика, который Facebook добавляет к ссылке), сводки «регистрация → первая оплата» по приложению, стране и офферу, выгрузка базы офферов партнёрских сетей и движок правил, который предлагает решения по связкам «кампания трекера и её кампании в Meta».

03 · Возможности

Десять главных функций из 80 с лишним

01 · Пакет
Пакетный запуск: 2–10 кампаний за раз

Таблица с правкой прямо в ячейках, автонумерация постов, полоса прогресса у каждой строки и итог по каждой: успех или ошибка.

02 · Хранилище
Шифрованное хранилище токенов

Fernet (AES-128-CBC + HMAC-SHA256), главный ключ в переменных окружения, отдельная роль vault-admin. Без повторного ввода пароля токен с сервера не уходит.

03 · Подсказки
Подсказки по истории запусков

«Вы обычно берёте этот магазин с этим продуктом», подсказки по времени («14:00 — ваше обычное время публикации»).

04 · Автосохранение
Черновик сохраняется каждые 5 секунд

Форма сама сохраняется в базу. Если браузер или приложение упали, черновик восстанавливается из последнего сохранения. Есть кнопка «очистить черновик».

05 · Проверка имени
Уникальность имени проверяется сразу

Рамка поля становится красной или зелёной, при совпадении кнопка блокируется. В пакетном режиме имя правится само: добавляется -2, -3 или случайное слово.

06 · Шаблоны
Шаблоны по категориям

Группировка по стране и магазину, применение в одно нажатие, предпросмотр перед применением, импорт и экспорт в JSON, шаблоном можно поделиться с командой.

07 · История
Полный журнал действий с поиском

Каждое изменение записывается со временем. Поиск и фильтры (кампания, пост, объявления, ошибки), фильтр по датам, выгрузка в CSV или JSON, переход к кампании одним нажатием.

08 · Копии
Резервные копии

Интервал копирования задаётся в настройках, копию можно сделать вручную кнопкой в меню, время последнего сохранения видно в строке состояния.

09 · Защита от дублей
Поиск повторов перед запуском

Предупреждение, если создаётся кампания с тем же магазином, продуктом и страной, что у существующей; рядом показывается сравнение с прошлой версией.

10 · Горячие клавиши
Работа с клавиатуры

Cmd+1 … Cmd+0 переключают вкладки, Cmd+H открывает историю.

Это моя личная разработка, внутренний инструмент для собственной работы. Я показываю её как пример того, что умею собирать в одиночку: продукт с тремя интерфейсами, выкладка в рабочую среду, права доступа по ролям, около 80 проработанных функций. К сентябрю 2026 года у десктопа 13 вкладок, у веб-версии 33 экрана, служебных скриптов 85. В клиентских проектах я уделяю деталям то же внимание, а инструменты подбираю под вашу задачу.

04 · Технологии

На чём это собрано

Интерфейс веб-версии (v3)
  • Next.js 14 (App Router)
  • React 18 + TypeScript
  • Tailwind CSS + shadcn/ui
  • Компоненты Radix UI
  • react-hook-form и проверка форм на Zod
  • Sonner для всплывающих уведомлений
Серверная часть (v3)
  • FastAPI 0.115 (async)
  • SQLAlchemy 2 (async) и миграции Alembic
  • Pydantic v2 для всех схем
  • JWT (jose, HS256, срок жизни 24 часа)
  • bcrypt для паролей
  • Fernet (AES + HMAC) для хранилища токенов
Данные и очереди
  • PostgreSQL 16 (pgcrypto, uuid-ossp)
  • Celery 5 для фоновых задач
  • Redis 7 как брокер очередей и кэш
  • SQLite в десктопной и Telegram-версиях
  • ClickHouse трекера: данные по каждому клику для ранних правил
Развёртывание и инфраструктура
  • Docker Compose, несколько сервисов
  • Nginx (TLS, заголовки безопасности, закрытые карты исходников)
  • Cloudflare DNS/CDN, адрес сервера скрыт
  • Vultr VPS, Ubuntu 24.04
  • Автоматические сертификаты Let's Encrypt
  • Задачи по расписанию на сервере трекера: расход каждые 15 минут, отчёт по правилам раз в сутки
Десктоп (v1)
  • Python 3 + Tkinter
  • Родное меню правки macOS
  • SQLite для локальной базы
  • py2app для сборки .app
Telegram (v2)
  • python-telegram-bot 20 (async)
  • Пошаговые сценарии диалога
  • Кнопки в сообщениях и обработка нажатий
  • Бот аналитики: карточки кампаний, пауза и запуск, решения движка правил, контроль состояния
Интеграции
  • Keitaro 11.10 API (кампании, посадочные страницы, офферы, расходы)
  • Facebook Graph API и Marketing API (посты, комментарии, страницы, кампании)
  • Meta Conversions API через собственный сервис-ретранслятор событий
  • Unity Ads Statistics API (расход и установки по часам)
  • Cutt.ly API (короткие ссылки)
  • API партнёрских сетей для сверки продаж
  • Приём вебхуков со статусами
Качество
  • Pytest: 221 тест в 10 файлах, 83 из них добавлены летом 2026
  • Проверка движка правил на 90 днях истории без заглядывания в будущее
  • Контроль состояния: 22 проверки в 7 группах каждые 30 минут
  • Журнал действий в базе
  • Единая обработка ошибок
  • Структурированные журналы
05 · Результат

Что изменилось в работе

Время запуска кампании
2 ч ~15 мин

в 8 раз быстрее, с защитой от дублей и проверкой всех полей

Пакетный режим
1 2–10

кампаний за один запуск, каждая настраивается отдельно прямо в таблице

Сделано функций
80+

за 10 этапов, от первой рабочей версии до полноценного сервиса

События конверсий с идентификатором клика
27% 100%

фильтр префиксов fbclid отбрасывал 492 из 672 кликов в сутки, и продажи уходили в Meta без идентификатора клика; проверено на живых журналах: 180/672 → 672/672

Клик → кампания, группа, объявление
0 35,1%

кликов по одной ссылке в комментарии размечаются до объявления: 13,5% дописывает Meta, 21,6% даёт собственный разбор fbclid; четыре кампании с одинаковым названием больше не сливаются в одну

Короткая ссылка без своего домена
270 с 4,9 с

сервис коротких ссылок отвечал ошибкой на запрос со своим доменом, и программа повторяла запрос 14 раз с растущей паузой; теперь она сразу переходит на домен по умолчанию

Что это дало в целом: платформа стала единым источником данных по всем рекламным запускам команды. Telegram-бот нужен специалистам в дороге, веб-приложение — для офиса и совместной работы, десктоп — тем, кому удобнее приложение на macOS. Все три версии используют общий код бизнес-логики.

Вывод для клиентских проектов: если бизнес-логика вынесена отдельно и не зависит от интерфейса, новый интерфейс — мобильное приложение, интеграцию со Slack, голосового помощника — можно добавить поверх той же серверной части, не переписывая логику.

Лето 2026: расход и сводки. Расход Meta записывается в трекер по часовому поясу каждого рекламного кабинета. Раньше кабинеты одного профиля работали в двух часовых поясах, сутки съезжали примерно на 10 часов, и часть расхода попадала на соседний день. Флаг уникальных кликов при записи убрал завышение на 10–15%. Запись идёт полной суммой за день, поэтому повторный запуск безопасен: 96 прогонов в сутки. Вчерашний день досчитывается после полуночи, пока сеть досылает поздние часы. Сводки «регистрация → первая оплата» по кампаниям второй сети собираются так: расход и установки берутся из самой сети, регистрации, оплаты и выручка — из трекера. Данные склеиваются по шестисимвольному идентификатору кампании в её названии. В сводке — цена установки, доли по шагам воронки, ROI и точка безубыточности. Доля оплат по регистрациям старше 6 часов показала, что один и тот же оффер конвертирует по-разному в разных приложениях, поэтому сначала смотрят на приложение, потом на оффер. Оплаты доходят за 24–48 часов, поэтому доля за первые сутки помечена в отчёте как заниженная.

Атрибуция клика до объявления. Фильтр префиксов fbclid в сборщике событий отбрасывал 492 из 672 кликов в сутки: продажа уходила в Conversions API без идентификатора клика, и из 4 продаж за день кабинет видел 2. Проверка по семейству префикса подняла долю до 672/672. Затем список префиксов убран целиком: такой список устаревает при следующей смене формата. 48 продаж за 7 дней отправлены заново с прежним идентификатором события, принято 48 из 48. Несколько кампаний показывают один пост с одной ссылкой, и трекер сливал их клики вместе. Поле adid внутри fbclid совпало с настоящим идентификатором объявления в 0 из 137 проверенных кликов. Поэтому таблица соответствия ведётся своя: она заполняется из кликов, к которым Meta сама дописывает идентификаторы. Итог: 262 пары, 22 объявления, ни одного конфликта, независимая сверка 361 из 361. Справочник «объявление → группа → кампания» по 10 кабинетам (912 объявлений, 760 групп, 244 кампании) собран без нарушений целостности. Повторный прогон сборщика с той же отметкой времени ничего не меняет, а раньше каждый прогон удваивал счётчики. Бот аналитики удваивал показатели трекера на одноимённых кампаниях и брал продажи только из одного потока: 10 продаж при 13 в трекере. Это давало ложный сигнал на остановку. Теперь суммируются все потоки, и отчёт сходится с трекером до цента. 34 теста на реальных образцах работают без подключения к сети.

Движок правил. Пять решений по связкам «кампания трекера × кампании Meta», от ранней остановки до масштабирования. Движок предлагает, решает человек: в трекер и кабинеты движок ничего не записывает. Данные идут из трёх источников. Трекер — единственный источник денег и воронки. Meta даёт ранг, текущий расход и состояние кабинета. Партнёрская сеть служит предохранителем через сверку продаж: если сеть показывает больше продаж, чем трекер, остановка запрещена. Пороги выведены из данных за 92 дня по всем кампаниям и совпали с правилами, которыми специалист пользовался на глаз: это точки, где ROI меняет знак, по цене уникального клика и цене перехода. Восстановление по отдельным кликам сошлось с отчётом трекера в 1 704 из 1 704 ячеек «день × кампания». Проверка на 90 днях истории без заглядывания в будущее нашла ошибку: первая версия предлагала остановить главную связку, которая потом принесла 139% прибыли аккаунта. Добавлен предохранитель «связку в плюсе остановить нельзя». Минимум продаж для решения по цене продажи (CPA) поднят с 3 до 8. Правило «худшая зона цен» теперь требует минимум 2 продажи: раньше оно выносило 9 из 17 решений при нуле продаж. Эффект правил на 90 днях — 0,8–1,8% расхода, и отчёт говорит об этом прямо. 49 тестов, ежедневный отчёт в Telegram. Карточки бота считают решение тем же движком и показывают его причину.

Бот аналитики и хранилище. Профили Meta добавляются и переключаются прямо из чата. Токен проверяется и сразу удаляется из переписки. Пауза и запуск кампаний работают под любым из токенов пользователя. Если запрос упирается в лимиты Meta, он повторяется с паузами 1, 2 и 5 секунд. Хранилище токенов веб-версии: проверка срока и прав, показ токена после повторного ввода пароля, архив с восстановлением, автоблокировка, журнал устройств входа. Оффер с пустым адресом или адресом-заглушкой создать нельзя: это правило появилось после случая, когда 33 оффера вели на заглушку.

Готовы начать?

Начните с аудита за 5 000 ₽: письменный отчёт и расчёт окупаемости

Расскажу, что автоматизировать в первую очередь, когда это окупится и нужен ли вашей задаче ИИ вообще. Иногда он не нужен.

Или просто задайте вопрос. В рабочее время отвечаю в течение 2 часов