Представьте файл orders_2026-11-01.csv. Он лежит на диске, открывается в таблице, в нём тысячи строк, и выглядит он как надёжная страховка. Откроем одну строку: 10458; 2026-10-28; Новый; 48 600; 3412. Что здесь клиент? Число 3412 — это он или менеджер? Что в заказе куплено? Где счёт, который просила бухгалтерия? Что означает статус «Новый» и кто его выставил? Строка честно записана, но продолжать по ней работу нельзя. Это не плохая выгрузка, а выгрузка, у которой не спросили, для чего она нужна.
Поэтому начнём не с команд и расписаний, а с вопроса: что должен суметь сделать человек, если кабинет SaaS недоступен — доступ закрыт, аккаунт заблокирован, тариф не оплачен или сервис просто недоступен несколько дней. От ответа зависит, какие сущности сохранять, как их связывать и как проверять результат.
Сначала операции, потом поля
Архив заказов — не копия платформы. Он не вернёт автоматизации, роли пользователей, настройки воронок, интеграции и всё, что в системе работало как поведение, а не как данные. Он хранит только то, что вы сумели получить через доступные выгрузки и API, в том виде, в каком получили. Если в брифе к архиву написать «полная резервная копия SaaS», разочарование гарантировано. Честнее формулировка: «независимый архив заказов и связанных с ними записей, достаточный для набора операций».
Составьте короткий список операций, которые нельзя остановить. Для типичного магазина или сервисной компании он выглядит примерно так:
- найти заказ по номеру, телефону или названию клиента и понять, на какой он стадии;
- отгрузить или выполнить уже оплаченное: нужны позиции, количества, адрес, комментарии;
- повторно отправить клиенту счёт, акт или накладную;
- ответить на претензию: что и когда было заказано, кто вёл сделку;
- отчитаться перед бухгалтерией за период: суммы, налоги, реквизиты покупателя.
Каждая операция тянет за собой свои данные. Отгрузке нужны позиции и адрес, но не нужна история звонков. Претензии нужна хронология и комментарии, а бухгалтерии — реквизиты и документы. Если вы честно проведёте мысленно каждую операцию без кабинета, быстро обнаружите, каких сущностей не хватает.
Что теряется в одинокой строке
Возьмём условный пример: заказ № 10458 на 48 600 ₽. В системе он выглядит как карточка, а в плоской выгрузке заказов — как одна строка. Разложим, что в этой карточке на самом деле.
| Часть заказа | В строке заказа | Что нужно сохранить отдельно |
|---|---|---|
| Клиент | Число 3412 в столбце «Контакт» | Карточка контакта или компании: название, телефон, e-mail, реквизиты, ответственный |
| Позиции | Только итоговая сумма | Список товаров: артикул, название на момент заказа, количество, цена, скидка, ставка налога |
| Статус | Слово «Новый» или код стадии | Справочник стадий: код, название, порядок, признак успешного и закрытого этапа |
| Документ | Ничего или временная ссылка | Сам файл счёта, его номер, дата, привязка к заказу, контрольная сумма |
| Ответственный | Число 27 | Справочник сотрудников: имя, подразделение, признак действующего |
| Пользовательские поля | Столбцы с техническими названиями | Описание полей: человекочитаемое имя, тип, список допустимых значений |
Теперь видно, чего не хватает. Одинокая строка хранит ссылки на другие сущности, но не сами сущности. Это нормальная реляционная логика: в хорошей базе клиент записан один раз, а заказы ссылаются на него по идентификатору. В выгрузке эти идентификаторы становятся внешними ключами, которые указывают в пустоту, если не сохранить таблицы, на которые они ссылаются.
Особенно коварны справочники. Статус «Новый» сегодня означает одно, а через год вы переименуете стадию, и в выгрузке за тот год та же стадия будет называться иначе. Если справочник не сохранён вместе с датой состояния, вы не отличите «новый» заказ от заказа, который просто лежит в стадии с кодом, смысл которого забыт. Такая же история с ценами в позициях: нужна цена на момент заказа, а не текущая цена из каталога, поэтому каталог — отдельная сущность с собственной датой.
И последнее про документы. Счёт в SaaS часто генерируется по шаблону и отдаётся по ссылке, которая работает только для залогиненного пользователя или живёт ограниченное время. Если в архиве лежит такая ссылка, вы сохранили не документ, а указатель, который перестанет работать именно тогда, когда понадобится. Файл надо скачать и положить рядом, а в записи заказа хранить путь к локальной копии и его контрольную сумму.
Состав архива: от заказа к его окружению
Теперь можно собрать список сущностей. Идите от заказа по связям, пока не дойдёте до данных, без которых операции из списка невыполнимы:
- Заказы (сделки) — основная таблица с идентификатором, датами создания и изменения, стадией, суммой, валютой, ответственным, ссылкой на клиента.
- Позиции заказов — отдельная таблица, где каждая строка содержит идентификатор заказа, номер позиции, артикул, название, количество, цену, скидку, налог.
- Клиенты — контакты и компании со связью между ними, реквизиты, каналы связи.
- Справочники — стадии, воронки, типы оплаты, способы доставки, значения списков в пользовательских полях, сотрудники.
- Описание полей — какое поле как называется, какого типа, что значат его коды.
- Документы и вложения — сами файлы с привязкой к заказу и контрольными суммами.
- Комментарии и история — если по ним ведутся споры или они содержат условия, которых нет в полях.
Не всё из этого доступно во всех системах и редакциях. Одни продукты отдают позиции вместе с заказом, другие — отдельным запросом. Где-то историю изменений можно получить, а где-то только текущее состояние. Вложения могут отдаваться по API, а могут только через интерфейс. Не стоит делать вывод, что чего-то нет, потому что вы не нашли это на одной странице документации: проверьте на тестовой записи, спросите поддержку, посмотрите реальный ответ. А то, что получить нельзя, зафиксируйте в описании архива как известный пробел — это тоже полезное знание для того, кто будет им пользоваться.
Полная постраничная выгрузка и дата состояния
Выгрузка «одним запросом» бывает только у маленьких баз. Обычно API отдаёт записи порциями, и задача скрипта — пройти все страницы до конца. Возьмём как пример метод crm.item.list из документации Битрикс24: он позволяет задать список полей (select), условия отбора (filter), порядок (order) и стартовую позицию (start), а в ответе при наличии следующей страницы возвращается значение next. Отсюда общая схема любого постраничного обхода: запросили порцию, сохранили, взяли значение для следующей, повторяем, пока следующей нет.
Из этого следует несколько практических решений, которые от конкретного SaaS не зависят.
Порядок сортировки должен быть устойчивым
Если обходите страницы по дате изменения, а записи в это время меняются, часть заказов может перескочить с одной страницы на другую: вы получите дубль или пропустите запись. Для архива лучше упорядочивать по неизменному полю, например по идентификатору, а изменения догонять отдельным проходом по дате изменения. Дубли потом снимаются по идентификатору, а пропуск устранить сложнее, поэтому лучше пусть дублей будет больше.
Выбирайте поля явно
Список select лучше задавать явно, а не полагаться на набор по умолчанию. Тогда состав архива — ваше решение, записанное в скрипте, а не поведение сервиса, которое может измениться. Та же документация напоминает, что поля зависят от типа сущности, а пользовательские поля имеют свой формат; значит, для каждого типа записей нужен свой список и своё описание структуры. Не пытайтесь выгрузить «всё одинаково».
Сохраняйте сырой ответ
Прежде чем превращать данные в таблицы, положите ответ API как есть — в файл с именем по дате и номеру страницы. Так вы сможете переразобрать данные, если ошиблись в преобразовании, а ещё увидите поля, о которых не подумали. Таблицы и просмотр строятся уже из сырых файлов, а не из живого сервиса.
Запишите дату состояния и паспорт запуска
Архив — это снимок на момент. Без даты он вводит в заблуждение: человек видит заказ в статусе «в работе» и не знает, было ли это вчера или полгода назад. Рядом с каждой выгрузкой кладите маленький файл-паспорт: время начала и конца, сущности, число записей по каждой, число страниц, список полей, версия вашего скрипта, признак успешного завершения. Расхождение «в прошлый раз 12 408 заказов, сейчас 12 391» — повод разобраться, а не молча принять.
Папки удобно называть по дате и писать в них сначала во временный каталог. Только когда все страницы получены и сверены, каталог переименовывается в итоговое имя. Тогда оборванный запуск не превращается в «последний хороший архив» и не вытесняет предыдущий.
Расписание: как часто и что считать пропуском
Частота выгрузки определяется ответом на вопрос «сколько работы мы готовы потерять». Если заказы идут десятками в день и без кабинета вы всё равно сможете восстановить последние сутки по почте и мессенджерам, достаточно ночной выгрузки. Если каждый заказ — крупная сделка с долгой работой, пересмотрите. Справочники и каталог меняются редко, и их достаточно выгружать раз в неделю и при изменениях.
Практичная схема: ежедневный проход по заказам, изменённым за последние дни с запасом (скажем, берёте не сутки, а трое суток, чтобы перекрыть сбойный запуск), плюс еженедельная полная выгрузка, которая служит точкой отсчёта. Запас в окне изменений стоит дёшево: повторные записи отсеются по идентификатору, зато ночной сбой не оставит дыру.
Запускать можно обычным планировщиком cron, но важнее другое: скрипт должен сообщать о результате. Тихий скрипт, который полгода падает с ошибкой авторизации, опаснее отсутствия скрипта, потому что создаёт иллюзию архива. Самая простая защита — проверка «свежести»: если в каталоге нет паспорта младше двух суток, приходит уведомление. Это отдельная проверка, а не часть самого скрипта, ведь скрипт может не запуститься вовсе.
Как искать пропуски
Заказы имеют идентификаторы, которые обычно растут, но дыры в нумерации не обязательно означают потерю: записи удаляют. Поэтому сравнивайте не нумерацию, а счётчики: сколько записей вернул API по фильтру и сколько вы записали. Для периода можно сверять число заказов по месяцам с отчётом внутри самого SaaS. Если отчёт показывает 1 204 заказа за октябрь, а в архиве 1 198, надо понять, куда делись шесть — это либо удалённые после выгрузки, либо потерянные страницы. Для ежедневной работы достаточно записывать счётчики в паспорт и смотреть на резкие скачки.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации Россия, США, Франция и Великобритания. Оплата картой РФ и по СБП.
Доступ скрипта к SaaS
Скрипту нужен ключ или токен, и это самое чувствительное место архива: он открывает персональные данные клиентов. Здесь уместны рекомендации OWASP по управлению секретами: давать минимально необходимые права и поддерживать ротацию секретов, по возможности автоматизированную. В нашем случае это значит завести для выгрузки отдельного пользователя или токен с правом только чтения нужных разделов, а не использовать ключ администратора. Если сервис не позволяет ограничить права настолько тонко, это ограничение стоит знать и компенсировать: хранить секрет вне каталога с архивом, выдавать доступ к файлу только пользователю, под которым запускается скрипт, и менять ключ по графику. Ротация — рекомендация безопасности, а не гарантированное свойство любой интеграции, так что поддерживает ли конкретный сервис смену ключа без остановки, проверьте заранее.
Форматы: что прочитается через пять лет
Теперь о самих файлах. У архива две задачи: быть удобным сейчас и оставаться читаемым потом. Хорошо, когда формат открывается без специальной программы и без сервиса, который его создал. О том, как бывает иначе, есть отдельный разбор — выгрузка из SaaS в формате, который никто не читает.
Для табличных данных практичны CSV и JSON, и у каждого свои подводные камни. В CSV нет единого стандарта на разделитель и экранирование: модуль csv в Python поддерживает диалекты именно потому, что варианты различаются. Запятые, точки с запятой, кавычки внутри текста, переводы строк в комментариях — всё это ломает наивный разбор. Он же возвращает значения строками без преобразования типов, поэтому сумма «48600.00», дата и номер телефона с ведущим нулём приходят одинаково — текстом, и типы вы должны задать сами. Практический вывод: фиксируйте диалект в паспорте, пишите заголовки столбцов в первой строке и используйте единые кодировку и формат даты, а описание типов храните отдельным файлом.
JSON лучше сохраняет вложенность: заказ с позициями естественно записывается одним объектом. Но он хуже подходит для просмотра глазами и для людей, привыкших к таблицам. Разумная пара — сырые JSON-ответы как первоисточник и аккуратные CSV для работы и анализа. Если что-то не так с CSV, всегда можно построить его заново.
Файлы не должны зависеть от чужих ссылок
Проверьте, не лежит ли в ваших данных что-либо, что работает только пока жив исходный сервис. Типичные случаи: ссылка на скачивание документа с токеном, адрес картинки в чужом хранилище, внутренний идентификатор файла, который понятен только API. В архиве нужен сам файл, а ссылка допустима как справочное поле. Быстрая проверка: отключитесь от сети или выйдите из кабинета и откройте несколько случайных документов из архива. Если открылись — файл настоящий, если нет — вы сохранили указатель.
Для каждого скачанного файла полезно хранить имя, размер и контрольную сумму, например SHA-256. Это позволит убедиться, что файл не повреждён при копировании и не подменён, а заодно находить дубли.
Где хранить: свой сервер и его роль
Независимость архива начинается с места хранения. Если он лежит в том же аккаунте SaaS или в облаке, доступ к которому закроется вместе с кабинетом, независимости нет. Нужно место под вашим контролем, куда скрипт ходит по расписанию, а люди заходят без исходной системы.
Для такой роли подходит небольшой VPS. Нагрузка скромная: ночные запросы к API, запись файлов и небольшой просмотр для сотрудников. В публичном предложении VPS MAATRIX указаны NVMe-диски, процессоры AMD EPYC и root-доступ, а локации перечислены такие: UK, US, RU и FR. Тарифная линейка начинается с Ba (1 vCPU, 2 ГБ RAM, 40 ГБ NVMe) и идёт через Uab (2 vCPU, 4 ГБ, 80 ГБ) и Heka (4 vCPU, 8 ГБ, 160 ГБ) к Maat, Djed и выше. Для сохранения только таблиц и справочников хватит самого малого размера; место съедают вложения. Оцените его просто: умножьте число документов на средний размер файла и добавьте запас под несколько версий архива. Если за год накапливается, допустим, 20 тысяч файлов по 300 КБ, это около 6 ГБ — число условное, подставьте своё. Ресурсы тарифа — характеристики конфигурации, а не обещание ёмкости под любую нагрузку, поэтому оценивайте по собственным данным.
Важно и то, чего публичное предложение не обещает: автоматические резервные копии не заявлены для всех тарифов. Значит, копию архива надо делать самому: хранить предыдущие версии выгрузок на сервере и дополнительно копировать на другой носитель или другую площадку. Архив на единственном диске — всё ещё единственная копия. Выбор локации зависит от ваших требований к данным и доступности, и автоматического соответствия законам она не создаёт — это решение владельца. Срок хранения также ваш выбор: он зависит от бизнеса и обязательств, а не от технических возможностей.
В каталоге MAATRIX также упомянуты n8n и Nextcloud с установкой; доступность и операционная система уточняются в форме заказа. Первый может взять на себя оркестрацию запусков и уведомлений, второй — раздачу файлов сотрудникам. Но это необязательные удобства: скрипт, cron и простой просмотр справятся без них, а чем меньше движущихся частей, тем проще архив пережить смену людей.
Просмотр, который не требует системы-источника
Файлы на диске — ещё не доступный архив. Бухгалтер не станет собирать счёт из трёх CSV вручную. Поэтому последний шаг — собрать небольшую автономную оболочку, через которую человек находит заказ и видит всё, что с ним связано.
Минимальный вариант не требует разработки. Загрузите таблицы в локальную базу, например SQLite: заказы, позиции, клиенты, справочники и список документов. Тогда одна связка запросов превращает разрозненные файлы в карточку. Принцип такой:
SELECT o.id, o.created, s.name AS stage, c.name AS client, c.phone, i.sku, i.title, i.qty, i.price, d.path
FROM orders o
JOIN clients c ON c.id = o.client_id
JOIN stages s ON s.id = o.stage_id
LEFT JOIN items i ON i.order_id = o.id
LEFT JOIN documents d ON d.order_id = o.id
WHERE o.id = 10458;Запрос иллюстрирует схему; имена таблиц и столбцов у вас будут свои. Обратите внимание на LEFT JOIN: заказ без документа или без позиций не должен исчезать из результата, иначе проблемные записи — самые интересные для проверки — пропадут молча. Если нужен веб-вид, поверх этой базы делается статическая страница или простой поиск по номеру и телефону, но сначала проверьте, что связки вообще работают.
Пробный импорт одной связанной группы
Лучшая проверка архива — не сверка счётчиков, а прохождение одной цепочки до конца. Выберите заказ с клиентом, несколькими позициями и документом — вроде нашего № 10458 — и проверьте по шагам:
- Найти заказ по номеру и по телефону клиента — в обоих случаях получается одна и та же карточка.
- Статус отображается названием, а не кодом, и совпадает с тем, что было в кабинете на дату выгрузки.
- Сумма позиций с учётом скидок сходится с итогом заказа; если нет, ищите округления, налоги или скрытые поля.
- Документ открывается с диска, а его контрольная сумма совпадает с записанной.
- Ответственный и пользовательские поля показаны человеческими названиями.
Затем повторите на трёх-пяти разных заказах: старом, с отменой, с нестандартной позицией, с кириллицей и переносами строк в комментарии. Эти случаи ломают разбор чаще всего. Если нужна проверка на импорт в другую систему, загрузите ту же группу записей в тестовую среду нового сервиса и посмотрите, не потеряются ли связи. Цель не в том, чтобы воспроизвести прежнюю систему, а в том, чтобы убедиться: данных хватает для работы, и вы знаете, чего не хватает.
Повторяйте такую проверку регулярно, например раз в квартал и после любого изменения скрипта или структуры SaaS. Разметка полей в системе меняется незаметно: добавили поле, переименовали стадию, — а архив продолжает аккуратно складывать то, что было актуально год назад.
Что архив не вернёт
Скажем прямо, чтобы не обещать лишнего. Из архива заказов вы не восстановите: правила автоматизации и роботов, права доступа сотрудников, шаблоны писем и документов (только их результаты), интеграции с другими сервисами, отчёты и дашборды как настройки (только данные, из которых их можно собрать заново). Часть этого можно описать текстом или скриншотами и положить рядом, но это уже документация, а не данные. Такая граница — не недостаток, а честное описание того, что вы делаете: сохраняете возможность вести дела, а не клонируете платформу.
Утро без кабинета
Теперь вернёмся к строке 10458; 2026-10-28; Новый; 48 600; 3412. Допустим, кабинет закрыт, а клиент звонит и просит повторить счёт. Сотрудник открывает внутренний просмотр, вводит номер заказа и видит карточку: имя компании и телефон, три позиции с артикулами и количествами, стадию словами, фамилию ответственного, дату состояния архива в шапке — и ссылку на счёт, который открывается с вашего сервера. Он отправляет файл клиенту и уточняет в комментарии, что отгрузка по этому заказу ещё не оформлена. Никто не вспоминал пароли и не писал в поддержку. Для этого и нужен архив: не чтобы красиво лежать, а чтобы в обычное утро нужная запись нашлась за минуту.