Как работает бот — схемы процессов

Документ для Дениса. Семь схем — как бот находит дела, следит за ними и готовит рассылку. Без кода, простым языком. Текстовое описание каждого шага — в АЛГОРИТМ.md; здесь то же самое, но картинками.

Цвета на схемах: - 🔵 синий — вход / начало - 🟡 жёлтый — развилка (бот принимает решение) - 🟢 зелёный — дело движется дальше / лид - ⚪ серый — дело отсеяно - 🟣 бирюзовый — уведомление тебе в Telegram - ⬜ пунктир — ещё не запущено (в работе / план)


0. Общая картина

Бот работает в двух режимах одновременно: Discovery (раз в сутки ищет новые дела) и Monitor (каждые 15 минут следит за отобранными). Дальше из дел рождаются лиды для рассылки.

flowchart LR
    CB[("casebook.ru<br/>новые дела за сутки")]:::start
    KAD[("kad.arbitr.ru<br/>каждые 15 минут")]:::start
    CB --> DISC[Discovery<br/>отбор по выручке]:::decision
    DISC --> W[В мониторинге<br/>watching]:::good
    W --> MON[Monitor<br/>следим за судом]:::decision
    KAD --> MON
    MON --> ALERT[Telegram-алерт]:::alert
    MON --> OBEZ[Обездвижка<br/>слабый заявитель]:::good
    MON --> RET[Возврат заявления]:::good
    OBEZ --> RASS[Рассылка писем<br/>помощь заявителю]:::planned
    RET --> RASS
    classDef start fill:#dbeafe,stroke:#60a5fa,color:#1e3a5f
    classDef decision fill:#fef3c7,stroke:#fbbf24,color:#78350f
    classDef good fill:#dcfce7,stroke:#4ade80,color:#14532d
    classDef skip fill:#f1f5f9,stroke:#cbd5e1,color:#475569
    classDef alert fill:#ccfbf1,stroke:#2dd4bf,color:#134e4a
    classDef planned fill:#f5f3ff,stroke:#c4b5fd,color:#4c1d95,stroke-dasharray: 5 5

1. Discovery — поиск новых дел (раз в сутки)

Каждое утро бот забирает из casebook все вчерашние заявления о банкротстве юрлиц, проверяет ИНН и отсеивает мелкие компании. Проходят только крупные — их и берём в мониторинг.

flowchart TD
    A[("casebook: все банкротства<br/>юрлиц за вчера")]:::start --> B{ИНН должника<br/>корректный?}:::decision
    B -->|"мусорный ИНН"| S1[Отсеять:<br/>невалидный ИНН]:::skip
    B -->|"12 цифр — физлицо/ИП"| S2[Отсеять:<br/>физлицо]:::skip
    B -->|"да, юрлицо"| C{Достаточно<br/>крупная?}:::decision
    C -->|"выручка ≥ 300 млн ₽<br/>ИЛИ активы ≥ 1 млрд ₽"| W[В мониторинг<br/>watching]:::good
    C -->|"меньше порога"| S3[Отсеять:<br/>низкие показатели]:::skip
    C -.->|"«живой» гейт<br/>(готов, ждёт включения)"| U{"3 условия:<br/>работает + нужная форма +<br/>выручка ≥ 300 млн ИЛИ активы ≥ 1 млрд<br/>(по свежим данным bo.nalog)"}:::planned
    U -.->|"всё совпало"| W
    U -.->|"нет"| S4[Отсеять:<br/>не прошла по живым данным]:::skip
    classDef start fill:#dbeafe,stroke:#60a5fa,color:#1e3a5f
    classDef decision fill:#fef3c7,stroke:#fbbf24,color:#78350f
    classDef good fill:#dcfce7,stroke:#4ade80,color:#14532d
    classDef skip fill:#f1f5f9,stroke:#cbd5e1,color:#475569
    classDef planned fill:#f5f3ff,stroke:#c4b5fd,color:#4c1d95,stroke-dasharray: 5 5

