← усі кейси
Виробник і роздріб продуктів здорового харчування E-commerce / FoodTech ·

Дзеркало бази замовлень: коли кожна нова автоматизація впирається в ту саму стелю

Кожна нова автоматизація конкурувала зі старими за доступ до даних, а зріз по каналах збирався пів дня руками. Власна копія бази замовлень зняла цю стелю: тепер дані належать бізнесу, і рахувати по них можна скільки завгодно.

  • 56 665 замовлень у власній копії, медіанне відставання від CRM - близько 2 хвилин
  • Ліміт 2 000 звернень на добу перестав бути межею: сервіси й аналітику годує локальна база
  • Зріз по 12 каналах рахується за секунди замість пів дня ручних вивантажень: 4 396 виконаних замовлень за 30 днів при середньому чеку 1 062 грн, із порівнянням до попереднього періоду
  • Знайдено три викривлення в обліку, невидимі в самій CRM: канал без перевізника, канал із нульовою атрибуцією і підозра на подвійний облік
Python 3.12FastAPIasyncpgAPSchedulerPostgreSQL 16Docker ComposeTraefik

Спочатку це виглядає як дрібниця. Ви хочете, щоб система раз на хвилину дивилась у CRM: чи не зʼявилось нове замовлення, чи не змінився статус. Через тиждень CRM починає відповідати помилками - і не тому, що вона погана, а тому, що в неї є ліміт звернень на добу, і ви його вибрали.

З цього моменту кожна нова автоматизація конкурує зі старими за право спитати. Аналітика конкурує з ботом, бот - зі звіркою платежів. А на просте питання «скільки ми продали за минулий місяць у розрізі каналів» ніхто в компанії не відповідає швидше ніж за пів дня ручних вивантажень.

Ми зняли цю стелю: підняли власну копію бази замовлень, яка наповнюється сама і в яку можна дивитись скільки завгодно.

56 665
замовлень у власній копії
12
каналів продажу в одному зрізі
секунди
на звіт замість пів дня ручних вивантажень

Проблема: дані є, а взяти їх не можна

CRM віддає замовлення назовні з трьома лімітами одночасно: на хвилину, на годину і на добу. Регулярне опитування раз на хвилину зʼїдає майже три чверті добового ліміту, ще нічого корисного не зробивши.

Далі починається неприємне. При вичерпанні ліміту система відповідає не «зачекайте», а звичайною помилкою запиту. Тобто ваш сервіс не розуміє, що його притримали - він вважає, що зламався.

Три причини, чому «просто ходити в CRM» не працює

Ліміт один на всіх

  • кожен новий сервіс відбирає звернення в попередніх
  • кількість автоматизацій обмежена не потребою, а квотою

Глибина вибірки

  • історію за рік не вивантажити одним запитом
  • на великій сторінці вибірка просто ламається

Немає довідників

  • у даних лише номери статусів, каналів і менеджерів
  • назв немає ніде, розшифровка збирається руками

Як автоматизація це вирішує

Замість того щоб питати CRM щоразу, ми тримаємо її копію в себе. CRM сама повідомляє про кожну подію, а окремий процес регулярно звіряє, чи нічого не загубилось. Усі інші системи працюють уже з копією - і не бачать жодних лімітів.

Наповнення копії і доступ до неї
Подія в CRM сповіщення про подію звірка за розкладом локальна копія
Схема-контракт роль лише на читання звіти інші сервіси

Ключова ідея: сповіщенням не можна вірити на слово

Найнесподіваніше в цьому кейсі виявилось не там, де його чекали. Ми перевірили, звідки насправді приїхали записи в копії: переважну більшість принесли не миттєві сповіщення про подію, а планова звірка.

Формально сповіщення працювали: приходили, оброблялись, не давали помилок. Фактично потік тримала звірка. Якби ми побудували систему тільки на сповіщеннях і не додали другий механізм, вона виглядала б справною і мовчки втрачала дані.

Що дістається людям

Поверх копії зріз за 30 і за 7 днів рахується будь-коли й будь-ким: кількість замовлень і середній чек по всіх каналах разом і по кожному окремо, з порівнянням до попереднього рівного періоду. Порахований зріз зберігається і потім не перераховується, тому вчорашня цифра завтра лишається такою самою.

