Перейти к содержанию

Перенос конфигурации между площадками

Утилита переноса конфигурации позволяет администратору перенести настройки с одной площадки 1Формы на другую. Через неё переносят категории и разделы, дополнительные параметры (ДП), статусы и маршруты, порталы, отчёты, публикации, автоматизации (смарт-пакеты, смарт-выражения, смарт-расписания) и другие элементы конфигурации. Переносятся именно настройки — рабочие данные (задачи, комментарии, пользовательские файлы) утилита не выгружает (исключение — записи справочников 2.0, см. ниже). Администратор выбирает нужные объекты в дереве, выгружает их в архив на площадке-источнике и загружает этот архив на площадке-приёмнике. Инструмент рассчитан на администратора или настройщика площадки и работает через раздел администрирования.

Кто может переносить конфигурацию

Перенос конфигурации между площадками — импорт и экспорт архива, предпросмотр импорта, просмотр дерева объектов, полная фоновая выгрузка — доступен только пользователям с правами администратора (God). Пользователь или сервисная учётная запись без прав администратора получает отказ в доступе. Ограничение действует одинаково и для операций в интерфейсе администрирования, и для вызовов через MCP-сервер миграции.

Практическое следствие: интеграции и автоматизации, которые обращались к переносу конфигурации под неадминистративной учётной записью, нужно перевести на учётную запись администратора.

Важные условия и ограничения

⚠️ Версии площадок должны совпадать. Экспорт и импорт конфигурации предназначены не для обновления платформы, а только для переноса настроек между экземплярами одной версии, поэтому версии площадки-источника и площадки-приёмника должны совпадать. Утилита поддерживает и кросс-версионный перенос: при расхождении версий она автоматически создаёт заглушки для недостающих зависимостей (категории, группы, справочники) и сопоставляет объекты по GUID. Если на приёмнике нет таблиц или колонок из более новой версии, сначала выполняют миграцию схемы базы (dbdeploy).

⚠️ Площадка-приёмник должна быть «чистой». На приёмнике не должно быть заранее созданных сущностей — кроме пользователей, оргструктуры и групп пользователей. Все настройки должны попадать в базу только через перенос. Иначе возможны конфликты идентификаторов и перезапись чужих данных.

⚠️ Для лога в реальном времени нужен доступный endpoint /migrationUtilityHub. Чтобы на странице переноса в реальном времени обновлялись лог и статусы, через reverse proxy должен быть доступен SignalR-endpoint /migrationUtilityHub. Без него экспорт всё равно выполнится (как фоновая операция), но интерфейс не будет показывать обновления статуса.

Без остановки приложения. Перенос не требует остановки приложения. Новые настройки применяются без перезагрузки пула приложения.

Что переносится, а что настраивается вручную

При переносе объекты сопоставляются по GUID, а не по ID — это защищает от дублирования. Ниже собраны все правила и особенности переноса: что переносится автоматически, что тянется вместе со связанными объектами, а что нужно донастроить на приёмнике вручную.

Привязка к модулю у отдельного объекта. Если архив объекта не содержит сам модуль, новый объект после импорта остаётся без привязки к модулю: совпавший на приёмнике числовой идентификатор модуля не используется, и сопоставление модуля по GUID не выполняется — назначьте модуль вручную в форме администрирования. Если объект уже есть на приёмнике и найден по GUID, импорт сохраняет назначенную там привязку. Правило относится к разделам, категориям, дополнительным параметрам, статусам, подписям, пакетам действий, смарт-выражениям и скриптам. Когда архив содержит сам модуль, привязка переносится как обычно.

