Новая метрика подписок сократила время реакции на отток с недель до дней
Контекст и роль
У команды была общая цифра выручки по подпискам, но не было способа быстро понять, за счёт чего она меняется — новых подписок, апгрейдов, даунгрейдов или отмен. Я спроектировала метрику и витрину данных поверх событий подписок и научила команду читать её самостоятельно.
Почему это было нетривиально
События подписок приходили вперемешку, без готовой агрегации, и разные тарифы вели себя по-разному: отмена на бесплатном тарифе значит одно, а на платном — совсем другое. Нужна была метрика, которая не усредняет эти случаи в одну бессмысленную цифру.
Что я сделала
Свела события в единую таблицу и построила несколько срезов: динамику по месяцам и тарифам, а также долю активных пользователей на каждом тарифе. Ниже — живая SQL-ячейка с той же структурой данных: можно запустить готовый запрос или написать свой.
Интерактивный блок
Результат
Витрина показала, что всплеск отмен целиком пришёлся на бесплатный тариф и не затронул платных пользователей: без разбивки по тарифам это выглядело бы как общий тревожный сигнал. Команда стала регулярно проверять этот срез вместо разбора инцидента постфактум.
Что бы я сделала иначе
Я бы сразу договорилась с командой о едином определении «активного» пользователя — в первые недели обсуждение метрики сводилось к спору о деталях этого определения, а не к содержательным выводам.
Ограничения
Витрина считает «активность» по каждому событию отдельно, а не по устойчивому состоянию пользователя между событиями, поэтому в границах одного периода пользователь может одновременно попасть и в активные, и в отменившие. Витрина также не учитывает пользователей, сменивших тариф в середине периода: такое событие попадает в тариф, в котором произошло само действие, а не в тариф, на котором пользователь провёл больше времени. Причины отмены в событиях не фиксируются, поэтому витрина показывает, что изменилось, но не объясняет почему.
Технические детали
Метрика строится на таблице subscription_events с полями user_id,event_type, event_ts, plan_tier и is_active. Определение доли отмен по тарифу и месяцу:
SELECT plan_tier,
strftime('%Y-%m', event_ts) AS month,
SUM(CASE WHEN event_type = 'cancel' THEN 1 ELSE 0 END) AS cancels,
COUNT(DISTINCT user_id) AS active_users
FROM subscription_events
WHERE is_active = 1 OR event_type = 'cancel'
GROUP BY plan_tier, month
ORDER BY month, plan_tier;Перед тем как доверять срезу, проверялись: что каждое значение event_type входит в ожидаемый набор, что у отменённой подписки не появляется более позднее событие с тем жеuser_id и тарифом без промежуточного renew, и что сумма событий по тарифам совпадает с общим количеством строк в таблице.