Про сам ранковий звіт власнику в нас є окремий кейс; цей - про шар даних, без якого його неможливо порахувати.

Що це дало бізнесу

Найочевидніше: аналітику стало можливо будувати взагалі. Тридцятиденний зріз - 4 396 виконаних замовлень при середньому чеку 1 062 грн, і поруч той самий набір за попередні 30 днів. Це рахується за секунди і не забирає жодного звернення в бота чи звірки платежів.

Менш очевидне: копія показала те, чого не видно в інтерфейсі CRM.

Три знахідки, які змінили методику розрахунку
ДоставкаРоздрібні точки майже ніколи не мають перевізника - 1 005 замовлень із 1 013 за чотири місяці. Будь-яка метрика доставки, порахована «по всіх», занижена на тисячу замовлень
АтрибуціяКанал, який у списку CRM існує, за всю історію має нуль замовлень. Тобто трафік із нього приписується комусь іншому
ОблікВ одного каналу середній чек упʼятеро вищий за решту при 16 позиціях у замовленні. Схоже не на продаж, а на відвантаження в точку, тобто на подвійний облік. Питання винесене власнику, до відповіді нічого не міняємо

Чого система не робить. Вона не пише в CRM і не виправляє дані. Це свідомо: копія тільки читає. Виправляти облік мають ті, хто ним володіє, а наше завдання - показати розбіжність, а не приховати її зручним запитом.

Як це влаштовано всередині

Далі - інженерна частина

Наступний розділ пояснює, як система влаштована. Якщо вас цікавить лише результат, його можна пропустити - нижче є розділ про те, кому це підходить.

Два джерела, одна таблиця. Копію наповнюють вебхуки з CRM і плановий полінг за розкладом; обидва пишуть в одну таблицю з захистом від повторної вставки. Саме тому втрата окремого вебхука не означає втрату запису - його приносить наступний прохід звірки.

Копія не віддає сиру базу нікому. Для споживачів зроблена окрема схема-контракт: у ній лежать матеріалізовані представлення з уже обчисленими ознаками - виконане, втрачене, термінальне - і окрема роль тільки на читання з обмеженням часу запиту й кількості зʼєднань. Наслідок: власник копії може міняти внутрішню структуру, не ламаючи споживачів, а важкий запит споживача не покладе базу.

Три рішення в розрахунку, без яких числа були б неправильні
СтатусиОзнака «виконане» - це тип статусу, а не список номерів. Список довелося б правити щоразу, коли в CRM зʼявиться новий статус. Тип приїжджає з довідника сам
ДатаРахуємо за датою закриття замовлення. Журнал змін статусів у копії почався пізніше, ніж потрібно для порівняння періодів, тому по ньому попередній період був би порожній. Дата закриття заповнена у всіх виконаних замовлень і збігається з подією зміни статусу в 99,8% випадків - це перевірено, а не припущено
Середній чекРахується як сума, поділена на кількість. У штатної функції бази результат відрізнявся на дві гривні: в одного замовлення сума порожня, і функція просто не рахувала його в знаменнику

Для сервісів, які живуть поверх копії, зроблений захисний шар: модель даних ігнорує невідомі поля, відповіді кешуються на 45 секунд, а три невдачі поспіль вмикають хвилину тиші замість шторму повторів. Контрактний тест ганяється власником копії перед кожним оновленням - щоб зміна в джерелі не ламала споживачів мовчки.

Кому це підходить

Усім, у кого понад одну автоматизацію поверх однієї CRM або обліковки. І особливо тим, хто вже чув від розробників «нам не дає API, треба тарифом вище».

Як зрозуміти, що це про вас: якщо ви не можете відповісти на питання «скільки замовлень ми зробили за минулий місяць у розрізі каналів» швидше ніж за пів дня вивантажень - дані у вас є, а доступу до них немає.

Поки дані живуть тільки в чужій системі, стеля у вас не своя. Ви будете підганяти під неї всі свої плани - доки не піднімете дані до себе.

Потрібне схоже рішення?

Опишіть задачу - підберу архітектуру під ваш бюджет і дані.