supersam/docs/integrations/delivery-orchestration.md

246 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Оркестрация процесса согласования доставки
## Цель
Этот документ фиксирует, как должен работать процесс согласования доставки по схеме:
- готовность заказа определяется внешним XML-файлом на FTP;
- клиент получает SMS со ссылкой на публичную страницу выбора доставки;
- при отсутствии реакции запускаются повторные уведомления и ручная обработка логистом;
- после доставки статус передается обратно во внешнюю учетную систему.
## Короткий ответ по архитектуре
Рекомендуемое разделение ответственности такое:
- `Supabase` — источник истины для пользователей, заказов, статусов, истории, клиентских ссылок и подтвержденных действий.
- `Edge Functions` — безопасные серверные точки входа для изменения состояния заказа и валидации переходов.
- `n8n` — оркестратор расписания и интеграций: FTP XML, SMS-провайдер, напоминания по времени, обмен с `1С` и внешними системами.
Иными словами:
- состояние процесса хранится и проверяется в `Supabase`;
- время, расписание и внешние вызовы удобнее и надежнее исполнять в `n8n`.
## Почему не стоит строить это только на Supabase
Теоретически часть сценариев можно делать только через `Supabase Edge Functions`, но в этом проекте это будет слабее, чем связка `Supabase + n8n`, по трем причинам:
1. Источник готовности заказа приходит из внешнего XML на FTP.
Это интеграционный сценарий, а не чисто внутренний backend-flow.
2. Напоминания завязаны на время.
Нужны регулярные проверки: через 3 часа, через 1 час, через 2 часа, перенос на рабочее время.
3. Есть внешние каналы и обратный обмен.
SMS, `1С`, возможные ошибки доставки и повторная отправка лучше ложатся на отдельный orchestration-слой.
Поэтому для этого проекта оптимальная модель такая:
- `n8n` решает, когда и что запустить;
- `Supabase` решает, можно ли менять статус и что именно записать.
## Роли систем
### Supabase
В `Supabase` хранится:
- `orders`
- `order_history`
- `delivery_slots`
- `delivery_invitations`
- `integration_events`
- пользователи и роли
Через `Edge Functions` выполняются только валидные переходы:
- создание клиентской ссылки;
- чтение состояния ссылки;
- подтверждение выбора клиентом;
- передача логисту;
- перевод в платное хранение;
- фиксация результата доставки.
### n8n
В `n8n` реализуются сценарии:
- чтение XML с FTP по расписанию;
- определение новых заказов, готовых к доставке;
- запуск первой SMS;
- запуск повторной SMS;
- запуск reminder после незавершенного выбора;
- передача заказа логисту при SLA timeout;
- отправка SMS о платном хранении;
- отправка результата доставки во внешнюю систему.
### Публичное приложение
Клиентская страница на `dost.supersamsev.ru`:
- получает token из SMS;
- читает invitation state из `Supabase`;
- показывает допустимый интерфейс;
- сохраняет выбор доставки через `Edge Function`.
## Основной поток данных
### 1. Проверка готовности заказа
`n8n` по расписанию читает XML на FTP.
На этом шаге workflow:
- забирает XML;
- парсит записи заказов;
- определяет, какие заказы стали полностью готовыми к доставке;
- сверяет их с `Supabase`.
Если заказ уже заведен и еще не переведен в delivery agreement flow, `n8n` вызывает `create-delivery-invitation`.
### 2. Первая SMS
После успешного вызова `create-delivery-invitation`:
- в `Supabase` создается или обновляется `delivery_invitations`;
- заказ получает статус `Ожидает ответа клиента`;
- `n8n` отправляет первую SMS со ссылкой.
### 3. Контроль перехода по ссылке
`n8n` по расписанию проверяет заказы в статусе `Ожидает ответа клиента`.
Основание для решения:
- `delivery_invitations.sent_at`
- `delivery_invitations.opened_at`
- `delivery_invitations.confirmed_at`
- `orders.status`
Если клиент не перешел по ссылке в течение 3 часов:
- `n8n` отправляет повторную SMS;
- фиксирует это в `integration_events` или отдельном поле reminder state.
Если и после повторной SMS перехода нет:
- `n8n` вызывает `transfer-to-logistics`;
- заказ получает статус `Передан логисту`.
### 4. Незавершенный выбор
Если клиент открыл ссылку, но не подтвердил время:
- это видно по `opened_at`, при этом `confirmed_at` остается пустым;
- `n8n` запускает reminder через 1 час;
- если подтверждения нет еще 2 часа, `n8n` передает заказ логисту.
Проверка рабочего времени должна жить именно в `n8n`, потому что это orchestration rule.
### 5. Ручная работа логиста
После статуса `Передан логисту` автоматический сценарий считается неуспешным и дальше заказ ведет логист.
Логист:
- связывается с клиентом;
- согласует доставку вручную;
- либо переводит заказ в `Доставка согласована`;
- либо после безуспешных попыток переводит заказ в `Платное хранение`.
После перевода в `Платное хранение`:
- `n8n` отправляет клиенту отдельную SMS.
### 6. Доставка и обратная интеграция
После статуса `Доставка согласована`:
- логист планирует доставку;
- водитель выполняет доставку;
- приложение фиксирует `Доставлен` или `Проблема доставки`.
При успешной доставке:
- `n8n` отправляет статус во внешнюю систему.
При проблеме доставки:
- заказ возвращается логисту;
- цикл ручного согласования повторяется.
## Где живет “понятие времени”
Это ключевой вопрос проекта.
Само приложение не должно самостоятельно “просыпаться” и решать, что прошло 3 часа.
Правильная модель такая:
- приложение и `Supabase` только фиксируют события и timestamps;
- `n8n` регулярно запускается по cron и вычисляет, наступило ли время следующего действия.
То есть логика выглядит так:
- `Supabase` хранит `sent_at`, `opened_at`, `confirmed_at`, текущий статус;
- `n8n` каждые 5-15 минут проверяет, какие записи пересекли SLA-порог;
- если порог наступил, `n8n` запускает нужный сценарий.
## Рекомендуемый набор workflow в n8n
1. `FTP XML Poller`
Читает XML с FTP и определяет готовые заказы.
2. `Delivery Offer Dispatcher`
Создает invitation и отправляет первую SMS.
3. `Delivery Reminder Scheduler`
Проверяет timeouts:
- 3 часа до повторной SMS
- еще 3 часа до передачи логисту
- 1 час до reminder после opened/no-confirm
- 2 часа до передачи логисту после reminder
4. `Paid Storage Notifier`
Отправляет SMS при статусе `Платное хранение`.
5. `Delivery Result Exporter`
Передает итог доставки во внешнюю систему.
## Минимальный набор данных, который нужен для orchestration
Чтобы схема работала стабильно, в `Supabase` должны быть доступны как минимум:
- `orders.id`
- `orders.order_number`
- `orders.status`
- `orders.delivery_agreement_status`
- `delivery_invitations.order_id`
- `delivery_invitations.token_hash`
- `delivery_invitations.state`
- `delivery_invitations.sent_at`
- `delivery_invitations.opened_at`
- `delivery_invitations.confirmed_at`
- `delivery_invitations.logistics_transferred_at`
- `delivery_invitations.paid_storage_at`
- `delivery_invitations.delivered_at`
- `delivery_slots`
- `integration_events`
## Итоговое решение
Для этого проекта рабочая и рекомендуемая архитектура такая:
- FTP XML читает `n8n`;
- time-based automation исполняет `n8n`;
- SMS и внешние интеграции исполняет `n8n`;
- `Supabase` хранит бизнес-состояние;
- `Edge Functions` валидируют и фиксируют изменения состояния;
- клиентское приложение показывает состояние и принимает подтверждение клиента.
Это дает понятное разделение:
- `n8n` отвечает за “когда запускать сценарий”;
- `Supabase` отвечает за “какое состояние заказа сейчас истинно”.