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

TL;DR

Дизайнер раздела — основа продукта. Это инструмент, через который клиенты адаптируют CRM под свой бизнес: выделяют нужные им сущности, проектируют объектную модель этих сущностей, не привлекая разработку. Без него платформа не имела бы смысла как low-code-решение.

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

Проектировал с нуля. Собрал трёхпанельный редактор с прогрессивным раскрытием настроек, набор типов полей под разные бизнес-задачи (текст, число, дата, время, чекбокс, нумератор, селект, контакт, связь, деталь), валидацию граничных случаев на разных уровнях.

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

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

Трёхпанельный редактор

Трёхпанельный редактор

Дизайнер раздела устроен как редактор с тремя областями. Слева — общие свойства раздела. В центре — холст, на котором собирается макет страницы записи из выбранного пресета сетки. Справа — палитра типов полей и контекстная панель настроек выбранного объекта. Настройки раскрываются по мере действий пользователя.

Типы и свойства полей

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

Валидация

В дизайнере раздела продумана валидация на нескольких уровнях. Часть проверок блокирует сохранение, часть выводит предупреждение с возможностью пропуска. На одно поле может приходиться сразу несколько ошибок — их нужно было разместить так, чтобы все были видны и понятны.

Нумератор

Нумератор

Автоматическая нумерация записей с двумя моделями счётчика и настраиваемыми масками.

Ситуация

В работе с разделами встречается сценарий, когда требуется автоматическая нумерация записей. Это не редкий кейс, и для него нужен no-code-инструмент, доступный клиенту для самостоятельной настройки.

Задача

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

Действия

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

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

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

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

Результат

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

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

Деталь

Деталь

Вложенная таблица на странице записи, через которую видны связанные с ней записи из другого объекта.

Ситуация

В работе с разделами встречается сценарий, когда на странице записи нужно показать связанные с ней записи из другого раздела. Без встроенного механизма пользователь не может настроить это сам — нужен no-code-инструмент.

Задача

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

Действия

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

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

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

Результат

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

Настройка детали целиком собирается в дизайнере раздела, не вынося пользователя в отдельный конструктор. Связь между основной записью и записями детали настраивается не только по идентификатору, но и по любым полям — это закрывает класс сценариев с непрямыми связями между разделами.

Итог

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

Настройки в дизайнере раздела не заканчиваются на самом дизайнере. Каждое решение по типам полей и их свойствам прорастает в страницу записи, в режимы отображения данных (таблица, канбан), в edge-cases при добавлении или изменении полей в работающем разделе.

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

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