romi

Мультиарендный кабинет маркетолога на Django 5.2: расходы рекламных кабинетов, сделки из CRM и ROMI по каналам. Эксперименты ниже идут на живом сервисе — настоящие Postgres с row-level security, Celery, Redis и вымышленная рекламная сеть, которая ведёт себя как настоящие.

Ключи для API

Две демо-организации и по ключу наблюдателя (viewer: только чтение). В Swagger UI — кнопка Authorize, значение ключа. Всё, что ниже меняет данные, делает сервер сам и только с демо-данными.

Загрузка…

1. Чужие данные по id

Наблюдатель Acme пробует прочитать Globex: по чужому slug в URL и по id чужого проекта под своим slug. Правильный ответ — 404 в обоих случаях, а не 403: ответ не должен подтверждать, что такой slug или id существует. Последняя строка — контроль: владелец тех же данных тем же запросом получает 200, значит 404 выше — не опечатка в URL.

2. Отчёт: два запроса при любом размере

Расход, лиды, продажи, выручка и ROMI проекта Acme за 30 дней. Расходы и сделки агрегируются отдельно: один JOIN двух таблиц фактов умножил бы обе суммы. Повторный запрос приходит из кэша, пока данные не изменятся.

3. Вебхук CRM: дважды и не по порядку

Сервер шлёт в собственный вебхук одну сделку четырьмя подписанными (HMAC) событиями: заявку, ту же доставку повторно (CRM решила, что мы не ответили), выигрыш — и опоздавшее событие из прошлого. Повтор должен быть подтверждён и выброшен, опоздавший «open» не должен отменить «won». Отчёт после этого обязан пересчитаться, а не прийти из кэша.

4. Импорт: площадка правит прошлое

Рекламная сеть неделями правит прошлые дни: возвращает деньги за скликивание, убирает строки. Импорт каждый раз перечитывает окно в 21 день и заменяет его: исправленное перезаписывается, пропавшее удаляется. Кнопка просит сеть поправить прошлое и ставит импорт в очередь Celery; ниже — его запуск, как его видит API.