Сейчас: по умолчанию работает классический фильтр — проходит, если выручка ≥ 300 млн ₽ ИЛИ активы ≥ 1 млрд ₽ (берёт свежие цифры из bo.nalog, где они есть, иначе локальную налоговую базу). «Живой» гейт (пунктир) дополнительно проверяет, что компания действующая и нужной организационно-правовой формы, и квалифицирует строго по свежим данным. Он готов; включим после ретро-проверки уже отобранных дел, чтобы не выкинуть нужное вслепую.


2. Monitor — слежка за делом (каждые 15 минут)

Бот обходит дела в мониторинге и смотрит, что суд сделал с заявлением. Частота зависит от возраста дела — свежие проверяем чаще, старые реже.

flowchart TD
    W[Дело в мониторинге]:::good --> AGE{Возраст дела}:::decision
    AGE -->|"0–3 дня"| WAIT[Ждём,<br/>суд ещё не вынес]:::skip
    AGE -->|"3–7 дней"| CARD
    AGE -->|"7–15 дней"| CARD
    AGE -->|"15–30 дней"| CARD
    AGE -->|"30+ дней без движения"| STALE[Снять с слежки<br/>stale]:::skip
    CARD[Открыть карточку<br/>kad.arbitr]:::decision --> GHOST{"Страница<br/>не найдена?"}:::decision
    GHOST -->|"да — дело объединили"| LINK[Привязать к<br/>головному делу]:::skip
    GHOST -->|"нет"| ACT{Последний акт<br/>суда?}:::decision
    ACT -->|"принятие"| SRO[Извлечь СРО → §3]:::alert
    ACT -->|"оставление<br/>без движения"| OB[Обездвижка → §4<br/>дело остаётся в слежке]:::good
    ACT -->|"возврат"| RT[10-дневное окно → §5<br/>дело остаётся в слежке]:::good
    ACT -->|"прекращение / отказ"| REJ[Закрыть дело<br/>rejected]:::skip
    classDef good fill:#dcfce7,stroke:#4ade80,color:#14532d
    classDef decision fill:#fef3c7,stroke:#fbbf24,color:#78350f
    classDef skip fill:#f1f5f9,stroke:#cbd5e1,color:#475569
    classDef alert fill:#ccfbf1,stroke:#2dd4bf,color:#134e4a

3. Алерт о принятии — извлечение СРО

Когда суд принял заявление, бот скачивает определение и ищет в нём название СРО. От того, какая СРО (или её нет) — зависит, придёт ли тебе алерт.

flowchart TD
    A[Определение о принятии]:::good --> B[Скачать PDF]:::decision
    B --> C[Метод 1: словарь<br/>73 известных СРО]:::decision
    C -->|"не нашёл"| D[Метод 2: общий шаблон<br/>«СРО «...»»]:::decision
    D -->|"не нашёл"| E[Метод 3: ИИ читает PDF]:::decision
    C --> R{Какая СРО?}:::decision
    D --> R
    E --> R
    R -->|"наша — ЦФОП АПК"| T1[Telegram:<br/>ЦЕЛЕВОЙ алерт]:::alert
    R -->|"СРО не указана<br/>(суд адресует всем)"| T2[Telegram:<br/>«случайная выборка»]:::alert
    R -->|"любая другая СРО"| S[Тихо отметить,<br/>не беспокоить]:::skip
    classDef good fill:#dcfce7,stroke:#4ade80,color:#14532d
    classDef decision fill:#fef3c7,stroke:#fbbf24,color:#78350f
    classDef skip fill:#f1f5f9,stroke:#cbd5e1,color:#475569
    classDef alert fill:#ccfbf1,stroke:#2dd4bf,color:#134e4a

4. Обездвижка — слабый заявитель → будущее письмо