№ Правило Пояснение
1 Данные задач и пользовательские файлы не переносятся Утилита выгружает только настройки и отдельные объекты (например, перечисления). Рабочие данные задач и вложения остаются на источнике
2 Кастомные объекты БД настраиваются вручную Хранимые процедуры, SQL-функции, представления (view), шаблоны файлов (печатные формы) утилита не переносит — их создают на приёмнике вручную (см. предупреждение ниже)
3 При переносе ДП переносятся только его настройки Связанные категории, разделы, сводные разделы и другие ДП нужно выбирать в дереве вручную. Исключение: привязка ДП к блокам и доступ к ДП на статусах включаются автоматически
4 При переносе категории подтягиваются связанные группы Группы с правами на категорию, ответственная группа, группа уведомления о превышении плана, группы из настроек доступа к ДП и из уведомлений
5 Состав группы (участники) не переносится При переносе группы создаётся только сама группа с тем же ID; список её участников не передаётся
6 Объекты, удалённые на источнике, удаляются и на приёмнике Касается ДП, подписей на переходе, JS/CSS-вставок, кнопок, произвольных событий, блоков «Используется», блоков ДП, а также привязок ДП к блокам. Важно учитывать при повторном (инкрементальном) переносе
7 Для lookup/multilookup ДП категорию-источник выбирают вручную При первом переносе такого ДП или после изменений в категории-источнике. Если ДП настроен на сводный раздел — выбирают сам раздел и входящие в него категории
8 При экспорте multilookup сохраняются настройки «Параметры в гриде» Они восстанавливаются вместе с ДП при импорте. Это настройка колонок табличного представления выбранных задач внутри параметра; настройки табличного представления самого источника данных — отдельная сущность (правило 33)
9 Для сквозных ДП проверяют наличие целевого ДП и категории В целевом приложении должны быть и ДП, на который ссылается сквозной параметр, и соответствующая категория
10 Параметры действий с группами и оргструктурой сопоставляются автоматически Параметры смарт-действий с группами сопоставляются по соответствиям пакета, параметры с подразделениями — по идентификатору при наличии объекта на приёмнике. Если объекта нет, одиночный параметр действия удаляется (без сбоя импорта), а из списков ненайденные значения исключаются; запись об этом есть в журнале импорта. Идентификаторы групп внутри SQL смарт-выражений по-прежнему при необходимости выверяются вручную
11 Общие смарт-выражения (SMART) выбирают вручную В дереве экспорта — в ветке «Смарт-выражения»
12 Почтовые ящики в автоматизациях меняют вручную После переноса указывают почтовые ящики целевой площадки
13 Настройки мобильного приложения переносят вручную Шаблоны задач, источники данных, контейнеры, шаблоны. Привязка шаблонов к категории переносится автоматически
14 Порталы корректно переносятся только с сохранением ID Перенос порталов работает только при импорте с сохранением идентификаторов. В архив входят блоки корневой раскладки, адаптивных раскладок (размеры экрана xs…xl) и секций Board: блок, размещённый только в секции или только на одном размере экрана, сохраняется при выгрузке и загрузке, а раскладка приёмника при домерже не затирается. Вместе с порталами переносятся JS/CSS и смарты блоков; кастомные объекты БД блоков настраивают вручную Зависимости блоков, ссылающиеся на объекты конфигурации, при импорте перепривязываются по GUID к объектам приёмника: у блока «Профиль пользователя» так переносятся узел оргструктуры и смарт-выражения источника и подстрочника. Ссылку на конкретного пользователя перенос не поддерживает — таблица пользователей в конфигурацию переноса не входит, поэтому блок с источником «фиксированный пользователь» останавливает импорт с явной ошибкой, а не подставляет идентификатор площадки-источника.
15 Публикации переносятся со связанными объектами Вместе с публикацией переносятся связанные объекты доступа, смарт-пакеты и представления
16 Локализованные объекты переносятся с локализациями При конфликте идентификатора локализации утилита генерирует новые ID. Язык локализованного значения сопоставляется не по номеру, а по коду языка LangAlias (запасной путь — по культуре): справочник языков источника экспортируется в _meta/languages.json. Языка нет на приёмнике или его код неоднозначен — локализованное значение не импортируется и уходит в отчёт переноса, чужой язык не подставляется. Архив без файла языков разбирается по номеру, как раньше, с предупреждением в лог.
17 Смарт-выражения и LUA-скрипты переносятся со всеми версиями
18 Смарт-выражение при переносе на боевую площадку автоматически повышает версию Если версии выражения на площадках различаются
19 Отдельные типы объектов можно исключить из экспорта Настройка приложения MigrationExportSettings позволяет не выгружать выбранные типы объектов (например, права доступа групп к категории)
20 Смарт-доступ по ДП переносится вместе с параметром; при конфликте ID генерируются новые Правило смарт-доступа тянет связанный дополнительный параметр в пакет экспорта как зависимость, поэтому на приёмнике привязка правила к параметру приезжает рабочей. Если на приёмнике уже есть запись прав с тем же ID, но другим GUID, утилита создаёт новые уникальные идентификаторы
21 Настройки сквозного ДП обновляются под приёмник При расхождении между площадками утилита заменяет пути в настройках сквозного параметра
22 Гибкие права на задачи переносятся вместе с ДП категории
23 Системный журнал категорий переносится по умолчанию
24 Раздел «Статусы» можно экспортировать отдельно Статусы экспортируются независимо от категории. Это удобно при конфликтах маршрутов (дублирующиеся идентификаторы маршрутов)
25 Права групп на категорию синхронизируются при импорте категории целиком Права групп в целевой категории приводятся в точное соответствие с пакетом: отсутствующие в экспорте — удаляются, присутствующие — добавляются или обновляются. Работает и на MS SQL, и на PostgreSQL
26 Admin-настройки табличного представления категории и блоков «Используется» (БИ) переносятся вместе с категорией Переносятся обе разновидности админской настройки табличного вида — и для табличного представления категории, и для каждого блока «Используется»; владелец настройки сопоставляется с объектом на приёмнике по GUID, поэтому состав и порядок колонок, ширины и фильтры совпадают с источником, даже если идентификаторы на площадках разные. Переносятся только записи без привязки к пользователю; пользовательские настройки колонок и фильтров не переносятся и пересоздаются автоматически на приёмнике
27 Параметры фильтра отчёта переносятся с сохранением ID В стандартном режиме идентификаторы параметров фильтра сохраняются так же, как у отчёта и самого фильтра. Вместе с параметрами в архив попадают связи между зависимыми параметрами, поэтому настроенные зависимости работают на приёмнике без ручной правки
28 Валидаторы ДП переносятся вместе с категорией Валидатор уезжает в архив следом за своими привязками — к шагу маршрута и к кнопке карточки задачи, — поэтому на приёмнике проверки значений ДП работают без ручной донастройки
29 Настройки произвольных источников данных и общие выборки переносятся с категорией В пакет попадают настройки источника и сохранённые выборки, помеченные как общие; личные выборки и личные настройки конкретных пользователей не экспортируются. При импорте номера задач внутри сохранённых выборок пакета заменяются на номера задач приёмника — и в списке задач фильтра, и в поле отдельной задачи, и в фильтрах сохранённого вида выборки: в фильтре «Выбор значений», в мультилукап-фильтре по задачам и в конструкторе поиска (модель продвинутого фильтра); границы страницы выборки не меняются. Если личная выборка всё же оказалась в пакете, номера задач в ней заменяются так же, как в общей
30 Опрос переносится вместе со своим шаблоном По решению владельца шаблон уезжает вместе с категорией: задачи-шаблоны опросов этой категории, конфигурация каждого опроса и его вопросы, а также режим опроса самой категории. Отдельно выбирать опросы в дереве экспорта не нужно. Созданные опросы, назначения опросов задачам и результаты прохождения не переносятся — это рабочие данные площадки-источника. При импорте утилита перепривязывает ссылки на задачи и файлы внутри конфигурации опроса во всех режимах, включая стандартный, а задачу вне пакета ищет на приёмнике по GUID. Ссылка, которую сопоставить не удалось, остаётся прежней, а в лог переноса пишется предупреждение. Состояние на сборке 2.268: задачи-шаблоны в пакет не попадают — их отсекает экспортный фильтр выгрузки категории, поэтому шаблон опроса пока не переносится; исправление готовится
31 Теги категории переносятся вместе с ней Вместе с категорией переезжают типы тегов и маппинги тегов. При повторном переносе на приёмник, где такие теги уже есть, совпавшие записи не дублируются: утилита сопоставляет их по паре «тип тега и имя» или «тип тега, алиас параметра и внешний параметр» и переводит запись в обновление. Если маппинг источника совпал с разными записями приёмника или две записи источника ведут на одну запись приёмника, импорт прерывается с перечислением конфликтующих записей.
32 Запись с несопоставленной обязательной ссылкой не переносится Если обязательная ссылка — часть составного ключа или обычная обязательная ссылка — не нашлась на приёмнике ни по идентификатору, ни по GUID, утилита не подставляет вместо неё произвольную запись справочника: запись отбрасывается, а в лог переноса идёт предупреждение с типом сущности и значением ссылки. Исключение — ссылка на пользователя: вместо ненайденного подставляется системный робот. Для параметров действий пакетов правило своё: значение параметра-пользователя сопоставляется с пользователями приёмника по идентификатору, и если такого пользователя на приёмнике нет, одиночное значение заменяется системным роботом, а в списке пользователей ненайденные убираются — робот вместо элемента списка не подставляется. Каждая такая замена и каждое удаление попадают в журнал переноса. Если записей не хватает после импорта, ищите эти предупреждения в логе
33 Настройки экрана «Источник данных» лукапа и мультилукапа переносятся вместе с параметром В пакет включаются админские настройки табличного представления источника данных: состав и порядок колонок, «Доступность», «Видимость по умолчанию», «Стиль», «Выравнивание», «Ширина», «Тип фильтра», а также общие настройки экрана — «Тип статуса», «Группировать по», «Группировать одной строкой», «Позиция закрепления». Переносятся только админские настройки; личные настройки пользователей остаются на своей площадке. Если у параметра на приёмнике уже была сохранена своя настройка источника, она заменяется настройкой площадки-источника — вторая запись не создаётся. Категорию-источник при этом по-прежнему выбирают вручную (правило 7), отдельно переносятся «Параметры в гриде» мультилукапа (правило 8)
34 Привязки ДП к блокам синхронизируются при повторном переносе Привязка «ДП → блок» приводится в соответствие с пакетом: привязки перенесённого ДП, которых нет в пакете, на приёмнике снимаются. Это важно при повторном (инкрементальном) переносе на непустой приёмник: если на источнике ДП переместили из блока A в блок B, а категорию переносят второй раз, привязка к блоку A на приёмнике снимается, и параметр остаётся только в блоке B. На сборках до 2.268 «Скульптор» привязка к прежнему блоку сохранялась, и один ДП отображался в карточке дважды — в старом и новом блоках

