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