Перейти к основному содержимому

Понимание метамодели, управляемой данными

В большинстве EA-инструментов объектная модель жёстко закодирована в исходном коде приложения. Canopy использует иной подход: каждый структурный элемент — типы карточек, поля, подтипы, связи, роли заинтересованных сторон и вычисляемые поля — хранится как данные в базе данных, а не как код. На этой странице объясняется, почему было принято такое решение и что оно означает на практике.

Что такое метамодель

Метамодель — это схема вашей EA-модели. Она определяет:

  • Типы карточек — виды сущностей, которые вы отслеживаете (Application, BusinessCapability, Initiative и т. д.)
  • Поля — свойства, которыми могут обладать эти сущности (статус жизненного цикла, стоимость, владелец, технологический стек и т. д.)
  • Подтипы — детализированные варианты типа, использующие один и тот же набор полей (например, Application → Microservice, SaaS, AI Agent)
  • Типы связей — допустимые рёбра между типами (Application «работает на» ITComponent, Initiative «реализует» BusinessCapability и т. д.)
  • Роли заинтересованных сторон — роли, которые пользователи могут занимать применительно к конкретной карточке (Technical Owner, Business Owner, Data Steward и т. д.)
  • Вычисляемые поля — формулы, получающие значения полей из других данных при сохранении

Все перечисленные элементы хранятся как строки в таблицах card_types, relation_types и связанных JSONB-столбцах. Для их изменения не требуются ни правки кода, ни перезапуск приложения.

Почему данные, а не код?

Настройка без форков

У разных организаций метамодели EA кардинально различаются. Одни команды отслеживают «Vendor», «License» и «SLA». Другие — «Data Domain», «ESG Capability» и «Value Stream». Если бы метамодель была кодом, любая настройка требовала бы либо создания форка продукта, либо системы плагинов — оба варианта дороги в обслуживании.

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

Эволюция схемы без миграций для каждого клиента

Когда Canopy выпускает новый встроенный тип карточки или поле, это происходит через seed.py — процедуру запуска, которая проверяет наличие встроенной записи и создаёт её только в случае отсутствия. Существующие настройки никогда не затрагиваются. Это означает:

  • Обновление Canopy не перезаписывает ваши пользовательские поля
  • Встроенные типы остаются редактируемыми (вы можете изменить значок, цвет или метку «Application», не создавая форк)
  • Если значение встроенного типа по умолчанию изменилось, защищённая миграция Alembic исправляет только незатронутые строки

Мультиарендность в единой кодовой базе

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

Структура fields_schema

Каждый тип карточки хранит определения полей в виде JSONB-массива разделов:

[
{
"section": "Technology",
"columns": 2,
"fields": [
{
"key": "techStack",
"label": "Technology Stack",
"type": "multiple_select",
"options": [{"key": "java", "label": "Java"}, {"key": "python", "label": "Python"}],
"weight": 2
}
]
}
]

Параметр weight каждого поля влияет на оценку качества данных — карточки получают оценку от 0 до 100% в зависимости от того, насколько заполнены взвешенные поля. Это превращает метамодель в механизм контроля качества: вы сами определяете, что означает «хорошие» данные, назначая более высокие веса наиболее важным полям.

Что нельзя изменить через метамодель

Метамодель управляет структурой, но не поведением. Ряд вещей по-прежнему задаётся в коде:

  • Механизм вычислений — безопасная среда для вычисления формул является Python-библиотекой (simpleeval). Сами формулы — это данные, но вычислитель — это код.
  • Система разрешений — набор допустимых ключей разрешений представляет собой список разрешённых значений в файле backend/app/core/permissions.py. Добавление нового ключа разрешения (не просто его предоставление) требует изменения кода.
  • Схема базы данных — добавление новой таблицы верхнего уровня (например, нового модуля вроде PPM или GRC) требует миграции Alembic. Схема атрибутов карточки расширяется без миграций, поскольку атрибуты хранятся в JSONB.

Смотрите также