Понимание метамодели, управляемой данными
В большинстве 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.
Смотрите также
- Администрирование метамодели — добавление и редактирование типов через интерфейс
- Вычисления — определение формул для вычисляемых полей
- Разрешения и роли — взаимодействие модели разрешений с типами карточек