# Модель архитектуры в нотации ArchiMate

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

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

## Файлы

| Файл | Формат | Чем открывать |
|---|---|---|
| `example-technology.archimate` | нативный формат [Archi](https://www.archimatetool.com/) | десктопный Archi: File → Open |
| `example-technology.xml` | The Open Group ArchiMate Model Exchange File Format 3.1 | любой инструмент с импортом Open Exchange, в том числе archi-online.com: **Import, save, and create models** → Open Exchange |
| `preview.html` | SVG-рендер всех представлений плюс справочник компонентов прикладного слоя | любой браузер, без установки чего-либо |
| `matrix.example.json` | снимок матрицы «приложение → технологический сервис» | вход для сборки |
| `calls.example.json` | снимок графа межсервисных вызовов | вход для сборки |
| `app-summaries.md` | короткие описания компонентов прикладного слоя (1–3 предложения) | вход для сборки; попадает в поле `Documentation` модели |
| `app-docs.md` | развёрнутые описания тех же компонентов | справочник; в модель по умолчанию не идёт |

91 элемент, 369 отношений, 40 представлений.

| Представление | Что показывает |
|---|---|
| L1 | Легенда нотации: что означает каждый тип элемента и каждый тип линии. Собрана из настоящих элементов модели — заодно разобранный пример |
| T1 | Кластер, ПО внутри него, внешние узлы, технологические сервисы. Без приложений — обзорная схема |
| T2 | Развёртывание по узлам: какая группа узлов какие компоненты несёт |
| T3 | Внешние интеграции: чем контур связан с инфраструктурой заказчика — каталог предприятия, брокер идентификации, служба федерации, почтовый релей |
| T4–T13 | По одному представлению на технологический сервис: кто им пользуется |
| A0 | Карта прикладного слоя: все компоненты по смысловым группам, без связей |
| A1 | Ядро прикладного слоя: восемь самых связанных сервисов и вызовы между ними |
| A2–A12 | По представлению на сервис с тремя и более потребителями: кто от него зависит |
| P1–P13 | Паспорт сервиса — зеркало к A2–A12: не «кто сломается без него», а «без чего не работает он сам» |

`preview.html` показывает не только схемы. Сверху — оглавление по всем представлениям, внизу — справочник прикладного слоя: описания всех компонентов, разложенные по тем же смысловым группам, что и на карте A0. Описания лежат в модели (поле `Documentation`), но на схемах их не видно — там помещается только имя, поэтому то же описание всплывает подсказкой при наведении на любой блок любой схемы. В Archi эти же тексты видны в панели свойств.

Направление связи — как принято в ArchiMate: стрелка идёт от вызываемого к вызывающему (serving). Читается как «кого лишишься — тот и сломается». Тот же вопрос с другой стороны — представления P: что нужно самому сервису, чтобы работать.

Разбиение по сервисам сделано осознанно: 152 связи «технологический сервис → приложение» и 86 межсервисных вызовов на одной схеме нечитаемы. В модели они лежат одним набором, представления — это срезы.

Метамодель намеренно урезана. Технологический слой: `Node`, `SystemSoftware`, `TechnologyService`, `Artifact`. Прикладной: `ApplicationComponent`. Смысловая группировка: `Grouping`. Отношения: `Composition`, `Aggregation`, `Realization`, `Serving`, `Assignment`. Не используются `Device`, `Path`, `CommunicationNetwork`, `TechnologyFunction` — они не несут информации на этом уровне.

## Как собрать модель для реального контура

1. Снять с нужного кластера матрицу использования технологических сервисов и граф межсервисных вызовов:

   ```
   py scan_contour.py <имя-кластера> matrix.json
   py scan_calls.py   <имя-кластера> calls.json
   ```

2. Скопировать `contour-profile.example.json`, подставить настоящие имена кластера, узлов, доменов и реестра. **Копию хранить вне репозитория.**

3. Собрать модель и производные форматы:

   ```
   py build_archimate.py <профиль.json> matrix.json out.archimate calls.json app-summaries.md
   py to_open_exchange.py out.archimate out.xml
   py render_preview.py out.archimate out.html
   ```

   Аргументы после имени выходного файла необязательны и распознаются по расширению: `.json` — граф вызовов (без него собирается только технологический слой), `.md` — описания компонентов (без них у компонентов остаётся путь к манифестам). Файлов с описаниями можно передать несколько, каждый следующий переопределяет предыдущий по совпадающим заголовкам: `app-docs.md app-summaries.md` даст короткие описания там, где они есть, и развёрнутые для остальных.

Результат шага 3 в репозиторий не коммитить — он содержит данные контура.

## Откуда взяты связи

Не нарисованы от руки, а выведены из манифестов, поэтому проверяемы.

| Связь | Источник |
|---|---|
| Состав кластера, версии чартов | `clusters/<контур>/kustomization.yaml`, `infrastructure/<comp>/base/helmrelease.yaml` |
| Приложение → PostgreSQL | env `POSTGRES_*`, `DB__HOST` или путь Vault `secrets/data/apps/<app>/postgres` |
| Приложение → RabbitMQ | env `RABBITMQ*`, `AMQP__*` |
| Приложение → Kafka | env `KAFKA*`, `BOOTSTRAP_SERVERS` |
| Приложение → S3 | env `S3__*`, `S3_ENDPOINT`, `S3_ACCESS`, `S3_BUCKET` |
| Приложение → Redis | env `REDIS_HOST`, `REDIS__*` |
| Приложение → Vault | аннотации `vault.hashicorp.com/agent-inject*` |
| Приложение → Zitadel | env `ZITADEL*`, `JWKS`, `OIDC`, секрет `jwt-public` |
| Приложение → почтовый релей | env `SMTP_*_HOST`, `SMTP__HOST`, `FROM_EMAIL`, `EMAIL_FROM` |
| Приложение → Istio | `service:` в маршрутах `infrastructure/istio-config/<контур>/istio-config.yaml` (закомментированные не считаются) |
| Приложение → приложение | адрес `<сервис>.<namespace>` в манифестах вызывающего; либо переменная `<APP>_URL` / `_HOST` / `_BASE_URL` / `_ENDPOINT` |

Сканируются `*.yaml` в `apps/<app>/base/` и `apps/<app>/<контур>/`. Для матрицы технологических сервисов документация `*.md` служит вторым источником, для графа вызовов — `*ENDPOINTS.md` и `*CONFIGURATION.md`.

Две поправки, без которых граф вызовов врёт:

- **суффикс контура в namespace.** Адреса встречаются в формах `documentations`, `documentations-prod`, `bim-api`; без нормализации связь теряется, а короткая форма `<сервис>.<namespace>` без `.svc.cluster.local` не распознаётся вовсе.
- **инфраструктурный сегмент в имени переменной.** `DJANGO_POSTGRES_HOST` и `ISSUES_DB_HOST` адресуют базу данных чужого сервиса, а не сам сервис. Это связь другого рода, и как вызов её показывать нельзя.

`matrix.example.json` и `calls.example.json` — снимки. В них только имена приложений и флаги связей; идентификаторов контура нет.

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

| Схема | Цепочка | Когда нужна |
|---|---|---|
| прямая | каталог → провайдер идентификации | каталог доступен по LDAPS и источник пользователей один |
| с брокером | каталог → Keycloak → провайдер идентификации | источников несколько либо каталог опубликован по SAML |
| с доменным входом | каталог + центр выдачи билетов → Keycloak → провайдер идентификации | нужен вход без повторного пароля для рабочих станций домена; проверку билета по SPNEGO умеет только брокер |
| через федерацию | каталог → AD FS → провайдер идентификации | у заказчика уже есть федеративная служба как штатная точка входа |

В представлении T3 показаны все четыре сразу — при сборке модели для конкретного контура лишние узлы из профиля убираются. Keycloak поставляется и чартом платформы (`infrastructure/keycloak`), поэтому брокер может стоять как у заказчика, так и внутри контура.

**Группировка прикладного слоя по доменам — тоже не из манифестов.** В репозитории нет ничего, что относило бы приложение к «контролю качества» или «полевым данным»: это смысл, а не конфигурация. Группы заданы в профиле, блок `domains`, и сверены с доменной группировкой в [../apps/README.md](../apps/README.md). От контура к контуру они не меняются — в отличие от остального в профиле, это свойство продукта. Последняя группа с `"apps": "*"` собирает всё, что не попало в предыдущие: так новое приложение не исчезает с карты молча, а всплывает в группе «Не отнесено». Если группа пуста, в модель она не попадает.

Описания компонентов в `app-docs.md` и `app-summaries.md` выведены не из этого репозитория, а из исходного кода компонентных репозиториев, и потому проверяются иначе — чтением кода, а не грепом по манифестам. Там, где доказательств не хватило, это сказано в самом описании; такие места стоит подтверждать у команды платформы, а не считать фактом.

## Про формат файлов

Нативный `.archimate` нигде не стандартизирован, и его словарь неочевиден: объекты схем сериализуются как `<child xsi:type="archimate:DiagramObject">`, соединения — через атрибут `relationship`. Имена EClass из метамодели (`DiagramModelArchimateObject`, `archimateRelationship`) в XML **не используются** — на них легко попасться, модель тогда открывается с пустыми представлениями.

Эталон для сверки — любая модель из [archimatetool/ArchiModels](https://github.com/archimatetool/ArchiModels), созданная самим Archi.

Пояснительные надписи на легенде — объекты `archimate:Note`: они принадлежат схеме, а не модели, поэтому в счёт элементов не идут и в других инструментах ничего не ломают. В обменном формате им соответствуют узлы `xsi:type="Label"`.

`example-technology.xml` проверен на соответствие официальной схеме `archimate3_Diagram.xsd`. Если сторонний инструмент не берёт нативный формат, используйте его. Отличие обменной версии: вложенность узлов развёрнута в плоский список с абсолютными координатами (в обменном формате трактовка координат вложенного узла неоднозначна между реализациями). Визуально раскладка та же, но компоненты внутри кластера не будут его дочерними элементами.

## Скрипты

Требуется Python 3, внешних зависимостей нет. На Windows запускать через `py`, а не `python`.

| Скрипт | Назначение |
|---|---|
| `scan_contour.py` | матрица «приложение → технологический сервис» по кластеру |
| `scan_calls.py` | граф межсервисных вызовов прикладного слоя |
| `build_archimate.py` | сборка модели из профиля и матрицы |
| `to_open_exchange.py` | конвертация в обменный формат |
| `render_preview.py` | рендер представлений в HTML со встроенным SVG |

**Внимание:** после ручной правки модели в Archi источником истины становится `.archimate`, а повторный запуск `build_archimate.py` затрёт расстановку элементов. Производные форматы (`to_open_exchange.py`, `render_preview.py`) пересобирать после каждой правки, иначе они разъедутся с моделью.
