Логування подій hiring-бота
src/stack/components/user/StackHiringBot/hiring-bot-event.repository.ts · таблиця ClickHouse hiring_bot_events
Кожен крок проходження кандидатом анкети в @BeSocialHR_bot фіксується як рядок у ClickHouse. Це основа для аналітики.
Таблиця
Партиціонується по місяцях, TTL — 2 роки. Сортування по (date, user_id, timestamp).
| Поле | Тип | Опис |
|---|---|---|
timestamp | DateTime | UTC, формат YYYY-MM-DD HH:MM:SS |
date | Date | похідна від timestamp, для партиціонування і фільтрів по діапазону |
user_id | String | MongoDB ObjectId кандидата |
step_id | LowCardinality | крок анкети або lifecycle-маркер (start, lead_submit) |
event_type | LowCardinality | тип події (div. нижче) |
platform | LowCardinality | ios / android / desktop / '' |
platform_raw | String | сирий userAgent (лише в події start) |
error_type | LowCardinality | категорія помилки (лише в події error) |
utm_source/medium/campaign/content/manager/account | String/LowCardinality | UTM-мітки (лише в start і lead_submit) |
Типи подій
event_type | Коли фіксується | Що означає |
|---|---|---|
start | новий кандидат запустив бота вперше (/start) | точка входу у воронку; несе UTM і платформу |
bot_message_sent | бот надіслав питання | кандидат отримав крок |
user_reply_received | кандидат відповів на питання | кандидат пройшов крок |
lead_submit | кандидат завершив анкету (здав номер телефону) | точка конверсії; несе ті ж UTM/платформу що і start |
error | технічна помилка на кроці | виключається з усіх метрик воронки і трафіку |
Які кроки логуються
step_id для подій bot_message_sent / user_reply_received — це ключ питання анкети. Логуються не всі питання, лише ті що релевантні для аналітики воронки:
name → age → vacancy → experience → devices → employmentType → workShift → voiceCommunication → salaryInfo → about → phoneNumber
Для lifecycle-подій step_id збігається з event_type: start і lead_submit.
Якщо в
navigationHandlersдодається або прибирається питання — список логованих кроків теж потрібно синхронізувати (константаLoggedCandidateQuestionKeyу репозиторії).
Послідовність подій для одного кандидата
start
→ bot_message_sent (name)
→ user_reply_received (name)
→ bot_message_sent (age)
→ user_reply_received (age)
→ ...
→ bot_message_sent (phoneNumber)
→ user_reply_received (phoneNumber)
lead_submit
Кандидат що не відповідає на запитання на devices матиме bot_message_sent (devices) але не матиме user_reply_received (devices) — це і є drop-off на цьому кроці.
Де і коли пишуться події
start — одразу після створення нового кандидата в базі (перший /start). При повторному /start (перезапуск анкети) подія start не дублюється.
bot_message_sent — після того як бот відправив питання кандидату. Викликається для кожного питання окремо.
user_reply_received — після відповіді кандидата.
lead_submit — коли кандидат надав номер телефону і анкета повністю заповнена. UTM беруться з поля candidate.utm — тих самих що записались при start.
error — фіксується у трьох точках:
- у
catch-блоці основного обробникаmessagesFromHiringBot:api_fail(якщо впав Telegram API) абоcrm_error(решта);step_id=currentQuestionкандидата. - у хелпері
handleTelegramError(глобальний catch telegraf-обробників): та сама класифікація. - при невалідній відповіді на питання:
input_error;step_id= поточне питання.
Категорії помилок
error_type | Коли |
|---|---|
api_fail | помилка Telegram API (мережа, rate limit, невалідний токен) |
crm_error | помилка нашої логіки (БД, бізнес-правила, непередбачений стан) |
input_error | кандидат ввів невалідне значення, яке не пройшло валідацію |
timeout | тип зарезервований; поки що не використовується |
Нюанси
-
UTM і платформа — тільки в
startіlead_submit. Дляbot_message_sent/user_reply_receivedв полеutm_*іplatformзаписується порожній рядок. При аналітичних запитах з UTM-фільтром спочатку знаходять множинуuser_idза умовоюstep_id='start' AND utm_*=..., потім до неї приєднуються всі інші події цих юзерів. -
Платформа визначається на сервері за userAgent-рядком.
ios— якщо UA міститьiPad/iPhone/iPod,android— якщоandroid, інакшеdesktop. -
event_type='error'виключається з усіх воронкових метрик. Запити по воронці, часу відповіді і трафіку явно фільтруютьevent_type != 'error'або вибирають тільки конкретніevent_type.