246 lines
11 KiB
Markdown
246 lines
11 KiB
Markdown
# Оркестрация процесса согласования доставки
|
||
|
||
## Цель
|
||
|
||
Этот документ фиксирует, как должен работать процесс согласования доставки по схеме:
|
||
|
||
- готовность заказа определяется внешним 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` отвечает за “какое состояние заказа сейчас истинно”.
|