4 242 товари, 73 категорії, 4 постачальники з автоматичною синхронізацією, AI-генерація описів і SEO-тегів, пошук з толерантністю до помилок, автоматична конвертація зображень у WebP — і все це працює на Django 4.2 з PostgreSQL. Це не навчальний проект і не MVP. Це живий продакшн-магазин airstep.com.ua, який щодня обслуговує реальних покупців.
У цьому кейсі ми розповімо, як команда Artbrain побудувала повноцінну e-commerce платформу з нуля: від кастомної CMS-адмінки до zero-downtime деплою. Розберемо технічні рішення, які зробили цей проект швидким, зручним для менеджера і масштабованим для бізнесу.
Виклик: чому не Shopify, WooCommerce чи Prom.ua
Перше питання, яке ставить бізнес: «А навіщо кастомна розробка, якщо є готові платформи?» У випадку Airstep відповідь була очевидною:
Робота з кількома постачальниками одночасно. Airstep — це не виробник, а ритейлер. Товари надходять від 4 різних постачальників, у кожного свій XML-фід, своя структура даних, свої правила ціноутворення. Жодна коробкова платформа не підтримує такий сценарій із коробки. Потрібна кастомна логіка синхронізації, маппінгу категорій і автоматичної наценки.
Контроль над адмінкою. Стандартні адмінки e-commerce платформ розраховані на один магазин з одним складом. Коли у вас 4 242 товари від 4 постачальників і потрібно масово генерувати описи через AI, конвертувати зображення і синхронізувати залишки — потрібен зовсім інший інтерфейс. Ми побудували CMS-адмінку, яка дозволяє менеджеру керувати всім каталогом з одного місця.
Швидкість і SEO. Магазин на Django — це повний контроль над HTML, CSS і серверною логікою. Ми можемо оптимізувати кожен байт: від Core Web Vitals до структурованих даних. На Shopify чи WooCommerce такий рівень контролю неможливий.
Це саме той випадок, коли кастомна розробка інтернет-магазину — не примха, а бізнес-необхідність. Детальніше про те, чому ми обираємо Django, ми писали в окремій статті.
Архітектура проекту: що під капотом
Технологічний стек: Django 4.2 (LTS) на бекенді, PostgreSQL як основна база даних, Meilisearch для пошуку, vanilla JavaScript на фронтенді (без React — свідомий вибір на користь швидкості), Nginx + Gunicorn на продакшні.
Архітектура побудована за принципом «мінімум залежностей, максимум контролю». Ми не використовуємо Django REST Framework для фронту магазину — він працює на серверному рендерингу з мінімальним JavaScript для інтерактивних елементів (кошик, пошук, фільтри). Це дає блискавичний First Contentful Paint і відмінні показники Core Web Vitals.
Синхронізація з 4 постачальниками: головний виклик проекту
Це серце всієї системи. Чотири постачальники — Villomi, Vzutik, Sollorini та Lor — кожен має власний XML/YML-фід з товарами. Дані оновлюються щодня. Задача: автоматично забирати фіди, парсити товари, завантажувати зображення, розраховувати ціни з наценкою і оновлювати каталог.
Кожен постачальник реалізований як окрема Django management command. Це дозволяє запускати синхронізацію як вручну через адмінку (кнопки «Villomi», «Vzutik», «Sollorini», «Lor» на скріншоті), так і автоматично через cron.
Як працює пайплайн синхронізації
- Завантаження XML-фіда від постачальника
- Парсинг товарів — витягуємо назву, артикул, ціну, розміри, кольори, матеріали, зображення
- Очистка назв — regex видаляє бренди постачальників та артикули з заголовків (бо покупець не повинен бачити внутрішні коди)
- Автоматична наценка — для кожного постачальника налаштовується відсоток наценки через адмінку
- Маппінг категорій — категорії постачальника автоматично зіставляються з категоріями магазину
- Завантаження та конвертація зображень — фото з URL постачальника завантажуються, конвертуються в WebP, зберігаються локально
- Оновлення або створення товарів — якщо товар вже існує (за sync ID), оновлюються ціна, наявність, розміри; якщо новий — створюється
- Управління наявністю — товари, яких більше немає у фіді, автоматично знімаються з публікації
Захист від дублів та зомбі-процесів
Один із підводних каменів — що станеться, якщо менеджер натисне кнопку синхронізації, коли попередня ще не завершилася? Або якщо cron-задача запуститься паралельно з ручним запуском?
Ми реалізували систему PID-файлів. При старті синхронізація створює PID-файл із ID процесу. Перед запуском нової — перевіряється, чи існує PID-файл, і чи жий процес (через /proc/[pid]/status). Якщо процес жий — API повертає 409 Conflict. Якщо PID-файл існує, але процес мертвий (зомбі) — файл видаляється і нова синхронізація стартує нормально.
AI-модуль: генерація описів та SEO-тегів
Одна з найцікавіших фіч проекту. В адмінці вбудований AI-модуль на базі Claude API, який вміє:
- Генерувати описи товарів — на основі назви, матеріалу, кольору та категорії AI створює унікальний HTML-опис з ключовими словами для SEO
- Генерувати мета-теги — title і description для кожного товару, оптимізовані під пошукові запити
- Автоматично перекладати — контент генерується українською з можливістю автоперекладу на англійську
- Пакетна обробка — можна вибрати сотні товарів і прогнати їх через AI за один раз (кнопки «AI опис» та «AI SEO» на скріншоті каталогу)
Все логується в ProductActivityLog — для кожної AI-генерації зберігається дифф (що було до, що стало після). Менеджер завжди може відкотити зміни.
Адмінка: все під контролем менеджера
CMS-адмінка побудована повністю кастомно — це не стандартна Django Admin, а власний інтерфейс із продуманим UX. На скріншоті картки товару видно ключові елементи:
- Двомовність — перемикач «Українська / English» для всіх текстових полів
- AI-генерація — кнопка «AI опис» генерує опис товару одним кліком
- Візуальний вибір розмірів — інтерактивна сітка розмірів замість текстового поля
- Характеристики — колір, матеріал, внутрішнє оздоблення з можливістю додавання нових
- Прозоре ціноутворення — видно ціну постачальника, наценку, акційну ціну. Менеджер бачить повну картину
- Прив'язка до постачальника — ID, артикул постачальника, посилання на товар у системі постачальника
В каталозі (перший скріншот) видно: дерево категорій зліва, список товарів з фото, цінами та статусами наявності. Панель інструментів вгорі — кнопки синхронізації кожного постачальника окремо або всіх разом, пакетний AI, конвертація в WebP, експорт у Google Merchant Feed.
Пошук на Meilisearch: миттєвий і толерантний до помилок
Стандартний SQL-пошук (LIKE або Full Text Search у PostgreSQL) не підходить для e-commerce. Покупець пише «крросівки» замість «кросівки», «замшеві чиревики» замість «замшеві черевики» — і нічого не знаходить. Це втрачені продажі.
Ми інтегрували Meilisearch — пошуковий движок з вбудованою толерантністю до помилок. Як це працює:
- Typo tolerance — «крросівки» знаходить «кросівки», «чиревики» знаходить «черевики»
- Instant search — результати з'являються під час набору тексту, з debounce 200мс
- Фасетна фільтрація — пошук одразу показує кількість товарів по категоріях
- AbortController — якщо користувач продовжує набирати текст, попередній запит автоматично скасовується (не витрачає ресурси)
- Rate limiting — 120 запитів на хвилину з одного IP (захист від зловживань)
Автоматичний пайплайн зображень
Зображення — це найбільша проблема будь-якого магазину. 4 000+ товарів, по 3-5 фото на кожен — це десятки тисяч файлів. У постачальників фото в JPEG різної якості та розміру. Покупцям потрібні оптимізовані WebP для швидкого завантаження.
Ми побудували повністю автоматичний пайплайн:
- Завантаження — фото скачується з URL постачальника
- Ресайз — максимум 1920×1920 пікселів, LANCZOS-ресемплінг (через Pillow)
- Конвертація в WebP — quality 85%, оптимальний баланс розміру і якості
- Запис у БД — шляхи одразу зберігаються як .webp, ніякого рассинхрону між файлами та записами
Є також пакетна конвертація — кнопка «WebP» в адмінці конвертує всі зображення, які ще не в WebP. Використовується пагінація по курсору, щоб не перевантажувати пам'ять при обробці тисяч файлів.
Розумна фільтрація каталогу
Фільтрація — це те, що відрізняє хороший магазин від поганого. У Airstep реалізовано:
- 13 кольорових груп з українськими назвами та ключовими словами. Наприклад, група «бежевий» включає слова «бежев», «айвор», «кремов», «молочн», «капучін». Це означає, що товар «Черевики кольору капучіно» потрапить у фільтр «бежевий» автоматично
- Сезонний буст — демісезонні товари (весна-осінь) піднімаються вище у видачі, бо підходять ширшій аудиторії
- Фільтрація по ціні з округленням до 100 грн (зручніше для користувача)
- Оптимізація на рівні БД — вся логіка фільтрації працює через Django
Case/Whenвиключно на стороні PostgreSQL, без завантаження товарів у Python
Вітрина магазину: що бачить покупець
Фронтенд магазину побудований на серверному рендерингу Django templates з мінімальним JavaScript (vanilla JS, без фреймворків). Це дає:
- Блискавичний First Contentful Paint
- Повний контроль над SEO і структурованими даними
- Мінімальний розмір сторінки
- Повна адаптивність під мобільні пристрої
Кошик реалізований на localStorage — працює навіть офлайн. Коли покупець починає оформлення, але не завершує — дані (телефон, ім'я, email, сума) зберігаються в AbandonedCart. Менеджер бачить кинуті кошики в адмінці і може зв'язатися з клієнтом.
Також є Availability Notifications — якщо товару немає в наявності, покупець може підписатися на сповіщення. Коли товар з'являється після синхронізації — клієнт отримує повідомлення.
Безпека: CSP, HSTS та санітизація контенту
Безпека в e-commerce — це не опція, а обов'язок. Ми реалізували:
- Content Security Policy (CSP) — вайтліст дозволених доменів для скриптів, стилів, зображень. Захист від XSS-атак
- HSTS на рік — браузер запам'ятовує, що сайт працює тільки через HTTPS
- Захист від clickjacking —
frame-ancestors 'none', сайт неможливо вбудувати в iframe - Permissions Policy — відключена геолокація, камера, мікрофон (не потрібні магазину)
- HTML-санітизація через Bleach — тієрові правила: для користувацького контенту (відгуки) жорсткіші обмеження, для адмінського (описи товарів) — ширші
CSS-пайплайн та оптимізація фронтенду
9 CSS-модулів проходять через пайплайн: PostCSS → autoprefixer → PurgeCSS → мініфікація. Результат:
- Dev: ~143 KB → Prod: ~107 KB (мінус 25%)
- PurgeCSS видаляє невикористані стилі, але з safelist на regex для динамічних класів (swiper-*, animate__*, pc-*)
- JS мініфікація через terser
- Nginx gzip_static — пре-стиснуті .gz файли роздаються без витрат CPU на стиснення в реальному часі
- 30-денний immutable кеш для статики — з версійними хешами для cache busting
Zero-downtime деплой
Магазин має бути доступний 24/7 — будь-яка перерва в роботі це втрачені замовлення. Ми налаштували:
- Systemd + Gunicorn з graceful reload (HUP signal) — нові воркери стартують, старі завершують поточні запити
- Auto-restart при крашах — затримка 5 секунд, до 10 рестартів за 5 хвилин
- OOM protection — OOMScoreAdjust=-500, ядро Linux буде вбивати Gunicorn в останню чергу
- Nginx роздає статику напряму, не навантажуючи Django
Аналітика без Google Analytics
Замість стороннього трекінгу ми побудували власну систему аналітики:
- SearchQuery — логування пошукових запитів з нормалізацією. Менеджер бачить, що шукають покупці, і може відмічати «популярні» запити для відображення на головній
- ProductActivityLog — аудит всіх змін товарів з JSON-діффами (хто, коли, що змінив)
- AnalyticsEvent — події view, search, add-to-cart, purchase. Достатньо для розуміння воронки без сторонніх скриптів, які сповільнюють сайт
IndexNow: миттєва індексація змін
При створенні або оновленні товару система автоматично пінгує Bing, Yandex та інші пошуковики через IndexNow API. Батчева відправка до 10 000 URL за один запит. Реалізовано на чистому urllib.request — без зовнішніх залежностей. Подібний підхід ми використовуємо і на інших наших проектах.
Ключові результати
Після запуску платформи Airstep отримав:
Автоматизація замість ручної роботи. Раніше менеджер вручну додавав товари, завантажував фото, писав описи. Тепер синхронізація з 4 постачальниками відбувається автоматично. AI генерує описи. Зображення конвертуються самостійно. Менеджер займається бізнесом, а не рутиною.
4 242 товари в каталозі. З них 3 842 в наявності. 73 категорії. Все синхронізується щодня без участі людини.
Миттєвий пошук. Покупці знаходять товари навіть з помилками в запиті. Конверсія пошуку значно вища, ніж при стандартному SQL-пошуку.
Прозоре ціноутворення. Менеджер бачить ціну постачальника, наценку, акції — все в одному інтерфейсі. Ніяких табличок в Excel.
Zero-downtime. Оновлення коду, синхронізація, AI-генерація — все працює без зупинки магазину.
Подивитися сторінку проекту з технічними деталями можна у нашому портфоліо — кейс Airstep.
Висновок: коли потрібна кастомна e-commerce платформа
Готові платформи (Shopify, WooCommerce, Prom.ua) покривають 80% задач. Але є ситуації, коли вони не підходять:
- Кілька постачальників з різними форматами даних і правилами ціноутворення
- Потреба в AI-автоматизації — генерація контенту, переклади, SEO-оптимізація на масштабі тисяч товарів
- Специфічна бізнес-логіка — наценки по постачальниках, abandoned cart recovery, availability notifications
- Повний контроль над SEO — структуровані дані, Core Web Vitals, мета-теги для кожного товару
- Масштабування без обмежень платформи — ніяких лімітів на товари, категорії чи API-запити
Якщо ви впізнали свою ситуацію — напишіть нам. Ми проведемо безкоштовну консультацію, проаналізуємо ваш бізнес і чесно скажемо, чи потрібна вам кастомна розробка, чи можна обійтися готовим рішенням. Розрахувати орієнтовну вартість можна через наш онлайн-калькулятор.
Детальніше про наші послуги розробки та реалізовані проекти.