Задачи-шаблоны опросов лежат в категориях задач, поэтому выгрузка категории забирает их независимо от флага выгрузки справочников: раньше шаблоны попадали в пакет только из категорий-справочников и в обычном режиме не уезжали вовсе.

⚠️ Кастомных объектов БД в дереве экспорта нет. Хранимые процедуры, SQL-функции и представления (view) утилита не выгружает — отдельной ветки под них в дереве объектов нет, искать их там не нужно. Их создают на площадке-приёмнике вручную (через SSMS/psql), и только после этого настраивают зависящие от них объекты (например, SQL-представление доступа к категории).

⚠️ Повторный перенос на площадку, где настройка вида уже настроена. Админские настройки табличного вида категории и блоков «Используется» сопоставляются с приёмником по GUID: если для того же блока или категории на приёмнике уже сохранена своя настройка, перенос добавит рядом вторую запись, а не заменит существующую. Замена сохранённой настройки гарантирована только для настроек экрана «Источник данных» лукапа и мультилукапа (правило 33). Перед переносом на непустой приёмник проверьте, не настроен ли нужный блок или категория вручную.

Экспорт конфигурации

Администратор открывает дерево объектов, отмечает нужные элементы и выгружает их. Выгруженная конфигурация упаковывается в ZIP-архив. При импорте формат архива определяется автоматически, поэтому архивы, выгруженные разными версиями утилиты, загружаются без дополнительной подготовки.

Поиск настроек на странице экспорта

Чтобы не искать нужные настройки перебором в дереве объектов, над деревом есть поле поиска. Поиск, как и остальные операции переноса, доступен только администратору (God).

Поиск идёт по названию настройки (вхождение подстроки, без учёта регистра) или по точному числовому id — например, по id категории или дополнительного параметра. Запускается он, когда в поле набрано не меньше символов, чем задано настройкой приложения NumberCharactersForSearch; числовой запрос ищет с первого символа.