«Оставление без движения» значит, что у заявителя недочёты в заявлении. Это потенциальный клиент: ему можно предложить помощь. Бот ловит каждое такое определение, определяет причину (основание), а дальше готовится письмо.

flowchart TD
    A[Определение об оставлении<br/>без движения]:::good --> G{Это правда обездвижка,<br/>не отложение?}:::decision
    G -->|"нет"| X[Пропустить]:::skip
    G -->|"да"| SAVE[Сохранить КАЖДУЮ обездвижку<br/>во вкладку «Обездвижка»]:::good
    SAVE --> REASON[Пометить основание<br/>причину обездвижки]:::good
    REASON -.-> CAL[/"Сейчас: калибруем точную разметку<br/>по 5 основаниям Дениса —<br/>прогнали 100 дел, размечаем вместе"/]:::planned
    CAL -.-> R1[Госпошлина]:::planned
    CAL -.-> R2["Форма / содержание / приложения"]:::planned
    CAL -.-> R3[Нет публикации на ЕФРСБ]:::planned
    CAL -.-> R4[Не направлена копия]:::planned
    CAL -.-> R5[Нет депозита суда]:::planned
    R1 -.-> LET[Шаблон письма под<br/>основание + тип заявителя]:::planned
    R2 -.-> LET
    R3 -.-> LET
    R4 -.-> LET
    R5 -.-> LET
    LET -.-> OUT[В рассылку → §7]:::planned
    classDef good fill:#dcfce7,stroke:#4ade80,color:#14532d
    classDef decision fill:#fef3c7,stroke:#fbbf24,color:#78350f
    classDef skip fill:#f1f5f9,stroke:#cbd5e1,color:#475569
    classDef planned fill:#f5f3ff,stroke:#c4b5fd,color:#4c1d95,stroke-dasharray: 5 5

Где мы сейчас: бот уже ловит все обездвижки и проставляет основание. Идёт калибровка — прогнали 100 определений, ты с нами размечаешь правильность, по итогам донастраиваем. Следующий шаг (пунктир) — шаблоны писем под каждое основание (должник по ст. 37 / кредитор по ст. 39 — письма разные) и автоподготовка рассылки.


5. Возврат — 10-дневное окно

Если суд вернул одно из заявлений, дело может быть ещё живо (другие кредиторы могли подать свои). Поэтому бот не закрывает дело сразу, а ждёт 10 дней.

flowchart TD
    A[Определение о возврате]:::good --> B[Не закрываем сразу.<br/>Ставим окно 10 дней,<br/>дело остаётся в слежке]:::good
    B --> C[Проверяем каждые 12 часов]:::decision
    C --> D{Что произошло<br/>за 10 дней?}:::decision
    D -->|"новое принятие"| E[Перевести в notified<br/>дело живо]:::alert
    D -->|"новая обездвижка"| F[Зафиксировать обездвижку → §4]:::good
    D -->|"прекращение / отказ"| G[Закрыть, rejected]:::skip
    D -->|"ничего за 10 дней"| H[Финал: возвращено<br/>returned → лид на помощь]:::good
    H -.-> OUT[В рассылку → §7]:::planned
    B --> CHIP["На вкладке «Возвраты» помечаем<br/>формулировки: подсудность · ст.7 ·<br/>30 дней · публикация · 15 дней"]:::good
    classDef good fill:#dcfce7,stroke:#4ade80,color:#14532d
    classDef decision fill:#fef3c7,stroke:#fbbf24,color:#78350f
    classDef skip fill:#f1f5f9,stroke:#cbd5e1,color:#475569
    classDef alert fill:#ccfbf1,stroke:#2dd4bf,color:#134e4a
    classDef planned fill:#f5f3ff,stroke:#c4b5fd,color:#4c1d95,stroke-dasharray: 5 5

6. Заявители — несколько заявителей в одном деле (план)

