Воронка найма: hiring_project
Для разработчиков. Состояние на 28.09.2026. Переменные, все ручки, порядок выкатки и отката — README и RUNBOOK репозитория Buharestskie/hiring_project.
Коротко
hiring_project — воронка найма менеджеров по продажам («охотников») для самой компании: от входа кандидата на сайт до выхода на обучение. Кандидат входит через Telegram, VK или MAX, заполняет анкету и записывает голосовой ответ. Голос оценивает Gemini, решение принимает РОП прямо в Google Sheet, дальше кандидату приходит сообщение в мессенджер, приглашение на групповое собеседование в Телемосте и ссылка на онлайн-обучение. В amoCRM кандидат попадает только после собеседования.
Сейчас сервис на наших серверах не развёрнут: проект передан новому владельцу и ждёт переезда. Домен hiring.donula.online, заложенный в целевую схему, пока не настроен. Внешней пробы в мониторинге нет.
Путь кандидата
- Вход. Сайт запрашивает одноразовый токен (
/api/auth/token, живёт 10 минут) и открывает бота в выбранном мессенджере. Кандидат отправляет боту телефон, сайт опрашивает/api/auth/checkи получает имя и телефон из мессенджера, а не из формы. - Анкета.
/api/submitпринимает анкету и голос (audio/webm,audio/mp4,audio/m4a, от 1 KiB до 10 MiB). Анкета сначала пишется в журнал на диске, затем строкой в лист «Кандидаты» через Apps Script. Повтор с тем жеrequest_idвторую строку не создаёт. - Оценка. Бэкенд отправляет голос в Gemini (через ProxyAPI): пять критериев от 1 до 5. 20 баллов и выше — PASS, кандидату сразу уходит приглашение на собеседование; 10–19 — GRAY, решает РОП; меньше 10 — FAIL, кандидату уходит отказ. Если модель недоступна, ставится GRAY с пометкой «AI недоступен, слушайте вручную».
- Решение РОПа — в таблице: столбец T («Одобрен» / «Отклонён») и W — итог собеседования («Принят» / «Отклонён» / «Не пришел»). Apps Script складывает изменения в лист «Webhook Outbox» и доставляет их в бэкенд подписанным запросом на
/api/webhook/rop; бэкенд пишет кандидату. - Собеседование — ближайший понедельник, среда или пятница не раньше чем через сутки, в 12:00 по Москве, в Телемосте. Напоминания — за 24 часа и за час.
- Обучение. После «Принят» создаются контакт и сделка
Найм: <имя>в воронке найма amoCRM, кандидат получает персональную ссылку на курс (живёт 90 дней). Сайт обучения отмечает визит и прохождение, сделка двигается только вперёд: принят → зашёл на обучение → готов к ролевке. После курса открывается ссылка в закрытое сообщество.
Как устроен
- Бэкенд — один процесс FastAPI на Python 3.12 (
runtime/backend/). Состояние — в каталогеDATA_DIR: SQLite для переписки, JSON-файлы для соответствия чатов, записей на собеседование и токенов amoCRM, и журнал анкет. Журнал одновременно служит очередью эффектов: после рестарта недоделанное доигрывается. - Google Sheet и Apps Script (
runtime/apps-script/google-apps-script-hiring.js) — рабочее место РОПа: листы «Кандидаты», «Обучение», «Трафик», «Расписание МР», «Дашборд», «Системное», «Webhook Outbox». Скрипт выкатывается вручную в редакторе таблицы. - Мессенджеры — своя реализация, не общая с
messenger_connector: Telegram через long polling, VK и MAX через вебхуки. - Inbox (
runtime/sites/inbox) — общая лента переписки со всеми кандидатами из трёх мессенджеров и ответ из веб-интерфейса. - Фоновые циклы внутри процесса: напоминания, вечерняя сводка РОПу в Telegram-группу в 20:00 и утренняя в 09:00 по Москве.
- Статика
runtime/sites/{auth,inbox,training}отдаётся nginx и обращается к бэкенду по относительным/api/…— открывать её нужно с того же адреса, что и бэкенд.
Где код и как запустить
- Репозиторий
Buharestskie/hiring_project. Документы о передаче проекта (STATUS.md,TRANSFER.md,ROUTE_MAP.md) описывают старое размещение и устарели. - Офлайн-тесты (внешняя сеть заблокирована, нужен ещё Node.js для тестов Apps Script):
bash runtime/tests/run_all.shпосле установкиruntime/backend/requirements.lockв venv. - Бэкенд локально —
uvicorn main:appизruntime/backendс явнымиDATA_DIR,DISABLE_SCHEDULED=trueиTG_POLLING_ENABLED=false. Без явногоDATA_DIRзапуск упадёт на правах доступа./api/submitбез настоящего Apps Script тестовой таблицы отвечает503. - Целевая выкатка — релизными архивами:
scripts/build-release.shсобирает архив,scripts/deploy-release.shраскладывает его на хост и переключает симлинк, при провале/healthвозвращает предыдущий;scripts/rollback-release.sh— откат. systemd-юниты и шаблон nginx — вinfra/. Когда сервис будет развёрнут, сначала завести внешнюю пробу, потом выкатывать в окне обслуживания.
На что наступают
- Только один Telegram-поллер и один планировщик. Второй процесс на тех же токенах без
DISABLE_SCHEDULED=trueиTG_POLLING_ENABLED=falseдаёт дубли сообщений кандидатам. DISABLE_SCHEDULEDне выключает эффекты анкеты. Оценка, сообщение кандидату и уведомление РОПу запускаются прямо из/api/submit. Стенд с боевыми токенами пишет живым людям.- Утренняя сводка включена по умолчанию. Если
ENABLE_ROP_MORNING_NOTIFICATIONне задана, она уходит, хотя по решению проекта выключена. - Сессии входа живут в памяти. Рестарт сбрасывает незавершённые входы кандидатов и начатую авторизацию amoCRM. Токен входа удаляется через 10 минут, поэтому напоминания «через 30/60 минут» почти не срабатывают.
- Строки в «Кандидатах» не удалять и не сортировать. Строки находятся по скрытому
request_idв столбце X. Листы «Системное» и «Webhook Outbox» руками не редактируются. - Триггер Apps Script должен быть installable и работает от имени создателя. Потерял аккаунт доступ — решения РОПа копятся в «Webhook Outbox» и не уходят.
- Поток GRAY с пометкой «AI недоступен» — почти всегда кончился ключ или баланс ProxyAPI.
- Сделку в amoCRM бэкенд ищет по названию
Найм: <имя>(первый результат) — однофамильцы могут перепутаться. Ошибка создания сделки только логируется. - MAX:
user_idне равенchat_id, соответствие хранится в JSON-файле вDATA_DIR. Потеря файла ломает доставку в MAX. - Запись голоса во встроенном браузере мессенджера не работает — сайт просит открыть ссылку в Safari или Chrome.
build-release.shне проверяет чистоту дерева (проверка унаследована из монорепозитория и смотрит не туда): незакоммиченные правки попадут в архив под чужим SHA. Перед сборкой —git status.runtime/backend/Dockerfile,backup_sheets.shиlegacy/— наследие старого размещения, целевая схема их не использует.
Нет комментариев для отображения
Нет комментариев для отображения