diff --git a/.vitepress/config.ts b/.vitepress/config.ts index f6ad7c1..96e2935 100644 --- a/.vitepress/config.ts +++ b/.vitepress/config.ts @@ -8,6 +8,7 @@ const sidebar = [ { text: 'Слои', link: '/architecture/layers' }, { text: 'Модули', link: '/architecture/modules' }, { text: 'Сегменты', link: '/architecture/segments' }, + { text: 'Монорепозитории', link: '/architecture/monorepo' }, ], }, ]; diff --git a/README.md b/README.md index 271a0d9..f57688e 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,9 @@ Scoped Layered Module Design — модульная архитектура фр - [Слои](docs/architecture/layers.md) — уровни организации `src/`, направление зависимостей и зона ответственности каждого слоя. - [Модули](docs/architecture/modules.md) — границы ответственности, публичный API, типы модулей и отличие модуля от компонента. - [Сегменты](docs/architecture/segments.md) — внутренние папки модуля (`ui/`, `parts/`, `hooks/`, `types/` и другие) и правила размещения файлов. +- [Монорепозитории](docs/architecture/monorepo.md) — применение SLM в `apps/` и `packages/`, правила выноса общих слоёв и ограничения для business. -Рекомендуемый порядок чтения: обзор → слои → модули → сегменты. +Рекомендуемый порядок чтения: обзор → слои → модули → сегменты → монорепозитории. ## Преимущества @@ -41,6 +42,10 @@ Cross-domain зависимости в бизнес-слое реализуют При росте проекта слои не теряют структуру — модули группируются по естественным признакам: бизнес-домены по субдоменам, страницы по разделам, UI-компоненты по уровню абстракции (примитивы и композиции). +### Адаптация к монорепозиториям + +SLM применяется внутри каждого приложения, а `packages/*` используются только для общего кода из слоёв `ui`, `infra` и `shared`. Бизнес-домены остаются внутри приложений, чтобы не размывать продуктовые границы. + ## Происхождение SLM Design вырос на основе: diff --git a/docs/architecture/index.md b/docs/architecture/index.md index 544cc22..4f45f1e 100644 --- a/docs/architecture/index.md +++ b/docs/architecture/index.md @@ -13,8 +13,9 @@ Scoped Layered Module Design — модульная архитектура фр - [Слои](/architecture/layers) — уровни организации `src/`, направление зависимостей и зона ответственности каждого слоя. - [Модули](/architecture/modules) — границы ответственности, публичный API, типы модулей и отличие модуля от компонента. - [Сегменты](/architecture/segments) — внутренние папки модуля (`ui/`, `parts/`, `hooks/`, `types/` и другие) и правила размещения файлов. +- [Монорепозитории](/architecture/monorepo) — применение SLM в `apps/` и `packages/`, правила выноса общих слоёв и ограничения для business. -Рекомендуемый порядок чтения: обзор → слои → модули → сегменты. +Рекомендуемый порядок чтения: обзор → слои → модули → сегменты → монорепозитории. ## Преимущества @@ -46,6 +47,10 @@ Cross-domain зависимости в бизнес-слое реализуют При росте проекта слои не теряют структуру — модули группируются по естественным признакам: бизнес-домены по субдоменам, страницы по разделам, UI-компоненты по уровню абстракции (примитивы и композиции). +### Адаптация к монорепозиториям + +SLM применяется внутри каждого приложения, а `packages/*` используются только для общего кода из слоёв `ui`, `infra` и `shared`. Бизнес-домены остаются внутри приложений, чтобы не размывать продуктовые границы. + ## Происхождение SLM Design вырос на основе: diff --git a/docs/architecture/monorepo.md b/docs/architecture/monorepo.md new file mode 100644 index 0000000..803ee9e --- /dev/null +++ b/docs/architecture/monorepo.md @@ -0,0 +1,235 @@ +--- +title: Монорепозитории +description: "Правила применения SLM Design для frontend-проектов, находящихся в монорепозитории" +--- + +# Монорепозитории + +Раздел описывает, как применять SLM Design, когда фронтенд-проекты находятся в одном монорепозитории. В нём показано, что остаётся внутри приложений, что можно выносить в `packages/` и какие ограничения действуют для общих пакетов. + +## Определение + +**Монорепозиторий — внешний уровень организации нескольких фронтенд-приложений и общих пакетов. SLM применяется внутри каждого приложения, а frontend-пакеты, относящиеся к SLM, содержат переиспользуемый код, вынесенный из слоёв `ui`, `infra` и `shared`.** + +## Базовая структура + +Каждое приложение внутри `apps/` сохраняет собственную SLM-структуру в `src/`. + +```text +repo/ +├── apps/ +│ ├── web/ +│ │ └── src/ +│ │ ├── app/ +│ │ ├── layouts/ +│ │ ├── screens/ +│ │ ├── widgets/ +│ │ ├── business/ +│ │ ├── infra/ +│ │ ├── ui/ +│ │ └── shared/ +│ └── admin/ +│ └── src/ +│ └── ... +└── packages/ + ├── ui/ + │ ├── button/ # самостоятельный пакет UI-модуля + │ ├── input/ # самостоятельный пакет UI-модуля + │ └── modal/ # самостоятельный пакет UI-модуля + ├── infra/ + │ ├── theme/ # самостоятельный пакет infra-модуля + │ ├── backend-api/ # самостоятельный пакет infra-модуля + │ └── logger/ # самостоятельный пакет infra-модуля + └── shared/ # единый shared-пакет + ├── package.json + └── src/ + ├── lib/ # переиспользуемые утилиты + ├── helpers/ # переиспользуемые helpers + └── index.ts +``` + +`apps/{app}/src` — граница SLM-приложения. `packages/*` находятся выше SLM и не добавляют новые архитектурные слои. + +## Группировка frontend-пакетов + +Frontend-пакеты, вынесенные из SLM-приложений, рекомендуется группировать по источнику кода: `ui`, `infra`, `shared`. + +```text +packages/ui/* # пакеты UI-модулей +packages/infra/* # пакеты infra-модулей +packages/shared # единый shared-пакет +``` + +Эта группировка повторяет названия SLM-слоёв для навигации, но сама не является слоистой архитектурой внутри `packages/`. Монорепозиторий может содержать другие пакеты: tooling, конфиги, SDK, схемы, e2e и другие технические пакеты вне SLM. + +## Пакет и модуль + +Пакет не равен SLM-модулю: модуль — архитектурная единица внутри слоя приложения, package — единица монорепозитория для переиспользования, владения, сборки и публикации. + +В `packages/ui/*` размещаются пакеты самостоятельных UI-модулей. В `packages/infra/*` размещаются пакеты самостоятельных инфраструктурных модулей. `packages/shared` устроен иначе: это единый пакет для переиспользуемых утилит, helpers и другого фундаментального кода без привязки к конкретному приложению. + +```text +packages/ui/button/ +packages/ui/modal/ +packages/infra/theme/ +packages/infra/backend-api/ +packages/shared/ +``` + +## Что остаётся в приложении + +Слои `app`, `layouts`, `screens`, `widgets` и `business` остаются внутри конкретного приложения. + +```text +apps/web/src/app/ +apps/web/src/layouts/ +apps/web/src/screens/ +apps/web/src/widgets/ +apps/web/src/business/ +``` + +`app`, `layouts` и `screens` привязаны к роутингу, каркасу и страницам конкретного приложения. `widgets` не выносятся в пакеты, потому что это слой композиции интерфейса приложения. + +`business` не выносится в `packages/*`. Домены остаются рядом со сценариями приложения, чтобы не превращать монорепозиторий в общий бизнес-слой. + +## Что можно выносить + +В пакеты выносится только код из `ui`, `infra` и `shared`, который потенциально будет использоваться в двух и более фронтенд-приложениях монорепозитория. + +| Группа | Что выносить | Пример | +|--------|--------------|--------| +| `packages/ui/*` | Самостоятельные UI-модули без бизнес-логики | `packages/ui/button` | +| `packages/infra/*` | Самостоятельные технические сервисы | `packages/infra/backend-api` | +| `packages/shared` | Общие утилиты, helpers и фундаментальный код | `packages/shared` | + +Пакет можно создавать сразу, если модуль имеет общую природу и ожидается его переиспользование между приложениями. App-specific код остаётся внутри приложения. + +## UI-пакеты + +В `packages/ui/*` размещаются переиспользуемые UI-модули. + +```text +packages/ui/button/ +├── package.json +└── src/ + ├── button.tsx + ├── styles/ + ├── types/ + └── index.ts +``` + +UI-пакет не содержит бизнес-логику, обращения к API, сценарные хуки приложения и композицию страниц. + +## Infra-пакеты + +В `packages/infra/*` размещаются переиспользуемые инфраструктурные модули. + +```text +packages/infra/backend-api/ +├── package.json +└── src/ + ├── clients/ + ├── config/ + ├── types/ + └── index.ts +``` + +Привязанные к конкретному приложению сервисы остаются в `apps/{app}/src/infra`. Например, локализация со словарями конкретного продукта остаётся в приложении; общим пакетом может быть только переиспользуемый i18n-движок. + +## Shared-пакет + +`packages/shared` является единым пакетом. + +```text +packages/shared/ +├── package.json +└── src/ + ├── lib/ + ├── helpers/ + └── index.ts +``` + +В `packages/shared` сразу выносится общий фундаментальный код: чистые функции, helpers, утилиты, независимые константы и другой код без знания о продукте. + +Проектные стили, типы приложения, продуктовые конфиги и ресурсы, завязанные на одно приложение, в общий `shared` не выносятся. + +## Имена пакетов и импорты + +Путь импорта задаётся `name` в `package.json`, а не расположением директории. + +```json +{ + "name": "@repo/theme" +} +``` + +```text +packages/infra/theme/package.json +``` + +```ts +import { ThemeProvider } from '@repo/theme' +``` + +Пакеты должны импортироваться только через публичный API. Deep imports внутрь пакета запрещены. + +```ts +// Хорошо +import { Button } from '@repo/button' + +// Плохо +import { Button } from '@repo/button/src/button' +``` + +## Зависимости + +На уровне монорепозитория приложения зависят от пакетов, а пакеты не зависят от приложений. + +```text +apps → packages +packages -/→ apps +``` + +Внутри приложения продолжает действовать обычное направление зависимостей SLM. + +```text +app → [ layouts | screens ] → widgets → business → infra → ui → shared +``` + +Пакеты не должны нарушать природу своей группы: `packages/ui/*` не импортирует `packages/infra/*`, `packages/shared` не импортирует другие группы, а `packages/infra/*` не знает о приложениях. + +## Когда не выносить + +Не выносите код в пакет, если он не может быть использован в двух и более фронтенд-приложениях, зависит от роутинга или страниц, содержит бизнес-логику, отражает продуктовую композицию конкретного интерфейса или не имеет стабильного публичного API. + +Фактическое использование в одном приложении не запрещает пакет, если модуль имеет общую природу и потенциально нужен нескольким приложениям. + +```text +# Плохо +apps/web/src/screens/home/parts/promo-section/ +packages/ui/promo-section/ +``` + +Если блок нужен только одной странице или отражает продуктовую композицию конкретного приложения, он остаётся локальным `parts/`-модулем. + +## Конфигурационные пакеты + +Конфигурационные пакеты не относятся к SLM-архитектуре. + +Если в монорепозитории есть общие настройки TypeScript, ESLint, сборки или форматирования, они относятся к tooling-инфраструктуре репозитория. Такие пакеты могут находиться в `packages/`, но их структура зависит от выбранного инструментария и не участвует в правилах слоёв внутри `src/`. + +## Правила + +- SLM применяется внутри каждого `apps/{app}/src`. +- Frontend-пакеты, вынесенные из SLM-приложений, группируются в `packages/ui`, `packages/infra`, `packages/shared`. +- Группы `packages/ui`, `packages/infra`, `packages/shared` не являются SLM-слоями. +- В `packages/ui/*` размещаются пакеты самостоятельных UI-модулей. +- В `packages/infra/*` размещаются пакеты самостоятельных инфраструктурных модулей. +- `packages/shared` является единым пакетом для переиспользуемых утилит и helpers. +- Модуль можно размещать в пакете, если он потенциально будет использоваться в двух и более фронтенд-приложениях. +- `business`, `app`, `layouts`, `screens`, `widgets` не выносятся в пакеты. +- Проектные стили, типы приложения и продуктовые конфиги не выносятся в `packages/shared`. +- Пакеты не импортируют приложения. +- Межпакетные импорты идут только через публичный API. +- Deep imports внутрь пакетов запрещены. +- Локальная колокация важнее преждевременного выноса в `packages/*`. diff --git a/docs/index.md b/docs/index.md index 54ed705..791dee2 100644 --- a/docs/index.md +++ b/docs/index.md @@ -12,6 +12,7 @@ title: Документация - Если проектируете структуру `src/` — откройте [Слои](/architecture/layers). - Если создаёте новый домен или блок интерфейса — используйте [Модули](/architecture/modules). - Если выбираете папку внутри модуля — смотрите [Сегменты](/architecture/segments). +- Если адаптируете SLM к монорепозиторию — откройте [Монорепозитории](/architecture/monorepo). ## Разделы @@ -21,6 +22,7 @@ title: Документация | [Слои](/architecture/layers) | Нужно определить, где должен жить код и какие зависимости допустимы. | | [Модули](/architecture/modules) | Нужно оформить границы модуля, публичный API или фабрику. | | [Сегменты](/architecture/segments) | Нужно выбрать внутреннюю папку для компонента, хука, стиля, типа или конфига. | +| [Монорепозитории](/architecture/monorepo) | Нужно понять, что можно выносить в `packages/*` и какие слои остаются внутри приложения. | ## Для ассистентов diff --git a/public/ARCHITECTURE.md b/public/ARCHITECTURE.md index 78829e1..51c0a61 100644 --- a/public/ARCHITECTURE.md +++ b/public/ARCHITECTURE.md @@ -13,8 +13,9 @@ Scoped Layered Module Design — модульная архитектура фр - [Слои](#слои) — уровни организации `src/`, направление зависимостей и зона ответственности каждого слоя. - [Модули](#модули) — границы ответственности, публичный API, типы модулей и отличие модуля от компонента. - [Сегменты](#сегменты) — внутренние папки модуля (`ui/`, `parts/`, `hooks/`, `types/` и другие) и правила размещения файлов. +- [Монорепозитории](#монорепозитории) — применение SLM в `apps/` и `packages/`, правила выноса общих слоёв и ограничения для business. -Рекомендуемый порядок чтения: обзор → слои → модули → сегменты. +Рекомендуемый порядок чтения: обзор → слои → модули → сегменты → монорепозитории. ## Преимущества @@ -46,6 +47,10 @@ Cross-domain зависимости в бизнес-слое реализуют При росте проекта слои не теряют структуру — модули группируются по естественным признакам: бизнес-домены по субдоменам, страницы по разделам, UI-компоненты по уровню абстракции (примитивы и композиции). +### Адаптация к монорепозиториям + +SLM применяется внутри каждого приложения, а `packages/*` используются только для общего кода из слоёв `ui`, `infra` и `shared`. Бизнес-домены остаются внутри приложений, чтобы не размывать продуктовые границы. + ## Происхождение SLM Design вырос на основе: @@ -821,4 +826,236 @@ lib/ config/ ├── routes.ts └── constants.ts -``` \ No newline at end of file +``` + + +## Монорепозитории + +Раздел описывает, как применять SLM Design, когда фронтенд-проекты находятся в одном монорепозитории. В нём показано, что остаётся внутри приложений, что можно выносить в `packages/` и какие ограничения действуют для общих пакетов. + +### Определение + +**Монорепозиторий — внешний уровень организации нескольких фронтенд-приложений и общих пакетов. SLM применяется внутри каждого приложения, а frontend-пакеты, относящиеся к SLM, содержат переиспользуемый код, вынесенный из слоёв `ui`, `infra` и `shared`.** + +### Базовая структура + +Каждое приложение внутри `apps/` сохраняет собственную SLM-структуру в `src/`. + +```text +repo/ +├── apps/ +│ ├── web/ +│ │ └── src/ +│ │ ├── app/ +│ │ ├── layouts/ +│ │ ├── screens/ +│ │ ├── widgets/ +│ │ ├── business/ +│ │ ├── infra/ +│ │ ├── ui/ +│ │ └── shared/ +│ └── admin/ +│ └── src/ +│ └── ... +└── packages/ + ├── ui/ + │ ├── button/ # самостоятельный пакет UI-модуля + │ ├── input/ # самостоятельный пакет UI-модуля + │ └── modal/ # самостоятельный пакет UI-модуля + ├── infra/ + │ ├── theme/ # самостоятельный пакет infra-модуля + │ ├── backend-api/ # самостоятельный пакет infra-модуля + │ └── logger/ # самостоятельный пакет infra-модуля + └── shared/ # единый shared-пакет + ├── package.json + └── src/ + ├── lib/ # переиспользуемые утилиты + ├── helpers/ # переиспользуемые helpers + └── index.ts +``` + +`apps/{app}/src` — граница SLM-приложения. `packages/*` находятся выше SLM и не добавляют новые архитектурные слои. + +### Группировка frontend-пакетов + +Frontend-пакеты, вынесенные из SLM-приложений, рекомендуется группировать по источнику кода: `ui`, `infra`, `shared`. + +```text +packages/ui/* # пакеты UI-модулей +packages/infra/* # пакеты infra-модулей +packages/shared # единый shared-пакет +``` + +Эта группировка повторяет названия SLM-слоёв для навигации, но сама не является слоистой архитектурой внутри `packages/`. Монорепозиторий может содержать другие пакеты: tooling, конфиги, SDK, схемы, e2e и другие технические пакеты вне SLM. + +### Пакет и модуль + +Пакет не равен SLM-модулю: модуль — архитектурная единица внутри слоя приложения, package — единица монорепозитория для переиспользования, владения, сборки и публикации. + +В `packages/ui/*` размещаются пакеты самостоятельных UI-модулей. В `packages/infra/*` размещаются пакеты самостоятельных инфраструктурных модулей. `packages/shared` устроен иначе: это единый пакет для переиспользуемых утилит, helpers и другого фундаментального кода без привязки к конкретному приложению. + +```text +packages/ui/button/ +packages/ui/modal/ +packages/infra/theme/ +packages/infra/backend-api/ +packages/shared/ +``` + +### Что остаётся в приложении + +Слои `app`, `layouts`, `screens`, `widgets` и `business` остаются внутри конкретного приложения. + +```text +apps/web/src/app/ +apps/web/src/layouts/ +apps/web/src/screens/ +apps/web/src/widgets/ +apps/web/src/business/ +``` + +`app`, `layouts` и `screens` привязаны к роутингу, каркасу и страницам конкретного приложения. `widgets` не выносятся в пакеты, потому что это слой композиции интерфейса приложения. + +`business` не выносится в `packages/*`. Домены остаются рядом со сценариями приложения, чтобы не превращать монорепозиторий в общий бизнес-слой. + +### Что можно выносить + +В пакеты выносится только код из `ui`, `infra` и `shared`, который потенциально будет использоваться в двух и более фронтенд-приложениях монорепозитория. + +| Группа | Что выносить | Пример | +|--------|--------------|--------| +| `packages/ui/*` | Самостоятельные UI-модули без бизнес-логики | `packages/ui/button` | +| `packages/infra/*` | Самостоятельные технические сервисы | `packages/infra/backend-api` | +| `packages/shared` | Общие утилиты, helpers и фундаментальный код | `packages/shared` | + +Пакет можно создавать сразу, если модуль имеет общую природу и ожидается его переиспользование между приложениями. App-specific код остаётся внутри приложения. + +### UI-пакеты + +В `packages/ui/*` размещаются переиспользуемые UI-модули. + +```text +packages/ui/button/ +├── package.json +└── src/ + ├── button.tsx + ├── styles/ + ├── types/ + └── index.ts +``` + +UI-пакет не содержит бизнес-логику, обращения к API, сценарные хуки приложения и композицию страниц. + +### Infra-пакеты + +В `packages/infra/*` размещаются переиспользуемые инфраструктурные модули. + +```text +packages/infra/backend-api/ +├── package.json +└── src/ + ├── clients/ + ├── config/ + ├── types/ + └── index.ts +``` + +Привязанные к конкретному приложению сервисы остаются в `apps/{app}/src/infra`. Например, локализация со словарями конкретного продукта остаётся в приложении; общим пакетом может быть только переиспользуемый i18n-движок. + +### Shared-пакет + +`packages/shared` является единым пакетом. + +```text +packages/shared/ +├── package.json +└── src/ + ├── lib/ + ├── helpers/ + └── index.ts +``` + +В `packages/shared` сразу выносится общий фундаментальный код: чистые функции, helpers, утилиты, независимые константы и другой код без знания о продукте. + +Проектные стили, типы приложения, продуктовые конфиги и ресурсы, завязанные на одно приложение, в общий `shared` не выносятся. + +### Имена пакетов и импорты + +Путь импорта задаётся `name` в `package.json`, а не расположением директории. + +```json +{ + "name": "@repo/theme" +} +``` + +```text +packages/infra/theme/package.json +``` + +```ts +import { ThemeProvider } from '@repo/theme' +``` + +Пакеты должны импортироваться только через публичный API. Deep imports внутрь пакета запрещены. + +```ts +// Хорошо +import { Button } from '@repo/button' + +// Плохо +import { Button } from '@repo/button/src/button' +``` + +### Зависимости + +На уровне монорепозитория приложения зависят от пакетов, а пакеты не зависят от приложений. + +```text +apps → packages +packages -/→ apps +``` + +Внутри приложения продолжает действовать обычное направление зависимостей SLM. + +```text +app → [ layouts | screens ] → widgets → business → infra → ui → shared +``` + +Пакеты не должны нарушать природу своей группы: `packages/ui/*` не импортирует `packages/infra/*`, `packages/shared` не импортирует другие группы, а `packages/infra/*` не знает о приложениях. + +### Когда не выносить + +Не выносите код в пакет, если он не может быть использован в двух и более фронтенд-приложениях, зависит от роутинга или страниц, содержит бизнес-логику, отражает продуктовую композицию конкретного интерфейса или не имеет стабильного публичного API. + +Фактическое использование в одном приложении не запрещает пакет, если модуль имеет общую природу и потенциально нужен нескольким приложениям. + +```text +# Плохо +apps/web/src/screens/home/parts/promo-section/ +packages/ui/promo-section/ +``` + +Если блок нужен только одной странице или отражает продуктовую композицию конкретного приложения, он остаётся локальным `parts/`-модулем. + +### Конфигурационные пакеты + +Конфигурационные пакеты не относятся к SLM-архитектуре. + +Если в монорепозитории есть общие настройки TypeScript, ESLint, сборки или форматирования, они относятся к tooling-инфраструктуре репозитория. Такие пакеты могут находиться в `packages/`, но их структура зависит от выбранного инструментария и не участвует в правилах слоёв внутри `src/`. + +### Правила + +- SLM применяется внутри каждого `apps/{app}/src`. +- Frontend-пакеты, вынесенные из SLM-приложений, группируются в `packages/ui`, `packages/infra`, `packages/shared`. +- Группы `packages/ui`, `packages/infra`, `packages/shared` не являются SLM-слоями. +- В `packages/ui/*` размещаются пакеты самостоятельных UI-модулей. +- В `packages/infra/*` размещаются пакеты самостоятельных инфраструктурных модулей. +- `packages/shared` является единым пакетом для переиспользуемых утилит и helpers. +- Модуль можно размещать в пакете, если он потенциально будет использоваться в двух и более фронтенд-приложениях. +- `business`, `app`, `layouts`, `screens`, `widgets` не выносятся в пакеты. +- Проектные стили, типы приложения и продуктовые конфиги не выносятся в `packages/shared`. +- Пакеты не импортируют приложения. +- Межпакетные импорты идут только через публичный API. +- Deep imports внутрь пакетов запрещены. +- Локальная колокация важнее преждевременного выноса в `packages/*`. \ No newline at end of file