Я руковожу продуктовой командой, которая запускает гибридные онлайн-курсы.
Наш формат: часть обучения студенты проходят асинхронно (материалы всегда доступны на платформе), часть — в режиме вебинара с преподавателем.

Вебинары построены вокруг практики: студент должен прийти с выполненным домашним заданием или хотя бы попыткой решения. Преподавателю важно заранее увидеть работы группы, чтобы понять, где у студентов ошибки, разобрать разные пути решения, показать точно рабочее решение.

Для этого преподавателю нужно видеть домашки студентов за 2–3 дня до вебинара.

Роль куратора (и проблема)

В курсе есть куратор: он напоминает студентам о дедлайнах и вебинарах.
Но когда курсов стало несколько, у каждой группы — свои даты и дедлайны, куратор просто утонул в таблицах: часть напоминаний забывалась, часть дублировалась.

Очевидный вывод: рутинные напоминания нужно автоматизировать.

В статье покажу, как настроить систему уведомлений на примере одного курса:

  • студент получает напоминание в личку (а не в общий чат),

  • не получает лишних сообщений, если уже сдал ДЗ,

  • всё работает слаженно, на связке n8n + Google Sheets + Telegram и не требует денег (в отличии от куратора).

Что такое n8n

n8n — это no-code/low-code конструктор автоматизаций.
Представьте себе взрослую версию Scratch: вместо «котика, который прыгает» у вас «бот пишет студенту, что дедлайн завтра». Собирается тоже, как пазл. При сборке нашего решения, мы будем использовать две основные сущности:

  • Trigger (триггер) — событие. Например: «пришло сообщение», «шеф снова написал “срочно” в 23:59».

  • Action (действие) — то, что произойдет в ответ. Например: «отправить уведомление студенту» (или, если триггером было сообщение от шефа, то действие — «твой глаз дергается»).

Мы будем использовать:

  • триггеры Schedule и Telegram,

  • действия с Google Sheets и отправку сообщений в Telegram.

1. Готовим таблицу в Google Sheets

Создаём файл с несколькими листами:

  • students: student_id, name, email, telegram_id, tz, channel, course_id

  • homeworks: hw_id, student_id, course_id, due_at, status, link_to_submit

  • webinars: webinar_id, course_id, title, start_at, duration, meeting_url, ics_uid

  • course: course_id, title, start_at, duration, meeting_url, ics_uid

  • notifications_log: type, who, what_id, sent_at, channel, status

? Пример таблицы

Советы:

  • tz — реальный часовой пояс студента (по умолчанию Europe/Moscow).

  • даты — в формате ISO 8601 с таймзоной (2025-09-20T18:00:00+02:00).

  • telegram_id пока пустое — соберём позже автоматически.

2. Создаём Telegram-бот

Чтобы студенты получали напоминания в личные сообщения, нужен отдельный бот-куратор.
Создать его просто:

  1. В Telegram открываем @BotFather.

  2. Вводим команду /newbot.

  3. Даем имя и ник (ник должен заканчиваться на bot). Пример: course_helper_bot.

  4. BotFather выдаст Bot Token. Скопируем его — он понадобится в n8n.

  5. Напиши своему боту /start, чтобы инициировать диалог.

Зачем нужен Bot Token

Bot Token — это ключ доступа к API Telegram.
Через него n8n сможет получать сообщения студентов (например, когда они пишут «/start») и отправлять студентам напоминания.

Позже мы добавим в n8n ноду Telegram Trigger, чтобы поймать chat_id студента и записать его в поле telegram_id на листе students в Google Sheets.

3. Подключаем сервисы в n8n

Теперь подключим наши сервисы к n8n: Google Sheets и Telegram.

Подключаем Google Sheets

  1. Открываем редактор n8n.

  2. Переходим в раздел Credentials.

  3. Создаем новую запись → Google Sheets (OAuth2).

  4. Следом надо разрешить доступ к своему Google Drive. Это нужно, чтобы n8n мог читать и записывать данные в таблицу курса.

Подключаем Telegram

  1. В том же разделе Credentials жмем Create Credential (красная кнопка справа сверху или плюсик рядом).

  2. В поиске ищем Telegram.

  3. В появившейся форме Telegram API Token → вставляем токен, полученный у @BotFather. Остальные поля можно оставить пустыми.

  4. Жмем Save.