Поиск охватывает разделы, категории, дополнительные параметры (ДП) и ДП в составе категории. Остальные настройки, как и раньше, ищут в дереве вручную.

Найденное показывается списком, сгруппированным по типу настройки; у каждой записи видны название и её id. Записи разных типов с одинаковым числовым id показываются отдельными строками и выбираются независимо друг от друга. Найденную категорию можно раскрыть прямо из результатов и отметить в ней нужные дочерние настройки — искать её отдельно в дереве не требуется.

Отмеченные из результатов поиска настройки остаются в выборе и после очистки строки запроса. Кнопка «По умолчанию» очищает и выбор, и поиск.

Если подходящих записей больше, чем помещается в выдачу, страница об этом сообщает и предлагает уточнить запрос.

При поиске поле «Поиск» остаётся над списком дерева. Если поиск выполняется, ничего не нашёл или выдача ограничена, сообщение состояния показывается под деревом и остаётся видимым без прокрутки страницы. Прокручивается список дерева: у области страницы экспорта своей вертикальной или горизонтальной полосы прокрутки нет. Длинные названия прокручиваются по горизонтали внутри списка.

Поиск ищет только то, что есть в дереве экспорта.

Полная выгрузка

Кнопка «Полная выгрузка» запускает фоновую выгрузку всей конфигурации площадки. Готовый архив помещается в файловое хранилище, в папку «Файлы автоматизации / Export configurations»; доступ к нему получает группа администраторов (GodGroup). По завершении система присылает уведомление. Пока выгрузка идёт, кнопка неактивна.

Частичный экспорт и родительские разделы

При частичном экспорте можно выбрать отдельную категорию. Если её родительский раздел есть на источнике, но отсутствует на приёмнике, он автоматически добавляется в пакет. Если переносится весь раздел, он будет создан в целевом приложении.

Частичный экспорт выполняется сразу и ждёт ответа сервера. На больших объёмах запрос может не уложиться в отведённое время — тогда система сообщает, что выгрузить файл не удалось, и рекомендует «Полную выгрузку», которая работает в фоне.

Перенос справочников 2.0

Утилита переносит не только структуру категории-справочника (поля, маршруты, представления), но и сами записи справочника вместе с заполненными дополнительными параметрами. Это позволяет перенести готовый справочник целиком с одной площадки на другую. Перенос значений справочника включается отдельной опцией при экспорте.

Что попадает в пакет: - Категория справочника (название, дополнительные параметры, представления, маршруты). - Записи справочника — как задачи соответствующей категории. - Значения дополнительных параметров этих записей: lookup-связи на другие справочники, выбранные задачи и папки, табличные ДП.

Что пока не переносится: - Значения ДП типа «Выбор пользователей», «Выбор групп», «Выбор подразделений» — при экспорте по ним остаётся предупреждение в системном логе.

Ссылка на задачу вне пакета переноса. Если запись справочника через lookup ссылается на задачу, которая не вошла в пакет, утилита запоминает её GUID. При импорте она ищет задачу с этим GUID на площадке-приёмнике: если такая задача есть, ссылка автоматически привязывается к ней. Если задачи с этим GUID нет ни в пакете, ни на приёмнике, ссылка пропускается без ошибки — остальные записи импортируются штатно, а о пропущенных значениях остаётся запись в системном логе.

Ссылка на запись справочника в смарт-выражениях и скриптах. При переносе номер записи справочника подставляется автоматически, если запись перенесена в том же пакете и её номер стоит в SQL-сравнении с taskid, SelectedTaskId, NaturalValue или с колонкой ExtParam{N}NativeValue лукап-ДП - в смарт-выражениях, в SQL отчётов и в строковых литералах смарт-скриптов, которые распознаны как SQL. Номер, собранный конкатенацией, вычисленный или записанный вне такого сравнения, утилита не узнаёт и не меняет - там на запись справочника ссылаются по GUID.

Ссылки на задачи и параметры в настройках смарт-действий. Фиксированные значения параметров действий в пакетах тоже приводятся к приёмнику: номер задачи в параметрах действий «Отправить сообщение пользователю» (вставка текста и открытие задачи) и «Сгенерировать по шаблону», значение лукап-параметра и номер дополнительного параметра в действиях «Изменить значение ДП» и «Массово изменить значение ДП», а также SQL в действиях «Выполнить SQL» и «Создать или обновить смарт-фильтр» — он разбирается так же, как SQL смарт-выражений. Пользовательские действия и действия, неизвестные этой версии, пропускаются без изменений и не прерывают импорт; значение, которое не удалось разобрать или сопоставить, остаётся прежним, а в лог переноса пишется предупреждение.

Пользователи в параметрах действий. Параметры типа «Пользователь» и «Список пользователей» приводятся к приёмнику так же, как ссылки на задачи: значение сверяется с пользователями приёмника по идентификатору. Если пользователь на приёмнике есть, значение сохраняется; если его нет, одиночный параметр заменяется системным роботом приёмника, а из списка ненайденные пользователи убираются. Робот проверки прав не проходит насквозь, а снимает их, поэтому подмену важно заметить: по каждому параметру с явно заданными пользователями в журнал переноса идёт предупреждение с пакетом, действием, параметром, исходными идентификаторами и результатом.

Группы и оргструктура в параметрах действий. Параметры действий с группами и типами групп сопоставляются по соответствиям пакета, а параметры с подразделениями и типами подразделений — по идентификатору при условии, что объект есть на приёмнике. Если группа или подразделение на приёмнике не найдены, одиночный фиксированный параметр не перезаписывается пустым значением, а удаляется из действия (иначе таблица параметров не примет пустое значение без выражения), а из списочного параметра ненайденные идентификаторы исключаются. Перенос конфигурации при этом завершается успешно, а каждое убранное значение попадает в журнал импорта отдельной строкой с действием, параметром и идентификатором. Перенос внутри одной базы данных работает как прежде.