Твоя идея: в одном деле несколько заявителей, у каждого свой акт суда, и каждый — отдельный лид. Сейчас бот видит дело как «один должник — один заявитель». Эта схема — то, что мы проектируем (тикет #313).

flowchart TD
    A[Дело в банкротстве]:::start -.-> B[Заявитель 1]:::planned
    A -.-> C[Заявитель 2]:::planned
    A -.-> D[Заявитель 3 ...]:::planned
    B -.-> B1{Статус<br/>заявителя?}:::planned
    C -.-> C1{Статус<br/>заявителя?}:::planned
    D -.-> D1{Статус<br/>заявителя?}:::planned
    B1 -.->|"обездвижен"| L1[Лид: помощь<br/>по обездвижу]:::planned
    C1 -.->|"возвращён"| L2[Лид: помощь<br/>по возврату]:::planned
    D1 -.->|"принят"| L3[Процедура пошла,<br/>не лид]:::skip
    B1 -.->|"пока никого не приняли"| POLL["Опрашивать 2–3 раза в неделю:<br/>новые заявители + статусы"]:::planned
    L1 -.-> OUT[В рассылку → §7]:::planned
    L2 -.-> OUT
    classDef start fill:#dbeafe,stroke:#60a5fa,color:#1e3a5f
    classDef skip fill:#f1f5f9,stroke:#cbd5e1,color:#475569
    classDef planned fill:#f5f3ff,stroke:#c4b5fd,color:#4c1d95,stroke-dasharray: 5 5

Статус: проектируем. Нужно от тебя: как опознавать заявителя (по ИНН?), какие статусы считаем лидом, как часто опрашивать. По этому — отдельный разбор.


7. Рассылка — от лида до письма

Лиды (обездвижка и возвраты) превращаются в письма. Сначала находим контакты, проверяем почты, потом шлём волнами. Пока ничего не отправляется — стоят два стоп-крана, ждём твои тексты писем.

flowchart TD
    A[Лиды: обездвижка + возвраты]:::good --> B[Найти контакты компании<br/>почты и телефоны]:::decision
    B --> C[Проверить почты:<br/>живые / битые]:::decision
    C --> D{Тип домена?}:::decision
    D -->|"корпоративный"| W1[Волна 1:<br/>корп-почты]:::good
    D -->|"бесплатный (mail/yandex)"| W2[Волна 2:<br/>через 5 дней]:::good
    W1 --> G{Стоп-краны}:::decision
    W2 --> G
    G -->|"🔴 источники WHERE 1=0"| STOP1[Кандидатов нет]:::skip
    G -->|"🔴 общий выключатель OFF"| STOP2[Отправка заблокирована]:::skip
    G -.->|"когда включим"| SEND[Отправка через Smartlead]:::planned
    classDef good fill:#dcfce7,stroke:#4ade80,color:#14532d
    classDef decision fill:#fef3c7,stroke:#fbbf24,color:#78350f
    classDef skip fill:#f1f5f9,stroke:#cbd5e1,color:#475569
    classDef planned fill:#f5f3ff,stroke:#c4b5fd,color:#4c1d95,stroke-dasharray: 5 5

Что готово: поиск контактов, проверка почт, волновая логика, лендинг и почтовый ящик. Что держит: (1) тексты писем под каждое основание — за тобой; (2) предикаты источников и общий выключатель отправки — включаем вместе, когда тексты готовы. Цель — первая рассылка ~15 июня.


Что нужно от тебя (короткий список)

Для чего Что нужно
§4 Письма Тексты под каждое из 5 оснований (должник / кредитор)
§4 Калибровка Разметить грейд-лист на 100 обездвижках
§6 Заявители Алгоритм: как опознавать, какие статусы — лид, частота опроса
§1 Выручка Границы тиров (упоминал 900 млн – 1,155 млрд)
§7 Рассылка Подтвердить тексты → снимаем стоп-краны

Текстовая версия со всеми деталями и глоссарием — в АЛГОРИТМ.md.