После этого в списке появится новая запись Telegram account.

В итоге будут два подключения в Credentials:

  • Google Sheets

  • Telegram

4. Получаем telegram_id студента

Чтобы бот мог писать студенту в личку, нужно узнать его chat_id в Telegram.
Для этого создадим отдельный вспомогательный workflow.

Workflow: Get-Telegram-ChatId

  1. В n8n создаем новый workflow с именем Get-Telegram-ChatId.

  2. Добавляем ноду Telegram Trigger → режим On message.

  3. Добавляем ноду Set.

  4. Активируем workflow (Activate).

  5. Пишем боту любое сообщение (например, «Привет!»).

Проверяем результат

  1. В n8n надо открыть вкладку Executions.

  2. Найти последнюю запись выполнения.

  3. Кликнуть по ней и смотреть Output у ноды Telegram Trigger. Там будет JSON с объектом message.chat.id.

Пример:

"chat": {
  "id": 123456789,
  "first_name": "Имя",
  ...
}

Значение 123456789 — это и есть telegram_id. Его надо вставить в таблицу в соответствующее поле. После этого можно деактивировать Get-Telegram-ChatId.

Сейчас мы сделали первый сценарий, всего у нас их будет два:

  1. Get-Telegram-ChatId (с нодой Telegram Trigger) — разовый воркфлоу, чтобы поймать chat_id. У него свой триггер, поэтому он живёт в отдельном workflow.

  2. HW-Reminders-3d — основной сценарий с Schedule/Cron, чтением из Google Sheets, IF и отправкой сообщений. У него другой триггер, поэтому это другой workflow.

В n8n у каждого воркфлоу свой «вход». Смешивать два разных триггера в одном нет смысла.

Идём дальше.

5. Создаём workflow для напоминания о ДЗ

Создаём новый workflow: HW-Reminders-3d. Для этого в n8n жмем кнопку Create Workflow. Даем имя HW-Reminders-3d.
Далее, будем добавлять ноды. Помним, чтобы добавить ноду, жмем плюсик справа (Add Node).

1. Schedule Trigger

  • запускается каждый день в 09:00 (таймзона Europe/Moscow).

2. Чтение данных

Добавляем ноду Google Sheets → настроить Credential (из раздела Credentials) → указать таблицу.

  • Resource: Sheet

  • Operation: Read

  • Mode: All

  • Spreadsheet: выбираем свой файл

  • Sheet: homeworks

Эта нода прочитает все строки листа homeworks.

Сразу после неё — нода Code Normalize HW (тип Code):

return items.map(it => {
  const j = it.json;
  const sid = String(j.student_id || '').trim().toLowerCase();
  const status = String(j.status || '').trim().toLowerCase(); // убираем пробелы
  return { json: { ...j, sid, status } };
});

Читаем студентов из Google Sheets

Добавим вторую ноду Google Sheets (можно скопировать предыдущую), но указать лист students:

  • Resource: Sheet

  • Operation: Read

  • Mode: All

  • Sheet: students

После неё — нода Code Normalize STU:


return items.map(it => {
  const j = it.json;
  const sid = String(j.student_id || '').trim().toLowerCase();
  return { json: { ...j, sid } };
});

Теперь нужно склеить домашки со студентами, для этого добавим ноду Merge

  • Mode: Combine

  • Field to Match (Input 1): sid

  • Field to Match (Input 2): sid

  • Input 1Normalize HW

  • Input 2Normalize STU

Высчитываем «сколько осталось до дедлайна» с учётом часового пояса студента

Для этого добавим ноду Code Compute Deadline Diff:

const j = $json;
const due = new Date(j.due_at);
const start_at = new Date(j.start_at);
const tz = j.tz || 'Europe/Moscow';
const nowTz = new Date(new Date().toLocaleString('en-US', { timeZone: tz }));
const diffDays = Math.floor((due - nowTz) / 86400000);
const diffHours = Math.round((due - nowTz) / 3.6e6);
return { ...j, diffDays, diffHours };

IF: выбираем только те элементы, где нужно напомнить

