Аудиторія: автор сторінки (людина або AI) у момент створення/оновлення. Це довідник правил формату — «який тег, яка шапка, яка обов’язкова секція».
Мета: за 10 секунд згадати потрібне правило під час написання.
Як ця документація фізично існує — у README.
Процес створення (з чого почати, чекліст) — у AUTHORING.
Принципи
Карта території, не покрокова інструкція. Фіксуй важливе так, щоб швидко орієнтуватись і розуміти картину, а не читати з початку.
UI — хребет, бек — опорні картки. Читач стартує з UI (що бачить у програмі) і переходить на бек по лінках (що це тригерить / звідки оновлюється).
API — це Swagger, не markdown. Контракт API живе в auto-Swagger самого сервісу (через routing-controllers). У docs описуємо тільки бізнес-нюанси і ставимо deeplink на конкретний endpoint у Swagger UI.
Схематично + нюанси. Не описуємо що робить кожна стрічка. Описуємо що є, в якому порядку, які числа/умови, які нюанси і чому вони такі.
Рішення, не реалізація. Якщо рішення неочевидне — фіксуй чому так зробили, не як зроблено на рівні синтаксису.
Один файл — одна одиниця. UI-секція і бек-сервіс живуть у різних файлах і пов’язуються лінками.
Файл ↔ нода Canvas. Кожен файл у docs/ має бути представлений як нода на Canvas (локальному Canvas.canvas сервісу або глобальному architecture/Canvas.canvas). Якщо підтема надто мала щоб мати окрему ноду — зливаємо з батьківським файлом у секцію.
Не посилайся на те, чого немає на Canvas. Wiki-лінки [[X]] у тілі файлів можна ставити тільки на файли які представлені нодою на Canvas. Якщо хочеться послатись на дрібну підтему — злий її у файл який є на Canvas, і посилайся через [[файл#секція|Секція]].
Межа глибини
Описуємо:
Числа: таймаути, інтервали, ліміти, пороги
Умови, фільтрації, послідовність кроків
Залежності: хто що тригерить, хто від кого залежить
Нюанси поведінки що неочевидні з коду
Чому саме таке рішення — якщо неочевидне
Не описуємо:
Синтаксис виклику методів
Деталі транспорту (fetch vs axios, Promise.race vs Promise.all) — якщо не впливає на поведінку
Інфраструктура без бізнес-логіки (IPC, ping між вікнами, tab-to-tab запити)
Імена полів і типи які очевидні з коду
Запит/відповідь endpoint’ів — це робота Swagger, не markdown
Правило великого пальця: якщо без цього факту читач може прийняти помилкове рішення — описуємо. Якщо це тільки як зроблено, без впливу на поведінку — пропускаємо. У сумнівах — описуємо коротко в секції «Нюанси».
Людська мова, не імена з коду
Текст сторінки описує процеси зрозумілою людською мовою, без ідентифікаторів з коду. Не «sendMessage() викликає checkLimits()», а «перед відправкою повідомлення перевіряються ліміти». Імена функцій, методів і змінних у тілі сторінки не вживаємо — вони застарівають при рефакторингу і нічого не кажуть читачу який не дивиться в код.
Де імена з коду доречні:
H1 і контекстна стрічка бек-сторінок (назва класу + шлях у src/)
назви колекцій/таблиць і полів на Entity-сторінках
ключі settings / env-змінні / назви RMQ-черг — те, що читач буде шукати дослівно
Структура папок сервісу
Розкладка <service>/docs/. Розкладка root stack-docs/ — у README.
Базовий набір — згори. Кожен сервіс бере тільки те що йому треба (ui/ лише для фронту, flows/ коли є складні процеси). Якщо в сервісі є природна підгрупа яка не вміщається в одну з цих папок (наприклад інтеграції із зовнішніми системами, фонові воркери, інтервали, фічі) — створюй для неї окрему top-level папку, не вкладену:
docs/
├── services/ # generic бек-сервіси
├── workers/ # фонові воркери з таймером
├── intervals/ # тимчасові тригери
├── senders/ # сендери (chat / mail)
├── integrations/ # інтеграції із зовнішніми системами
├── features/ # бізнес-фічі цього сервісу (Statistics, Sender…)
├── ui-triggered/ # бек-сервіси що тригеряться з UI
└── ...
Список не закритий — додавай свою категорію якщо вона є природною групою. Головне правило: папок верхнього рівня може бути багато, але вкладеність — ні.
Один погляд на сайдбар має давати ясно: Title Case = top-level концепт, Stack X = сервіс, lowercase скрізь = вміст сервісу. Жодних PascalCase у назвах файлів — навіть для бек-класів. Зв’язок «doc-файл ↔ клас у коді» вказуй у H1 і контекстній стрічці самого файлу.
Не ставити title: в <folder>/index.md — інакше сайдбар покаже Title Case і це створить дисонанс з сусідніми lowercase-папками. Виняток — <service>/docs/index.md (див. нижче).
Без вкладеності. Усі папки — на одному рівні в docs/. Якщо потрібна підгрупа (наприклад workers, senders, integrations) — створюй її як окрему top-level папку, не як services/workers/.
Файли
Завжди kebab-case, lowercase — без винятків. UI-екран, flow, entity, бек-сервіс, контролер — всі однаково (course-service.md, mentor-service.md, memory-chunk.md, login.md, operator-card.md). Зміст всередині — українською (H1, текст, секції); англійський kebab — лише для імені файлу.
Причина: одне правило без винятків → сайдбар однорідний, wiki-лінки передбачувані, URL у Quartz чисті. Зв’язок з кодовим класом (CourseService у course.service.ts) залишається через H1 і контекстну стрічку у самому файлі (# CourseService + `src/modules/course/course.service.ts`).
Home.md не використовуємо — вхід через Canvas.canvas.
Index-файли
Кожна папка в сервісі повинна мати свій index.md — інакше Quartz покаже сторінку папки як голий auto-листинг файлів без контексту. У файлі — опис призначення папки і ключові файли з людськими описами; Quartz додасть auto-листинг знизу як комплемент.
Рівень
title: у frontmatter
Як виходить
<service>/docs/index.md (root сервісу)
потрібен (auto-inject Stack <X> коли немає)
сайдбар: Stack Golden / Stack AI. Для акронімів (ai → Stack AI) — пиши вручну
<folder>/index.md (підпапка всередині)
не ставити
сайдбар: слаг папки lowercase. H1 у файлі і вміст — як завгодно, важлива тільки відсутність title:
Cкелет для нової підпапки:
---tags: [Meta]---# Folder NameОдна-дві фрази: що в цій папці і навіщо.- [[file-one]] — короткий опис цього файлу і коли до нього звертатись- [[file-two]] — ...
Цей bullet-скелет — для малої папки (≤4-5 сторінок). Коли сторінок багато — переходимо на таблицю з мітками покриття (нижче).
Мітки покриття в індексах
Індекс має показувати не лише список файлів, а й скільки з них реально заповнено — інакше це купа однакових лінків без сигналу де ще порожньо. Стан кожного елемента позначаємо однією з трьох міток:
Мітка
Сенс
✅
заповнено — основний контент є, читається як готова сторінка
🟡
частково — є суттєвий контент, але лишились прогалини / #TODO
⬜
скелет — тільки шапка + пара нотаток, основне не описано
Це мітка повноти опису, не плутати зі стан-тегами сторінки (#draft, #reviewed, #TODO, #fix). Сторінка може бути ✅ заповнена і водночас нести #TODO — коли борг у коді, а не в доці (приклад: воркери golden — описані повністю, а #TODO маркує відкрите питання в логіці).
Підпапка з багатьма сторінками (<folder>/index.md): таблиця з колонкою Стан, згрупована по логічних групах (кожна група — окрема H2-таблиця або секція-сепаратор). Зверху — підсумок X ✅ · Y 🟡 · Z ⬜ (з N).
**Покриття:** 4 ✅ · 2 🟡 · 25 ⬜ (з 31). Легенда: ✅ заповнено · 🟡 частково · ⬜ скелет.## Група А| Стан | Сторінка | UI | Що робить ||---|---|---|---|| ✅ | [[folder/page-a]] | … | … || ⬜ | [[folder/page-b]] | … | … |
Розділ де одиниця виміру інша (наприклад entities — реєстр колонок готовий, а окремих сторінок 0/~50) у числову таблицю не пхаємо — виносимо приміткою під таблицею.
Підтримка вручну. Цифри оновлює автор при заповненні: підняв ⬜→✅ — поправ підсумок у підіндексі і зведену таблицю в root. Один рядок правки, зате миттєвий сигнал прогресу і backlog.
Шаблон сторінки
Обов’язковий початок
#Тег1 #Тег2[[Назва-файлу]]# Людська назва`контекстна стрічка: шлях в коді або "(UI-елемент)"` — одна фраза опису
Теги — тип сторінки (див. нижче). Один рядок, без ком.
Backlink[[Назва-файлу]] — для зворотного пошуку в Obsidian.
H1 — як називаємо в розмові (для UI), або назва класу/сервісу (для бек).
Контекстна стрічка — для бек: шлях `src/...ts`. Для UI: (UI-елемент) або (UI-секція). Для роле/ентіті — пропускаємо.
Опційні секції (використовувати за потреби)
## СутьОдин абзац: що це за елемент і яку роль він грає в системі.## Use casesОдин абзац: хто і за яким сценарієм сюди приходить. Бізнес-контекст, не механікакліків. Обов'язкова для UI-сторінок (див. «Правила для UI-сторінок» нижче).## Числа / Інтервали / ТаймаутиТаблиця або список з бізнес-значеннями.## Логіка / Умови / ФільтриПронумерований список або таблиця.## НюансиНеочевидні моменти з поясненням *чому*.## Зв'язки- Тригерить: [[...]]- Оновлюється від: [[...]]- Читає: [[...]]- Стартує: [[...]]## Чому такПояснення неочевидних архітектурних рішень. Тільки коли справді є причина.
Порядок секцій — приблизно такий як вище, але можна адаптувати. Обов’язкова тільки «шапка» (теги + backlink + H1 + контекстна стрічка + одна фраза).
Інфраструктура без бізнес-логіки (БД, settings, tabs)
Роль
#Role
Роль доступу (director, supervisor, operator …)
API
#API
Огляд API-групи бек-сервісу + лінки на Swagger
Архітектура
#Architecture
Крос-сервісна картина — лежить тільки в root
Мета
#Meta
Самі конвенції, індекси, глосарії
Теги типу можна комбінувати (#Service #Interval). Один з цих тегів обов’язковий у шапці кожного файла.
Сервісні теги (автоматичні)
Кожен файл під services/<service>/ на сайті отримує тег з назвою сервісу (#electron, #golden, #client, #stack, #prime, #udate, #chathouse, #academy, #ai). Це робить inject-doc-meta при білді — руками не писати.
Для чого: на зібраному сайті клік по тегу #electron дає список усіх документів у відповідному сервісі.
Винятки коли варто додати сервісний тег руками: root-документ який крос-сервісний, але переважно про конкретний сервіс — наприклад entities/<X> де сутність живе в RMQ-обміні, але споживається переважно одним сервісом. Тоді в шапку додаємо #<service> руками — він з’явиться як додатковий ярлик.
Стан-теги
Документ за замовчуванням — чорновик (часто AI-генерація), сліпо не довіряй. Стан-теги додаються коли треба позначити особливий стан явно.
Тег
Сенс
Коли ставити
#reviewed
Документ верифікований — людина пройшлася і перевірила що відповідає реальності.
Ставимо після ручної перевірки. Якщо документ суттєво змінено — зняти, бо треба перевіряти заново. Клік по #reviewed на сайті дає список того чому довіряємо.
#draft
Документ написаний на гілці docs сервісу до того як відповідний код приземлився у master. Не зверений з реальним кодом.
Ставимо коли пишемо док-перш. На сайті ці сторінки видно поряд з рештою — клік по #draft дає список того що чекає зверки.
#TODO
Документ незавершений або потребує уточнення.
Коли лишаєш TODO: ... у тексті, додай тег у шапку. Клік по #TODO на сайті дає список усього що треба добити.
#fix
Описана логіка є кривою/тимчасовою. Документуємо як є зараз, але хочемо переписати.
Коли документ описує реальну поведінку коду який є костилем, hack’ом, технічним боргом. Не для UI-багів — для архітектурних плям. Сигнал «коли торкатимемось — переписати і код, і цей документ».
Зніми #TODO коли всі недоробки в документі закриті. Зніми #fix коли код переписаний і документ оновлений. Зніми #reviewed якщо документ суттєво переписали — треба перевіряти заново.
Lifecycle #draft → #reviewed.#draft живе на гілці docs сервісу — туди пишемо док-перш, поки відповідний код ще на feature-гілці. Коли код приземляється у master і доки мерджимо з docs у master — обов’язково проходимось по #draft-сторінкам, звіряємо опис з реальним кодом, і замінюємо #draft на #reviewed (або лишаємо без тегу якщо це чорновик не вартий статусу «довіряємо»). У master тегу #draft бути не повинно.
Теги — єдиний інструмент фільтрації, тримаємо їх дисципліновано.
Лінки і навігація
Wiki-лінки (всередині vault)
Всередині свого сервісу — звичайний [[Назва файлу]]:
На глобальний контент (root) — пишемо повний шлях від кореня vault:
Доступ обмежено [[roles|роллю operator]].
Користувач визначений у [[entities/Lady]].
На інший сервіс — повний шлях через services/:
Дивись [[services/golden/api/index|Golden API]].
Cleanup runner стартується по подіях [[services/stack/flows/UserSignup]].
Якщо ти редагуєш у режимі «один сервіс» (vault — тільки твій сервіс), крос-сервісні wikilinks показуватимуться сірими у твоєму локальному Obsidian. На зібраному сайті вони працюють. Це не баг — пиши лінк нормально.
Жодних інших зовнішніх систем у markdown без необхідності.
Правила лінкування
UI → бек: обов’язкова секція Зв'язки з лінками на сервіси/ендпоінти що цей UI використовує.
UI → API: не описуємо запит/відповідь у markdown — ставимо deeplink на Swagger. Якщо є бізнес-нюанс який Swagger не показує (особлива комбінація ролі + whitelist, наприклад) — описуємо саме нюанс.
Бек → UI: в секції Зв'язки — куди йде результат сервісу.
Бек → ентіті: лінк на [[entities/X]] (локальний або глобальний).
Не дублюй reverse-лінк на index/menu. Якщо сторінку X уже лінкує index/menu/матриця — не пиши в X.Зв'язки wikilink на цю index/menu. Quartz Backlinks-панель сама покаже всі вхідні посилання, а інакше Backlinks роздуваються 20-30 одноманітними entries без сенсу. Wikilinks у Зв'язки — лише для семантичного зв’язку (X пояснює Y, X читає Y, X залежить від Y). Це правило ще буде уточнюватися — зараз draft.
Правила для UI-сторінок
Назва — як звемо в команді («колонка фаворитів»), а не як в коді (FavoritesColumn.tsx)
Обов’язкова секція ## Use cases — один абзац: хто (роль/функція) і за яким сценарієм сюди заходить. Бізнес-контекст, не повторення > навігації і не матриця прав з Доступи. Якщо use case один — речення; якщо ролей з різними сценаріями кілька — bullet’и за ролями.
Обов’язкова секція Зв'язки — звідки дані (лінк на бек-ендпоінт у Swagger), що тригерить (лінк на дію)
Описуємо: які дані показуються, які дії доступні, які фільтри й стани, які обмеження
Не описуємо: верстку, стилі, компоненти, імена пропсів, форму запиту/відповіді
Канон структури: фічі + ендпоінти
Еталони для копіювання: Courses (single-backend) і Favorites (per-Family).
1. Таблиця кліків-фіч. Карта екрану одним поглядом: рядок = одна дія / під-екран. Коли доступ залежить від ролі чи призначення — колонки на access-тип (як Director / Mentor / Trainee у Courses). Деталі кожної фічі — нижче окремими секціями.
2. Ендпоінти — deeplink’и на Swagger, не контракт. Під фічами — посилання на конкретні Swagger-ендпоінти + 2-3 слова «що робить». Форму запиту/відповіді не пишемо (це робота Swagger). Формат залежить від типу екрану:
Single-backend (ui-shared/* — academy, stack…): під кожною фічею своя таблиця Endpoint | Що робить, одна колонка. Як у Courses.
Per-Family (ui-family/*): один екран працює на 4 Family (Udate / TalkyTimes / GoldenBride / Chathouse) з різними беками. Тому ендпоінти — таблиця з колонкою на Family: рядок = під-фіча, колонки golden / prime / udate / chathouse. Де бек ще не мігрований у Swagger — *TODO*. Як у Favorites (секція ## API).
Розбіжності полів між Family (на per-Family сторінці) фіксуємо окремою таблицею «поле × Family» з ✓/— (як у Favorites → «Таблиця фаворитів — поля по Family» + «Розбіжності»). Один UI-екран = 4 контракти, тому єдиного лінку «на бек» не буває — завжди розклад по Family.
Правила для Service-сторінок
Шлях у коді — обов’язковий у шапці
#Interval — якщо є таймер
Секції: Інтервал (якщо є), Логіка, Нюанси, Зв'язки
Нюанси зазвичай найцінніше: stop-листи, watchdog’і, захисти від подвійного запуску, рандомізації
Доступ за ролями — якщо ендпоінт має guard([...]), перерахуй ролі або пошлися на [[roles/<role>]]. Не дублюй логіку гварда — Swagger її показує. Описуй бізнес-причину обмеження якщо вона неочевидна.
Правила для Entity-сторінок
Описуємо структуру даних і ключові властивості сутності
Глобальні ентіті (живуть у RMQ-обміні між сервісами або в спільних таблицях) — у stack-docs/entities/
Локальні (тільки всередині одного сервісу) — в <service>/docs/entities/
Лінки на сервіси які цю сутність продукують/споживають
BE-схеми (Mongoose / SQL)
Коли сутність відповідає колекції/таблиці БД конкретного сервісу:
Контекстна стрічка — `<шлях до схеми>` · колекція `<ім'я колекції>` (для SQL — таблиця). Приклад: `src/modules/course/schemas/course.schemas.ts` · колекція `academy_courses`.
Обов’язкова секція ## Поля — bullet-list з описом кожного поля що має бізнес-значення:
- **name** — назва курсу- **role: `StackRoles`** — на яку роль курс розрахований- **mentors[]: `{mentorId, allowEdit}`** — Mentors курсу- **clientManagerId** — ObjectId на [[entities/<Other>]]
Типи вказуй тільки коли неочевидні (enum, кастомний DTO, ObjectId-ref). Скаляри без типу. Тривіальні required: true / default: ... не описуй.
Секція ## Нюанси — індекси, каскадні видалення, кешовані поля, transform-плагіни, нетривіальні валідатори. Не вмикай у цей розділ загальний toJSON плагін якщо він однаковий по всьому сервісу — це описано в CLAUDE.md сервісу.
Не описуй Swagger-схему request/response DTO — для них є Swagger UI. Entity-сторінка про storage shape, не про API contract.
Реєстр сутностей
Кожен сервіс з ≥3 BE-сутностями веде <service>/docs/entities/index.md з тегом #Meta — список усіх колекцій/таблиць сервісу (включно з логами, буферами, технічним сміттям, для яких окремої entity-сторінки нема і не буде).
Формат: bullet-list з жирним підписом групи (не H3, бо H3 займає забагато вертикалі в рендері). Рядок:
**Admin / Agency**- `golden_admins` — Адмін-акаунт партнерського API → —- `golden_agensy_list` — Список зовнішніх агенцій → —**Lady (TU)**- `golden_lady` — TU, центральна сутність → [[Lady]]
Один bullet = одна колекція.
Назва колекції в ` (моноширинно), далі — опис, в кінці → [[Name]] якщо є окрема entity-сторінка або → — якщо нема.
Якщо багато колекцій — групуй жирним підписом групи (**Group name**). Якщо багато сховищ (MongoDB + ClickHouse) — H2 на сховище, далі групи bold-ом.
Без полів — це індекс. Деталі лежать на самій entity-сторінці.
Правила для Flow-сторінок
Структура — пронумерований список кроків
Короткі flow (≤3 кроки) — описуємо в одному файлі
Довгі flow — окрема сторінка на крок, у головній тільки список з лінками
Крос-сервісні flow (наприклад user signup що зачіпає stack + golden + RMQ) — у stack-docs/architecture/flows/
API сервісу
У сервісних доках власних сторінок про API не пишемо — у <service>/docs/index.md ставимо лінк на корінь Swagger відповідного бека. Контракт описує сам Swagger.
Глобальна карта всіх Swagger-ів + єдина конвенція відповідей + крос-сервісні нюанси гвардів — у API Map.
Бізнес-нюанс конкретного ендпоінту якого Swagger не показує (рідкісна комбінація ролей, особлива побічна дія, legacy-quirk) — описуй у файлі відповідного сервісу або контролера, не створюй окрему api/ папку.
Правила для Role-сторінок
Усі ролі — в одному файлі roles на рівні root. Один рядок таблиці на роль (код + кому + коротке призначення). Не розводимо окремий файл на кожну роль — це довідник, а не онбординг.
Якщо якась роль вимагає глибшого опису (складна матриця доступів, багатокроковий процес видачі) — виносимо тільки її в окремий файл roles/<role>.md і лінкуємо з таблиці.
Конвенції бекенд-коду (DTO)
Глобальні правила для backend-сервісів які генерують Swagger з декораторів (academy NestJS, golden routing-controllers). Окремі сервіси можуть мати додаткові локальні нюанси у своєму CLAUDE.md, але базові правила DTO — тут.
Response DTO — <Entity>ResponseDto. Приклади: AdminResponseDto, LadyResponseDto. Один клас на унікальну форму відповіді.
PascalCase скрізь.
Mongoose IXxx interface — алиас на response DTO: export type IAdmin = AdminResponseDto;. Якщо storage має додаткові поля що не віддаються назовні — interface IAdmin extends AdminResponseDto { _internal: string }.
Розташування файлів
DTO живуть у <module>/dto/ всередині свого модуля.
Правило файл/клас:
Top-level Response/Request DTO → свій файл<Name>ResponseDto.ts / <Name>RequestDto.ts. Клас і ім’я файлу збігаються.
Nested DTO використаний лише в одному батьку → у тому ж файлі що батько, без export. Це «внутрішня деталь» response shape, не самостійна сутність.
Якщо такий nested-клас починає юзатися ще десь → виносимо у власний файл <Name>Dto.ts і експортуємо.
Поле id додаємо у XxxResponseDtoтільки якщо воно реально віддається назовні і споживач його використовує. Не додавати «про всяк випадок» якщо дублюється з _id мангузника який ніхто не читає.
Для запитів які не мають body / query DTO (порожній POST, GET без params) — DTO не пишемо.
Nested array (масив іншого DTO)
class-validator-jsonschema не вміє автовиведення items-типу для Cls[] навіть з @Type(() => Cls) — генерує generic Array ref який Swagger UI не резолвить. Для нашого стеку є helper з @it-monkeys/stack-commons:
import { NestedArray } from '@it-monkeys/stack-commons';export class CalendarItem { @IsString() date: string; @IsInt() count: number;}export class ResponseDto { @NestedArray(() => CalendarItem) calendar: CalendarItem[]; @IsInt() totalIds: number;}
@NestedArray(() => Cls) всередині комбінує @ValidateNested({each:true}) + @Type(() => Cls) + @JSONSchema({type:'array', items:{$ref:'#/components/schemas/Cls'}}) в один декоратор.
Виняток до правила «nested = не експортуємо»: клас-айтем мусить бути export (Swagger schemas registry резолвить refs по імені класу, без експорту ім’я з namespace не виходить). Файлова структура та сама — nested класи живуть у файлі parent-DTO.
Для AI
Не плутати action-named DTO з generic: AdminCreateDto ≠ «якийсь admin DTO» — це request для /create.
Не змішувати Request і Response в одному файлі.
Не створювати nested DTO як окремий файл «про всяк» — спочатку інлайн у батька.
Локальний<service>/docs/Canvas.canvas — мапа всередині сервісу (як зараз в електроні). Ноди = файли в docs/ цього сервісу.
Кольори по типах
Тип
Колір
Hex
UI
блакитний
#2196f3
Service
зелений
#66bb6a
Entity
фіолетовий
#ab47bc
Flow
помаранчевий
#ffa726
System
сіро-зелений
#78909c
Role
жовтий
#ffd54f
API
бірюзовий
#26a69a
Meta
червоний
#e03131
Типи стрілок (підпис на стрілці)
тригерить — натискання/подія запускає процес
оновлює — сервіс пише дані в UI/entity
читає — UI читає дані з entity/store
стартує — один сервіс стартує інший (ініціалізація)
викликає — крос-сервіс HTTP виклик
публікує / слухає — RMQ події
Групи
Обводимо ноди одного типу в групу з кольоровим підписом (наприклад «Інтервали оператора», «Сервіси TU»). Використовуємо для ≥3 нод одного типу в одному місці.