Ссылки на объекты, которых нет в пакете. Если пользователь или группа упоминается в переносимых данных, но сам объект в пакет не входит, ссылка ищется не по номеру, а по смысловому ключу: пользователь — по логину, группа — по своему идентификатору в справочнике. Раньше такая ссылка подбиралась по номеру, и если номер на приёмнике был занят другим объектом, ссылка молча указывала на чужого сотрудника или чужую группу, строки в журнале не появлялось. Если объекта на приёмнике нет, ссылка убирается по общему правилу, а случай попадает в журнал переноса.

Группа уведомления шага, которой нет на приёмнике. Если у шага маршрута задана группа уведомления, а на площадке-приёмнике такой группы нет, импорт снимает уведомление целиком: вместе со ссылкой на группу очищаются флаг уведомления и текст. После переноса такой шаг не отправляет ни уведомление, ни письма, а в журнал импорта попадает запись с объектом, полем, исходным идентификатором группы и итогом. Причина в том, что пустая группа для потребителя означает не «никому», а «всем»: получателем становится заданная группа, а если её нет — все пользователи с правом просмотра задач категории, и шаг, настроенный на узкий круг, после переноса рассылал бы уведомления всем. Если группа на приёмнике есть или шаг и на источнике уведомлял без группы, поведение не меняется. Группы и пользователи в настройках. Ссылки на группы и пользователей в настройках при переносе сверяются с площадкой-приёмником по идентификатору, а не переезжают как есть: ненайденная ссылка убирается — одиночное значение остаётся пустым, из списка ненайденные значения убираются, исходный идентификатор не сохраняется и системный робот вместо отсутствующего объекта не подставляется. Сверяются, в частности, группы смарт-доступа, группа уведомления в маршруте категории, приглашённая группа категории, группа-источник данных блока портала, значения по умолчанию колонок табличных параметров с выбором пользователей, значения параметров действий по изменению параметров и созданию задачи, автор задачи и инициатор шага у переносимых задач и шаблонов. Если у правила смарт-доступа после переноса не осталось ни одной группы, правило вместе с привязкой к категориям на приёмник не переносится: правило без групп означает доступ для всех, и создавать его нельзя.

Журнал переноса. Каждое убранное значение попадает в журнал отдельной строкой: объект, поле и исходный идентификатор. О блоке портала отдельно: у него поле группы — не видимость, а источник данных рабочего места, поэтому отсутствие группы не расширяет доступ к блоку — кто видит блок, по-прежнему определяют связи блока с группами, и перенос их не трогает.

Если на приёмнике нет объекта, на который ссылается перенос

Перенос не обрывается, если на площадке-приёмнике нет пользователя, задачи или адреса, на которые ссылаются переносимые данные. Значения дополнительных параметров записей справочников очищаются: ссылка на задачу, адрес и выбранный пользователь остаются пустыми. Строка настроек колонок иерархии задач с отсутствующим пользователем не переносится вовсе — в отличие от ссылок в записях справочников, системный робот вместо него не подставляется. Каждый такой случай пишется в журнал импорта отдельной строкой с сущностью, полем и исходным идентификатором, а сам импорт считается успешным. Проверить, что не переехало, можно по журналу переноса после завершения импорта.

Денормализация значений. После импорта утилита сама обновляет денормализованное представление справочника и пересоздаёт денорм-представления табличных ДП, чтобы значения сразу были видны в табличных представлениях, фильтрах и связанных задачах — без перезагрузки пула приложения.

Паритет PostgreSQL. На PostgreSQL поведение одиночных lookup-связей приведено к поведению MS SQL Server, поэтому импорт справочников 2.0 даёт одинаковый результат на обеих СУБД.

Несопоставленные ссылки: сводка в конце переноса. Замена идентификаторов — не блокирующая проверка: если ссылку сопоставить не удалось, импорт не прерывается, а в конце переноса утилита печатает одну сводку уровня Warn — по каждому объекту его вид, название, GUID и несопоставленные номера. Сводка идёт в системный лог приёмника и параллельно транслируется в открытое окно переноса (SignalR-хаб MigrationUtilityHub, событие notify). После переноса сводку стоит просмотреть: до первого срабатывания настройки несопоставленная ссылка внешне себя не проявляет. Иначе ведут себя обязательные ссылки в записях справочника — такая запись не переносится вовсе (см. правило 32).

Опции импорта

По умолчанию утилита переносит объекты с сохранением их идентификаторов: объекты сопоставляются по GUID, уже существующие на приёмнике обновляются, а новые добавляются с тем же ID, что и на источнике. Это стандартный сценарий переноса настроек между площадками одной версии.

После выбора файла миграции становятся доступны дополнительные опции:

