docs(architecture): переработать раздел архитектуры

- заменил описание слоёв и модулей FSD на новую модель с компонентами
- добавил раздел 'Что важно знать' с пояснением что архитектура надстройка над FSD
- добавил описание master component и его правил
- добавил раздел сегментов с таблицей
- убрал дублирующиеся правила зависимостей и публичного API
This commit is contained in:
2026-03-31 15:17:47 +03:00
parent 3993909b98
commit e337ec78fa
3 changed files with 259 additions and 268 deletions

View File

@@ -62,6 +62,11 @@ Full documentation in a single MD file: https://gromlab.ru/docs/frontend-style-g
Base technology stack and libraries used in projects.
<!-- /basics/naming -->
## Naming
Naming should be predictable, concise, and reflect the meaning of the entity.
<!-- /basics/architecture -->
## Architecture
@@ -72,11 +77,6 @@ Architecture based on FSD (Feature-Sliced Design) and strict module boundaries.
Unified code formatting rules: indentation, line breaks, quotes, import order, and readability.
<!-- /basics/naming -->
## Naming
Naming should be predictable, concise, and reflect the meaning of the entity.
<!-- /basics/documentation -->
## Documentation

View File

@@ -64,14 +64,6 @@
Порядок действий при разработке — от создания проекта до реализации фич.
### Начало работы
Подготовка окружения перед началом разработки.
1. Открыть проект в VS Code.
2. Установить рекомендуемые расширения (редактор предложит автоматически).
3. Ознакомиться со стеком: Next.js (App Router), Mantine, Zustand, FSD.
### Создание проекта
Инициализация нового проекта из готового шаблона.
@@ -155,99 +147,245 @@
<!-- /basics/tech-stack -->
## Технологии и библиотеки
Базовый стек технологий и библиотек, на который опираются проекты и примеры в документации.
Этот раздел описывает базовый стек технологий и библиотек, принятый в проекте.
### Что используем
#### Стек
- **React/TypeScript** — основной стек для UI и приложения.
- **Next.js** — для продуктовых сайтов.
- `React` / `TypeScript` — основной стек для UI и приложения.
- `Next.js` — для продуктовых сайтов.
#### Архитектура
- **FSD (Feature-Sliced Design)** — структура проекта и границы модулей.
- `FSD (Feature-Sliced Design)` — структура проекта и границы модулей. Используется кастомизированная версия — подробнее в разделе [Архитектура](/basics/architecture).
#### UI компоненты
- **Mantine UI** — базовые UI-компоненты.
- `Mantine UI` — базовые UI-компоненты.
#### Fetch (API)
- **@gromlab/api-codegen** — генерация APIклиентов и типов.
- **SWR** — получение, кеширование, ревалидация, дедубликация.
- **SWR (useSWRSubscription)** - сокеты, реалтайм подписки.
#### Работа с данными (API)
- `@gromlab/api-codegen` — генерация APIклиентов и типов.
- `SWR` — получение, кеширование, ревалидация, дедубликация.
- `SWR (useSWRSubscription)` — сокеты, реалтайм подписки.
#### Store
- **Zustand** — глобальное состояние.
- `Zustand` — глобальное состояние.
#### Локализация
- **i18next (i18n)** — локализация всех пользовательских текстов.
- `i18next (i18n)` — локализация всех пользовательских текстов.
#### Тестирование
- **Vitest** — тестирование.
- `Vitest` — тестирование.
#### Стили
- **PostCSS Modules** — изоляция стилей.
- **Mobile First** — подход к адаптивной верстке.
- **clsx** — конкатенация CSSклассов.
- `PostCSS Modules` — изоляция стилей.
- `Mobile First` — подход к адаптивной верстке.
- `clsx` — конкатенация CSSклассов.
#### Генерация
- **@gromlab/create** — шаблонизатор для создания слоёв и других файлов из шаблонов.
- `@gromlab/create` — шаблонизатор для создания слоёв и других файлов из шаблонов.
<!-- /basics/naming -->
## Именование
Этот раздел описывает соглашения об именовании в проекте. Единые правила делают код предсказуемым и упрощают навигацию по проекту.
### Базовые правила
| Что | Рекомендуется |
| ---------------- | ---------------------- |
| Папки | `kebab-case` |
| Файлы | `kebab-case` |
| Переменные | `camelCase` |
| Константы | `SCREAMING_SNAKE_CASE` |
| Классы | `PascalCase` |
| React-компоненты | `PascalCase` |
| Хуки | `useSomething` |
| CSS классы | `camelCase` |
### Именование файлов
Суффикс обозначает роль или тип файла. Пишется в единственном числе.
Формат: `name.<suffix>.ts`.
**Хуки**
- `use-name.hook.ts` — файл хука, функция именуется `useName`
**Логика**
- `.store.ts` — стор
- `.service.ts` — сервис
**Типы и контракты**
- `.type.ts` — типы и интерфейсы
- `.interface.ts` — интерфейсы
- `.enum.ts` — enum
- `.dto.ts` — внешние DTO
- `.schema.ts` — схемы валидации
- `.constant.ts` — константы
- `.config.ts` — конфигурация
**Утилиты**
- `.util.ts` — утилиты
- `.helper.ts` — вспомогательные функции
- `.lib.ts` — библиотечный код
**Тесты**
- `.test.ts` — тесты
- `.mock.ts` — моки
**Хорошо**
```text
features/
└── auth-by-email/
├── ui/
│ └── login-form.tsx
├── hooks/
│ └── use-auth.hook.ts
├── stores/
│ └── auth.store.ts
├── types/
│ └── auth.interface.ts
├── auth-by-email.feature.tsx
└── index.ts
```
**Плохо**
```text
features/
└── authByEmail/
├── LoginForm.tsx
├── useAuth.ts
├── authStore.ts
└── index.ts
```
### Булевы значения
- Использовать префиксы `is`, `has`, `can`, `should`.
**Хорошо**
```ts
const isReady = true;
const hasAccess = false;
const canSubmit = true;
const shouldRedirect = false;
```
**Плохо**
```ts
// Плохо: неясное булево значение без префикса.
const ready = true;
const access = false;
const submit = true;
```
### События и обработчики
- Обработчики начинать с `handle`.
- События и колбэки начинать с `on`.
**Хорошо**
```ts
const handleSubmit = () => { ... };
const onSubmit = () => { ... };
```
**Плохо**
```ts
// Плохо: неочевидное назначение имени.
const submitClick = () => { ... };
```
### Коллекции
- Для массивов использовать имена во множественном числе.
- Для словарей/мап — использовать суффиксы `ById`, `Map`, `Dict`.
**Хорошо**
```ts
const users = [];
const usersById = {} as Record<string, User>;
const userIds = ['u1', 'u2'];
const ordersMap = new Map<string, Order>();
const featureFlagsDict = { beta: true, legacy: false } as Record<string, boolean>;
```
**Плохо**
```ts
// Плохо: имя не отражает, что это коллекция.
const user = [];
// Плохо: словарь назван как массив.
const usersMap = [];
// Плохо: по имени непонятно, что это словарь.
const users = {} as Record<string, User>;
```
<!-- /basics/architecture -->
## Архитектура
Архитектура построена на FSD (`FeatureSliced Design`) и строгих границах модулей.
Цель — разделить ответственность, упростить сопровождение и контроль зависимостей.
Этот раздел описывает архитектуру проекта: из каких слоёв состоит приложение,
как организован код внутри слоёв и какие правила управляют зависимостями.
### Принципы
### Что важно знать
- Разделять UI, бизнес-логику и инфраструктуру.
- Держать зависимости однонаправленными.
- Открывать наружу только публичный API модулей.
- Не допускать циклических зависимостей.
Проект использует [FSD (Feature-Sliced Design)](https://feature-sliced.design/docs/get-started/overview)
как базовую архитектурную методологию. Если вы не знакомы с FSD — начните с официальной документации.
### Слои (FSD)
Данная архитектура является **надстройкой над FSD**, а не заменой. Все правила FSD действуют
по умолчанию — если правило явно не переопределено в этом документе, применяется стандарт FSD.
Единственное отклонение: вместо слайсов используются **компоненты**.
- **app** — инициализация приложения: провайдеры, глобальные стили. В Next.js эта же папка `app/` дополнительно содержит системные файлы роутинга (`layout.tsx`, `page.tsx`).
- **screens** — UI-компоненты страниц. Каждый экран — отдельный компонент, который собирает виджеты и фичи конкретной страницы. Роутинг только использует эти компоненты — он не является частью слоя `screens`. В Next.js файлы `page.tsx` остаются тонкими: импортируют экран и рендерят его.
- **layouts** — каркас и шаблоны страниц.
- **widgets** — крупные блоки интерфейса, собирающие несколько сценариев.
- **features** — отдельные пользовательские действия и сценарии.
- **entities** — бизнес-сущности и их модель.
- **shared** — переиспользуемая инфраструктура, утилиты и базовые UIкомпоненты.
### Слои
### Модули (FSD)
| Слой | Назначение |
|------|-----------|
| `app` | Инициализация: провайдеры, стили, роутинг Next.js |
| `screens` | Сборка страницы из виджетов и фич |
| `layouts` | Каркасы и шаблоны страниц |
| `widgets` | Крупные блоки интерфейса |
| `features` | Пользовательские сценарии и действия |
| `entities` | Бизнес-сущности |
| `shared` | Утилиты, UI-кит, инфраструктура |
- Модуль — это отдельная папка в слоях `screens`, `layouts`, `widgets`, `features`, `entities`, которая реализует один сценарий/блок. В корне модуля лежит главный файл (`*.screen.tsx`, `*.layout.tsx`, `*.widget.tsx`, `*.feature.tsx`, `*.entity.tsx`) и публичный API (`index.ts`).
- Внутри модуля используются подпапки (по необходимости):
- `ui/` — дочерние UIкомпоненты модуля.
- `model/` — состояние и бизнес‑логика модуля.
- `styles/` — локальные стили модуля.
- `helpers/` — локальные хелперы.
- `lib/` — утилиты модуля.
- `api/` — APIвызовы модуля.
Слой `pages` не используется — конфликтует с Next.js. Вместо него: `screens` и `layouts`.
### Правила зависимостей
Зависимости идут строго сверху вниз: `app → screens → layouts → widgets → features → entities → shared`.
- Допустимые импорты идут сверху вниз: `app → screens → layouts → widgets → features → entities → shared`.
- Импорты между слоями — через публичный API.
- Внутри одного слоя — относительные импорты.
### Компоненты
### Публичный API модулей
Компонент — стандартная UI-единица, такая же как в любом React-проекте. Содержит корневой `.tsx`,
публичный API (`index.ts`) и сегменты.
- Каждый модуль экспортирует наружу только то, что нужно другим слоям.
- Внешние импорты идут только через `index`‑файл модуля.
- Внутренние файлы не импортируются напрямую извне.
Компоненты располагаются в:
- `shared/ui/` — переиспользуемые компоненты без бизнес-контекста
- `ui/` внутри master component'а — дочерние компоненты *(подробнее в разделе [Master component](#master-component))*
### Границы ответственности
### Сегменты
- Бизнес‑логика не размещается в UIкомпонентах.
- UIкомпоненты должны быть максимально простыми и предсказуемыми.
- Связь между независимыми сценариями поднимается на уровень выше.
Сегмент — папка внутри компонента, группирующая код по техническому назначению. Набор не фиксирован.
### Типовые ошибки
| Сегмент | Назначение |
|---------|-----------|
| `styles/` | Стили |
| `types/` | Интерфейсы, типы, enums, DTO |
| `ui/` | Компоненты, провайдеры и любые другие элементы интерфейса |
| `stores/` | Сторы состояния |
| `hooks/` | React-хуки |
| `services/` | Внешние источники данных |
| `lib/` | Утилиты |
| `helpers/` | Вспомогательные функции |
| `config/` | Константы, конфигурация |
- Импорт из более высокого слоя в более низкий.
- Смешивание логики нескольких слоёв в одном модуле.
- Прямые импорты внутренних файлов, минуя публичный API.
### Master component
Master component — это обычный компонент, на который наложен ряд дополнительных правил.
Эти правила определяют его место в архитектуре и границы зависимостей.
- Может располагаться только в слоях: `screens`, `layouts`, `widgets`, `features`, `entities`
- Импортирует master component'ы только из слоёв ниже по иерархии
- Корневой `.tsx` именуется с суффиксом слоя: `header.widget.tsx`, `auth.feature.tsx`
- Корневой `.tsx` необязателен — `index.ts` может экспортировать несколько сущностей напрямую
- Дочерние компоненты в `ui/` доступны снаружи только через `index.ts`
- Компоненты внутри одного `ui/` могут импортировать друг друга
<!-- /basics/code-style -->
## Стиль кода
@@ -399,166 +537,10 @@ const options = { id: 1,name: 'User' };
const config = { url: '/api/users', method: 'GET', params: { page: 1, pageSize: 20 } };
```
<!-- /basics/naming -->
## Именование
Именование должно быть предсказуемым, коротким и отражать смысл сущности.
### Базовые правила
| Что | Рекомендуется |
| ---------------- | ---------------------- |
| Папки | `kebab-case` |
| Файлы | `kebab-case` |
| Переменные | `camelCase` |
| Константы | `SCREAMING_SNAKE_CASE` |
| Классы | `PascalCase` |
| React-компоненты | `PascalCase` |
| Хуки | `useSomething` |
| CSS классы | `camelCase` |
### Архитектурный неймспейс
Соглашение о суффиксах, которые обозначают слой (уровень абстракции), роль или тип файла.
- Суффиксы используются для обозначения слоя, роли или типа файла.
- Суффиксы всегда пишутся в единственном числе.
- Формат имени: `name.<suffix>.ts` или `name.<suffix>.tsx`.
**UI и слои FSD**
- `.screen.tsx` — экран
- `.layout.tsx` — layout
- `.widget.tsx` — виджет
- `.feature.tsx` — UI фичи
- `.entity.tsx` — UI сущности
Остальные `.tsx` файлы (компоненты в `shared/ui/`, дочерние компоненты в `ui/`) не помечаются суффиксами — расширение `.tsx` само по себе означает UIкомпонент.
**Логика и модель**
- `.store.ts` — стор
- `.service.ts` — сервис
**Типы и контракты**
- `.type.ts` — типы и интерфейсы
- `.interface.ts` — файл с интерфейсами (если нужен отдельный контракт)
- `.enum.ts` — enum
- `.dto.ts` — внешние DTO
- `.schema.ts` — схемы валидации
- `.constant.ts` — константы
- `.config.ts` — конфигурация
**Утилиты и хелперы**
- `.util.ts` — утилиты
- `.helper.ts` — вспомогательные функции
- `.lib.ts` — вспомогательные функции
**Тесты**
- `.test.ts` / `.test.tsx`
- `.mock.ts`
**Хорошо**
```text
src/
├── screens/
│ └── main/
│ ├── main.screen.tsx
│ └── index.ts
├── features/
│ └── auth-by-email/
│ ├── ui/
│ │ └── login-form.tsx
│ ├── auth-by-email.feature.tsx
│ └── index.ts
└── shared/
└── ui/
└── icon/
├── styles/
│ └── icon.module.css
├── types/
│ └── icon.interface.ts
├── icon.tsx
└── index.ts
```
**Плохо**
```text
// Плохо: нет единых правил для слоёв и публичных файлов.
src/
├── screens/
│ └── Main/
│ └── Main.tsx
└── features/
└── authByEmail/
└── login-form.tsx
```
### Булевы значения
- Использовать префиксы `is`, `has`, `can`, `should`.
**Хорошо**
```ts
const isReady = true;
const hasAccess = false;
const canSubmit = true;
const shouldRedirect = false;
```
**Плохо**
```ts
// Плохо: неясное булево значение без префикса.
const ready = true;
const access = false;
const submit = true;
```
### События и обработчики
- Обработчики начинать с `handle`.
- События и колбэки начинать с `on`.
**Хорошо**
```ts
const handleSubmit = () => { ... };
const onSubmit = () => { ... };
```
**Плохо**
```ts
// Плохо: неочевидное назначение имени.
const submitClick = () => { ... };
```
### Коллекции
- Для массивов использовать имена во множественном числе.
- Для словарей/мап — использовать суффиксы `ById`, `Map`, `Dict`.
**Хорошо**
```ts
const users = [];
const usersById = {} as Record<string, User>;
const userIds = ['u1', 'u2'];
const ordersMap = new Map<string, Order>();
const featureFlagsDict = { beta: true, legacy: false } as Record<string, boolean>;
```
**Плохо**
```ts
// Плохо: имя не отражает, что это коллекция.
const user = [];
// Плохо: словарь назван как массив.
const usersMap = [];
// Плохо: по имени непонятно, что это словарь.
const users = {} as Record<string, User>;
```
<!-- /basics/documentation -->
## Документирование
Документирование должно помогать понять назначение сущности, а не дублировать её типы или очевидные детали.
Этот раздел описывает правила документирования кода: когда и как писать комментарии к функциям, компонентам, типам и интерфейсам.
### Правила
@@ -620,8 +602,7 @@ export enum TodoFilter {
<!-- /basics/typing -->
## Типизация
Типизация обязательна для всех публичных интерфейсов, функций и компонентов.
Цель — предсказуемость, безопасность и автодополнение.
Этот раздел описывает правила типизации: как типизировать компоненты, функции и работу с `any`/`unknown`.
### Общие правила