From c0956ed2a000b6cf77c4872304f75427b0622df0 Mon Sep 17 00:00:00 2001 From: "S.Gromov" Date: Thu, 30 Jul 2026 17:25:44 +0300 Subject: [PATCH] =?UTF-8?q?style:=20=D1=83=D0=B1=D1=80=D0=B0=D1=82=D1=8C?= =?UTF-8?q?=20=D0=B8=D0=B7=D0=BB=D0=B8=D1=88=D0=BD=D0=B8=D0=B9=20=D0=B0?= =?UTF-8?q?=D0=BD=D0=B3=D0=BB=D0=B8=D1=86=D1=8B=D0=B7=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DRAFT/README.md | 2 +- DRAFT/index.md | 8 +- DRAFT/level-1/README.md | 2 +- DRAFT/level-2/README.md | 6 +- DRAFT/level-3/README.md | 70 ++++++++-------- DRAFT/level-3/dependencies.md | 42 +++++----- DRAFT/level-3/domains/README.md | 50 +++++------ DRAFT/level-3/domains/auth-example.md | 46 +++++----- DRAFT/level-3/domains/business.md | 58 ++++++------- DRAFT/level-3/domains/domain.md | 50 +++++------ .../level-3/domains/factory-ports-adapters.md | 50 +++++------ DRAFT/level-3/domains/framework-bindings.md | 36 ++++---- DRAFT/level-3/domains/open-questions.md | 24 +++--- DRAFT/level-3/domains/presets.md | 38 ++++----- DRAFT/level-3/domains/testing.md | 44 +++++----- DRAFT/level-3/terminology.md | 84 ++++++++++--------- DRAFT/level-3/validation.md | 40 ++++----- DRAFT/rules/README.md | 16 ++-- DRAFT/rules/level-3.md | 68 +++++++-------- 19 files changed, 369 insertions(+), 365 deletions(-) diff --git a/DRAFT/README.md b/DRAFT/README.md index 481242d..1f8fd12 100644 --- a/DRAFT/README.md +++ b/DRAFT/README.md @@ -6,7 +6,7 @@ - [Первый уровень](./level-1/README.md) - базовые слои, модули и зависимости. - [Второй уровень](./level-2/README.md) - доменный слой и доменные модули. -- [Третий уровень](./level-3/README.md) - строгая внутренняя архитектура Domain и runtime-границы. +- [Третий уровень](./level-3/README.md) - строгая внутренняя архитектура домена и границы сред выполнения. - [Правила](./rules/README.md) - канонические наборы, формат и правила формулировки. ## Соглашение diff --git a/DRAFT/index.md b/DRAFT/index.md index fb0d88f..e4410ae 100644 --- a/DRAFT/index.md +++ b/DRAFT/index.md @@ -5,7 +5,7 @@ title: SLM Design hero: name: SLM Design text: Последовательная архитектура фронтенд-приложений - tagline: Начните со слоёв и модулей, затем добавьте доменные границы и строгие runtime-ограничения только при реальной сложности. + tagline: Начните со слоёв и модулей, затем добавьте доменные границы и строгие ограничения сред выполнения только при реальной сложности. image: src: /logo.svg alt: SLM Design @@ -28,14 +28,14 @@ features: details: Слои, модули, публичные API, зависимости, вложенные границы и жизненный цикл ресурсов. - title: Level 2 · Доменные модули details: Новый слой domains локализует модели, правила, сценарии и продуктовое состояние без обязательной внутренней структуры домена. - - title: Level 3 · Строгие Domain - details: Domain объединяет business, ports, adapters, presets и framework modules с явными runtime- и lifecycle-границами. + - title: Level 3 · Строгие домены + details: Домен объединяет бизнес-логику, порты, адаптеры, типовые сборки и модули фреймворков с явными границами сред выполнения и жизненного цикла. - title: Канонические правила details: Точные блокирующие требования отделены от определений, рекомендаций и примеров и собраны по уровням. --- ## Что опубликовано -Сайт содержит рабочие черновики SLM Levels 1-3 и их канонические реестры правил. Монорепозитории и дополнительные режимы архитектуры пока не входят в опубликованную документацию. +Сайт содержит рабочие черновики трёх уровней SLM и их канонические реестры правил. Монорепозитории и дополнительные режимы архитектуры пока не входят в опубликованную документацию. Определения выбранного уровня нормативны внутри черновика. Точные формулировки блокирующих требований находятся только в [реестре правил](/rules/). diff --git a/DRAFT/level-1/README.md b/DRAFT/level-1/README.md index d76df6d..027d238 100644 --- a/DRAFT/level-1/README.md +++ b/DRAFT/level-1/README.md @@ -10,7 +10,7 @@ Level 1 задаёт основу SLM для лёгких проектов, ко |---|---| | Level 1 | Слои, зависимости, структурные сущности и жизненный цикл ресурсов | | Level 2 | Слой `domains` и доменные модули без строгой внутренней формы | -| Level 3 | Строгие роли и runtime-границы внутри доменов | +| Level 3 | Строгие роли и границы сред выполнения внутри доменов | Повышение уровня может требовать рефакторинга, но базовые понятия Level 1 сохраняются. diff --git a/DRAFT/level-2/README.md b/DRAFT/level-2/README.md index 6f84c51..183eaee 100644 --- a/DRAFT/level-2/README.md +++ b/DRAFT/level-2/README.md @@ -2,7 +2,7 @@ > Статус: рабочий черновик. Документы в этой папке не являются спецификацией. -Level 2 расширяет архитектурную базу Level 1 слоем `domains`. Он предназначен для проектов, в которых появились самостоятельные предметные области, но ещё не требуется строгая runtime-архитектура доменов. +Level 2 расширяет архитектурную базу Level 1 слоем `domains`. Он предназначен для проектов, в которых появились самостоятельные предметные области, но ещё не требуется строгая внутренняя архитектура доменов. ## Наследование Level 1 @@ -19,7 +19,7 @@ Level 2 расширяет архитектурную базу Level 1 слое |---|---| | Level 1 | Слои, зависимости, структурные сущности и жизненный цикл ресурсов | | Level 2 | Доменный слой и доменные модули без строгой внутренней формы | -| Level 3 | Строгая внутренняя архитектура и runtime-границы доменов | +| Level 3 | Строгая внутренняя архитектура и границы сред выполнения доменов | ## Основная идея @@ -38,7 +38,7 @@ src/domains/ Level 2 описывает роль слоя `domains`, границу доменного модуля, опциональную группировку и зависимости с участием нового слоя. -Level 2 не задаёт обязательные внутренние роли, каталоги или способ сборки доменного модуля. При появлении устойчивого business contract, нескольких execution contexts или сложного lifecycle следует рассмотреть [Level 3](/level-3/). +Level 2 не задаёт обязательные внутренние роли, каталоги или способ сборки доменного модуля. При появлении устойчивого контракта бизнес-логики, нескольких сред выполнения или сложного жизненного цикла следует рассмотреть [Level 3](/level-3/). ## Карта черновика diff --git a/DRAFT/level-3/README.md b/DRAFT/level-3/README.md index e3b6cf6..b2bc2d1 100644 --- a/DRAFT/level-3/README.md +++ b/DRAFT/level-3/README.md @@ -2,72 +2,72 @@ > Статус: рабочий черновик. Документы в этой папке не являются спецификацией. -Level 3 предназначен для приложений с существенной доменной логикой, несколькими execution contexts или длительным сроком поддержки. Он не добавляет новый слой: он делает внутреннюю форму слоя `domains` явной и проверяемой. +Level 3 предназначен для приложений со сложной предметной логикой, несколькими средами выполнения или длительным сроком поддержки. Он не добавляет новый слой, а задаёт явное и проверяемое устройство доменов внутри слоя `domains`. ## Когда выбирать Level 3 -Level 3 оправдан, когда предметная область имеет устойчивый business contract, несколько concrete integrations, отдельные browser/request/server assemblies, сложный lifecycle или независимую долгую поддержку. +Level 3 оправдан, когда предметная область имеет устойчивый контракт бизнес-логики, несколько технических интеграций, разные способы сборки для браузера и сервера либо сложный жизненный цикл ресурсов. -Количество файлов или размер проекта сами по себе не требуют перехода. Домен без такой сложности остаётся доменным модулем Level 2. +Количество файлов или размер проекта сами по себе не требуют перехода. Предметная область без такой сложности оформляется доменным модулем Level 2. ## Наследование предыдущих уровней -Проект Level 3 соблюдает определения и правила Levels 1-2, кроме явно заменённых положений. +Проект Level 3 соблюдает определения и правила Level 1 и Level 2, кроме явно заменённых положений. | Положение | Статус в Level 3 | |---|---| | Порядок `app → compositions → domains → infra → ui → shared` | Сохраняется | -| Модуль, Group, segment, component, public API и lifecycle | Сохраняют смысл Level 1 | -| Доменный модуль Level 2 и [`SLM-L2-DOMAIN-R001`](../rules/level-2.md#slm-l2-domain-r001) | Заменяются Domain Level 3 | -| Group внутри `domains` | Может содержать Domain, оставаясь только навигационной папкой | -| Прямые дочерние modules Domain | Не являются вложенными modules, потому что Domain не является module | +| Модуль, группа, сегмент, компонент, публичный API и жизненный цикл | Сохраняют смысл Level 1 | +| Доменный модуль Level 2 и [`SLM-L2-DOMAIN-R001`](../rules/level-2.md#slm-l2-domain-r001) | Заменяются доменом Level 3 | +| Группа внутри `domains` | Может содержать домены, оставаясь навигационной папкой | +| Прямые дочерние модули домена | Не являются вложенными, потому что домен сам не является модулем | -Domain не содержит исполняемого кода, поэтому не отменяет правило Level 1 о модульном владельце. Он задаёт предметную границу; конкретной ответственностью, public API и lifecycle по-прежнему владеет module. +Домен не содержит исполняемого кода и не отменяет правило Level 1 о модульном владельце. Он задаёт предметную границу, а конкретной ответственностью, публичным API и жизненным циклом по-прежнему владеет модуль. ## Основная идея ```text -Domain задаёт предметную границу. -Business определяет contract и поведение. -Ports описывают нужные business capabilities. -Adapters связывают ports с concrete runtime. -Presets собирают API для execution scope. -Framework module адаптирует готовый API к framework. -Graph owner удерживает API instance и выполняет lifecycle contract module-владельца. +Домен задаёт предметную границу. +Модуль бизнес-логики определяет правила, сценарии и публичный контракт. +Порты описывают возможности, которые нужны бизнес-логике. +Адаптеры реализуют порты в конкретной среде. +Типовые сборки повторяемо создают API. +Модуль фреймворка связывает готовый API с React, Vue или другим фреймворком. +Владелец графа удерживает экземпляр API и завершает его жизненный цикл. ``` -## Базовая форма Domain +## Базовая форма домена ```text src/domains/ -└── auth/ # Domain - ├── business/ # обязательный module +└── auth/ # домен + ├── business/ # обязательный модуль │ ├── errors/ │ ├── lib/ │ ├── ports/ │ ├── services/ │ ├── types/ │ └── index.ts - ├── presets/ # optional Group - │ └── application/ # preset module + ├── presets/ # необязательная группа + │ └── application/ # модуль типовой сборки │ ├── adapters/ │ └── index.ts - ├── adapters/ # optional Group - │ └── identity-provider/ # promoted adapter module + ├── adapters/ # необязательная группа + │ └── identity-provider/ # самостоятельный модуль адаптера │ └── index.ts - └── react/ # framework module + └── react/ # модуль фреймворка ├── hooks/ ├── providers/ └── index.ts ``` -`business` обязателен. `presets`, `adapters` и framework modules появляются только при реальной ответственности. `types`, `errors`, `lib`, `services`, `tests`, `ui`, `client` и `server` не являются самостоятельными корневыми ветками Domain. +Модуль `business` обязателен. Группы `presets` и `adapters`, а также модули фреймворков появляются только при реальной потребности. Каталоги `types`, `errors`, `lib`, `services`, `tests`, `ui`, `client` и `server` не становятся самостоятельными корневыми ветками домена. -Domain может быть размещён непосредственно в `domains` или внутри навигационной Group. Groups допустимы, но не участвуют в основных примерах и не меняют границы Domain, направление зависимостей или доступность его role modules. +Домен может находиться непосредственно в `domains` или внутри навигационной группы. Группа не меняет его границы, направление зависимостей и доступность модулей домена. ## Публичные границы -Domain не имеет root runtime entrypoint. Внешний код импортирует public API конкретного role module: +У корня домена нет общей точки входа для исполняемого кода. Внешний код импортирует публичный API конкретного модуля: ```ts import { authFactory, isAuthError } from '@/domains/auth/business' @@ -75,22 +75,22 @@ import { createApplicationAuth } from '@/domains/auth/presets/application' import { AuthProvider, useAuth } from '@/domains/auth/react' ``` -`@/domains/auth/business` является public API отдельного module, а не deep import. Напротив, `@/domains/auth/business/services/...` и root import `@/domains/auth` нарушают границу. +`@/domains/auth/business` является публичным API отдельного модуля, а не глубоким импортом. Пути вида `@/domains/auth/business/services/...` и общий импорт `@/domains/auth` нарушают границу. ## Карта черновика - [Терминология](./terminology.md) -- [Граница Domain](./domains/domain.md) -- [Business module](./domains/business.md) -- [Factory, ports и adapters](./domains/factory-ports-adapters.md) -- [Presets и SSR](./domains/presets.md) -- [React module](./domains/framework-bindings.md) +- [Граница домена](./domains/domain.md) +- [Модуль бизнес-логики](./domains/business.md) +- [Фабрика, порты и адаптеры](./domains/factory-ports-adapters.md) +- [Типовые сборки и SSR](./domains/presets.md) +- [Модуль React](./domains/framework-bindings.md) - [Зависимости](./dependencies.md) - [Тестирование](./domains/testing.md) - [Проверка](./validation.md) -- [Auth как пример миграции](./domains/auth-example.md) +- [Пример переноса домена](./domains/auth-example.md) - [Открытые вопросы](./domains/open-questions.md) ## Канонические правила -Level 3 использует правила Levels 1-2 и [дополнительный реестр Level 3](../rules/level-3.md). Тематические документы объясняют правила, но не объявляют их повторно. +Level 3 использует правила Level 1 и Level 2, а также [дополнительный реестр Level 3](../rules/level-3.md). Тематические документы объясняют правила, но не объявляют их повторно. diff --git a/DRAFT/level-3/dependencies.md b/DRAFT/level-3/dependencies.md index e0d264f..385b44e 100644 --- a/DRAFT/level-3/dependencies.md +++ b/DRAFT/level-3/dependencies.md @@ -1,6 +1,6 @@ # Зависимости Level 3 -> Уточнение графа зависимостей Level 2 внутри Domain. +> Уточнение графа зависимостей Level 2 внутри домена. ## Связанные правила @@ -9,40 +9,42 @@ - [`SLM-L3-ENVIRONMENT-A012`](../rules/level-3.md#slm-l3-environment-a012) - [`SLM-L1-DEPENDENCY-A005`](../rules/level-1.md#slm-l1-dependency-a005) -## Направление внутри Domain +## Направление внутри домена -| Исходный role module | Допустимые зависимости | +| Исходный модуль | Допустимые зависимости | |---|---| -| `business` | Собственные segments, нейтральный `shared`, ограниченные type-only contracts другого business module | -| Adapter | Business contracts, `infra`, concrete runtime и neutral `shared` | -| Preset | Business factory/contracts, private или promoted adapters | -| `react` | Business contracts, готовый business API и React runtime | -| Composition graph owner | Public preset, framework module и готовые API instances | +| `business` | Собственные сегменты, нейтральные ресурсы `shared`, в ограниченных случаях — публичные типы другого модуля `business` | +| Адаптер | Контракты `business`, модули `infra`, конкретная техническая реализация и нейтральные ресурсы `shared` | +| Модуль группы `presets` | Фабрика и контракты `business`, закрытые или самостоятельные адаптеры | +| `react` | Контракты `business`, готовый API и React | +| Модуль-владелец графа | Публичные API модулей `business`, типовых сборок и модулей фреймворков, входящих в граф | -Business не импортирует adapters, presets, framework modules, `infra`, product SDK, storage, framework runtime, browser/Node API или environment configuration. Adapter не импортирует preset или framework module. Preset не импортирует framework module. +Модуль `business` не импортирует адаптеры, сборки, модули фреймворков, `infra`, продуктовые SDK, хранилища, API браузера или Node.js и конфигурацию среды. Адаптер не импортирует сборку или модуль фреймворка. Модуль сборки не импортирует модуль фреймворка. ## Междоменные зависимости -Business одного Domain не создаёт factory другого Domain и не вызывает другой Domain runtime API напрямую. Если `orders` нужна capability авторизации, `orders/business` описывает собственный минимальный port, а graph owner передаёт реализацию над уже собранным `AuthApi`. +Модуль `business` одного домена не создаёт фабрику другого домена и не вызывает его исполняемый API напрямую. Если домену `orders` нужны сведения об авторизации, `orders/business` описывает собственный минимальный порт, а владелец графа передаёт его реализацию поверх уже созданного `AuthApi`. ```text -Auth preset +сборка auth → AuthApi - → orders assembly + → сборка orders → OrdersApi ``` -Type-only import public business contract другого Domain допустим только при реальной ацикличной зависимости. Он не даёт права вызвать другой Domain runtime API. Direct runtime import даже pure function не является обходом port boundary: независимое общее правило должно принадлежать `shared`, а предметная capability передаётся через port. +Импорт публичного типа из модуля `business` другого домена допустим только при реальной ацикличной зависимости. Такой импорт не разрешает вызывать API другого домена. -## Environment boundaries +Прямой импорт даже чистой функции не служит обходом порта. Независимое общее правило принадлежит `shared`, а предметная возможность другого домена передаётся через порт. -Server-only preset или adapter получает отдельный public entrypoint и framework/build marker. Он не реэкспортируется через `business`, `react`, client-compatible preset или root Domain. +## Границы сред выполнения + +Серверная сборка или адаптер получает отдельную публичную точку входа и предусмотренную фреймворком либо сборщиком метку: ```text -business # isomorphic -presets/application # client-compatible, если выбранные adapters совместимы -presets/request # server-only -react # client framework module +business # подходит клиенту и серверу +presets/application # подходит клиенту, если совместимы адаптеры +presets/request # только сервер +react # клиентский модуль React ``` -Путь `server/` или `client/` сам по себе ничего не доказывает. Проверяется transitive import graph entrypoint. +Серверная точка входа не реэкспортируется через `business`, `react`, клиентскую сборку или корень домена. Путь `server/` или `client/` сам по себе ничего не доказывает: проверяется весь граф импортов, достижимый из точки входа. diff --git a/DRAFT/level-3/domains/README.md b/DRAFT/level-3/domains/README.md index 16f805d..d4aae1f 100644 --- a/DRAFT/level-3/domains/README.md +++ b/DRAFT/level-3/domains/README.md @@ -1,8 +1,8 @@ # Домены Level 3 -> Пояснение строгой внутренней архитектуры Domain. +> Пояснение строгой внутренней архитектуры домена. -Level 3 превращает доменный module Level 2 в Domain: немодульную предметную границу с несколькими modules разных технических ролей. Это не новый слой и не обязательный scaffold для каждого проекта. +Level 3 заменяет доменный модуль Level 2 немодульной предметной границей — доменом. Внутри неё размещаются модули с разными техническими ролями. Это не новый слой и не обязательный каркас для каждого проекта. ## Связанные правила @@ -11,25 +11,25 @@ Level 3 превращает доменный module Level 2 в Domain: немо - [`SLM-L3-BUSINESS-R003`](../../rules/level-3.md#slm-l3-business-r003) - [`SLM-L1-MODULE-A004`](../../rules/level-1.md#slm-l1-module-a004) -## Роли внутри Domain +## Роли внутри домена ```text -Business определяет поведение и contract. -Ports описывают runtime capabilities business. -Adapters реализуют ports поверх concrete runtime. -Presets собирают API для execution context. -React module адаптирует готовый API к React. -Graph owner удерживает конкретный instance и выполняет lifecycle contract module-владельца. +Модуль бизнес-логики определяет поведение и публичный контракт. +Порты описывают возможности, которые нужны бизнес-логике. +Адаптеры реализуют порты в конкретной среде. +Типовые сборки повторяемо создают API. +Модуль React связывает готовый API с React. +Владелец графа удерживает экземпляр API и завершает его жизненный цикл. ``` | Роль | Структурный вид | Когда появляется | |---|---|---| -| `business` | Обязательный module | Всегда | -| Preset | Module внутри `presets` | Нужна повторяемая assembly | -| Adapter | Private segment preset или module внутри `adapters` | Нужна concrete integration | -| `react` | Framework module непосредственно в Domain | Domain имеет React integration | +| Бизнес-логика | Обязательный модуль `business` | Всегда | +| Типовая сборка | Модуль внутри `presets` | Нужен повторяемый способ сборки | +| Адаптер | Закрытый сегмент сборки или модуль внутри `adapters` | Нужна техническая интеграция | +| Связь с React | Модуль `react` непосредственно в домене | Домен предоставляет API для React | -## Форма Domain +## Форма домена ```text domains/auth/ @@ -53,13 +53,13 @@ domains/auth/ └── index.ts ``` -`business` обязателен; остальные ветки появляются по необходимости. `presets` и `adapters` являются Groups без собственного runtime/API. `errors`, `lib`, `ports`, `services`, `types`, `hooks` и `providers` являются segments соответствующих module-владельцев. +Модуль `business` обязателен; остальные ветки появляются по необходимости. `presets` и `adapters` являются группами без собственного исполняемого кода и API. Каталоги `errors`, `lib`, `ports`, `services`, `types`, `hooks` и `providers` являются сегментами соответствующих модулей-владельцев. -Navigation Groups в слое `domains` допустимы, но не являются Domain и не изменяют его import boundary. Основные примеры Level 3 намеренно показывают Domain непосредственно в `domains`. +Навигационные группы в слое `domains` допустимы, но не являются доменами и не меняют их публичные границы. Основные примеры Level 3 показывают домены непосредственно в `domains`. -## Public API modules +## Публичные API модулей -Domain root не имеет `index.ts` и не реэкспортирует роли. Внешний consumer использует только public entrypoint нужного module: +Корень домена не имеет `index.ts` и не реэкспортирует дочерние модули. Внешний потребитель использует публичную точку входа нужного модуля: ```ts import { authFactory, type AuthApi } from '@/domains/auth/business' @@ -67,15 +67,15 @@ import { createApplicationAuth } from '@/domains/auth/presets/application' import { AuthProvider, useAuth } from '@/domains/auth/react' ``` -Private adapter внутри `presets/application/adapters` не получает external entrypoint. Promoted adapter module получает собственный API для modules Domain; доступ за пределами Domain допускается только как явно объявленная integration extension point. +Закрытый адаптер внутри `presets/application/adapters` не получает внешней точки входа. Адаптер, оформленный самостоятельным модулем, предоставляет минимальный публичный API. Доступ к нему за пределами домена допускается только как явно объявленная точка расширения интеграции. ## Карта раздела -- [Граница Domain](./domain.md) -- [Business module](./business.md) -- [Factory, ports и adapters](./factory-ports-adapters.md) -- [Presets и SSR](./presets.md) -- [React module](./framework-bindings.md) +- [Граница домена](./domain.md) +- [Модуль бизнес-логики](./business.md) +- [Фабрика, порты и адаптеры](./factory-ports-adapters.md) +- [Типовые сборки и SSR](./presets.md) +- [Модуль React](./framework-bindings.md) - [Тестирование](./testing.md) -- [Auth как пример миграции](./auth-example.md) +- [Пример переноса домена](./auth-example.md) - [Открытые вопросы](./open-questions.md) diff --git a/DRAFT/level-3/domains/auth-example.md b/DRAFT/level-3/domains/auth-example.md index bc4aa1c..ae17b2e 100644 --- a/DRAFT/level-3/domains/auth-example.md +++ b/DRAFT/level-3/domains/auth-example.md @@ -1,10 +1,10 @@ -# Auth как пример миграции +# Перенос домена `auth` -> Проверочный пример Level 3. Он показывает направление декомпозиции, а не обязательный scaffold. +> Проверочный пример Level 3. Он показывает направление изменений, а не обязательный каркас. ## Исходная проблема -В более ранней форме SLM business contract Auth и concrete assembly могли находиться отдельно: +В более ранней форме SLM контракт бизнес-логики домена `auth` и его техническая сборка могли находиться в разных местах: ```text business/auth/ @@ -21,7 +21,7 @@ compositions/business/auth/ └── index.ts ``` -Такая форма отделяет pure business от concrete runtime, но разносит одну предметную область по разным архитектурным местам. Level 3 колоцирует их внутри Domain, не смешивая роли. +Такое устройство отделяет бизнес-логику от конкретной среды, но разносит одну предметную область по разным архитектурным местам. Level 3 размещает эти части внутри одного домена, сохраняя границы между их ролями. ## Целевая форма @@ -51,18 +51,18 @@ domains/auth/ | Исходная часть | Назначение в Level 3 | |---|---| -| `auth.factory.ts`, scenarios, validators, domain errors | `domains/auth/business` | -| SDK, storage и state manager integration | Private adapters выбранного preset | -| Повторяемый browser builder | `domains/auth/presets/application` | -| Request-specific cookies, headers и client | `domains/auth/presets/request` | -| React hooks, provider и domain UI | `domains/auth/react` | -| Page text, redirect и screen outcome | Consumer composition | +| `auth.factory.ts`, сценарии, проверки и ошибки домена | `domains/auth/business` | +| SDK, хранилище и конкретная система управления состоянием | Закрытые адаптеры выбранной сборки | +| Повторяемая сборка для браузерного приложения | `domains/auth/presets/application` | +| Файлы cookie, заголовки и клиент одного запроса | `domains/auth/presets/request` | +| React-хуки, провайдер и интерфейс домена | `domains/auth/react` | +| Текст страницы, перенаправление и устройство экрана | Модуль-потребитель в `compositions` | ## Проверка границ -`authFactory` не импортирует `useAuth`, `'use client'`, SDK или storage. React hook строится поверх готового `AuthApi`, например через framework-neutral `getSnapshot` и `subscribe`. +`authFactory` не импортирует `useAuth`, `'use client'`, SDK или хранилище. React-хук строится поверх готового `AuthApi`, например через независимые от фреймворка методы `getSnapshot` и `subscribe`. -Нормализация номера телефона может быть public pure business function: +Нормализация номера телефона может быть публичной чистой функцией бизнес-логики: ```ts import { @@ -71,11 +71,11 @@ import { } from '@/domains/auth/business' ``` -UI использует её для feedback, но `requestPhoneOtp` повторно валидирует значение внутри business scenario. +Интерфейс использует её для ранней подсказки, но `requestPhoneOtp` повторно проверяет значение внутри предметного сценария. -## Error contract +## Контракт ошибок -`AuthBusinessError` остаётся private implementation. Consumer получает только stable contract: +`AuthBusinessError` остаётся закрытой реализацией. Потребитель получает только устойчивый контракт: ```ts import { @@ -84,13 +84,13 @@ import { } from '@/domains/auth/business' ``` -Так React composition может выбрать сообщение или retry behavior по `code`, не зная SDK error, HTTP status или constructor private ошибки. +Так композиция React может выбрать сообщение или поведение повторной попытки по `code`, не зная класс ошибки SDK, статус HTTP или закрытый конструктор. -## Migration order +## Порядок перехода -1. Выделить `business` entrypoint и убедиться, что его transitive graph isomorphic. -2. Перенести concrete runtime в adapters выбранного preset. -3. Оформить повторяемую assembly как `presets/application`. -4. Перенести hooks и Provider в `react`, передавая им готовый API. -5. Сохранить page-specific UI и graph ownership в `compositions`. -6. Добавить factory, adapter, preset и React boundary tests до удаления старого пути. +1. Выделить точку входа `business` и убедиться, что её полный граф импортов не зависит от среды. +2. Перенести конкретные технические реализации в адаптеры выбранной сборки. +3. Оформить повторяемую сборку как `presets/application`. +4. Перенести хуки и провайдер в `react`, передавая им готовый API. +5. Сохранить интерфейс конкретной страницы и владение общим графом в `compositions`. +6. Добавить тесты фабрики, адаптеров, сборки и границы React до удаления старого пути. diff --git a/DRAFT/level-3/domains/business.md b/DRAFT/level-3/domains/business.md index bfeba10..9140074 100644 --- a/DRAFT/level-3/domains/business.md +++ b/DRAFT/level-3/domains/business.md @@ -1,6 +1,6 @@ -# Business module внутри Domain +# Модуль бизнес-логики внутри домена -> Пояснение semantic core Domain. +> Пояснение смыслового центра домена. ## Связанные правила @@ -11,20 +11,20 @@ ## Роль -`business` -- единственный обязательный module Domain. Он владеет: +`business` — единственный обязательный модуль домена. Он владеет: -- public business scenarios и `DomainApi`; -- factory, `Deps` и ports; -- business-owned types и contracts; -- детерминированными rules, validation и normalization; -- domain error contract; -- семантикой domain state, commands и selectors. +- публичными предметными сценариями и `DomainApi`; +- фабрикой, типом зависимостей `Deps` и портами; +- предметными типами и контрактами; +- детерминированными правилами, проверкой и нормализацией данных; +- публичным контрактом ошибок предметной области; +- моделью состояния, командами и средствами чтения этого состояния. -Business не владеет SDK, storage implementation, browser/Node API, framework integration, environment wiring или concrete state manager. +Модуль `business` не владеет SDK, реализацией хранилища, API браузера или Node.js, связью с фреймворком, конфигурацией среды и конкретной системой управления состоянием. -## Public API +## Публичный API -Business entrypoint открывает только contract, нужный consumers, presets и adapters: +Точка входа `business` открывает только контракт, необходимый потребителям, сборкам и адаптерам: ```ts export { authFactory } from './auth.factory' @@ -43,26 +43,26 @@ export type { } from './types' ``` -Port types экспортируются, потому что preset и promoted adapter реализуют именно эти contracts. `services`, private mappers, error constructor, source mapper, persistence key и concrete state runtime остаются закрытыми. +Типы портов экспортируются, потому что сборки и самостоятельные адаптеры реализуют эти контракты. Сервисы, внутренние преобразователи, конструктор ошибки, преобразование исходной ошибки, ключ хранения и конкретный механизм состояния остаются закрытыми. -## Types и pure functions +## Типы и чистые функции -`types`, `errors`, `lib`, `ports`, `services` и `tests` -- segments business module, а не отдельные Domain APIs. Type размещается у владельца: +Каталоги `types`, `errors`, `lib`, `ports`, `services` и `tests` являются сегментами модуля `business`, а не отдельными API домена. Тип размещается у владельца: -| Contract | Владелец | +| Контракт | Владелец | |---|---| -| `AuthApi`, `AuthDeps`, `AuthState`, ports | `business` | -| SDK DTO и transport error | Adapter или `infra` | -| React provider props | `react` | -| View model screen | Consumer composition | +| `AuthApi`, `AuthDeps`, `AuthState`, порты | `business` | +| DTO SDK и транспортная ошибка | Адаптер или `infra` | +| Свойства React-провайдера | `react` | +| Модель представления экрана | Модуль-потребитель в `compositions` | -Pure domain function может быть public, только если она выражает business rule и имеет реального external consumer. Она получает все данные аргументами, детерминирована, не использует `Deps`, state, clock, random, environment или framework runtime. +Чистая предметная функция может быть публичной, только если выражает предметное правило и нужна реальному внешнему потребителю. Она получает все данные аргументами, детерминирована и не использует `Deps`, состояние, часы, генератор случайных значений, окружение или фреймворк. -Consumer может применять `validateAuthPhone` для раннего UX feedback, но public business scenario повторяет validation на своей границе. +Потребитель может применять `validateAuthPhone` для ранней подсказки в интерфейсе, но публичный сценарий повторно проверяет данные на собственной границе. -## Domain errors +## Ошибки предметной области -Каждый public runtime scenario выдаёт только domain failure contract. Source error, SDK class, HTTP status, response body и transport code не становятся consumer API. +При сбое публичный сценарий выдаёт только ошибку из контракта домена. Исходная ошибка, класс SDK, статус HTTP, тело ответа и транспортный код не становятся API потребителя. ```ts export const AUTH_ERROR_CODES = { @@ -78,14 +78,14 @@ export type AuthError = Readonly<{ }> export const isAuthError = (value: unknown): value is AuthError => { - // Runtime validation of the public observation shape. + // Проверка публичной формы ошибки во время выполнения. } ``` -Если public API использует exceptions, entrypoint экспортирует domain-specific guard, codes и read-only observation shape, но не constructor или source error mapper. Если проект выбирает discriminated `Result`, тот же contract должен быть выражен в result branch. Один business API не смешивает оба способа для одинаковых scenario. +Если публичный API использует исключения, точка входа экспортирует проверку типа, коды и доступную только для чтения форму ошибки, но не её конструктор или преобразователь исходной ошибки. Если проект выбирает размеченный тип `Result`, тот же контракт выражается в ветви результата. Один API не смешивает оба способа для одинаковых сценариев. -## Domain state +## Состояние домена -Business определяет форму `AuthState`, начальное состояние, допустимые transitions и public observation contract. Concrete store, persistence, subscription source и framework hook реализуются снаружи business через ports/adapters. +Модуль `business` определяет форму `AuthState`, начальное состояние, допустимые переходы и публичный способ наблюдения. Конкретное хранилище, сохранение данных, источник подписки и хук фреймворка реализуются снаружи через порты и адаптеры. -Framework-neutral observation может иметь форму `getSnapshot` и `subscribe`. Это protocol business API, а не React hook или `StoreApi` конкретной библиотеки. +Независимый от фреймворка интерфейс наблюдения может состоять из `getSnapshot` и `subscribe`. Это часть API бизнес-логики, а не React-хук или `StoreApi` конкретной библиотеки. diff --git a/DRAFT/level-3/domains/domain.md b/DRAFT/level-3/domains/domain.md index 76ab61d..99f15cb 100644 --- a/DRAFT/level-3/domains/domain.md +++ b/DRAFT/level-3/domains/domain.md @@ -1,4 +1,4 @@ -# Граница Domain +# Граница домена > Пояснение предметной и структурной границы Level 3. @@ -12,31 +12,31 @@ ## Предметная граница -Domain представляет одну связную предметную область: `auth`, `catalog`, `orders` или `checkout`. Он собирает её business contract, concrete integrations, повторяемые assemblies и framework bindings, но не становится большим module со смешанными ролями. +Домен представляет одну связную предметную область: `auth`, `catalog`, `orders` или `checkout`. Он объединяет её бизнес-логику, технические интеграции, повторяемые сборки и модули фреймворков, но не превращается в большой модуль со смешанными ролями. -Domain является предметной границей, а не владельцем runtime-кода в смысле Level 1. Каждый scenario, adapter, preset и framework binding остаётся ответственностью конкретного module. Такое разделение позволяет одной области иметь несколько public module APIs без нарушения правила о единственном владельце ответственности. +Домен является предметной границей, а не владельцем исполняемого кода в смысле Level 1. Каждый сценарий, адаптер и способ сборки принадлежит конкретному модулю. Поэтому одна предметная область может иметь несколько публичных API, не нарушая правило о единственном владельце ответственности. ## Структурные виды и роли | Путь | Роль | Структурный вид | |---|---|---| -| `domains/auth` | Предметная область Auth | Domain | -| `domains/auth/business` | Business | Module | -| `domains/auth/business/ports` | Business capabilities | Segment | -| `domains/auth/presets` | Навигация assemblies | Group | -| `domains/auth/presets/application` | Application preset | Module | -| `domains/auth/presets/application/adapters` | Private integrations preset | Segment | -| `domains/auth/adapters` | Навигация promoted adapters | Group | -| `domains/auth/adapters/identity-provider` | Reusable adapter | Module | -| `domains/auth/react` | React binding | Module | +| `domains/auth` | Предметная область авторизации | Домен | +| `domains/auth/business` | Бизнес-логика | Модуль | +| `domains/auth/business/ports` | Необходимые бизнес-логике возможности | Сегмент | +| `domains/auth/presets` | Навигация по типовым сборкам | Группа | +| `domains/auth/presets/application` | Сборка уровня приложения | Модуль | +| `domains/auth/presets/application/adapters` | Закрытые адаптеры сборки | Сегмент | +| `domains/auth/adapters` | Навигация по самостоятельным адаптерам | Группа | +| `domains/auth/adapters/identity-provider` | Повторно используемый адаптер | Модуль | +| `domains/auth/react` | Связь с React | Модуль | -Role отвечает на вопрос, что делает код. Structural kind отвечает на вопрос, какую архитектурную границу он образует. Имя папки само по себе не доказывает ни роль, ни structural kind. +Роль отвечает на вопрос, что делает код. Структурный вид определяет, какую архитектурную границу он образует. Имя папки само по себе не доказывает ни роль, ни структурный вид. -## Корень Domain +## Корень домена -Корень Domain не содержит реализацию, state, lifecycle resources, `index.ts` или общий barrel. Его прямыми детьми могут быть `business`, Groups `presets` и `adapters`, а также framework modules с именем framework, например `react`. +Корень домена не содержит реализацию, состояние, ресурсы жизненного цикла, `index.ts` или общий файл реэкспортов. Его прямыми детьми могут быть модуль `business`, группы `presets` и `adapters`, а также модули фреймворков, например `react`. -Не создаются автоматически корневые ветки `model`, `types`, `errors`, `lib`, `ui`, `client`, `server` или `tests`. Такая ветка должна либо быть segment module-владельца, либо иметь самостоятельную module responsibility, выраженную одной из ролей Domain. +Корневые ветки `model`, `types`, `errors`, `lib`, `ui`, `client`, `server` или `tests` не создаются автоматически. Такой каталог должен быть либо сегментом модуля-владельца, либо самостоятельным модулем с одной из допустимых ролей домена. ## Публичная граница @@ -46,18 +46,18 @@ Role отвечает на вопрос, что делает код. Structural @/domains/auth/react ``` -Эти пути являются public API role modules. Root path `@/domains/auth` не существует как runtime boundary. Он не должен объединять isomorphic business, client React и server-only preset через `export *`. +Эти пути являются публичными API отдельных модулей. Корневого пути `@/domains/auth` для исполняемого кода не существует: он не должен объединять независимый от среды модуль `business`, клиентский React и серверную сборку через `export *`. ## Граница с другими слоями | Ответственность | Владелец | |---|---| -| Business scenarios, contracts, state semantics и errors | `domains/auth/business` | -| Concrete adapter одной assembly | Segment соответствующего preset | -| Reusable auth integration | Promoted adapter module | -| Повторяемая assembly `AuthApi` | Preset module | -| React provider, hook и domain-specific React UI | `domains/auth/react` | -| Page, route, redirect, screen и конкретный visual outcome | Module `compositions` | -| SDK wrapper или технический сервис без Auth semantics | Module `infra` | +| Предметные сценарии, контракты, модель состояния и ошибки | `domains/auth/business` | +| Технический адаптер одной сборки | Сегмент соответствующего модуля в `presets` | +| Повторно используемая интеграция авторизации | Самостоятельный модуль адаптера | +| Повторяемая сборка `AuthApi` | Модуль в `presets` | +| Провайдер, хук и относящийся к домену интерфейс React | `domains/auth/react` | +| Страница, маршрут, перенаправление, экран и конкретный визуальный результат | Модуль `compositions` | +| Обёртка над SDK или технический сервис без семантики авторизации | Модуль `infra` | -Framework dependency сама по себе не делает UI частью Domain. Component принадлежит `react` только когда он работает с domain contract и не определяет page, route или product composition. +Зависимость от фреймворка сама по себе не делает интерфейс частью домена. Компонент принадлежит `react`, только когда работает с контрактом домена и не определяет страницу, маршрут или продуктовую композицию. diff --git a/DRAFT/level-3/domains/factory-ports-adapters.md b/DRAFT/level-3/domains/factory-ports-adapters.md index 205ecd4..bae0f57 100644 --- a/DRAFT/level-3/domains/factory-ports-adapters.md +++ b/DRAFT/level-3/domains/factory-ports-adapters.md @@ -1,6 +1,6 @@ -# Factory, ports и adapters +# Фабрика, порты и адаптеры -> Пояснение runtime boundary business module. +> Пояснение границы между бизнес-логикой и средой выполнения. ## Связанные правила @@ -10,36 +10,36 @@ - [`SLM-L3-ADAPTER-R008`](../../rules/level-3.md#slm-l3-adapter-r008) - [`SLM-L3-BUSINESS-A004`](../../rules/level-3.md#slm-l3-business-a004) -## Factory и API instance +## Фабрика и экземпляр API ```text -Factory + implementations ports -> business API instance +фабрика + реализации портов → экземпляр API бизнес-логики ``` -Factory принадлежит `business`, получает полный `AuthDeps` и возвращает `AuthApi`: +Фабрика принадлежит модулю `business`, получает полный набор `AuthDeps` и возвращает `AuthApi`: ```ts export type AuthFactory = (deps: AuthDeps) => AuthApi ``` -Все presets одной factory предоставляют полный набор ports и получают одинаковый business API. Browser, request и server action не создают разные factory только из-за среды. Preset может открыть consumer суженный view API, но не меняет contract самой factory. +Все типовые сборки одной фабрики предоставляют полный набор портов и получают API одного контракта. Браузер, обработчик запроса и серверное действие не требуют разных фабрик только из-за среды выполнения. Сборка может открыть потребителю более узкое представление API, но не меняет контракт фабрики. -Factory construction создаёт только deterministic services и closures. Она не делает request, не читает cookies/storage/env, не запускает subscription/timer, не обращается к platform API, не выбирает adapter и не запускает framework lifecycle. +Вызов фабрики создаёт только объекты и замыкания без побочных эффектов. Он не выполняет запросы, не читает файлы cookie, хранилище или переменные окружения, не запускает подписки и таймеры, не обращается к API платформы, не выбирает адаптер и не выполняет операции жизненного цикла фреймворка. -## Isomorphic import graph +## Независимый от среды граф импортов -Проверяется весь production graph, достижимый из `business` entrypoint, а не только файл factory. Он не должен достигать: +Проверяется весь граф рабочего кода, достижимый из точки входа `business`, а не только файл фабрики. Он не должен достигать: -- React, Vue, Next.js и framework markers; -- browser-only, Node-only, `client-only` или `server-only` boundary; -- SDK, generated client, storage implementation или concrete state/query runtime; -- adapters, presets, framework modules и environment configuration. +- React, Vue, Next.js и служебных меток фреймворка; +- границ `client-only`, `server-only`, API браузера или Node.js; +- SDK, сгенерированного клиента, реализации хранилища или конкретной библиотеки состояния; +- адаптеров, сборок, модулей фреймворков и конфигурации среды. -Tree shaking не является доказательством изоляции. Type-only import concrete runtime создаёт ту же архитектурную зависимость и также запрещён. +Удаление неиспользуемого кода при сборке не доказывает изоляцию. Импорт только типов из конкретной реализации создаёт ту же архитектурную зависимость и также запрещён. -## Ports +## Порты -Port принадлежит business и описывает capability на business language: +Порт принадлежит бизнес-логике и описывает возможность на языке предметной области: ```ts export type AuthPhonePort = { @@ -54,21 +54,21 @@ export type AuthSessionPort = { } ``` -Port не принимает SDK client, generated operation, `Request`, `Window`, React hook, `StoreApi` или environment-specific type. Он абстрагирует implementation, а не доступность capability: optional port и method, который намеренно падает в одной среде, нарушают factory contract. +Порт не принимает клиент SDK, сгенерированную операцию, `Request`, `Window`, React-хук, `StoreApi` или тип конкретной среды. Он отделяет контракт от реализации, а не скрывает отсутствие возможности. Необязательный порт или метод, который намеренно падает в одной из сред, нарушает контракт фабрики. -`unknown` допустим только на границе непроверенного external result. Business обязан валидировать его до превращения в domain result, state или error. Если adapter уже может представить устойчивый business-owned result, port описывает именно этот result, а не concrete DTO. +`unknown` допустим только на границе непроверенного внешнего результата. Бизнес-логика обязана проверить такое значение до преобразования в предметный результат, состояние или ошибку. Если адаптер уже может вернуть устойчивый предметный результат, порт описывает этот результат, а не DTO конкретного транспорта. -## Adapters +## Адаптеры -Adapter соединяет business port и concrete runtime: +Адаптер соединяет порт с конкретной технической реализацией: ```text -business port <- adapter -> SDK / storage / platform / request input +порт business ← адаптер → SDK / хранилище / платформа / данные запроса ``` -Adapter может преобразовать domain argument в transport argument, вызвать concrete source, нормализовать техническую форму к port contract и вернуть source failure. Он не определяет domain error code, business fallback, invariant или public method `AuthApi`. +Адаптер может преобразовать предметные аргументы в транспортные, вызвать внешний источник, привести технический результат к контракту порта и вернуть исходный сбой. Он не определяет код ошибки домена, резервное предметное поведение, инвариант или публичный метод `AuthApi`. -Default location -- private segment минимального preset owner: +По умолчанию адаптер является закрытым сегментом минимальной типовой сборки: ```text domains/auth/presets/application/ @@ -77,7 +77,7 @@ domains/auth/presets/application/ └── index.ts ``` -Если один adapter имеет несколько assembly consumers или самостоятельную integration responsibility, он становится promoted module: +Если адаптер нужен нескольким сборкам или имеет самостоятельную ответственность интеграции, он становится отдельным модулем: ```text domains/auth/adapters/ @@ -85,4 +85,4 @@ domains/auth/adapters/ └── index.ts ``` -Promoted adapter сохраняет минимальный public API. Его появление не делает concrete SDK частью public business contract. +Самостоятельный адаптер сохраняет минимальный публичный API. Его появление не делает конкретный SDK частью публичного контракта `business`. diff --git a/DRAFT/level-3/domains/framework-bindings.md b/DRAFT/level-3/domains/framework-bindings.md index 963dbc8..e46c03d 100644 --- a/DRAFT/level-3/domains/framework-bindings.md +++ b/DRAFT/level-3/domains/framework-bindings.md @@ -1,6 +1,6 @@ -# React module внутри Domain +# Модуль React внутри домена -> Пояснение framework boundary Domain на примере React. +> Пояснение границы фреймворка на примере React. ## Связанные правила @@ -8,9 +8,9 @@ - [`SLM-L3-BUSINESS-A004`](../../rules/level-3.md#slm-l3-business-a004) - [`SLM-L3-ASSEMBLY-R010`](../../rules/level-3.md#slm-l3-assembly-r010) -## Имя и место module +## Имя и место модуля -Framework-specific module находится непосредственно в Domain и называется именем framework: +Зависящий от фреймворка модуль находится непосредственно в домене и называется именем фреймворка: ```text domains/auth/react/ @@ -21,18 +21,18 @@ domains/auth/react/ └── index.ts ``` -`react` точно обозначает framework и не создаёт пустую промежуточную Group вроде `framework/react` или `bindings/react`. Если Domain действительно поддерживает другой framework, он получает отдельный sibling module, например `vue`. +Имя `react` точно обозначает зависимость и не требует пустой промежуточной группы `framework/react` или `bindings/react`. Если домен действительно поддерживает другой фреймворк, он получает отдельный соседний модуль, например `vue`. -## Роль React module +## Роль модуля React -React module может: +Модуль React может: -- передать готовый `AuthApi` через context/provider; -- создать hook доступа к API или framework-neutral state; -- связать React lifecycle с subscription API; -- реализовать domain-specific React component. +- передавать готовый `AuthApi` через контекст и провайдер; +- предоставлять хук доступа к API или состоянию; +- связывать жизненный цикл React с подпиской; +- реализовывать относящийся к домену React-компонент. -Он не меняет business rules, не создаёт domain errors, не выбирает concrete adapters и не вызывает factory или preset. Сборка остаётся у composition graph owner; React module получает уже готовый instance. +Он не меняет предметные правила, не создаёт ошибки домена, не выбирает адаптеры и не вызывает фабрику или типовую сборку. Сборка остаётся у модуля-владельца графа; модуль React получает готовый экземпляр. ```tsx type AuthProviderProps = PropsWithChildren<{ @@ -44,9 +44,9 @@ export const AuthProvider = ({ api, children }: AuthProviderProps) => { } ``` -## Reactive state +## Наблюдение за состоянием -Если `AuthApi` предоставляет framework-neutral protocol `getSnapshot` и `subscribe`, React module может использовать `useSyncExternalStore`: +Если `AuthApi` предоставляет независимый от фреймворка интерфейс `getSnapshot` и `subscribe`, модуль React может использовать `useSyncExternalStore`: ```tsx 'use client' @@ -62,10 +62,10 @@ export const useAuthState = () => { } ``` -Business не импортирует React и не возвращает React hook как единственный способ наблюдать state. React module не создаёт subscription до commit и возвращает cleanup через protocol `useSyncExternalStore`. +Модуль `business` не импортирует React и не возвращает React-хук как единственный способ наблюдать состояние. Подпиской и её очисткой управляет `useSyncExternalStore`. -## Domain UI и compositions +## Интерфейс домена и композиции -Component принадлежит `react`, если его responsibility ограничена domain contract: он работает с `AuthApi`, domain state и stable domain errors. Он не владеет page, route, redirect, product copy или composition нескольких domains. +Компонент принадлежит `react`, если его ответственность ограничена контрактом домена: он работает с `AuthApi`, состоянием и устойчивыми ошибками домена. Он не владеет страницей, маршрутом, перенаправлением, продуктовым текстом или композицией нескольких доменов. -Screen, route outcome, локальный текст ошибки, redirect и page-specific UI остаются в `compositions`. Dependency от React сама по себе не доказывает принадлежность Domain. +Экран, результат маршрута, локальный текст ошибки, перенаправление и интерфейс конкретной страницы остаются в `compositions`. Зависимость от React сама по себе не доказывает принадлежность домену. diff --git a/DRAFT/level-3/domains/open-questions.md b/DRAFT/level-3/domains/open-questions.md index b6d4861..dde7c22 100644 --- a/DRAFT/level-3/domains/open-questions.md +++ b/DRAFT/level-3/domains/open-questions.md @@ -4,21 +4,21 @@ ## Зафиксированные решения -- Domain является сущностью только Level 3; в Level 2 предметная область остаётся одним domain module. -- Domain root не имеет общего runtime barrel. -- Framework module называется именем framework и размещается непосредственно в Domain: `domains/auth/react`. -- Framework module получает готовый API и не выполняет assembly. -- Runtime-взаимодействие business разных Domains проходит через consumer-owned port и graph owner. -- Navigation Groups допустимы в `domains`, но не являются частью базовых примеров. +- Домен является сущностью только Level 3; в Level 2 предметная область остаётся одним доменным модулем. +- Корень домена не имеет общей точки входа для исполняемого кода. +- Модуль фреймворка называется его именем и размещается непосредственно в домене: `domains/auth/react`. +- Модуль фреймворка получает готовый API и не выполняет сборку. +- Взаимодействие бизнес-логики разных доменов во время выполнения проходит через порт потребителя и владельца графа. +- Навигационные группы допустимы в `domains`, но не являются частью базовых примеров. -## Failure transport +## Форма передачи ошибок -Level 3 требует stable domain failure contract, но не навязывает проекту единый transport: exception с domain-specific runtime guard или discriminated `Result`. Нужно проверить, нужна ли общая политика для всех Domain одного приложения и как она влияет на server actions/RPC serialization. +Level 3 требует устойчивый контракт ошибок домена, но не навязывает единый способ передачи: исключение с проверкой типа во время выполнения или размеченный `Result`. Нужно проверить, нужна ли общая политика для всех доменов одного приложения и как она влияет на серверные действия и сериализацию RPC. -## Reactive state protocol +## Наблюдение за состоянием -Нужно проверить на реальном SSR/hydration кейсе точную форму framework-neutral observation protocol: initial snapshot, concurrent rendering, invalidation, subscription cleanup и поведение после request boundary. `getSnapshot` и `subscribe` пока являются базовой иллюстрацией, а не обязательной файловой формой. +На реальном примере SSR и гидратации нужно проверить точную форму независимого от фреймворка интерфейса наблюдения: начальный снимок, параллельный рендеринг, сброс данных, очистку подписки и поведение после завершения запроса. Методы `getSnapshot` и `subscribe` пока служат иллюстрацией, а не обязательной файловой формой. -## Architecture lint +## Автоматическая проверка архитектуры -Нужно выбрать формат project configuration для автоматической проверки Domain roots, role modules, public entrypoints, environment labels и запрещённых transitive imports. Проверка должна опираться на graph и metadata, а не только на имена папок. +Нужно выбрать формат конфигурации проекта для автоматической проверки корней доменов, их модулей, публичных точек входа, меток сред и запрещённых транзитивных импортов. Проверка должна опираться на граф и описание структуры, а не только на имена папок. diff --git a/DRAFT/level-3/domains/presets.md b/DRAFT/level-3/domains/presets.md index bfce5a5..0000481 100644 --- a/DRAFT/level-3/domains/presets.md +++ b/DRAFT/level-3/domains/presets.md @@ -1,6 +1,6 @@ -# Presets и SSR +# Типовые сборки и SSR -> Пояснение повторяемой assembly Domain. +> Пояснение повторяемой сборки домена. ## Связанные правила @@ -9,20 +9,20 @@ - [`SLM-L3-ENVIRONMENT-A012`](../../rules/level-3.md#slm-l3-environment-a012) - [`SLM-L3-FACTORY-R006`](../../rules/level-3.md#slm-l3-factory-r006) -## Роль preset +## Роль типовой сборки -Preset -- именованная повторяемая assembly одной business factory для конкретного execution context. Он выбирает concrete implementations ports, создаёт `AuthApi` и передаёт caller lifecycle operations, определённые module-владельцами resources. +Модуль в группе `presets` задаёт именованный повторяемый способ создания API одной фабрики для конкретного контекста выполнения. Он выбирает реализации портов, создаёт `AuthApi` и передаёт вызывающему коду операции жизненного цикла, определённые модулями-владельцами ресурсов. ```text authFactory -├── presets/application -> browser-compatible AuthApi -├── presets/request -> request-scoped AuthApi -└── presets/server-action -> server action AuthApi +├── presets/application → AuthApi уровня приложения +├── presets/request → AuthApi одного запроса +└── presets/server-action → AuthApi серверного действия ``` -Среда определяется preset и adapters, а не `mode` внутри factory. Tests создают per-test assembly напрямую через factory и не требуют общего `presets/testing`. +Среда определяется выбранной сборкой и её адаптерами, а не параметром `mode` внутри фабрики. Тесты создают отдельную сборку напрямую через фабрику и не требуют общего модуля `presets/testing`. -## Структура и public API +## Структура и публичный API ```text domains/auth/presets/application/ @@ -32,7 +32,7 @@ domains/auth/presets/application/ └── index.ts ``` -`application` -- пример имени. Preset называется по execution scope или устойчивому назначению: `application`, `request`, `server-action`. Он не называется по temporary consumer, если configuration не предназначена для повторного использования. +`application` — только пример имени. Модуль называется по контексту выполнения или устойчивому назначению: `application`, `request`, `server-action`. Временный потребитель не должен давать имя повторно используемой конфигурации. ```ts export const createApplicationAuth = (): AuthApi => { @@ -43,13 +43,13 @@ export const createApplicationAuth = (): AuthApi => { } ``` -Preset не добавляет scenario, не меняет error mapping и не скрывает business rule. Он также не становится монополией на factory: явный composition graph owner может собрать одноразовый graph, если он принимает на себя все обязанности assembly. +Типовая сборка не добавляет сценарии, не меняет преобразование ошибок и не скрывает предметные правила. Одноразовый владелец графа может вызвать фабрику напрямую, если сам выбирает все порты и отвечает за жизненный цикл результата. -## Scope и lifecycle +## Область жизни -Preset объявляет ожидаемый scope API instance. Application preset используется в application scope; request preset создаёт новый instance для каждого request. Graph owner удерживает instance только в этом scope и не хранит request data в application singleton. +Модуль сборки объявляет ожидаемую область жизни экземпляра API. Сборка `application` используется в течение жизни приложения, а `request` создаёт новый экземпляр для каждого запроса. Владелец графа не хранит данные одного запроса в общем экземпляре приложения. -Если assembly создаёт lifecycle resource, caller получает явный cleanup handle: +Если сборка создаёт ресурс жизненного цикла, вызывающий код получает явную операцию очистки: ```ts export type AuthRequestAssembly = { @@ -72,11 +72,11 @@ export const createAuthForRequest = ( } ``` -Factory и preset construction не запускают I/O или subscriptions. Если domain lifecycle должен начать resource, module-владелец выражает это отдельной API operation; graph owner вызывает её после начала scope и выполняет предоставленный cleanup при его завершении. +Создание API через фабрику или типовую сборку не запускает ввод-вывод и подписки. Если ресурс нужно запустить явно, модуль-владелец предоставляет отдельную операцию. Владелец графа вызывает её после начала своей области жизни и выполняет очистку при завершении. -## Server-only boundary +## Серверная граница -Server preset имеет отдельный entrypoint и marker выбранного framework/build system: +Серверная сборка имеет отдельную точку входа и служебную метку выбранного фреймворка или сборщика: ```ts import 'server-only' @@ -84,6 +84,6 @@ import 'server-only' export { createAuthForRequest } from './create-auth-for-request' ``` -Этот entrypoint не реэкспортируется через `business`, `react` или client-compatible preset. Server adapter может иметь собственный marker для защиты от ошибочного прямого import. +Эта точка входа не реэкспортируется через `business`, `react` или клиентскую сборку. Серверный адаптер также может иметь собственную метку, защищающую от ошибочного прямого импорта. -Framework module не вызывает preset и не создаёт factory. Он получает готовый `AuthApi` от graph owner, поэтому React lifecycle не смешивается с concrete assembly. +Модуль фреймворка не вызывает сборку и не создаёт фабрику. Он получает готовый `AuthApi` от владельца графа, поэтому жизненный цикл React не смешивается с технической сборкой зависимостей. diff --git a/DRAFT/level-3/domains/testing.md b/DRAFT/level-3/domains/testing.md index 38685a7..a87e5fd 100644 --- a/DRAFT/level-3/domains/testing.md +++ b/DRAFT/level-3/domains/testing.md @@ -1,8 +1,8 @@ -# Тестирование Domain +# Тестирование домена -> Verification границ и behavior Level 3. +> Проверка границ и поведения Level 3. -## Связанное правило +## Связанные правила - [`SLM-L3-TEST-R014`](../../rules/level-3.md#slm-l3-test-r014) - [`SLM-L3-FACTORY-R006`](../../rules/level-3.md#slm-l3-factory-r006) @@ -10,21 +10,21 @@ ## Принцип размещения -Тест живёт у module-владельца проверяемой ответственности. У Domain нет общей корневой папки `tests/`. +Тест находится рядом с модулем-владельцем проверяемой ответственности. У домена нет общей корневой папки `tests/`. | Проверяемая граница | Владелец теста | |---|---| -| Business scenarios, state и domain errors | `business` | -| Pure rule, mapper, parser или guard | Colocated segment `business` | -| Concrete port implementation | Adapter | -| Wiring, scope и cleanup assembly | Preset | -| Provider, hook и React lifecycle | `react` | -| Cross-domain graph | Composition graph owner | -| Полный пользовательский поток | E2E entry приложения | +| Предметные сценарии, состояние и ошибки домена | `business` | +| Чистая функция бизнес-логики | Соответствующий сегмент `business` | +| Реализация порта | Адаптер | +| Выбор зависимостей, область жизни и очистка | Модуль в `presets` | +| Провайдер, хук и жизненный цикл React | `react` | +| Граф нескольких доменов | Модуль-владелец графа | +| Полный пользовательский поток | Точка входа сквозного теста приложения | -## Factory-level tests +## Тесты через фабрику -Factory-level tests являются главным доказательством public business behavior. Они импортируют только public API `business` и передают controlled ports: +Тесты через фабрику являются главным доказательством публичного поведения бизнес-логики. Они импортируют только публичный API `business` и передают управляемые тестовые реализации портов: ```ts import { @@ -43,28 +43,28 @@ it('maps source failure to domain error', async () => { }) ``` -Factory-level suite проверяет форму public API, отсутствие side effects при construction, happy path, input validation, malformed port result, rejected promise, synchronous throw, domain error code, порядок effects, state transitions и значимые concurrent calls. +Такой набор тестов проверяет форму публичного API, отсутствие побочных эффектов при создании, успешные и ошибочные сценарии, проверку входных данных, переходы состояния и порядок внешних операций. -Business test не использует React, production SDK, storage или production preset. Если scenario нельзя проверить без них, runtime boundary проникла внутрь business. +Тест `business` не использует React, реальный SDK, хранилище или типовую сборку приложения. Если сценарий нельзя проверить без них, техническая зависимость проникла внутрь бизнес-логики. -## Test harness +## Вспомогательная тестовая сборка -Private test harness уменьшает boilerplate, но не является preset: +Закрытая тестовая функция уменьшает повторение, но не является модулем в `presets`: ```ts const { api, ports, state } = createAuthTestHarness({ requestCode }) ``` -Harness создаёт новый instance на каждый test case, допускает scenario-specific overrides и не экспортируется через production entrypoint. `presets/testing` не создаётся по умолчанию. +Она создаёт новый экземпляр для каждого теста, допускает нужные сценарию замены и не экспортируется через рабочую точку входа. Модуль `presets/testing` по умолчанию не создаётся. ## Тесты остальных ролей -Adapter test проверяет concrete operation, transport payload, mapping аргументов, raw result/error согласно port contract и subscription cleanup. Он не повторяет domain error mapping или scenario matrix. +Тест адаптера проверяет вызванную техническую операцию, переданные данные, преобразование аргументов, результат или ошибку согласно контракту порта и очистку подписки. Он не повторяет преобразование ошибок домена и полный набор предметных сценариев. -Preset test проверяет полный набор ports, выбор adapters, отсутствие I/O при construction, scope instance, передачу cleanup handle и server/client import boundary. Он не повторяет happy path business. +Тест типовой сборки проверяет полный набор портов, выбор адаптеров, отсутствие ввода-вывода при создании, область жизни экземпляра, передачу операции очистки и границу клиента и сервера. Он не повторяет успешные предметные сценарии. -React test получает fake `AuthApi` и проверяет Provider, access hook, update по `subscribe`, cleanup после unmount и поведение в Strict Mode. Smoke test с real factory добавляется только при отдельном integration risk. +Тест React получает тестовый `AuthApi` и проверяет провайдер, хук доступа, обновление по `subscribe`, очистку после размонтирования и поведение в `StrictMode`. Минимальный интеграционный тест с настоящей фабрикой добавляется только при отдельном риске интеграции. ## Минимальный набор -Файл test создаётся вместе с реальным risk, а не ради scaffold. Однако public business scenario не считается завершённым без factory-level tests; production preset без assembly test; adapter с нетривиальным transport mapping без adapter test; React binding с lifecycle behavior без framework test. +Тест создаётся в ответ на реальный риск, а не ради заполнения каркаса. При этом публичный предметный сценарий требует теста через фабрику, типовая сборка приложения — теста сборки, адаптер с нетривиальным преобразованием данных — теста адаптера, а модуль React с поведением жизненного цикла — теста фреймворка. diff --git a/DRAFT/level-3/terminology.md b/DRAFT/level-3/terminology.md index c731b38..f726111 100644 --- a/DRAFT/level-3/terminology.md +++ b/DRAFT/level-3/terminology.md @@ -2,84 +2,86 @@ > Нормативные определения рабочего черновика. Этот раздел не объявляет правила. -Level 3 наследует терминологию Levels 1-2 и заменяет структурную модель доменного модуля Level 2 новой сущностью Domain. +Level 3 наследует терминологию Level 1 и Level 2 и заменяет доменный модуль Level 2 новой структурной сущностью — доменом Level 3. -## Domain +## Домен Level 3 -### Domain +### Домен -Немодульная предметная граница слоя `domains`, представляющая одну самостоятельную предметную область. Domain объединяет role modules и Groups этой области, но не содержит собственного runtime-кода, состояния, lifecycle, public API или узла графа зависимостей. +Немодульная предметная граница слоя `domains`, представляющая одну самостоятельную предметную область. Домен объединяет модули и группы этой области, но не имеет собственного исполняемого кода, состояния, жизненного цикла, публичного API или узла графа зависимостей. -Domain не является module и не является Group. Он может находиться непосредственно в слое `domains` или внутри навигационной Group этого слоя. В этом частном случае Group вправе содержать Domain, но сохраняет все остальные свойства Group Level 1. +Домен не является ни модулем, ни группой. Он может находиться непосредственно в слое `domains` или внутри навигационной группы этого слоя. Такая группа вправе содержать домены, но сохраняет остальные свойства группы Level 1. -Module, расположенный непосредственно внутри Domain или внутри его Group, не является вложенным module: ближайшая внешняя граница Domain не является module. +Модуль, расположенный непосредственно внутри домена или одной из его групп, не считается вложенным: его ближайшая внешняя граница не является модулем. -### Role module +### Модуль домена -Module внутри Domain, чья ответственность определяется одной технической ролью: `business`, preset, adapter или framework binding. Каждый role module остаётся обычным module Level 1 со своим public API и узлом графа зависимостей. +Модуль внутри домена, ответственность которого соответствует одной технической роли: бизнес-логике, типовой сборке, адаптеру или связи с фреймворком. Каждый модуль домена остаётся обычным модулем Level 1 со своим публичным API и узлом графа зависимостей. -### Business module +### Модуль бизнес-логики -Обязательный module `business` внутри Domain. Он определяет public business scenarios, business contracts, factory, ports, domain errors, детерминированные правила и семантику domain state. +Обязательный модуль `business` внутри домена. Он определяет публичные предметные сценарии и контракты, фабрику, порты, ошибки предметной области, детерминированные правила и модель состояния. -`business` не зависит от concrete runtime, execution environment или framework. +Модуль `business` не зависит от конкретной среды выполнения, технической реализации или фреймворка. -### Port +### Порт -Минимальный business-owned contract runtime capability, которая нужна business для выполнения scenario. Port описывается языком предметной области и не раскрывает SDK, generated DTO, store, hook, platform object или другой concrete runtime. +Минимальный контракт возможности, которая нужна бизнес-логике для выполнения предметного сценария. Порт принадлежит модулю `business`, использует язык предметной области и не раскрывает SDK, сгенерированные DTO, хранилище, хук, объект платформы или другую техническую реализацию. -### Factory +### Фабрика -Функция business module, которая получает полный набор ports и создаёт business API instance. Factory не является assembly и не выбирает concrete implementation ports. +Функция модуля `business`, которая получает полный набор портов и создаёт экземпляр публичного API бизнес-логики. Фабрика не выбирает реализации портов и не является готовой сборкой для конкретной среды. -### Adapter +### Адаптер -Код, который реализует один или несколько business ports поверх concrete runtime: SDK, storage, platform API, request input, state manager или технического сервиса. Adapter может быть private segment preset module либо самостоятельным promoted adapter module. +Код, который реализует один или несколько портов поверх конкретного SDK, хранилища, API платформы, данных запроса, системы управления состоянием или технического сервиса. Адаптер может быть закрытым сегментом модуля сборки либо самостоятельным модулем в группе `adapters`. -### Preset +### Типовая сборка -Module с именованной повторяемой assembly одной business factory для execution context. Preset выбирает implementations ports и сообщает caller, как владеть созданным API instance. +Модуль в группе `presets`, который повторяемо создаёт API одной фабрики для именованного контекста выполнения. Он выбирает реализации портов и возвращает вызывающему коду операции, необходимые для управления жизненным циклом созданного экземпляра. -### Framework module +### Модуль фреймворка -Role module, который существует из-за contract конкретного framework. Такой module размещается непосредственно в Domain и называется именем framework: `react`, `vue` и аналогично. Он получает готовый business API, но не собирает factory и не реализует concrete adapter. +Модуль домена, который связывает публичный API бизнес-логики с конкретным фреймворком. Он размещается непосредственно в домене и называется именем фреймворка: `react`, `vue` и аналогично. Такой модуль получает готовый API, но не вызывает фабрику и не реализует технические адаптеры. -### Assembly site +### Место сборки -Место, которое вызывает business factory, передаёт полный набор ports и получает API instance. Reusable assembly оформляется preset module; одноразовая assembly принадлежит явному composition graph owner. Framework module не является assembly site. +Место, которое вызывает фабрику, передаёт полный набор портов и получает экземпляр API. Повторяемое место сборки оформляется модулем в группе `presets`; одноразовая сборка принадлежит явному владельцу графа. Модуль фреймворка не является местом сборки. -### Graph owner +### Владелец графа -Код, который удерживает конкретный runtime graph и API instances в execution scope и вызывает предоставленные start/cleanup operations. Graph owner не заменяет module-владельца lifecycle resource; contract создания, области жизни, числа instances и cleanup определяет module по правилам Level 1. Graph owner может быть application, route, page, request или test scope. +Код модуля, который удерживает собранный граф и его экземпляры API в пределах объявленной области жизни, а также вызывает предоставленные операции запуска и очистки. Владелец графа не заменяет владельца ресурса: контракт жизненного цикла определяет модуль, которому принадлежит ресурс, по правилам Level 1. -### Environment boundary +Владельцем графа может быть модуль приложения, маршрута, страницы, запроса или теста. -Граница между client-only, server-only и isomorphic import graphs. Она определяется достижимостью import graph, а не названием папки или надеждой на tree shaking. +### Граница среды выполнения + +Граница между графами импортов, предназначенными только для клиента, только для сервера или для обеих сред. Она определяется достижимостью импортов, а не названием папки или удалением неиспользуемого кода при сборке. ## Виды владения -Level 3 различает три вопроса, которые в обычной речи могут называться владением: +Level 3 разделяет три разных вопроса: | Вопрос | Ответственный | |---|---| -| Какая предметная область и словарь объединяют код | Domain | -| Кто владеет самостоятельной ответственностью и public API | Конкретный module | -| Кто удерживает API instance в execution scope и вызывает lifecycle operations | Graph owner | +| Какая предметная область и словарь объединяют код | Домен | +| Кто владеет самостоятельной ответственностью и публичным API | Конкретный модуль | +| Кто удерживает экземпляры API и завершает их жизненный цикл | Владелец графа | -Например, `business` владеет моделью `AuthState` и её допустимыми переходами. Adapter владеет concrete state runtime и его lifecycle contract. Graph owner удерживает конкретный `AuthApi` instance в допустимом scope и вызывает его cleanup. +Например, модуль `business` владеет моделью `AuthState` и допустимыми переходами между её состояниями. Модуль, содержащий адаптер, владеет конкретным механизмом хранения и определяет контракт его жизненного цикла. Владелец графа удерживает созданный `AuthApi` в допустимой области жизни и вызывает очистку. ## Структурная модель ```text -SLM root +корень SLM └── domains - └── Domain - ├── business module - ├── presets Group - │ └── preset module - ├── adapters Group - │ └── adapter module - └── react framework module + └── домен + ├── модуль business + ├── группа presets + │ └── модуль типовой сборки + ├── группа adapters + │ └── модуль адаптера + └── модуль react ``` -`presets` и `adapters` являются Groups только при наличии соответствующих modules. `errors`, `ports`, `services`, `types`, `hooks` и `providers` являются segments своих module-владельцев, если сами не образуют отдельный module. +Группы `presets` и `adapters` существуют только при наличии соответствующих модулей. Каталоги `errors`, `ports`, `services`, `types`, `hooks` и `providers` являются сегментами своих модулей-владельцев, если сами не образуют самостоятельный модуль. diff --git a/DRAFT/level-3/validation.md b/DRAFT/level-3/validation.md index dafdbb9..596e03a 100644 --- a/DRAFT/level-3/validation.md +++ b/DRAFT/level-3/validation.md @@ -1,42 +1,42 @@ # Проверка Level 3 -> Граница автоматической проверки, архитектурного ревью и verification Level 3. +> Граница автоматической проверки, архитектурного ревью и тестирования Level 3. ## Конфигурация проекта -Конфигурация проверки сопоставляет физические пути с Domain, role modules, Groups, public entrypoints и environment labels. Она также определяет, какие entrypoints считаются client-only, server-only или isomorphic. +Конфигурация проверки сопоставляет физические пути с доменами, их модулями, группами, публичными точками входа и метками сред выполнения. Она также определяет, какие точки входа предназначены только для клиента, только для сервера или для обеих сред. -Сопоставление путей не определяет предметный смысл Domain. Оно позволяет проверить форму Domain, public API modules, import graph, циклы и environment boundaries. +Сопоставление путей не определяет предметный смысл домена. Оно позволяет проверить его форму, публичные API модулей, граф импортов, циклы и совместимость сред. ## Автоматическая проверка Автоматическая проверка должна блокировать: -- отсутствие или множественность `business` module в Domain; -- runtime-код или root entrypoint у Domain; -- deep imports в segments role modules; -- достижение framework, concrete runtime, environment markers, adapters или presets из `business` entrypoint; -- достижение incompatible environment graph из client-only, server-only или isomorphic entrypoint; -- циклы между modules по общему правилу Level 1. +- отсутствие модуля `business` или несколько таких модулей в одном домене; +- исполняемый код или общую точку входа в корне домена; +- глубокие импорты во внутренние сегменты модулей домена; +- достижимость кода фреймворка, конкретной среды, адаптеров или сборок из точки входа `business`; +- достижимость несовместимой среды из клиентской, серверной или общей точки входа; +- циклы между модулями по общему правилу Level 1. ## Архитектурное ревью На ревью определяется: -- является ли Domain одной связной предметной областью; -- принадлежит ли business scenario, error contract и state semantics `business` module; -- описывает ли port минимальную business capability без concrete types; -- остаётся ли adapter техническим bridge без domain fallback и error mapping; -- является ли preset повторяемой assembly конкретного scope; -- определены ли module-владелец lifecycle contract, graph owner, scope instance, start и cleanup; -- проходит ли междоменная runtime-связь через consumer-owned port; -- принадлежит ли React UI Domain, а не конкретной page или route composition. +- представляет ли домен одну связную предметную область; +- принадлежат ли предметные сценарии, контракт ошибок и модель состояния модулю `business`; +- описывает ли порт минимальную предметную возможность без типов конкретной реализации; +- остаётся ли адаптер техническим преобразователем без предметных правил и преобразования ошибок в ошибки домена; +- представляет ли модуль группы `presets` повторяемую сборку для одного контекста выполнения; +- определены ли владелец ресурса, владелец графа, область жизни экземпляра, запуск и очистка; +- проходит ли связь между доменами во время выполнения через порт потребителя; +- принадлежит ли интерфейс React домену, а не отдельной странице или маршруту. -## Verification +## Тестирование -Business проверяется factory-level tests с controlled ports. Adapter проверяется на transport/wiring boundary, preset -- на assembly, scope и environment boundary, React module -- на provider, subscriptions и framework lifecycle. Полная cross-domain assembly проверяется у graph owner. +Бизнес-логика проверяется через публичный API фабрики с управляемыми тестовыми реализациями портов. Тест адаптера проверяет техническую границу, тест сборки — выбор зависимостей, область жизни и совместимость среды, тест модуля React — провайдер, подписки и жизненный цикл фреймворка. Полный междоменный граф проверяется у его владельца. -Тесты не заменяют автоматические import checks и архитектурное ревью. Они доказывают runtime behavior на уже выбранной границе. +Тесты не заменяют автоматическую проверку импортов и архитектурное ревью. Они подтверждают поведение уже выбранной границы. ## Связанные правила diff --git a/DRAFT/rules/README.md b/DRAFT/rules/README.md index 226fb06..f046682 100644 --- a/DRAFT/rules/README.md +++ b/DRAFT/rules/README.md @@ -51,15 +51,15 @@ SLM-L{level}-{group}-{class}{number} | `NESTED_MODULE` | Вложенные модули | | `LIFECYCLE` | Жизненный цикл | | `DOMAIN` | Домены | -| `BUSINESS` | Business contracts | -| `FACTORY` | Business factories | -| `PORT` | Business ports | -| `ADAPTER` | Adapters | -| `PRESET` | Presets | -| `ASSEMBLY` | Assembly и API instances | +| `BUSINESS` | Контракты бизнес-логики | +| `FACTORY` | Фабрики бизнес-логики | +| `PORT` | Порты бизнес-логики | +| `ADAPTER` | Адаптеры | +| `PRESET` | Типовые сборки | +| `ASSEMBLY` | Сборка и экземпляры API | | `ENVIRONMENT` | Границы сред выполнения | -| `FRAMEWORK` | Framework modules | -| `TEST` | Verification и тестирование | +| `FRAMEWORK` | Модули фреймворков | +| `TEST` | Тестирование | Код раздела записывается полным английским именем в `UPPER_SNAKE_CASE`. Новый код добавляется в таблицу до первого использования. diff --git a/DRAFT/rules/level-3.md b/DRAFT/rules/level-3.md index 2ca6a9d..42c80e3 100644 --- a/DRAFT/rules/level-3.md +++ b/DRAFT/rules/level-3.md @@ -1,97 +1,97 @@ # Правила SLM третьего уровня -Проект Level 3 соблюдает правила Levels 1-2, кроме заменённого `SLM-L2-DOMAIN-R001` и расширенного состава Groups внутри слоя `domains`, и дополнительные правила этого реестра. +Проект Level 3 соблюдает правила Level 1 и Level 2, кроме заменённого `SLM-L2-DOMAIN-R001` и расширенного состава групп внутри слоя `domains`, а также дополнительные правила этого реестра. -## Граница Domain +## Граница домена ### SLM-L3-DOMAIN-R001 -> **Предметная граница Domain** +> **Предметная граница домена** > -> Каждая самостоятельная предметная область слоя `domains` представлена ровно одним Domain; его role modules относятся только к этой области. +> Каждая самостоятельная предметная область слоя `domains` представлена ровно одним доменом; его модули относятся только к этой области. ### SLM-L3-DOMAIN-A002 -> **Корень Domain** +> **Корень домена** > -> Корень Domain не содержит файлов реализации, изменяемого состояния, ресурсов жизненного цикла, публичного API или реэкспортов и содержит только допустимые role modules и Groups. +> Корень домена не содержит файлов реализации, изменяемого состояния, ресурсов жизненного цикла, публичного API или реэкспортов и содержит только допустимые модули домена и группы. -## Business и factory +## Бизнес-логика и фабрика ### SLM-L3-BUSINESS-R003 -> **Business contract Domain** +> **Контракт бизнес-логики** > -> Каждый Domain содержит ровно один module `business`, который определяет публичные business scenarios, business contracts, domain errors и семантику domain state. +> Каждый домен содержит ровно один модуль `business`, который определяет публичные предметные сценарии и контракты, ошибки предметной области и модель её состояния. ### SLM-L3-BUSINESS-A004 -> **Изоморфный graph business** +> **Независимость бизнес-логики от среды** > -> Production import graph, достижимый из public entrypoint `business`, не достигает framework code, environment boundary, platform API, concrete runtime, adapter, preset или framework module. +> Граф импортов, достижимый из публичной точки входа `business`, не достигает кода фреймворков, зависимых от среды точек входа, API платформы, технических реализаций, адаптеров, сборок или модулей фреймворков. ### SLM-L3-FACTORY-R005 -> **Contract factory** +> **Контракт фабрики** > -> Business factory получает полный набор собственных ports и создаёт стабильный business API независимо от execution environment; среда не выражается через mode, optional port или метод, намеренно недоступный в части сред. +> Фабрика бизнес-логики получает полный набор собственных портов и создаёт API одного и того же контракта независимо от среды выполнения; различия сред не выражаются режимом, необязательным портом или методом, намеренно недоступным в части сред. ### SLM-L3-FACTORY-R006 -> **Создание API instance** +> **Создание экземпляра API** > -> Вызов business factory не выполняет ввод-вывод, не читает скрытое окружение, не запускает ресурс жизненного цикла, не выбирает concrete adapter и не выполняет framework lifecycle. +> Вызов фабрики не выполняет ввод-вывод, не читает скрытое окружение, не запускает ресурс жизненного цикла, не выбирает конкретный адаптер и не выполняет операции жизненного цикла фреймворка. ### SLM-L3-PORT-R007 -> **Business-owned port** +> **Порт бизнес-логики** > -> Каждая runtime capability, вызываемая business, описывается минимальным business-owned port, public contract которого не раскрывает concrete runtime, framework или environment types. +> Каждая возможность среды, необходимая бизнес-логике во время выполнения, описывается минимальным портом этой бизнес-логики; публичный контракт порта не раскрывает конкретную реализацию, фреймворк или типы среды. -## Assembly +## Сборка ### SLM-L3-ADAPTER-R008 -> **Ответственность adapter** +> **Ответственность адаптера** > -> Adapter преобразует concrete runtime в business port и не определяет business invariant, domain fallback или domain error. +> Адаптер реализует порт бизнес-логики поверх конкретной технической системы и не определяет предметный инвариант, резервное поведение или ошибку предметной области. ### SLM-L3-PRESET-R009 -> **Роль preset** +> **Роль типовой сборки** > -> Preset module собирает business API для одного именованного execution context выбором implementations ports и не изменяет business contract или scenarios. +> Модуль группы `presets` собирает API бизнес-логики для одного именованного контекста выполнения, выбирая реализации портов, и не изменяет контракт или предметные сценарии. ### SLM-L3-ASSEMBLY-R010 -> **Исполнение lifecycle contract** +> **Жизненный цикл собранного API** > -> Graph owner удерживает API instance только в scope, объявленном module-владельцем, и вызывает предоставленные ему lifecycle operations; module-владелец определяет lifecycle contract resource по правилам Level 1. +> Владелец графа удерживает экземпляр API только в области жизни, объявленной модулем-владельцем, и вызывает предоставленные операции жизненного цикла; модуль-владелец определяет создание, область жизни, число экземпляров и очистку ресурса по правилам Level 1. -## Междоменные и environment зависимости +## Междоменные зависимости и среды выполнения ### SLM-L3-DEPENDENCY-R011 -> **Междоменная runtime-граница** +> **Междоменная связь во время выполнения** > -> Business одного Domain не создаёт и не импортирует runtime API другого Domain; необходимая capability описывается собственным port и передаётся graph owner при assembly. +> Модуль `business` одного домена не создаёт и не импортирует исполняемый API другого домена; необходимая возможность описывается собственным портом и передаётся владельцем графа при сборке. ### SLM-L3-ENVIRONMENT-A012 -> **Environment import graph** +> **Совместимость графа импортов** > -> Public entrypoint, обозначенный как client-only, server-only или isomorphic, не импортирует и не реэкспортирует transitive graph несовместимой среды выполнения. +> Публичная точка входа, обозначенная как клиентская, серверная или общая для обеих сред, не импортирует и не реэкспортирует код несовместимой среды выполнения. -## Framework и verification +## Фреймворки и тестирование ### SLM-L3-FRAMEWORK-R013 -> **Framework module Domain** +> **Модуль фреймворка домена** > -> Framework-specific code находится в module Domain, названном именем framework, получает готовый business API и не реализует business decisions или concrete adapters. +> Зависящий от конкретного фреймворка код находится в модуле домена, названном именем фреймворка, получает готовый API бизнес-логики и не реализует предметные решения или технические адаптеры. ### SLM-L3-TEST-R014 -> **Проверка business contract** +> **Проверка контракта бизнес-логики** > -> Каждый public business scenario проверяется factory-level tests с controlled implementations ports; primary tests adapter, preset и framework module проверяют их собственную границу и не дублируют scenario matrix business. +> Каждый публичный предметный сценарий проверяется через фабрику с управляемыми тестовыми реализациями портов; основные тесты адаптера, сборки и модуля фреймворка проверяют собственные границы и не повторяют набор предметных сценариев.