Добавим ноду IF:

  • Условие 1: statusequalspending

  • Условие 2: diffDaysequals3

  • Combine Conditions: ALL (AND)

Подключим вход from Compute Deadline Diff.

Ветка false можно никуда не вести. Если хочется следить, кто «не попал» под условия — можно отправлять их в «NoOp» или на отдельный лист логов.

Отправляем сообщение в Telegram (ветка true)

Добавляем ноду Telegram → Send Message:

  • Credentials: наш Telegram account

  • Chat ID: {{$json.telegram_id}}

  • Text:

Привет, {{$json.name}}!
Через 3 дня дедлайн по ДЗ.
Сдать: {{$json.link_to_submit}}
Если уже сдал(а) — спасибо!

В n8n-хендлбарс-плейсхолдеры {{$json.field}} корректны для подстановки полей текущего элемента.

Пишем лог об отправке

Сразу после Telegram-ноды добавляем Google Sheets → Append row для листа notifications_log:

  • Resource: Sheet within document

  • Operation: Append (в некоторых версиях — Append row)

  • Document: наша таблица (всё время с одной и той же работаем)

  • Sheet: notifications_log

  • Fields to send:

    • typehw

    • who{{$json.student_id}}

    • what_id{{$json.hw_id}}

    • sent_at{{$now}}

    • channeltelegram

    • statusok

Этот лист — «бухгалтерия уведомлений»: тут видно, кому, когда и что отправили.

Обновляем статус домашки, чтобы не слать повторно

Нода Google Sheets → Update для листа homeworks:

  • Resource: Sheet

  • Operation: Update

  • Key Column: hw_id

  • Key Value: {{$json.hw_id}}

  • Fields to send:statusnotified

Это защищает от повторной отправки «за 3 дня» одному и тому же студенту по одному и тому же ДЗ.

Проверка: прогон и отладка

  1. Сохраняем workflow и Activate.

  2. Для быстрой проверки можно временно поменять время в Schedule Trigger или вместо него повесить Manual Trigger и выполнить запуск руками.

  3. Вкладка Executions покажет цепочку нод, вход/выход и возможные ошибки.

Расширение: несколько курсов и вебинары

Выше мы собрали минимальный вариант для одного курса и только для домашних заданий.
Но в реальной жизни курсов несколько, и у каждого свои вебинары. Чтобы не собирать отдельный workflow на каждый случай, лучше доработать существующий сценарий.

Блок Course

Добавляем лист course и ноду Course, которая подтягивает дополнительные данные по курсу:

  • связи между домашками и вебинарами,

  • даты ближайших вебинаров,

  • базовую информацию о курсе.

Это позволяет учитывать не только факт «сдать ДЗ», но и контекст курса в целом.

Loop Over Items → Get webinar for course

Этот блок нужен для циклической обработки вебинаров:

  • Loop Over Items берёт спис��к курсов,

  • для каждого курса запускает поиск связанных вебинаров в таблице,

  • на выходе получаем поток данных, где у студента есть и ДЗ, и вебинары.

Так reminders можно ставить не только для ДЗ, но и для событий (например, «через 2 дня вебинар»).

DateCompare + Code

Два блока, которые работают в паре:

  • DateCompare — упрощает сравнение дат (например, «меньше чем за 3 дня до события»).

  • Code — кастомные расчёты (diffDays, diffHours), которые можно использовать в IF-условиях.

С их помощью можно точно решить, нужно ли отправить студенту уведомление о вебинаре.

Merge1: объединяем потоки

Если первый Merge склеивал homeworks + students, то второй (Merge1) нужен для объединения результата с вебинарами.
На выходе получаем единый поток данных: у каждого студента есть информация и о домашних заданиях, и о вебинарах.

Финальный штрих: Update row in sheet

После успешной отправки уведомления добавляем шаг Update row in sheet:

  • обновляем строку в homeworks,

  • меняем поле status с pending на notified

Это защищает от повторной отправки одного и того же уведомления.
Лог в notifications_log при этом остаётся, и можно отследить историю отправок.

Вот такой вышел итоговый вариант:

Куратор вроде бы остался, но после автоматизации экспериментальный курс живёт уже вторую неделю без привычного «ой, я забыла».

Комментарии (0)