Опция Что делает
Нужна денормализация Запускает денормализацию переносимых категорий. Гарантированно применяется при полном переносе категории. При частичном импорте (только новые ДП или блоки) автоматическая денормализация может не обновить структуру денорм-таблицы — тогда денормализацию выполняют вручную после импорта. Для сводного раздела опция обязательна
Загружать все резолюции По умолчанию резолюции из статических подписей не импортируются вместе с категорией; опция включает их перенос
Импортировать как новые сущности Все объекты создаются заново — с новыми GUID и идентификаторами, которые выдаёт площадка-приёмник. Получается независимая копия конфигурации, не связанная с источником по ID. Автором версий указывается служебная учётная запись «Робот 1Ф». Исключения: системные статусы «Новая», «Выполняется», «Завершена», «Отклонена» не дублируются; служебные группы Administrators, «Исключить из чатов», «Включить в чаты» проверяются по общим настройкам приложения
Импортировать без сохранения идентификаторов Объекты сопоставляются по GUID: уже существующие обновляются с сохранением своих прежних ID, новые добавляются с идентификаторами приёмника. После импорта утилита сама заменяет ID в смарт-выражениях, ссылки в JSON-настройках порталов и параметры смарт-правил. Предназначен для обновления боевой площадки конфигурацией со стенда разработки, когда идентификаторы объектов разошлись

Какой режим переноса выбрать:

  • Стандартный перенос (с сохранением ID) — обычный перенос настроек между площадками одной версии. Никаких дополнительных опций включать не нужно: объекты сопоставляются по GUID, существующие обновляются, новые добавляются с прежними идентификаторами.
  • Импортировать как новые сущности — когда нужна независимая копия конфигурации с новыми идентификаторами (например, размножить готовую настройку на новом стенде).
  • Импортировать без сохранения идентификаторов — когда обновляют боевую площадку конфигурацией со стенда разработки, а ID объектов на площадках уже разошлись.

⚠️ Режим «Импортировать без сохранения идентификаторов» доступен только в утилите командной строки и в WinForms-версии. В веб-интерфейсе (раздел администрирования) этой опции нет.

Предпросмотр (Preview)

Кнопка «Проверить» запускает анализ переносимых объектов. В таблице предпросмотра показываются:

Колонка Что показывает
Название Название переносимого объекта
Таблица Таблица базы данных приёмника
GUID GUID переносимого объекта
Статус Один из четырёх статусов (см. ниже)
Изменённые поля Только для статуса «Обновить» — список отличающихся полей до запуска импорта

Статусы предпросмотра:

Статус Значение
Добавить Объект отсутствует на приёмнике и будет добавлен
Обновить Объект есть на приёмнике, но будет обновлён; доступен список изменённых полей
Конфликт Объект с таким идентификатором уже есть, загрузка невозможна
Без изменений Объект одинаков на источнике и приёмнике

Опция «Показать только изменяемые» скрывает записи со статусом «Без изменений».

После импорта

После завершения импорта рекомендуется:

  1. Вручную проверить корректность перенесённых настроек — в том числе настройки табличного представления: состав и порядок колонок табличного вида перенесённых категорий и блоков «Используется» должны совпадать с источником.
  2. Очистить кеш.
  3. Выполнить денормализацию категорий, для которых переносились настройки.
  4. Перезапустить пул приложения.
  5. Просмотреть журнал переноса и проверить пакеты, у которых в параметрах действий были явно заданы пользователи: сохранённые значения, удалённые из списков и замены на системного робота перечислены там отдельными предупреждениями. Замена на робота означает, что после переноса действие работает без проверки прав.
  6. Просмотреть журнал переноса на предмет убранных ссылок на группы и пользователей в настройках: каждая такая ссылка указана отдельной строкой с полем и идентификатором. Если у правила смарт-доступа не осталось групп, правило на приёмник не переносилось — его нужно настроить заново.

Импорт на непустую базу

При стандартном импорте (с сохранением идентификаторов) утилита добавляет объекты с теми же ID, что и на источнике. Из-за этого даже на, казалось бы, пустой базе возможны конфликты первичных ключей, если в ней уже есть предзаполненные (seed) данные платформы.

Типовой пример — конфликт по дополнительным параметрам: один и тот же внутренний идентификатор может быть занят разными ДП в импортируемом пакете и в seed-данных базы. В этом случае импорт прерывается ошибкой нарушения первичного ключа (Violation of PRIMARY KEY constraint).

Конфликт по дополнительному уникальному ключу (не первичному) утилита разбирает до начала импорта: уникальный составной индекс задаёт слот записи, и по каждому такому индексу переносимых типов она проверяет, нужен ли слот пакету и освободится ли он к концу импорта. Если слот освобождает удаляемая или сдвигаемая запись, запись пакета выполняется во второй фазе, и импорт проходит штатно; если слот занят записью приёмника, которую импорт не удаляет и не сдвигает, импорт останавливается до первой записи в базу и выводит перечень конфликтов — тип записи, имя уникального индекса, значение слота и GUID конфликтующих записей, — а данные приёмника остаются неизменными. Обмен слотами между двумя переносимыми записями утилита проводит через временное значение. Если нарушение уникальности всё же происходит внутри импорта, поведение прежнее: утилита пытается обновить запись по составному первичному ключу; если записи с таким первичным ключом нет — значит, конфликт пришёлся на другой уникальный ключ, — ошибка фиксируется в журнале с указанием ключа и импорт прерывается. Дубликат по самому составному первичному ключу приводит к обновлению существующей записи.

Что делать: для конфигураций, которые загружаются на чистый стенд, перед импортом проверьте наличие seed-сущностей и при необходимости очистите базу от предзаполненных категорий, дополнительных параметров, статусов и связанных системных сущностей, оставив только минимальный технический скелет площадки.

Если содержимое приёмной базы нужно сохранить, вместо стандартного сценария выберите режим импорта с переназначением идентификаторов — «Импортировать как новые сущности» или «Импортировать без сохранения идентификаторов».

Ссылки привязок JS/CSS-вставок при стандартном импорте разрешаются по GUID вставки: подробнее — в режимах импорта, раздел «Режим 1: KeepIdentity».

