Один экран с реальной экономикой SKU, движением денег из Finance API и алертами в Telegram - и в первые 24 часа всплыли: топ-1 артикул с 39% выручки и нулевым остатком, ~1.2 млн ₽ замороженного капитала в 6 неработающих SKU, реклама со сливом 13 тысяч ₽ в месяц при ROAS 0.47.
Клиент - селлер вафельных пледов на Озоне. 45 SKU, продажи только-только пошли, в Seller-кабинете - стандартные графики «выручка по дням», но решений по ним принимать неудобно: товарных карточек много, цвета и размеры перемешаны, какие тянут выручку, какие стоят мёртвым грузом - не видно. Запрос был простой: «хочу один экран, где видно деньги».
Собрал. И прямо в первые сутки этот экран показал такие вещи, ради которых дашборды и нужны.
Подняли FastAPI-сервис, который каждые 30 минут тянет данные из четырёх Озон-API в локальную SQLite:
На главной - 8 KPI-плиток с реальной экономикой. Дальше блоки:
Под каждый артикул - своя страница: фото, экономика юнита (цена - комиссия - эквайринг - себестоимость = прибыль), маржа, графики продаж за 90 дней, география заказов, история поставок, возвраты по этому SKU.
Себестоимость вбивается прямо в таблице товаров - и сразу пересчитывается прибыль с штуки, прибыль за 30 дней и через сколько дней закончится текущий остаток.
И ключевое - алерты в Telegram: новый заказ, новый возврат, SKU упал ниже 5 штук. Без дедупликации алерты бы захлёбывались, поэтому состояние пишется в отдельную таблицу alert_state - повторы режутся, при первом запуске бот молча запоминает baseline.
За первые 6 дней живых продаж - 57 заказов, выручка 107 104 ₽. И когда эти цифры легли в один экран, открылись четыре истории сразу.
| SKU | Заказов | Выручка | Доля |
|---|---|---|---|
| Брусника 220×170 | 28 | 42 000 ₽ | 39% |
| Тёмно-серый 220×170 | 10 | 23 564 ₽ | 22% |
| Капучино 220×170 | 9 | 18 000 ₽ | 17% |
| Светло-серый 220×170 | 6 | 13 332 ₽ | 12% |
Топ-1 = 39%, топ-3 = 78%, топ-4 = 90% всей выручки. Все топовые - один размер 220×170. И именно у Брусники 220×170 темп 4-5 штук в день, остаток на складе - ноль, в ближайшей поставке - нет.
Каждый день простоя - ~7 500 ₽ упущенной выручки. Это первое, что показал дашборд при запуске, и первое, что ушло в работу: экстренная допоставка минимум +50 штук Брусники.
«Зависшими» дашборд считает SKU с активным остатком и нулём продаж за 30 дней. На дату аудита таких было 6:
Плюс ещё 31 SKU вообще без истории поставок. Без дашборда такая пустая полка в каталоге легко проживает кварталами - в Seller-кабинете ты её не видишь, пока специально не пойдёшь смотреть карточку.
Решения дашборд тоже подсказал: Шоколад - реактивация (новые фото, скидка), 220×205 - снизить цену до 2 700-2 800 ₽ или выводить из ассортимента и не привозить.
На счёте крутились две кампании одного магазина, обе только что запущенные:
| Кампания | Тип оплаты | ROAS | CPO | Вердикт |
|---|---|---|---|---|
| Продвижение в поиске | CPO (за заказ) | ×10 | 189 ₽ | Отлично, поднять бюджет |
| Тестовая кампания | CPC (за клик) | ×0.47 | 4 647 ₽ | Сливает, выключить |
Разница в стоимости заказа между моделями оплаты - в 25 раз. Для пледов с чеком ~2 000 ₽ CPC оказался экономически невозможным. CPC-кампанию остановили прямо из дашборда одним запросом POST /api/client/campaign/{id}/deactivate - и тут же зафиксировали +12 870 ₽ в месяц чистого денежного потока.
4 из 57 заказов отменены покупателем до отгрузки. Регионы у отмен: Москва, СПб, Калининград, Караганда (Казахстан). Гипотеза, на которую вышли через дашборд - долгая доставка из единственного склада в Ярославле. После роста объёмов смотрим в сторону московского РФЦ.
Самое полезное в Finance API - что он показывает не «начисленную» выручку, а реальные движения денег:
Большая часть выручки ещё «зависла» в отложенных выплатах Озона (товар отгружен, деньги не дошли). После остановки CPC-кампании и при том же темпе продаж прогноз +30-40 тысяч ₽ чистого денежного потока в месяц до себестоимости пледа. С внесённой себестоимостью дашборд считает финальную прибыль автоматически.
Heatmap «день × час» показала кое-что неочевидное:
| Бэкенд | FastAPI + Jinja2, Python 3.11 |
| База | SQLite (для одного селлера хватает с запасом) |
| Графики | Chart.js, heatmap - чистый HTML grid без библиотек |
| Дизайн | Inter, тёмный sidebar 240px, primary #005BFF (в духе Озон-кабинета) |
| Синхронизация | systemd timer каждые 30 минут, 6 API-эндпоинтов |
| Алерты | Telegram-бот с дедупликацией через таблицу состояний |
| Деплой | systemd unit + nginx reverse-proxy + бэкап БД перед каждым fetch |
Дашборд - часть единого хаба из 4 сервисов селлера: дашборд + сервис генерации поставок ГМ + генератор инфографики для карточек + библиотека SEO-текстов карточек. Все четыре - в одном дизайне, переключение через единый sidebar. Селлер не прыгает между разными админками: всё про магазин - в одном месте.
В документации - «не более 1 месяца». На практике запрос за 30 дней (4 апреля - 4 мая) валится с too long period. Лимит «1 месяц» - это 29 дней. Использую ровно now - 29d - всё стабильно.
В разных гайдах ещё попадаются /v3/returns/company/fbo и /v3/returns/company/fbs. Оба отвечают obsolete method cannot be used. Рабочий путь - один: POST /v1/returns/list с пагинацией через filter + limit + last_id + has_next.
Daily-статистика возвращает суммы как строки с запятой: "moneySpent": "2493,49". На бэкенде - .replace(',', '.') перед float(), иначе тихо ловишь ValueError в середине ночного fetch.
"weeklyBudget": "18000000000" - это 18 000 ₽, а не 18 миллиардов. Делитель 1 000 000. Промахнулся - и KPI «бюджет рекламы» показывает миллионы.
Premium-trial (29 апреля - 29 мая) к Reviews API не подпускает: на любой запрос - PermissionDenied: not available with existing subscription. Ждать платного Premium, либо парсер публичных страниц. Пока в дашборде блок отзывов закрыт заглушкой.
За первые сутки после запуска дашборд:
Дашборд - это не «красивая визуализация» и не «отчётность для галочки». Это инструмент, который складывает разрозненные данные так, что решение становится очевидным.
Озон, Wildberries, Яндекс.Маркет - стек один и тот же: тянем API, считаем экономику юнита, прогнозируем остатки, шлём алерты. Срок сборки от 5 до 14 дней в зависимости от количества SKU и набора API.
Написать: @dfedorov86 · сайт: dimafedorov.ru