supersam/docs/n8n-order-group-delivery-fl...

13 KiB
Raw Permalink Blame History

Поток n8n для order_groups

Цель

Supabase хранит состояние доставки, генерирует ссылку для клиента и сохраняет все временные отметки. n8n отвечает за отправку SMS, повторные попытки и перевод зависших групп в ручную обработку.

Короткая ссылка с нашей стороны не нужна. Мы храним полную delivery_link, а сервис SMS сам сокращает ссылку при отправке.

Источник истины

Основная запись находится в public.order_groups.

Важные поля:

  • status - бизнес-готовность группы
  • delivery_status - состояние согласования доставки для клиента и логиста
  • delivery_link - полная публичная ссылка на /delivery/:token
  • delivery_invitation_id - связанная запись приглашения
  • notification_status - состояние SMS-оркестрации для n8n
  • sms_attempts - сколько было попыток отправки SMS
  • first_sms_sent_at - время первой SMS
  • second_sms_sent_at - время второй SMS
  • last_sms_error - текст последней ошибки провайдера
  • next_notification_check_at - когда n8n должен вернуться к записи
  • delivery_date и delivery_time - выбранный слот доставки после подтверждения клиентом
  • delivery_type - тип получения: delivery (доставка) или pickup (самовывоз)
  • pickup_date и pickup_time_slot - выбранный слот самовывоза после подтверждения клиентом

Окно отправки SMS

Чтобы не тревожить клиентов ночью, SMS отправляются только в местное окно:

09:00-20:00 Europe/Simferopol

Если запись стала готова к отправке вне этого окна, SMS не отправляется сразу. Supabase должен поставить ближайшее разрешенное время в next_notification_check_at:

  • до 09:00 - сегодня в 09:00
  • с 09:00 до 20:00 - сразу
  • после 20:00 - завтра в 09:00

Для этого в SQL есть helper:

public.next_order_group_sms_check_at(start_from timestamptz, delay interval)

n8n не должен сам решать, можно ли сейчас тревожить клиента. Он просто выбирает записи, где next_notification_check_at <= now().

Рекомендуемая модель статусов

delivery_status

  • pending_confirmation - клиент еще не выбрал слот
  • agreed - клиент выбрал слот доставки
  • manual_confirmation_required - автоматический поток не сработал, менеджер/логист должен продолжить вручную
  • no_contact - менеджер/логист пытался связаться вручную, но связи с клиентом нет
  • assigned_to_driver - доставка согласована и передана в планирование водителю
  • out_for_delivery - водитель уже в работе
  • delivered - доставка завершена
  • cancelled - группу больше не нужно обрабатывать
  • pickup - клиент выбрал самовывоз

notification_status

  • not_started - ссылка еще не подготовлена
  • link_ready - Supabase создал delivery_link, n8n может отправлять первую SMS
  • first_sms_sent - первая SMS принята провайдером
  • second_sms_sent - отправлено напоминание
  • confirmed - клиент выбрал слот
  • manual_required - после повторов подтверждения нет
  • send_failed - ошибка провайдера/API, можно повторить

Ответственность Supabase

1. Подготовка ссылки

Когда order_group попадает в поток согласования доставки:

  • status = 'ready_for_notification'
  • delivery_status = 'pending_confirmation'

Триггер Supabase order_groups_ensure_delivery_link должен:

  • создать запись delivery_invitations с order_group_id
  • сгенерировать token и полную публичную ссылку
  • подготовить слоты только на завтра и послезавтра
  • записать delivery_link в order_groups
  • установить delivery_invitation_id
  • установить notification_status = 'link_ready'
  • установить next_notification_check_at через public.next_order_group_sms_check_at()

SQL для этого триггера лежит здесь:

docs/sql/order-groups-auto-delivery-link.sql

n8n больше не должен вызывать create-delivery-invitation для order_groups. Ему нужно ждать, пока в строке уже будут notification_status = 'link_ready' и delivery_link is not null.

2. Прием выбора клиента

Публичная страница использует token. Когда клиент подтверждает слот, confirm-delivery-choice должен:

  • сохранить delivery_date и delivery_time
  • установить delivery_status = 'agreed'
  • установить notification_status = 'confirmed'

Это становится стоп-сигналом для всех напоминаний в n8n.

Потоки n8n

Поток 1. Отправка первой SMS

Триггер:

  • Cron каждые 5-10 минут
  • Опционально запасной webhook-триггер, если потом захочешь push-старт

Запрос:

  • status = 'ready_for_notification'
  • delivery_status = 'pending_confirmation'
  • notification_status = 'link_ready'
  • delivery_link is not null
  • next_notification_check_at <= now()

Действие:

  • отправить SMS с delivery_link

При успехе обновить order_groups:

  • notification_status = 'first_sms_sent'
  • sms_attempts = 1
  • first_sms_sent_at = now()
  • sms_sent_at = now()
  • last_sms_error = null
  • next_notification_check_at = public.next_order_group_sms_check_at(now(), interval '3 hours')