Модули и версионирование

Импорт модуля и разрешение конфликтов имён

При импорте конфигурации, содержащей модули, действуют такие правила:

  • Конфликт названий. Название модуля уникально без учёта регистра. Если модуль из архива претендует на название, занятое на площадке-приёмнике другим модулем, импорт прерывается до записи в базу — в любом режиме импорта. Администратор получает сообщение с названием модуля из архива и занятым именем вместо технической ошибки базы.
  • Автор и даты при импорте. Числовой идентификатор пользователя исходной базы в карточку модуля не переносится: для нового модуля автором становится пользователь, запустивший импорт, а датами создания и изменения — момент импорта.
  • Обновление существующего модуля. Если модуль сопоставлен по идентификатору с уже существующим, его первоначальный автор и дата создания сохраняются, а импорт фиксируется как изменение модуля: автор и дата последнего изменения обновляются на пользователя и время импорта.
  • Поле источника. Заполняется сведениями об источнике из архива нового формата; при импорте архивов старого формата остаётся пустым, а существующее описание модуля не затирается.

Модуль — это логическое объединение сущностей конфигурации для переноса и версионирования. В модуль обычно входят разделы, категории, ДП, статусы, подписи, отчёты, порталы, виджеты и автоматизации (смарт-пакеты, смарт-выражения, смарт-расписания).

Базовые операции с модулями:

  • Создание — указать название и сохранить.
  • Редактирование — изменить данные модуля в списке.
  • Удаление — возможно только если в модуле нет связанных сущностей: система проверяет категории и разделы, дополнительные параметры, пакеты действий, смарт-выражения и скрипты, подписи, статусы, блоки и шаблоны портала, отчёты, роли БП и версии конфигураций и при наличии связей сообщает, что именно мешает и сколько таких записей. Создание и удаление модулей доступны администратору с полными правами.
  • Назначение — в формах администрирования у объекта есть поле «Модуль». Если модуль не выбран, объект относится к общему (глобальному) модулю.

Что меняется при правке модуля

Название модуля уникально без учёта регистра: попытка создать или переименовать модуль в уже занятое имя отклоняется с понятной ошибкой. Пробелы по краям названия сервер отбрасывает сам, а имя длиннее 200 символов не принимает. Вместе с названием задаётся описание модуля.

Дата и автор последнего изменения двигаются, когда меняется сам модуль или создаётся его версия. Привязка категорий и правка настроек связанных сущностей датой последнего изменения модуля не считается — карточка модуля от этого не обновляется.

Что видно в карточке модуля

Карточка модуля несёт не только название. У модуля есть описание, автор-создатель и автор последнего изменения с признаком «пользователь или группа», источник модуля (текст из архива при импорте), дата создания и дата последнего изменения, а также категории, привязанные к модулю.

Версия в карточке — только своя. Система сопоставляет версию по паре «модуль и версия». Если версия для модуля не создавалась или сохранённый указатель ведёт на версию другого модуля, поле версии остаётся пустым: чужая версия и нулевой идентификатор в карточке не показываются. Вместе с версией приходят её идентификатор, значение и дата.

Карточка отдаёт и идентификатор сохранённого указателя на версию — он нужен интерфейсу выбора версии, и ориентироваться на него как на «версию модуля» не стоит: версия модуля — это отдельное поле с идентификатором, значением и датой.

Состав карточки расширен без смены формата ответа. Список модулей остаётся массивом в том же поле, поэтому выпадающие списки модулей в интерфейсе продолжают работать как прежде; на остальных операциях с конфигурациями и версиями поведение не менялось.

Наследование. При создании ДП и смартов внутри категории обычно наследуется модуль этой категории. Система ограничивает смешивание сущностей разных модулей в ряде сценариев настройки.

Навигация по модулю

Административная панель умеет показать, какие разделы администрирования относятся к конкретному модулю и сколько объектов в них уже привязано к модулю. Для этого у модуля есть контракт навигации GET /api/admin/modules/{moduleId}/navigation: в ответ приходят папки админки с формами модуля, а по каждой форме — два числа.

  • Собственные объекты модуля — сколько записей этой формы привязано к выбранному модулю.
  • Объекты без модуля — сколько записей той же формы модуля не имеет (относится к общему, глобальному контуру).

Число описывает именно объекты самой формы: у формы «Категории» это количество категорий, привязанных к модулю, а не количество задач в этих категориях, — и совпадает с тем, что открывается по клику. Ответ содержит только те формы, на которые у администратора есть права: скрытая форма не раскрывается ни названием, ни числом.

Контракт не меняет общее дерево администрирования: глобальное дерево форм по-прежнему отдаётся без контекста модуля и обслуживает главную страницу админки. Доступ к навигации модуля — только у администратора: пользователь без административных прав получает отказ, несуществующий модуль — ошибку «не найдено».

Версионирование модулей

Конфигурацию модуля можно сохранять версиями в репозитории и переключаться между ними. Поддерживаются два типа репозитория: файловая система (FileSystem) и Git. Прежде чем создавать или переключать версии, нужно настроить активный репозиторий. Доступные операции — создать версию, переключить версию, удалить версию. Отдельного мастера в интерфейсе для версионирования нет: оно выполняется через программный интерфейс (API), поэтому обычно применяется в связке с интеграциями и скриптами настройки.

Создание версии: либо версия создана, либо ничего не изменилось

