chore: sync

This commit is contained in:
2026-08-10 12:37:32 +03:00
parent af155fff0a
commit 1ba664f445
15 changed files with 684 additions and 238 deletions

View File

@@ -10,28 +10,27 @@
Слой → [Группа*] → Модуль → [Сегмент*]
```
Группа классифицирует несколько модулей внутри слоя. Сегмент классифицирует код одного модуля. Ни группа, ни сегмент не являются владельцами.
Группа классифицирует модули внутри слоя. Сегмент классифицирует код одного модуля. Ни группа, ни сегмент не являются владельцами.
Все файлы, компоненты, состояние, зависимости и код жизненного цикла сегмента принадлежат родительскому модулю. Исключением является только вложенный модуль, который начинает собственную границу владения.
Все файлы, framework-компоненты, состояние, зависимости и lifecycle-код сегмента принадлежат ближайшему модулю. Исключением является только вложенный модуль, который начинает собственную границу владения.
## Назначение
Сегмент используется, когда группировка внутренних файлов по назначению упрощает навигацию. Набор и названия сегментов определяет проект.
Возможная структура:
```text
profile/
├── index.ts
├── profile.tsx
├── hooks/ # Возможный сегмент
├── services/ # Возможный сегмент
├── stores/ # Возможный сегмент
├── types/ # Возможный сегмент
── ui/ # Возможный сегмент
├── index.ts # Публичный фасет
├── profile.tsx # Главная реализация
├── components/ # Возможный сегмент
├── hooks/ # Возможный сегмент
├── services/ # Возможный сегмент
├── stores/ # Возможный сегмент
── types/ # Возможный сегмент
└── styles/ # Возможный сегмент
```
Ни один из показанных сегментов не обязателен. Маленький модуль может хранить реализацию в корне без дополнительных каталогов.
Ни один сегмент не создаётся заранее. Модуль может обойтись без сегментов, если помимо публичных фасетов содержит только один главный implementation- или assembly-файл, однозначно выражающий его ответственность. Любая остальная реализация размещается в подходящих сегментах. Если главный файл нельзя определить уверенно, вся реализация остаётся в сегментах.
Сегмент:
@@ -41,52 +40,67 @@ profile/
- не является узлом графа зависимостей;
- не импортируется внешним кодом как отдельная архитектурная сущность.
Локальный `index.ts` может использоваться во внутренней единице сегмента, например в каталоге компонента. Он не превращает эту единицу или сегмент в модульную границу.
Локальный `index.ts` может использоваться во внутренней единице сегмента. Он не превращает эту единицу или сегмент в модульную границу.
## Компоненты и вложенные модули
## Framework-компоненты
Сегмент может содержать компоненты и вспомогательные файлы родительского модуля. Компонент вправе иметь локальные `styles/`, `types/`, `tests/` и внутренний `index.ts`; всё это остаётся реализацией ближайшего модуля.
Framework-компоненты являются обычным внутренним кодом модуля. Они могут выполнять визуальные и невизуальные роли, включая Provider, Guard или Error Boundary, если используемый фреймворк считает соответствующую сущность компонентом.
Помимо опционального главного framework-файла в корне, остальные компонентные единицы размещаются на одном внутреннем уровне относительно модуля. Каталог такой единицы может содержать локальные `styles`, `types`, `hooks`, `tests` и внутренний `index.ts`, но не содержит другие компонентные единицы или вложенные модули.
```text
header/ # Модуль
── components/ # Сегмент
└── button-submit/ # Компонент
├── button-submit.tsx
├── styles/
── button-submit.module.css
├── types/
── button-submit.types.ts
── index.ts # Внутренняя точка входа
header/ # Модуль
── index.ts # Публичный фасет
├── header.tsx # Главная реализация
└── components/ # Сегмент
├── button-submit/
── index.ts # Локальная точка входа
├── button-submit.tsx
── styles/
── types/
│ └── hooks/
└── icon.tsx # Соседняя компонентная единица
```
`ButtonSubmit` может рендерить `Icon`, но их файловые области не вкладываются друг в друга. Ограничение относится к файловой структуре, а не к runtime-дереву.
Внешний код не импортирует `components/button-submit`. Если компонент нужен снаружи, модуль-владелец реэкспортирует его через собственный публичный фасет.
Сегмент также может содержать вложенные модули. В отличие от остальных файлов сегмента, каждый вложенный модуль сам владеет отдельной ответственностью и имеет публичный API и границу зависимостей.
## Вложенные модули
Сегмент может содержать вложенные модули. В отличие от остальных файлов сегмента, каждый вложенный модуль владеет отдельно сформулированной подответственностью и имеет публичный API и границу зависимостей.
```text
landing/ # Родительский модуль
└── parts/ # Сегмент
└── modules/ # Сегмент
└── hero/ # Вложенный модуль
├── hero.tsx
── index.ts
├── index.ts # Публичный фасет вложенного модуля
── hero.tsx # Главная реализация hero
└── modules/ # Допустимая модульная рекурсия
└── media/
└── index.ts
```
Имя `parts` является примером, а не обязательным соглашением SLM.
Компонентный каталог не содержит `components` или `modules`. Рекурсивная структурная вложенность допускается только через вложенные модули. Имена `components` и `modules` являются примерами локального стайлгайда, а не обязательными соглашениями SLM.
## Выбор границы
## Выбор размещения
| Ситуация | Решение |
|---|---|
| Код относится к существующему владельцу и группируется только по назначению | Сегмент |
| Части нужна собственная ответственность, API, зависимости, состояние или область жизни | Модуль |
| Несколько модулей слоя нужно классифицировать для навигации | Группа |
| Нескольким файлам не нужна отдельная группировка | Оставить в корне модуля |
| Код относится к существующему владельцу и группируется по назначению | Сегмент |
| Вспомогательный код нужен только одной компонентной единице | Колоцировать в её локальном каталоге |
| Выделена отдельная framework-компонентная единица | Разместить на общем внутреннем уровне модуля |
| Код нужен нескольким внутренним единицам модуля | Поднять в ближайший общий сегмент |
| Появилась самостоятельная связная подответственность | Создать вложенный модуль |
| Файл однозначно является главной реализацией или сборкой ответственности | Допустимо разместить в корне модуля |
| Файл не является главным или его роль неоднозначна | Разместить в подходящем сегменте |
Размер каталога и количество файлов не определяют выбор между сегментом и модулем.
Размер каталога и количество файлов не определяют модульную границу. Её создаёт только самостоятельная ответственность и назначение нового владельца.
## Связанные правила
- [`SLM-SEGMENT-R008`](../rules/registry.md#slm-segment-r008)
- [`SLM-MODULE-A004`](../rules/registry.md#slm-module-a004)
- [`SLM-COMPONENT-R009`](../rules/registry.md#slm-component-r009)
- [`SLM-MODULE-R020`](../rules/registry.md#slm-module-r020)
- [`SLM-MODULE-R021`](../rules/registry.md#slm-module-r021)
- [`SLM-NESTED_MODULE-A010`](../rules/registry.md#slm-nested_module-a010)