# События бота в `bot_events` (для MCP и дашборда кураторов)

Все сообщения уже параллельно записываются через существующий `PlatformApi` в
`bot_messages`: входящие ученика, ответы бота и ручные ответы куратора.

Чтобы MCP и дашборд кураторов могли отдельно получить срочные кейсы, бот создаёт
дополнительную запись в таблице `bot_events` через action `bot_events_create`.

## Типы событий

| Что произошло | `event_type` | Когда пишется | Задача куратору |
|---|---|---|---|
| Учебная/личная проблема (`muammoli`) | `muammoli_oquv` | только если карточка успешно ушла в топик | да |
| Тех. проблема платформы (`muammoli_platforma`) | `muammoli_platforma` | только если карточка успешно ушла в топик | **нет** (решает тех. команда) |
| Вопрос оплаты (`tolov`), в т.ч. скриншот чека | `tolov_masalasi` | только если карточка успешно ушла в топик | да (финотдел) |
| Непонятное обращение (`offtopic`), в т.ч. голосовое | `offtopic` | только если карточка успешно ушла в топик | да |
| Инфо о ребёнке (`farzand`): добавить в группу, ссылка на бота, привести друга | `farzand_haqida_malumot` | только если карточка успешно ушла в топик | да |
| Ученик просит позвонить (метка `[надо позвонить]`) | `call_request` | **всегда**, независимо от Telegram | да |

Имена событий совпадают с названиями топиков в группе менторов — MCP читает все кейсы
единообразно, без разбора текста карточек.

`call_request` различается по МЕТКЕ в тексте, а не по категории: категория `farzand`
несёт разные смыслы (добавить в группу / ссылка на бота / привести друга / позвонить),
и для просьбы позвонить нужен отдельный тип. Метка проверяется ПЕРВОЙ и завершает
разбор, поэтому просьба позвонить пишется как `call_request` **вместо**
`farzand_haqida_malumot`, а не вдобавок к нему (двойных записей нет). Событие по метке
пишется независимо от успеха отправки карточки: задача куратору — самостоятельный
канал, она не должна теряться из-за сбоя Telegram.

Категории с ЗАКРЫТЫМИ топиками (`qoshimcha_dars`, `demo_day`) карточку в группу не шлют,
поэтому событий по ним нет — бот закрывает такие вопросы сам.

## Формат записи

- `chat_id` — Telegram ID ученика, связывает событие со всей перепиской в `bot_messages`;
- `event_type` — один из типов выше;
- `text_info` — **JSON** (UTF-8, без экранирования кириллицы);
- дата создания добавляется API платформы.

```json
{
  "text": "Iltimos qongiroq qiling 901234567",
  "tg_name": "Hasan Aliyev",
  "tg_username": "hasan1235656",
  "owner_username": "Kurator_Marjona",
  "owner_name": "Marjona Pardayeva"
}
```

`text` — исходное сообщение ученика. Любое поле, кроме `text`, может быть `null`.
Для скриншота оплаты без подписи в `text` попадает пометка `[скриншот оплаты без подписи]`,
для голосового оффтопа — расшифровка речи.

У `call_request` метка `[надо позвонить]` из текста срезана. У событий ПО КАТЕГОРИИ текст
может начинаться со служебной метки в квадратных скобках — она уточняет подслучай, её
удобно использовать как под-фильтр:

| Метка в начале `text` | Тип события | Подслучай |
|---|---|---|
| `[надо добавить в группу]` | `farzand_haqida_malumot` | прислал username / не добавили в группу / просит ссылку на группу |
| `[просит ссылку на Farzandim bot]` | `farzand_haqida_malumot` | нужна ссылка на бота успеваемости |
| `[хочет привести друга]` | `farzand_haqida_malumot` | ФИО и телефон друга |
| `[пропал страйк]` | `muammoli_oquv` | сгорел strike |
| `[стало неинтересно]` | `muammoli_oquv` | причина отказа от оплаты — потерял интерес |
| `[проблема с оплатой]` | `tolov_masalasi` | причина отказа от оплаты — финансы |
| `[проблема с бронированием qo'shimcha dars]` | `muammoli_platforma` | не смог забронировать доп. урок |

### Зачем owner и tg_*

`owner_username` — куратор, **которому написал ученик** (владелец Telegram Business
подключения). Дашборд кураторов маршрутизирует задачу именно по нему:
`owner_username` → `gl_sys_users.TG_USERNAME` → `group_list.ADMIN_ID`.
Обратите внимание: в событии username идёт **без `@`**, а в `gl_sys_users.TG_USERNAME`
он хранится **с `@`** — потребителю нужно нормализовать.

Путь «`chat_id` → ученик в LMS → его группа → куратор» использовать как основной нельзя:
на 14.08.2026 из 3977 чатов бота через `bot_registered_students` доводятся до куратора
только 67 (~1.7%). Поэтому куратор берётся из события, а связка с LMS — необязательное
обогащение карточки (ФИО, телефон, группа, ссылка в CRM).

`tg_name` / `tg_username` нужны, чтобы куратор понял, кто к нему обращается, когда
связки с LMS нет: в `bot_messages` поля `USERNAME`/`DISPLAY_NAME` у большинства
учеников пустые.

## Как читать

```sql
SELECT * FROM bot_events
WHERE ID > :cursor
  AND EVENT_TYPE IN ('call_request','muammoli_oquv','muammoli_platforma',
                     'tolov_masalasi','offtopic','farzand_haqida_malumot')
```

Затем по `chat_id` можно получить связанные сообщения из `bot_messages`, включая ответы
бота и куратора. Ошибки Platform API не влияют на работу Telegram-бота: запись
выполняется существующей асинхронной best-effort очередью.

Проверка транспорта — `tools/diag-logging.php` (блок «PATH D»).