Переключение версии при отсутствии активной. После удаления активной версии модуль может остаться без указателя на текущую версию. Переключение такого модуля на любую из оставшихся его версий отвечает успехом и применяет выбранную версию — внутренняя ошибка на этом пути не возникает. Если переключение не удалось, состояние откатывается к прежнему — то есть к модулю без активной версии, а несуществующая версия не подставляется. Переключение на версию другого модуля и на несуществующую версию по-прежнему отвечает отказом «не найдено».

Создание версии — двухшаговая операция: сначала система собирает снимок конфигурации модуля, затем выгружает его в активный репозиторий. Запись версии и указатель модуля на неё сохраняются только после успешной выгрузки. Если собрать или выгрузить снимок не удалось, созданная запись версии удаляется, а модулю возвращаются прежний указатель версии и данные последнего изменения: клиент получает ошибку, но в базе не остаётся ни версии, ни следа попытки.

Сравнение даты модуля на Microsoft SQL Server. При создании версии система сверяет состояние модуля перед записью указателя и аудита. Значение даты должно сравниваться с той же точностью, с которой оно хранится в базе: у типа с округлением миллисекунд сравнение с параметром другого временного типа может не найти неизменённую строку. Это не означает, что модуль действительно изменился параллельно. Исправление сохраняет корректное создание первой и следующих версий, а при ошибке выгрузки возвращает указатель версии и данные последнего изменения к состоянию до попытки, если модуль за это время не менялся. Если модуль был изменён параллельно, откат не перезаписывает чужие изменения; операция повторяется по актуальному состоянию либо завершается отказом. На PostgreSQL, при переключении версии и при удалении версии поведение не меняется.

Что это даёт на практике: после неудачной выгрузки название остаётся свободным, и повторный запрос с тем же названием выполняется как обычное создание версии, а не отклоняется как дубль. Отказ «версия с таким названием уже есть» приходит только тогда, когда версия с таким названием действительно создана ранее.

Остальное не меняется: отказ по занятому названию по-прежнему приходит до каких-либо записей, переключение модуля на другую версию и удаление версии работают как прежде.

Общая ветка в Git: что происходит с чужими файлами

Выгрузку версии можно направлять в уже существующую ветку, в которую пишет не только 1Форма. Файлы, появившиеся в ветке из чужих коммитов, выгрузка не трогает: она записывает и обновляет свои файлы, а всё, что не входит в опись снимка, остаётся на месте. Исключение — файлы, удалённые из самой конфигурации 1Формы: они снимаются с ветки вместе с выгрузкой.

Свои и чужие файлы система различает по описи снимка — служебному файлу .1forma-owned внутри каталога модуля. Опись записывается вместе с коммитом версии и приезжает на любой клон вместе с вершиной ветки, поэтому повторная выгрузка после чужого коммита в ту же ветку ничего из чужого не удаляет: в коммит попадают только файлы текущего снимка.

Если ветку выгружал только прежний код (до появления описи), при первой выгрузке новой версии система ещё не может отличить своё от чужого: такая выгрузка ничего на вершине не удаляет и только записывает опись снимка. Удаления настроек из конфигурации доезжают до такой ветки не с первой выгрузкой, а со следующей — отдельно чинить ничего не нужно, со второй выгрузки ветка ведёт себя как обычная.

Переключение версии читает вершину удалённой ветки

При переключении на версию система читает её прямо от вершины удалённой ветки модуля, а не слиянием с тем, что уже лежит в локальном клоне: она обновляет сведения об удалённой ветке, создаёт локальную ветку версии от её вершины, а если такая ветка уже есть — приводит её к вершине и выравнивает рабочую копию клона. Поэтому если в общую ветку модуля после выгрузки попал чужой коммит, переключение на версию вернёт состояние с вершины ветки, а не устаревший локальный снимок.

Чтение и выгрузка версии идут под одной блокировкой по каталогу локального клона: две операции, которые работают с одним и тем же клоном, выполняются по очереди. Это нужно потому, что выгрузка переключает рабочую ветку клона, — без общей блокировки параллельное чтение могло бы увидеть состояние чужой операции. Операции с версиями одного модуля на одном клоне запускайте подряд, а не одновременно.

Правка касается репозитория Git.

Повторная выгрузка версии: что попадает в ветку

Повторная выгрузка — обычная операция: версия заново выгружается в ту же ветку modules/<имя версии>, и в ветке появляется новый коммит поверх того, что там уже есть. История ветки не переписывается: коммиты, попавшие в ветку помимо 1Формы, остаются в её истории, принудительная отправка не используется и прав на неё в репозитории не требуется.

Что попадает в коммит:

  • все файлы версии, которые сейчас есть в конфигурации, — включая вложенные файлы мультифайловой раскладки;
  • настройка, удалённая из конфигурации, исчезает из отправленного снимка тем же коммитом: удаления считаются по всему пути версии, а не только по тем каталогам, которые остались на диске;
  • файл, который правила клона (.gitignore, info/exclude, глобальные правила) объявляют игнорируемым, всё равно попадает в снимок: файл версии служебный, и клиентские правила игнора не должны выбрасывать настройку из выгрузки.

Если с прошлой выгрузки конфигурация не менялась, новый коммит не создаётся, а выгрузка считается успешной: лишних пустых коммитов в истории ветки не появляется.

Первая выгрузка новой версии устроена так же: её ветка создаётся от пустого корневого коммита, поэтому в неё не попадают каталоги ранее выгруженных версий, и выгрузка работает даже тогда, когда репозиторий до этого был пустым. Несколько выгрузок разных версий подряд тоже не мешают друг другу: операции с локальной копией репозитория идут последовательно, и снимок каждой версии попадает в свою ветку.