diff --git a/docs/diagrams/README.md b/docs/diagrams/README.md
new file mode 100644
index 0000000..236897b
--- /dev/null
+++ b/docs/diagrams/README.md
@@ -0,0 +1,129 @@
+# Схема зависимостей облачных сервисов (docs/diagrams)
+
+Папка содержит все артефакты схемы: исходники, отрендеренные изображения и
+генератор. Здесь же описан процесс создания и результаты сверки с контрактами.
+
+## 1. Состав папки
+
+| Файл | Что это | Чем создаётся |
+|---|---|---|
+| `infra_services_flow.mmd` | исходник Mermaid-версии схемы | правится вручную |
+| `infra_services_flow.svg` | вектор Mermaid-версии | рендер через `mermaid.ink` |
+| `infra_services_flow.png` | растр Mermaid-версии | рендер через `mermaid.ink` |
+| `render_infra_diagram.py` | генератор стилизованной схемы (PNG + SVG) | чистый Python + Pillow |
+| `infra_services_diagram.png` | стилизованная схема, растр 1600×720 (рендер 2x + LANCZOS) | `render_infra_diagram.py` |
+| `infra_services_diagram.svg` | стилизованная схема, вектор | `render_infra_diagram.py` |
+
+Две версии существуют одновременно: Mermaid — для правок текстом и встраивания
+в Markdown; стилизованная — как готовая картинка для показа.
+
+## 2. Источник данных
+
+Единственный источник фактов — YAML-контракты сервисов:
+
+```
+generated/dev/resources_yaml/*.yaml
+```
+
+Из них берутся:
+
+- `service_id`, `service_display_name` — идентичность сервиса;
+- `operations[].params[].ref_svc_id` — **прямая зависимость** от другого сервиса;
+- `operations[].params[].depends_on` — зависимость порядка внутри операции;
+- `value_list`, `default`, `man`, `descr` — значения на блоках (CPU, сети и т.п.);
+- `service_man` — чек-листы и порядок действий, заданные самой платформой.
+
+Terraform-файлы `DEV_STAND/*` **не используются как источник** для этой схемы —
+они лишь один из примеров потребления.
+
+## 3. Как перегенерировать
+
+```bash
+cd /home/naeel/TF/tf_provider
+python3 docs/diagrams/render_infra_diagram.py
+```
+
+Скрипт пишет `infra_services_diagram.png` и `.svg` **в свою же папку**
+(`docs/diagrams/`), путь вычисляется от расположения файла.
+
+Требования: `python3` с `Pillow` и шрифты DejaVu
+(`/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf`, `...-Bold.ttf`).
+Сторонние библиотеки для SVG не нужны — SVG формируется текстом.
+
+Для Mermaid-версии нужен рендерер (`mermaid.ink`, `mmdc` или предпросмотр
+Markdown в VS Code); в этом репозитории использовался `mermaid.ink` через
+`python3` + `urllib`.
+
+## 4. Структура картинки
+
+Пять колонок = этапы создания, слева направо:
+
+1. **Тенант** — Организация в Cloud Director (19)
+2. **Пул ресурсов** — Виртуальный датацентр (21)
+3. **Сетевой периметр** — Сетевой шлюз периметра / Edge (22)
+4. **Среда запуска** — Каталог ВМ / vApp (26) + Внешние IP (vcOrg modify / 25)
+5. **Потребители** — Виртуальная машина (28) и Kubernetes кластер Штурвал (150)
+
+### Обозначения
+
+- **Сплошная стрелка** — обязательная зависимость, ссылка на UUID существующего
+ инстанса (`ref_svc_id`).
+- **Пунктирная стрелка** — выделение ресурса, операция `modify` или предусловие.
+- Направление стрелки всегда **от зависимости к потребителю**: `Org → vDC`,
+ `vApp → VM`. То есть стрелка отвечает на вопрос «что должно существовать до».
+- Цвет колонки кодирует этап, цвет рамки блока — группу (тенант / ресурсы / сеть /
+ потребители / адреса). Легенда — в правом нижнем углу картинки.
+
+### Бейджи точек выделения ресурсов
+
+| Бейдж | Где на схеме | Что означает |
+|---|---|---|
+| «здесь выделяются CPU / RAM / Диск» | блок vDC (21) | `cpuAllocated`, `memAllocated`, `storageConfig` |
+| «SNAT настраивается операцией modify» | блок Edge (22) | SNAT — не сервис, а `modify` у Edge |
+| «здесь выделяются IP» | блок «Внешние IP» | выделение адресов на организации |
+| «требует ALB + VS ≥ 3» | блок Штурвала (150) | обязательное условие из чек-листа |
+
+## 5. Результат сверки с YAML
+
+Проверено построчно (коммит `6791e8f`, дополнение — связь `vApp → Внешние IP`).
+
+| Утверждение на схеме | Источник |
+|---|---|
+| Организация: типы `iaas / saas` | `19_vc_org.yaml:47-53` |
+| Выделение IP через `vcOrg modify (vIPConfigure)` | `19_vc_org.yaml:115` |
+| Для внешних IP нужны vDC и Edge | `19_vc_org.yaml:112` (`man`) |
+| vDC: `cpuGuaranteed: 0% / 50% / 80%` | `21_vc_vdc.yaml:71-78` |
+| vDC: `cpuAllocated`, `memAllocated`, `storageConfig` | `21_vc_vdc.yaml:49,83,93` |
+| Edge: AVI Load Balancer | `22_vc_nsxt.yaml` (`needEnableAVI`) |
+| Edge: routed-сеть `10.10.102.0/24` | `22_vc_nsxt.yaml:5` |
+| Edge: SNAT настраивается операцией `modify` | `22_vc_nsxt.yaml` (`modify → ipSpaceName`) |
+| vApp → vDC (`vdcUid`), Edge (`nsxtUid`) | `26_vapp.yaml:38,56` |
+| ВМ → vApp (`vappUid`), `vmCpu · vmRam · vmDisk` | `28_vc_vm_v3.yaml:39,49,59,69` |
+| Штурвал: `vdcUid`, `nsxtUid`; `sizingPolicy · sizingDisk · count` | `150_k8s_sthutrval_cluster.yaml:41,47,132,141,148` |
+| Публичные IP: NAT/DNAT через сервис 25 | `25_vcexternalip.yaml:41,57,100` |
+| **Публичные IP требуют «Каталог» (vApp)** | `25_vcexternalip.yaml:5` (`service_man`) |
+| Штурвал: обязательны ALB и VS ≥ 3; суммарно 3 внешних адреса | `150_k8s_sthutrval_cluster.yaml` (`service_man`, чек-лист) |
+
+## 6. Известные ограничения
+
+1. **Переиспользование инстансов** («vDC и Edge могут быть переиспользованы»)
+ не написано в YAML буквально — это следствие семантики ссылок на UUID
+ существующего инстанса. Уверенность средняя, не высокая.
+2. Блок «Внешние IP» объединяет два механизма: выделение адресов на организации
+ (`vcOrg modify`) и правила NAT у сервиса 25 (`vcexternalip`). Они подписаны
+ раздельно внутри блока, но нарисованы одной вершиной.
+3. Остальные 33 сервиса каталога на схеме не показаны — отрисованы только
+ инфраструктурные цепочки и их прямые потребители.
+4. Схема — компоновка по контрактам, а не результат наблюдения за развёртыванием.
+ Фактический порядок и доступность нужно подтверждать отдельно.
+
+## 7. История
+
+| Дата | Изменение |
+|---|---|
+| 2026-09-26 | Создана Mermaid-версия (`infra_services_flow.*`) |
+| 2026-09-26 | Исправлена связь «вычислительный пул»: от vDC, а не от внешних IP |
+| 2026-09-26 | Добавлен генератор стилизованной схемы (`render_infra_diagram.py`) |
+| 2026-09-26 | Убрана дублирующая подпись `modify: SNAT` у блока Edge |
+| 2026-09-26 | Сверка с YAML; добавлена связь `vApp → Внешние IP` — предусловие сервиса 25 |
+| 2026-09-26 | Все артефакты перенесены в `docs/diagrams/` |
diff --git a/docs/diagrams/infra_services_diagram.png b/docs/diagrams/infra_services_diagram.png
new file mode 100644
index 0000000..b26d443
Binary files /dev/null and b/docs/diagrams/infra_services_diagram.png differ
diff --git a/docs/infra_services_diagram.svg b/docs/diagrams/infra_services_diagram.svg
similarity index 97%
rename from docs/infra_services_diagram.svg
rename to docs/diagrams/infra_services_diagram.svg
index 22cd070..3535b72 100644
--- a/docs/infra_services_diagram.svg
+++ b/docs/diagrams/infra_services_diagram.svg
@@ -113,6 +113,9 @@
modify: SNAT
+
+
+требует Каталог
внешний IP
@@ -128,7 +131,7 @@
(ссылка на UUID существующего инстанса)
-Пунктир — выделение ресурса / операция modify
+Пунктир — выделение ресурса / modify / предусловие
Тенант
diff --git a/docs/infra_services_flow.mmd b/docs/diagrams/infra_services_flow.mmd
similarity index 100%
rename from docs/infra_services_flow.mmd
rename to docs/diagrams/infra_services_flow.mmd
diff --git a/docs/infra_services_flow.png b/docs/diagrams/infra_services_flow.png
similarity index 100%
rename from docs/infra_services_flow.png
rename to docs/diagrams/infra_services_flow.png
diff --git a/docs/infra_services_flow.svg b/docs/diagrams/infra_services_flow.svg
similarity index 100%
rename from docs/infra_services_flow.svg
rename to docs/diagrams/infra_services_flow.svg
diff --git a/TOOLS/render_infra_diagram.py b/docs/diagrams/render_infra_diagram.py
similarity index 97%
rename from TOOLS/render_infra_diagram.py
rename to docs/diagrams/render_infra_diagram.py
index 8f85e68..760264e 100644
--- a/TOOLS/render_infra_diagram.py
+++ b/docs/diagrams/render_infra_diagram.py
@@ -68,6 +68,7 @@ EDGES = [
"modify: vIPConfigure", (161, 526), False),
([(870, 320), (870, 400), (1140, 400), (1140, 395)], MUTED, 2, True,
"modify: SNAT", (880, 386), False),
+ ([(1050, 210), (1050, 245)], MUTED, 2, True, "требует Каталог", (1060, 218), False),
([(1183, 270), (1255, 270), (1255, 160), (1327, 160)], MUTED, 2, True,
"внешний IP", (1187, 222), False),
([(1183, 350), (1327, 350)], RED, 2, True, "≥ 3 адреса", (1187, 330), False),
@@ -134,7 +135,7 @@ def build():
ops.append(op_text(1052, 597, "Сплошная линия — обязательная зависимость", 11, TEXT))
ops.append(op_text(1052, 613, "(ссылка на UUID существующего инстанса)", 10, MUTED))
ops.append(op_path([(980, 650), (1040, 650)], MUTED, 2, True))
- ops.append(op_text(1052, 641, "Пунктир — выделение ресурса / операция modify", 11, TEXT))
+ ops.append(op_text(1052, 641, "Пунктир — выделение ресурса / modify / предусловие", 11, TEXT))
swatches = [("#1565C0", "Тенант"), ("#F57C00", "Ресурсы"), ("#5E35B1", "Сеть"),
("#2E7D32", "Потребители"), ("#9E9E9E", "Адреса")]
@@ -295,8 +296,8 @@ def render_svg(ops, path):
if __name__ == "__main__":
- base = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "docs")
- base = os.path.normpath(base)
+ # Файлы кладём рядом со скриптом: docs/diagrams/
+ base = os.path.dirname(os.path.abspath(__file__))
ops = build()
print(render_png(ops, os.path.join(base, "infra_services_diagram.png")))
print(render_svg(ops, os.path.join(base, "infra_services_diagram.svg")))
diff --git a/docs/infra_services_diagram.png b/docs/infra_services_diagram.png
deleted file mode 100644
index 40154c0..0000000
Binary files a/docs/infra_services_diagram.png and /dev/null differ