Важно: если первая SMS ушла, например, в 18:30, проверка через 3 часа попала бы на 21:30. Helper перенесет следующую проверку на завтра 09:00.

При ошибке обновить order_groups:

  • notification_status = 'send_failed'
  • last_sms_error = <ошибка провайдера>
  • next_notification_check_at = public.next_order_group_sms_check_at(now(), interval '10 minutes')

Поток 2. Наблюдатель доставки

Триггер:

  • Cron каждые 10 минут

Назначение:

  • найти записи, где первый поток не завершился корректно
  • повторить неудачные первые отправки

Кандидаты для выбора:

  • notification_status = 'send_failed'
  • delivery_status = 'pending_confirmation'
  • next_notification_check_at <= now()

Поведение:

  • повторить первую SMS
  • если успех, перевести в first_sms_sent
  • если повторные ошибки превысили выбранный порог, перевести в manual_required
  • все новые значения next_notification_check_at считать через public.next_order_group_sms_check_at(...)

Поток 3. Напоминание по SMS

Триггер:

  • Cron каждые 10 минут

Запрос:

  • delivery_status = 'pending_confirmation'
  • notification_status = 'first_sms_sent'
  • next_notification_check_at <= now()

Действие:

  • отправить вторую SMS-напоминалку с той же delivery_link

При успехе обновить:

  • notification_status = 'second_sms_sent'
  • sms_attempts = 2
  • second_sms_sent_at = now()
  • last_sms_error = null
  • next_notification_check_at = public.next_order_group_sms_check_at(now(), interval '3 hours')

При ошибке обновить:

  • notification_status = 'send_failed'
  • last_sms_error = <ошибка провайдера>
  • next_notification_check_at = public.next_order_group_sms_check_at(now(), interval '30 minutes')

Поток 4. Передача в ручную обработку

Триггер:

  • Cron каждые 10 минут

Запрос:

  • delivery_status = 'pending_confirmation'
  • notification_status = 'second_sms_sent'
  • next_notification_check_at <= now()

Действие:

  • остановить автоматические напоминания
  • перевести группу в ручную обработку

Обновление:

  • delivery_status = 'manual_confirmation_required'
  • notification_status = 'manual_required'

После этого автоматические SMS больше не отправляются. В ЛК менеджер/логист должен вручную выбрать дату доставки или поставить результат no_contact, если связаться с клиентом не удалось.

Поток 5. Условия остановки

Каждый поток должен игнорировать строки, где:

  • delivery_status in ('agreed', 'no_contact', 'assigned_to_driver', 'out_for_delivery', 'delivered', 'cancelled')
  • notification_status in ('confirmed', 'manual_required')

Это не дает слать дублирующие SMS после ответа клиента или передачи кейса человеку.

Рекомендуемый текст SMS

Пример:

Ваш заказ готов к согласованию доставки.
Выберите удобные дату и время по ссылке:
{{delivery_link}}

Напоминание:

Напоминаем: нужно выбрать дату и время доставки вашего заказа.
Ссылка:
{{delivery_link}}

Что нужно фронтенду

Публичной странице нужны только:

  • token из URL
  • get-delivery-invitation
  • confirm-delivery-choice

Никакой логики SMS на фронтенде быть не должно. Никакой генерации ссылок на фронтенде быть не должно.

Самовывоз

Когда клиент выбирает вкладку «Самовывоз» на публичной странице:

  1. confirm-delivery-choice получает delivery_type = 'pickup' вместе с pickup_date и pickup_time_slot.
  2. RPC confirm_delivery_choice_by_token устанавливает delivery_status = 'pickup', delivery_type = 'pickup', pickup_date, pickup_time_slot.
  3. SMS-потоки n8n должны игнорировать строки со delivery_status = 'pickup' — клиент сам забирает заказ, напоминания о доставке не нужны.

Минимальный порядок внедрения

  1. Развернуть обновленную схему Supabase и docs/sql/order-groups-auto-delivery-link.sql.
  2. Проверить, что insert/update в order_groups пишет delivery_link и notification_status = 'link_ready'.
  3. Собрать поток n8n для первой SMS.
  4. Собрать поток n8n для напоминаний.
  5. Собрать поток n8n для ручной передачи.
  6. Проверить полный цикл на одной реальной записи order_group.

Сценарий проверки

  1. Пометить одну order_group как готовую к клиентскому согласованию доставки.
  2. Убедиться, что delivery_link появился в order_groups автоматически.
  3. Дать n8n отправить первую SMS.
  4. Открыть ссылку и подтвердить слот на клиентской странице.
  5. Убедиться, что delivery_status = 'agreed' и notification_status = 'confirmed'.
  6. Убедиться, что потоки напоминаний больше не трогают эту группу.