Один контракт данных, разные адаптеры: как перестать писать миграцию магазина заново

Wait 5 sec.

Первый файл, который я получил при переезде своего магазина с InSales, парсер прочитал как одну длинную строку мусора. Выгрузка заказов оказалась в UTF-16 LE с BOM и табуляцией вместо запятой — ни один разумный дефолт не подошёл.Тогда это выглядело как разовая неприятность: поправил чтение, написал скрипт, ночь работы, всё уехало, скрипт лёг в репозиторий. На следующем проекте он не переиспользовался — другая платформа, другие колонки, другие правила. На третьем стало видно, что повторяется почти вся работа: связать заказ с клиентом, не создать дублей, не потерять адреса страниц, уметь перезапуститься. Разное только на входе — кодировка, формат, названия колонок, единицы измерения.Отсюда вывод, к которому стоит прийти раньше, чем на третьем проекте: середина должна быть одна, а платформенная специфика — жить в тонком слое на входе. Ниже — как этот каркас устроен у меня, с кодом из работающего проекта: собственного магазина, который я перевёз с InSales на свой движок на Next.js и PostgreSQL.Сразу оговорюсь про доставленные миграции: полностью пройдена одна — та, о которой пойдёт речь. Про требования к адаптерам под 1С‑выгрузки и товароучётные API дальше я говорю как о проектных требованиях к каркасу; готовыми кейсами они не являются. Это важно, чтобы вы правильно оценили вес каждого утверждения.Резонный вопрос до всего остального: почему не готовый инструмент. Airbyte, n8n, коннекторы к товароучётным системам делают ровно это — вытащить, преобразовать, положить. Для регулярной синхронизации они и есть правильный выбор. Разовая миграция магазина отличается тем, что сложность сидит не в перекладывании строк, а в доменных правилах: как собрать заказ из нескольких строк, что делать с позицией, товара которой больше нет в каталоге, как при повторном прогоне не затереть свежие данные старыми. Эти правила всё равно пишутся руками, а в визуальной цепочке трансформаций их неудобно тестировать и нельзя перезапустить кусочком. Поэтому середина своя, а тонкими остаются края. Читать далее