Compare commits

2 Commits
main ... v2

Author SHA1 Message Date
47658cdbb9 sync 2026-04-20 09:43:43 +03:00
4aeb1dd6b2 feat: Progressive Disclosure документация 2026-04-20 06:40:34 +03:00
118 changed files with 1934 additions and 4842 deletions

View File

@@ -73,7 +73,7 @@ jobs:
ssh -i ~/.ssh/deploy_key root@188.225.47.78 bash -s <<'SCRIPT' ssh -i ~/.ssh/deploy_key root@188.225.47.78 bash -s <<'SCRIPT'
set -e set -e
IMAGE="${{ env.REGISTRY_IMAGE }}:latest" IMAGE="${{ env.REGISTRY_IMAGE }}:latest"
CONTAINER="nextjs-style-guide" CONTAINER="frontend-style-guide"
# Логин в реестр # Логин в реестр
echo '${{ secrets.CR_TOKEN }}' | docker login ${{ env.DOCKER_REGISTRY }} -u '${{ secrets.CR_USER }}' --password-stdin echo '${{ secrets.CR_TOKEN }}' | docker login ${{ env.DOCKER_REGISTRY }} -u '${{ secrets.CR_USER }}' --password-stdin

View File

@@ -3,6 +3,11 @@
При работе с документацией следовать правилам из CONTRIBUTING.md. При работе с документацией следовать правилам из CONTRIBUTING.md.
- Язык документации и коммитов — русский. - Язык документации и коммитов — русский.
- После изменений в `.md`-файлах — запустить `npm run docs` для обновления RULES.md. - Исходники документации — в `src/`, только `.md` файлы.
- При добавлении нового раздела — обновить сайдбар (`.vitepress/config.ts`) - Скрипты и манифесты сборки — в `scripts/`.
и порядок файлов (`concat-md.js`). - Общие правила — в `src/base/`.
- Фреймворк-специфичные — в `src/{framework}/`.
- Точки входа (`DEVELOP.md`, `REVIEW.md`) — в `src/{framework}/`.
- После изменений в `.md`-файлах — запустить `npm run build:ai` для пересборки `dist/ai/`.
- При добавлении нового раздела — добавить файл в `src/` и путь в манифест `scripts/{fw}.build.js`.
- Frontmatter каждого `.md`-файла содержит поля `title`, `scope`, `keywords`, `when`.

View File

@@ -1,201 +1,129 @@
# Правила работы над документацией # Правила написания документации
Мета-документ: как устроен проект, как писать и редактировать разделы. Как писать и редактировать разделы стайлгайда.
## О проекте ## Типы разделов
Документационный сайт с правилами и стандартами фронтенд-разработки на Next.js + TypeScript. ### Базовые правила (`basics/`)
- Движок: VitePress
- Языки: русский (основной), английский
- Русская версия: `docs/ru/`
- Английская версия: `docs/en/`
## Команды
| Команда | Что делает |
|---------|-----------|
| `npm run dev` | Локальный сервер разработки |
| `npm run build` | Сборка статического сайта |
| `npm run docs` | Генерация `generated/{lang}/RULES.md` — единый файл для AI-ассистентов |
## Структура файлов
```
docs/
├── ru/ # Русская версия (основная)
│ ├── index.md # Главная страница
│ ├── basics/ # Базовые правила
│ │ ├── tech-stack.md
│ │ ├── architecture.md
│ │ ├── code-style.md
│ │ ├── naming.md
│ │ ├── documentation.md
│ │ └── typing.md
│ └── applied/ # Прикладные разделы
│ ├── vscode.md
│ ├── project-structure.md
│ ├── components.md
│ ├── page-level.md
│ ├── templates-generation.md
│ ├── styles.md
│ ├── images-sprites.md
│ ├── svg-sprites.md
│ ├── video.md
│ ├── api.md
│ ├── stores.md
│ ├── hooks.md
│ ├── fonts.md
│ └── localization.md
├── en/ # Английская версия (зеркало ru/)
.vitepress/
├── config.ts # Конфигурация VitePress, сайдбары, локали
generated/
├── ru/RULES.md # Сгенерированный единый файл (ru)
└── en/RULES.md # Сгенерированный единый файл (en)
concat-md.js # Скрипт генерации RULES.md
```
### Добавление нового раздела
1. Создать `.md`-файл в нужной папке (`basics/` или `applied/`).
2. Добавить пункт в сайдбар — `.vitepress/config.ts` (оба языка, если есть перевод).
3. Добавить файл в массив `fileOrder``concat-md.js` (для генерации RULES.md).
## Два типа документации
### Базовые правила
**Отвечает на вопрос:** «Каким должен быть любой код?» **Отвечает на вопрос:** «Каким должен быть любой код?»
Универсальные стандарты, **не привязанные к конкретной области**. Универсальные стандарты, не привязанные к конкретной области.
Правило базовое, если оно применимо ко всему коду одинаково: именование переменных, оформление импортов, когда использовать `type` vs `interface`. Правило базовое, если оно применимо ко всему коду одинаково.
Примеры в базовых правилах допускаются, но служат иллюстрацией принципа, а не инструкцией по конкретной области. **Граница:** если правило касается только одной области — оно прикладное.
**Граница:** если правило касается только одной области (только стили, только компоненты, только API) — оно живёт в прикладном разделе, не в базовых. ### Прикладные разделы (`applied/`)
### Прикладные разделы
**Отвечает на вопрос:** «Как работать с X?» **Отвечает на вопрос:** «Как работать с X?»
Полное описание конкретной области: структура файлов, правила, именование, типизация, примеры. Полное описание конкретной области: структура файлов, правила, именование, типизация, примеры.
**Граница:** прикладной раздел не дублирует базовые правила. **Граница:** не дублирует базовые правила. Если правило уже описано в базовых — ссылается, но не повторяет.
Если правило уже описано в базовых — прикладной раздел ссылается на него, но не повторяет.
## Структура прикладного раздела ### Триггеры (`triggers/`)
Шаблон ниже описывает все допустимые секции. Раздел включает только те секции, которые для него релевантны — пустые секции не создаются. **Отвечает на вопрос:** «Как выполнить задачу X?»
```markdown Конкретная инструкция: какие разделы прочитать, какие шаги выполнить. Триггер ссылается на basics/ и applied/, но не дублирует их. Группируются по роли: `triggers/develop/`, `triggers/review/`, `triggers/architect/`.
# {Название}
Краткое описание: о чём раздел и какие аспекты работы с областью он охватывает. Структура триггера:
## Что нужно знать - **Заголовок** — глагол + объект ("Создать компонент", "Добавить иконку")
- **Описание** — одно предложение: что делает триггер
- **Прочитай перед началом** — ссылки на basics/ и applied/
- **Шаги** — нумерованный список действий со ссылками
- **Смежные триггеры** — ссылки на связанные задачи
- **Проверь себя** — чеклист из 2-5 пунктов для самопроверки
Неочевидная информация, которую читатель должен знать перед чтением раздела. ### Фреймворк-специфичные (`{framework}/`)
Если для раздела нет такой вводной — секция не создаётся.
## Структура Разделы и триггеры, которые применимы только к конкретному фреймворку. Те же категории — `applied/` и `triggers/`.
Файловая организация: какие файлы создавать и куда класть. **Граница:** если правило одинаково для всех фреймворков — оно в `base/`.
Обязательно — дерево файлов через code-block.
## Правила ## Frontmatter
Конкретные требования, специфичные для области. Делятся на две подсекции:
### Реализация
Как написан код внутри файла: синтаксис, паттерны, API.
Отвечает на вопрос: «Как писать код?»
Примеры: объявление через `const`, деструктуризация пропсов, формат вызова `cl()`, способ подключения стилей, структура хука.
### Организация
Как компонент/модуль встроен в проект: файловые границы, зоны ответственности, экспорт.
Отвечает на вопрос: «Где что лежит и за что отвечает?»
Примеры: один компонент — один файл, вложенные компоненты в `ui/`, логика выносится в `model/`.
Формат обеих подсекций — маркированный список.
Для неочевидных случаев — блоки «Хорошо / Плохо».
Если в области нет правил одной из категорий — подсекция не создаётся.
## Именование
Соглашения по именам, специфичные для этой области.
Только то, что НЕ покрыто в базовом разделе «Именование».
## Типизация
Правила типизации, специфичные для этой области.
Только то, что НЕ покрыто в базовом разделе «Типизация».
## Документирование
Что и как документировать в этой области.
Только то, что НЕ покрыто в базовом разделе «Документирование».
## Примеры
Полноценные примеры кода.
Каждый пример с путём к файлу и пояснениями.
```
### Порядок секций
Порядок фиксированный: контекст → структура → правила → специализации базовых правил → примеры.
Логика: читатель сначала понимает «что это», потом «где это лежит», потом «как это делать», и в конце видит полный пример.
### Секции-расширения базовых правил
«Именование», «Типизация», «Документирование» в прикладном разделе — это **точки расширения** базовых правил.
- В базовых описано общее: `camelCase` для переменных, `type` vs `interface`, формат JSDoc.
- В прикладном разделе описано специфичное: как именовать CSS-классы (стили), как типизировать пропсы компонентов (компоненты), как документировать хуки (хуки).
Если для области нет специфики по именованию, типизации или документированию — секция не создаётся.
## Конвенции оформления
### Frontmatter
Каждый `.md`-файл начинается с YAML frontmatter: Каждый `.md`-файл начинается с YAML frontmatter:
```yaml ```yaml
--- ---
title: Название раздела title: Название раздела
scope: basics | applied | triggers
keywords: [ключевое слово 1, ключевое слово 2]
when: "Когда агенту читать этот раздел"
--- ---
``` ```
Значение `title` совпадает с текстом `h1`-заголовка в файле. | Поле | Описание |
|------|----------|
| `title` | Название раздела. Совпадает с `h1` в файле |
| `scope` | Тип: `basics`, `applied` или `triggers` |
| `keywords` | Ключевые слова для поиска агентом |
| `when` | Описание ситуации, когда раздел релевантен |
## Структура прикладного раздела
Раздел включает только релевантные секции — пустые не создаются.
```markdown
# {Название}
Краткое описание: о чём раздел.
## Что нужно знать
Неочевидная вводная информация (если есть).
## Структура
Файловая организация. Обязательно — дерево файлов.
## Правила
### Реализация
Как писать код: синтаксис, паттерны, API.
### Организация
Где что лежит: файловые границы, зоны ответственности, экспорт.
## Именование
Специфичные для области соглашения (не покрытые в basics/naming).
## Типизация
Специфичные для области правила (не покрытые в basics/typing).
## Документирование
Специфичные для области правила (не покрытые в basics/documentation).
## Примеры
Полноценные примеры кода с путями к файлам.
```
Порядок фиксированный: контекст -> структура -> правила -> специализации базовых -> примеры.
## Конвенции оформления
### Заголовки ### Заголовки
- Один `h1` на файл — совпадает с `title` из frontmatter. - Один `h1` на файл — совпадает с `title` из frontmatter.
- Сразу после `h1` — вводный абзац (одно-два предложения). - Сразу после `h1` — вводный абзац.
- Основные секции — `h2`. - Основные секции — `h2`. Подсекции — `h3`. `h4` не используется.
- Подсекции внутри `h2``h3`.
- `h4` не используется.
### Примеры кода ### Примеры кода
- Блоки кода с указанием языка: ` ```tsx `, ` ```css `, ` ```bash `, ` ```text `. - Блоки кода с указанием языка: ` ```tsx `, ` ```css `, ` ```bash `, ` ```text `.
- Путь к файлу указывается перед блоком кода текстом или комментарием внутри блока. - Путь к файлу перед блоком кода или комментарием внутри.
- Дерево файлов — ` ```text ` с символами `├──`, `└──`, `│`. - Дерево файлов — ` ```text ` с символами `├──`, `└──`, `│`.
### Блоки «Хорошо / Плохо» ### Блоки «Хорошо / Плохо»
Используются для контрастного сравнения правильного и неправильного подхода.
Формат:
```markdown ```markdown
**Хорошо:** **Хорошо:**
@@ -212,16 +140,16 @@ title: Название раздела
### Таблицы ### Таблицы
Используются для структурированных перечислений: настройки, команды, соответствия.
Формат — стандартный Markdown: `| Ключ | Описание |`. Формат — стандартный Markdown: `| Ключ | Описание |`.
### Ссылки между разделами ### Ссылки между разделами
Прикладной раздел может ссылаться на другие разделы, но не дублирует их содержимое. Ссылаться можно, дублировать содержимое — нет.
## Принципы ## Принципы
1. **Не дублировать.** Одна мысль живёт в одном месте. Остальные ссылаются. 1. **Не дублировать.** Одна мысль одно место. Остальные ссылаются.
2. **Базовое vs прикладное.** Если правило применимо ко всему коду — оно базовое. Если только к одной области — прикладное. 2. **Базовое vs прикладное.** Применимо ко всему коду — базовое. К одной области — прикладное.
3. **Пустые секции не создавать.** Если для раздела нет специфики по именованию — секции «Именование» в нём нет. 3. **Общее vs специфичное.** Одинаково для всех фреймворков — в `base/`. Для одного — в `{framework}/`.
4. **Примеры обязательны.** Прикладной раздел без примеров кода — незавершён. 4. **Пустые секции не создавать.**
5. **Примеры обязательны.** Прикладной раздел без примеров — незавершён.

View File

@@ -1,19 +0,0 @@
# Ассистент
## Для ассистента
- Всегда используй Русский язык для общения и генерации документации/комментариев/коммитов.
- Всегда следуй этим правилам при генерации кода и ответах.
- Всегда пиши план действий перед генерацией кода.
- Всегда спрашивай разрешения у пользователя перед генерацией кода.
- Всегда проверяй, что код соответствует линтингу и форматированию.
- Всегда сверяйся с чек-листом при генерации кода.
- Не предлагай решения, которые противоречат этим правилам этого файла.
- Если не уверен — уточни у пользователя, не гадай, не придумывай.
## Обязательность чек-листов
- Все чек-листы, приведённые в правилах, обязательны к исполнению.
- Ассистент обязан сверяться с чек-листом при выполнении любой задачи, связанной с кодом.
- Нельзя сокращать, игнорировать или опускать пункты чек-листа — каждый пункт должен быть выполнен или явно отмечен как невыполнимый с объяснением причины.
- В каждом ответе, связанном с генерацией или изменением кода, ассистент обязан ссылаться на соответствующий чек-лист и подтверждать его выполнение.

View File

@@ -1,84 +0,0 @@
---
title: Stores
---
# Stores
## Сторы (Stores)
> В этом разделе собраны основные правила и рекомендации по созданию и оформлению сторов. Следуйте этим принципам, чтобы обеспечить чистую архитектуру, удобство поддержки и единый стиль работы с состоянием в проекте.
> В проекте для организации состояния используется только библиотека Zustand.
### Структура
- Store размещается в файле `<store-name>.store.ts` в папке `stores/` на своём уровне абстракции согласно архитектуре проекта.
- Интерфейс состояния описывается в этом же файле с суффиксом `State` (PascalCase).
- Для каждого store создаётся отдельный хук доступа (например, `useTodoStore`).
- Для глобальных сторов используйте только `shared/store`.
### Именование
- Соблюдайте [правила именования файлов и папок](#правила-именования-файлов-и-папок):
- Файл store — `<store-name>.store.ts` (kebab-case).
- Имя интерфейса состояния — PascalCase с суффиксом `State`.
- Имя хука — camelCase с префиксом `use`.
### Требования
- В store допускается только хранение состояния и методы управления им, без бизнес-логики, асинхронных операций и side-effects (см. раздел "Правила организации и использовалья Store").
- Для методов, изменяющих состояние через set, если используется функция — тело функции в фигурных скобках, return с новой строки после стрелки.
- Не дублируйте логику между сторами.
### Типизация
- Всегда указывайте типы для всех полей состояния и методов.
- Не используйте неявное приведение типов и не полагайтесь на автоматический вывод, если это может снизить читаемость или безопасность.
### Документирование
- Документируйте только назначение store и смысл полей, строго по [правилам документирования кода](#правило-для-документирования-кода).
### Экспорт
- Экспортируйте хук доступа к store и интерфейс состояния через `index.ts` слоя/компонента.
### Примеры
```ts
import { create } from 'zustand';
import { TodoItem } from './types/todo-item.interface';
/**
* Состояние хранилища задач.
*/
export interface TodoStoreState {
/** Массив задач. */
items: TodoItem[];
/** Добавить задачу. */
addTodo: (item: TodoItem) => void;
/** Удалить задачу. */
removeTodo: (id: string) => void;
}
/**
* Хук для доступа к хранилищу задач.
*/
export const useTodoStore = create<TodoStoreState>((set) => ({
items: [],
addTodo: (item) => set((state) => {
return {
items: [...state.items, item],
};
}),
removeTodo: (id) => set((state) => {
return {
items: state.items.filter((t) => t.id !== id),
};
}),
}));
```
### Чек-лист
- [ ] Store размещён в `stores/<store-name>.store.ts` на своём уровне абстракции согласно архитектуре проекта.
- [ ] Именование файлов и сущностей соответствует [правилам именования файлов и папок](#правила-именования-файлов-и-папок).
- [ ] Все поля и методы строго типизированы (см. [общие правила типизации](#общие-правила-типизации)).
- [ ] В store только состояние и методы управления им, без бизнес-логики и side-effects.
- [ ] Для методов, изменяющих состояние через set, используется функция с return с новой строки.
- [ ] Документировано только назначение store и смысл полей (см. [правила документирования кода](#правило-для-документирования-кода)).
- [ ] Нет неиспользуемого или невалидного кода.
- [ ] Экспорт через индексный файл.

View File

@@ -1,227 +0,0 @@
---
title: CSS
---
# CSS
## Правила оформления и стилизации CSS-кода
- **Препроцессоры**
Используй PostCSS и модули для стилизации.
- **Архитектура написания стилей**
Используй подход **Mobile First**
Используй CSS переменные для стилизации.
Используй Custom Media Queries для адаптивных стилей.
Используй BEM для именования классов.
Между каждым CSS-правилом (селектором) должен быть один пустой сброс строки, пример:
```css
.todo-list {
max-width: 600px;
padding: var(--space-3);
@media (--md) {
max-width: 800px;
}
}
.todo-list__text {
font-size: 18px;
@media (--md) {
font-size: 22px;
}
}
```
Запрещено писать правила подряд без пустой строки:
```css
/* Так делать нельзя! */
.todo-list { ... }
.todo-list__text { ... }
```
- **Методология именования классов**
Использовать методологию **BEM** для именования классов.
- Блок: kebab-case, пример `.user-bar { }`
- Елемент: kebab-case, соеденный с блоком двойным нижним подчеркиванием, пример `.user-bar__slide { }`
- Модификатор: kebab-case, отдельный самостоятельный класс, **не соединяется** с блоком/елементом, имя модификатора всегда начинается с нижнего подчеркивания, пример: `._red { }`
- **Единицы измерения**
Используй `px` как основная единица измирения, так-же допускается использовать остальные единицы измерения если того требует реализуемый дизайн.
- **Импорт стилей**
Стили компонента должны импортироваться только внутри соответствующего компонента.
Запрещено импортировать стили одного компонента в другой.
Запрещено импортировать `css переменные` в файлы стилей, они доступны глобально.
Запрещено импортировать `custom media` в файлы стилей, они доступны глобально.
- **Переменные**
Все значения переменных нужно писать в `/shared/styles` или в Mantine ThemeProvider.
Все что не является цветами, брекпоинтами, отступами, скруглением допускаются использоваться в компонентах.
Обязательное создавай CSS перменные для:
- "Цветов", пример: `--color-danger: red;`.
- "Брекпоинты", описываем в (Сustom media) пример: `@custom-media --md (min-width: 62em);`.
- "Отспупы (--space)", , пример: `--space-1: 4px;`, `--space-2: 8px;`, `--space-3: 12px;` итд..
- "Скругление углов (--radius)", пример: `--radius-1: 4px;`,`--radius-2: 8px;`,`--radius-3: 12px;` итд..
- **Вложенность селекторов**
Запрещено использовать вложенность селекторов.
Разрешено использовать вложенность только для:
- Псевдо-классов `:hover`, `:active` итд..
- Псевдо-елементов `::before`, `::after`
- Медиа запросов `@media`
- Классы **модификаторы** по методологии BEM
Каждый вложенный селектор отделяется 1 пустой строкой.
- **Медиа запросы**
Строго запрещено использовать `@media` без вложения в селектор.
Строго запрещено использовать в теле `@media` любые селекторы.
Разрешено использовать только Custom Media Queries (например, `@media (--md) {}`).
Запрещено использовать любые произвольные значения breakpoints (например, max-width: 768px).
**Пример как правильно писать @media**
```css
.todo-list {
max-width: 600px;
padding: 24px;
@media (--md) {
max-width: 800px;
}
}
.todo-list__text {
font-size: 18px;
@media (--md) {
font-size: 22px;
}
}
```
**Пример как неправильно писать @media**
```css
// Медиа запрос не вложен в селектор
@media (--md) {
.todo-list {
max-width: 600px;
padding: 24px;
}
.todo-list__text {
font-size: 18px;
}
}
// Используется стандартный `min-width: 992px` вмето Custom Media Queries
@media (min-width: 992px) {
// Внутри @media запроса используются селекторы
.todo-list {
max-width: 600px;
padding: 24px;
}
.todo-list__text {
font-size: 18px;
}
}
```
- **Глобальные стили и сбросы**
Все глобальные стили (например, сбросы) должны располагаться в отдельном файле, например, `src/app/styles/global.css`.
- **Использование Mantine и PostCSS**
Для стандартных визуальных компонентов (кнопки, инпуты, layout, grid, notifications и т.д.) использовать только Mantine и его ThemeProvider.
Запрещено использовать в Mantine компонентах его props/styling, вмето этого нужно добавлять кастомные стили PostCSS.
Кастомные стили допускаются только в случае, если требуемый дизайн невозможно реализовать средствами Mantine.
При написании кастомных стилей стараться использовать переменные и токены Mantine, если это возможно.
- **Порядок CSS-свойств**
В стилях рекомендуется придерживаться логического порядка свойств:
1. Позиционирование (position, top, left, z-index и т.д.)
2. Блочная модель (display, width, height, margin, padding и т.д.)
3. Оформление (background, border, box-shadow и т.д.)
4. Текст (font, color, text-align и т.д.)
5. Прочее (transition, animation и т.д.)
- **Комментарии**
В стилях запрещено использовать комментарии.
- **Дублирования**
Не дублировать стили между компонентами. Общие стили выносить в shared/styles или использовать переменные.
- **Примеры кода стилей**
Пример как хорошо:
```css
/* Блок BEM */
.user-bar {
display: none;
color: black;
/* Медиа запрос custom media и отделяется 1 пустой строкой */
@media (--md) {
display: flex;
}
}
/* Елемент BEM отделяется 1 пустой строкой*/
.user-bar__button-next {
background-color: #f0f0f0;
/* Псевдо-класс отделяется 1 пустой строкой*/
&:hover {
background-color: #e0e0e0;
}
/* Модификатор BEM отделяется 1 пустой строкой*/
&._blue {
background-color: #2b2bbe;
}
/* Модификатор BEM отделяется 1 пустой строкой*/
&._green {
background-color: #29c53d;
}
}
```
Пример как плохо писать:
```css
.user-bar {
display: none;
color: black;
&__button {
&_next {
background-color: #f0f0f0;
&:hover {
background-color: #e0e0e0;
}
&._blue {
background-color: #2b2bbe;
}
&._green {
background-color: #29c53d;
}
}
}
}
@media (min-width: 992px) {
.user-bar {
display: flex;
}
}
```
**Чек лист для проверки стилизации.**
- [ ] Используется PostCSS и CSS-модули для стилизации.
- [ ] Применён подход Mobile First.
- [ ] Именование классов строго по BEM:
- [ ] Модификатор — отдельный класс, начинается с нижнего подчёркивания (например, `._red`, `._active`)
- [ ] Все CSS-переменные (цвета, брейкпоинты, отступы, скругления) определены только в `/shared/styles` или через Mantine ThemeProvider.
- [ ] Для медиа-запросов используются только custom media переменные из `/shared/styles/media.css`.
- [ ] Соблюдается правила вложености селекторов.
- [ ] Соблюдается правила отступов селекторов.
- [ ] Глобальные стили (reset) вынесены в отдельный файл, остальные стили — модульные.
- [ ] Для стандартных UI-элементов используются только компоненты Mantine, кастомные стили — только при необходимости.
- [ ] В Mantine-компонентах не используются props/styling для стилизации, только PostCSS.
- [ ] Кастомные стили используют переменные и токены Mantine, если это возможно.
- [ ] В стилях нет комментариев.
- [ ] Стили компонента импортируются только внутри соответствующего компонента.
- [ ] Нет импорта стилей одного компонента в другой.
- [ ] Нет импорта файлов переменных и custom media — они доступны глобально.
- [ ] Нет дублирования стилей между компонентами, общие стили вынесены в shared/styles или используются переменные.

View File

@@ -1,88 +0,0 @@
---
title: Компоненты
---
# Компоненты
## Правила создания и работы с компонентами.
### 1. Структура компонента
Ассистент при создании/рефакторинге компонента должен **строго** придерживаться следующей структуры файлов и папок:
```
component-name/
index.ts
component-name.tsx
styles/
component-name.module.css
locales/
ru.json
en.json
types/
component-name.interface.ts
component-name.type.ts
component-name.enum.ts
schemas/
schema-name.schema.ts
utils/
util-name.util.ts
hooks/
use-hook-name.hook.ts
stores/
store-name.store.ts
ui/
... # вложенные компоненты для component-name
```
Пояснения к структуре компонента:
**Обязательные файлы** обязательны для всех компонентов, даже если они пустые.
- component-name/: Папка компонента корень для всего компонента.
- index.ts: экспортирует главный компонент, интерфейс и всё, что может быть переиспользовано.
- component-name.tsx: главный компонент.
- styles/component-name.module.css: стили компонента.
- locales/ru.json: локализация на русском языке.
- locales/en.json: локализация на английском языке.
- types/component-name.interface.ts: интерфейс пропсов компонента.
**Не обязательные файлы** добавляются только при необходимости
- types/component-name.type.ts: типы компонента.
- types/component-name.enum.ts: enum компонента.
- schemas/schema-name.schema.ts: схемы валидации.
- utils/util-name.util.ts: утилиты компонента.
- hooks/use-hook-name.hook.ts: хуки компонента.
- stores/store-name.store.ts: хранилища состояния компонента.
- ui/: Папка для вложенных компонентов.
### Требования к компоненту
- Использовать `memo()` для всех компонентов, которые принимают пропсы.
- Использовать `useMemo` для всех вычислений, которые передаются в пропсы других компонентов.
- Использовать `useCallback` для всех функций/методов, которые передаются в пропсы других компонентов.
### Требования к вложенным компонентам
- Вложенный компонент — это полноценный компонент, который обязан полностью соблюдать все правила, описанные для компонентов (структура, именование, документация, типизация, стилизация и т.д.).
- Все вложенные компоненты размещаются только в папке ui/ основного компонента.
**Пояснение**
Нет необходимости повторять структуру и требования — вложенный компонент подчиняется тем же правилам, что и любой другой компонент, только располагается в папке ui/ родительского компонента.
### Требования к локализации
- Все добавленные локализации обязательно подключать в экземпляр `app/i18n` (чтобы новые namespace были доступны для i18next).
---
### Чек-лист для создания нового компонента
- [ ] Главный компонент размещён в корне и назван по правилу PascalCase.
- [ ] Создан файл стилей в папке `styles/`, имя в kebab-case, используется BEM.
- [ ] Все классы применяются через `className={styles['component-name']}`.
- [ ] Создана папка `locales/` с файлами `ru.json` и `en.json`.
- [ ] Создан файл интерфейса пропсов в папке `types/`, даже если интерфейс пустой.
- [ ] Создан файл `index.ts` с экспортом главного компонента и интерфейса.
- [ ] Внутренние компоненты (если есть) размещены в папке `ui/`.
- [ ] Все важные части кода документированы по TSDoc (см. раздел 16).
- [ ] Остальные файлы (schemas, дополнительные типы, enum) добавлены только при необходимости.
- [ ] Именование файлов и папок соответствует правилам (см. выше).
- [ ] Нет неиспользуемого или невалидного кода.
- [ ] Для компонентов с пропсами используется `React.memo`.
- [ ] Для вычислений, передаваемых в пропсы, используется `useMemo`.
- [ ] Для функций, передаваемых в пропсы, используется `useCallback`.
- [ ] Все тексты вынесены в локализационные файлы и используются через i18n.
- [ ] Новые namespace подключены в экземпляр i18n.

View File

@@ -1,68 +0,0 @@
# Хуки (React Hooks)
> В проекте для создания пользовательских хуков используется только React (функциональные компоненты и хуки).
> В этом разделе собраны основные правила и рекомендации по созданию и оформлению хуков. Следуйте этим принципам, чтобы обеспечить чистую архитектуру, переиспользуемость и единый стиль работы с хуками в проекте.
## Рекомендации по использованию сторонних хуков
- Если есть возможность, используйте хуки Mantine в компонентах и кастомных хуках для работы с состоянием, темизацией, медиа-запросами и другими возможностями библиотеки.
- Не дублируйте функциональность, уже реализованную в Mantine.
## Структура
- Каждый хук размещается в отдельном файле с именем `use-<hook-name>.hook.ts` в папке `hooks/` на своём уровне абстракции согласно архитектуре проекта.
- Имя хука — в стиле camelCase с префиксом `use` (например, `useTodoFilter`).
- Для сложных возвращаемых структур использовать отдельные типы или интерфейсы, размещая их в папке `types/` на своём уровне абстракции.
## Именование
- Соблюдайте [правила именования файлов и папок](#правила-именования-файлов-и-папок):
- Файл хука — `use-<hook-name>.hook.ts` (kebab-case).
- Имя хука — camelCase с префиксом `use`.
## Требования
- Хук должен быть строго типизирован: все параметры, возвращаемые значения и внутренние переменные должны иметь явные типы.
- Не хранить бизнес-логику, связанную с несколькими слоями — хук должен быть изолирован в рамках своего слоя/feature.
- Не дублировать логику между хуками — общие части выносить в shared.
- Не использовать side-effects вне useEffect/useLayoutEffect.
- Для мемоизации возвращаемых значений и функций использовать useMemo и useCallback.
- Не использовать устаревшие или неразрешённые паттерны React.
## Типизация
- Всегда явно указывать типы для всех параметров, возвращаемых значений и состояния внутри хука.
- Не используйте неявное приведение типов и не полагайтесь на автоматический вывод, если это может снизить читаемость или безопасность.
## Документирование
- Документируйте только назначение хука (описание), строго по [правилам документирования кода](#правило-для-документирования-кода).
## Экспорт
- Экспортируйте хук только именованным экспортом через `index.ts` слоя/компонента.
## Примеры
```ts
import { useMemo } from 'react';
import { TodoItem } from '../types/todo-item.interface';
import { TodoStatus } from '../types/todo-status.enum';
/**
* Хук фильтрации задач по статусу.
*/
export const useTodoFilter = (items: TodoItem[], filter: TodoStatus): TodoItem[] => {
return useMemo(() => {
if (filter === TodoStatus.ALL) return items;
if (filter === TodoStatus.ACTIVE) return items.filter((t) => !t.completed);
return items.filter((t) => t.completed);
}, [items, filter]);
};
```
## Чек-лист
- [ ] Хук размещён в файле `use-<hook-name>.hook.ts` в папке `hooks/` на своём уровне абстракции согласно архитектуре проекта.
- [ ] Именование файлов и сущностей соответствует [правилам именования файлов и папок](#правила-именования-файлов-и-папок).
- [ ] Все параметры, возвращаемые значения и внутренние переменные строго типизированы.
- [ ] Вся бизнес-логика изолирована в рамках слоя/feature.
- [ ] Нет дублирования логики между хуками.
- [ ] Для мемоизации используется useMemo/useCallback.
- [ ] Не используются side-effects вне useEffect/useLayoutEffect.
- [ ] Документировано только назначение хука (см. [правила документирования кода](#правило-для-документирования-кода)).
- [ ] Нет неиспользуемого или невалидного кода.
- [ ] Экспорт только именованный через индексный файл.

View File

@@ -1,124 +0,0 @@
# Хуки API (React Hooks)
> В проекте для работы с API-хуками используется только React и библиотека SWR для получения данных (GET-запросы).
> В этом разделе собраны основные правила и рекомендации по созданию и оформлению хуков для работы с API. Следуйте этим принципам, чтобы обеспечить чистую архитектуру, переиспользуемость и единый стиль работы с API-хуками в проекте.
## Описание и назначение API-хуков
API-хуки предназначены для получения данных с сервера (GET-запросы) и используются в компонентах или других хуках.
В проекте для этого применяется библиотека SWR, которая обеспечивает кэширование, автоматическое обновление и удобную работу с асинхронными запросами.
**Fetcher** — это функция, которую использует SWR для выполнения запроса к API. В проекте fetcher обычно экспортируется из файла клиента (например, `backendFetcher` из `shared/api/backend/client.ts`) и инкапсулирует логику обращения к конкретному API-клиенту.
**API-клиент** — это отдельный модуль (папка), отвечающий за взаимодействие с конкретным внешним или внутренним API.
API-клиент включает:
- инициализацию экземпляра HTTP-клиента (например, Axios),
- настройку базового URL, интерцепторов и общих обработчиков ошибок,
- организацию всех сущностей и методов для работы с этим API (например, users, auth, orders и т.д.),
- экспорт всех функций, типов и fetcher через индексные файлы.
Каждый API-клиент размещается в папке `src/shared/api/<client-name>/` и имеет собственную структуру согласно архитектуре проекта.
## Структура
- Каждый API-хук размещается в отдельном файле с именем `use-<method-name>.hook-api.ts` в папке `hooks/api/<client-name>/` на своём уровне абстракции согласно архитектуре проекта.
- Имя хука — в стиле camelCase с префиксом `use` (например, `useGetUser`).
- Для сложных возвращаемых структур используйте отдельные типы или интерфейсы, размещая их в папке `types/` на своём уровне абстракции.
## Именование
- Соблюдайте [правила именования файлов и папок](#правила-именования-файлов-и-папок):
- Файл хука — `use-<method-name>.hook-api.ts` (kebab-case).
- Имя хука — camelCase с префиксом `use`.
## Требования
- Хук должен быть строго типизирован: все параметры, возвращаемые значения и внутренние переменные должны иметь явные типы.
- Для получения данных используйте только SWR.
- Не дублируйте логику между хуками — общие части выносите в shared.
- Не используйте side-effects вне useEffect/useLayoutEffect.
## Типизация
- Всегда явно указывайте типы для всех параметров, возвращаемых значений и состояния внутри хука.
- Придерживайтесь [общих правил типизации проекта](#общие-правила-типизации).
- Не используйте неявное приведение типов и не полагайтесь на автоматический вывод, если это может снизить читаемость или безопасность.
## Документирование
- Документируйте только назначение хука (описание), строго по [правилам документирования кода](#правило-для-документирования-кода).
## Экспорт
- Экспортируйте хук только именованным экспортом через `index.ts` слоя/компонента.
## Пример API хука
```ts
// use-get-me.hook-api.ts
import useSWR from 'swr';
import { backendFetcher } from 'shared/api/backend/client';
import { UserDto } from 'shared/api/backend/entities/users/get-me.api';
/**
* Хук для получения информации о текущем пользователе.
*/
export const useGetMe = () => {
const { data, error, isLoading } = useSWR<UserDto>('/users/me', backendFetcher);
return {
data,
error,
isLoading,
};
};
```
### Пример использования хука в компоненте
```tsx
import React from 'react';
import { useGetMe } from 'shared/hooks/api/backend/use-get-me.hook-api';
export const UserInfo: React.FC = () => {
const { data, error, isLoading } = useGetMe();
if (isLoading) {
return <div>Загрузка...</div>;
}
if (error) {
return <div>Ошибка загрузки данных</div>;
}
if (!data) {
return <div>Нет данных о пользователе</div>;
}
return (
<div>
<div>Имя: {data.name}</div>
<div>Email: {data.email}</div>
</div>
);
};
```
## Чек-лист для создания API-хука
- [ ] Для каждого GET-запроса создан отдельный хук.
- [ ] Хук размещён в `hooks/api/<client-name>/use-<method-name>.hook-api.ts` на своём уровне абстракции согласно архитектуре проекта.
- [ ] Именование файлов и сущностей соответствует [правилам именования файлов и папок](#правила-именования-файлов-и-папок).
- [ ] Используется SWR для получения данных.
- [ ] Все параметры, возвращаемые значения и внутренние переменные строго типизированы.
- [ ] Нет дублирования логики между хуками.
- [ ] Не используются side-effects вне useEffect/useLayoutEffect.
- [ ] Документировано только назначение хука (см. [правила документирования кода](#правило-для-документирования-кода)).
- [ ] Нет неиспользуемого или невалидного кода.
- [ ] Экспорт только именованный через индексный файл.
---
## Чек-лист для использования API-хука
- [ ] Импортируется только нужный хук через публичные экспорты (`index.ts`).
- [ ] Использование хука строго по назначению (только для получения данных).
- [ ] Если требуется получить данные через GET-запрос в компоненте — обязательно используется соответствующий API-хук.
**Запрещено вызывать GET-методы API напрямую в компонентах, только через хуки.**
- [ ] Обработка состояний загрузки, ошибки и данных реализована корректно.
- [ ] Не происходит дублирования логики, связанной с получением данных.
- [ ] Нет неиспользуемого или невалидного кода.

View File

@@ -1,242 +0,0 @@
# API
> В этом разделе собраны основные правила и рекомендации по созданию, оформлению и использованию API-клиентов и функций для работы с сервером. Следуйте этим принципам, чтобы обеспечить единый стиль, безопасность и удобство поддержки API-слоя в проекте.
## Описание и назначение API-клиента
API-клиент — это модуль (папка), отвечающий за взаимодействие с конкретным внешним или внутренним API.
В проекте для HTTP-запросов используется только Axios.
API-клиент инкапсулирует:
- инициализацию экземпляра Axios,
- настройку базового URL, интерцепторов, обработчиков ошибок,
- организацию всех сущностей и методов для работы с этим API (например, users, auth, orders и т.д.),
- экспорт всех функций, типов и fetcher через индексные файлы.
Каждый API-клиент размещается в папке `src/shared/api/<client-name>/` и имеет собственную структуру согласно архитектуре проекта.
## Использование методов API
- Все методы API должны использоваться строго внутри блока `try...catch`.
- При вызове методов API всегда используйте полный путь, например:
`await api.backend.createUser({ email, password });`
- Запрещено вызывать методы API вне блока `try...catch` даже в тестах, утилитах и других вспомогательных функциях.
## Структура клиента
```text
src/shared/api/backend/
├── client.ts
├── index.ts
└── entities/
├── users/
│ ├── get-me.api.ts
│ ├── create-user.api.ts
│ ├── update-user.api.ts
│ └── index.ts
├── auth/
│ ├── login.api.ts
│ ├── register.api.ts
│ └── index.ts
└── index.ts
```
## Описание ключевых элементов
- **client.ts**
Экземпляр Axios с настройками, интерцепторами, экспортом fetcher для SWR.
- **index.ts**
Главная точка экспорта: экспортирует client, fetcher, все сущности и их методы.
- **entities/**
Папка для бизнес-сущностей (например, users, auth, orders и т.д.).
- **`<entity>/`**
Папка для отдельной сущности. Имя — в kebab-case, отражает бизнес-область (например, users, auth).
- **`<operation>.api.ts`**
Файл для каждой операции (CRUD, спец. действия).
Внутри:
- DTO (интерфейсы запроса/ответа)
- Функция, реализующая запрос через client
- **index.ts (внутри `<entity>`/)**
Экспортирует все методы и типы этой сущности.
- **index.ts (внутри entities/)**
Экспортирует все сущности (users, auth и т.д.).
## Именование
- Соблюдайте [правила именования файлов и папок](#правила-именования-файлов-и-папок):
- Файл клиента — `client.ts`.
- Файл функции — `<operation>-<entity>.api.ts` (например, `create-user.api.ts`).
- DTO — в папке `dto/` (например, `create-user.dto.ts`).
- Все функции и типы экспортируются через индексные файлы на каждом уровне (сущность, entities, клиент).
## Требования
- Для каждого действия (CRUD, спец. действия) — отдельная функция и файл.
- Все функции используют общий экземпляр Axios из `client.ts`.
- Все функции строго типизированы (используются DTO).
- DTO объявляется в отдельном файле в папке `dto/` перед функцией, которая его использует.
- Для каждого GET метода обязательно должен быть создан API-хук.
- Все API-хуки должны создаваться строго по [документации раздела "Хуки для API"](#хуки-для-api-api-hooks).
## Типизация
- Все функции и DTO строго типизированы.
- Все интерфейсы, типы и enum размещены в папке `types/` на своём уровне абстракции.
- Все DTO размещены в папке `dto/` на своём уровне абстракции.
- Придерживайтесь [общих правил типизации проекта](#общие-правила-типизации).
## Документирование
- Документируйте только назначение функций и DTO.
- В описании указывается только смысл функции/типа.
## Экспорт
- Все функции и типы экспортируются через индексные файлы на каждом уровне (сущность, entities, клиент).
## Примеры
### Пример клиента API
```ts
// client.ts
import axios, { AxiosInstance } from "axios";
export { AxiosError, isAxiosError } from 'axios';
export type { AxiosResponse } from 'axios';
/**
* Экземпляр HTTP-клиента для работы с backend API.
*/
export const backendHttpClient: AxiosInstance = axios.create({
baseURL: '/api',
timeout: 10000,
});
// Интерцептор запроса
backendHttpClient.interceptors.request.use(
(config) => {
// Здесь можно добавить авторизационные заголовки или другую логику
return config;
},
(error) => Promise.reject(error)
);
// Интерцептор ответа
backendHttpClient.interceptors.response.use(
(response) => response,
(error) => {
// Здесь можно обработать ошибки (например, показать уведомление)
return Promise.reject(error);
}
);
```
### Пример DTO
```ts
// dto/create-user.dto.ts
/**
* DTO для создания пользователя.
*/
export interface CreateUserDto {
/** Email пользователя. */
email: string;
/** Пароль пользователя. */
password: string;
}
```
### Пример API-функции
```ts
// create-user.api.ts
import { backendHttpClient } from '../client';
import { CreateUserDto } from './dto/create-user.dto';
/**
* Создать пользователя.
*/
export const createUser = (data: CreateUserDto) => backendHttpClient.post('/users', data);
```
### Пример index.ts (в папке сущности)
```ts
export * from './create-user.api';
export * from './get-user.api';
```
### Пример использования API-функции в компоненте
```tsx
import React, { useState } from 'react';
import { api } from 'shared/api';
export const CreateUserForm: React.FC = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
await api.backend.createUser({ email, password });
console.log('Пользователь создан!');
} catch {
console.log('Ошибка создания пользователя');
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={e => setEmail(e.target.value)}
placeholder="Email"
required
/>
<input
type="password"
value={password}
onChange={e => setPassword(e.target.value)}
placeholder="Пароль"
required
/>
<button type="submit">Создать пользователя</button>
</form>
);
};
```
## Чек-лист для создания клиента
- [ ] Новый клиент размещён в `src/shared/api/<client-name>/`.
- [ ] В корне клиента есть client.ts (экземпляр Axios) и index.ts (главный экспорт).
- [ ] Все бизнес-сущности размещены в entities/, каждая — в отдельной папке.
- [ ] Для каждой операции создан отдельный файл `<operation>`.api.ts с DTO и функцией.
- [ ] DTO объявлен непосредственно перед функцией.
- [ ] В каждой папке сущности есть свой index.ts для экспорта методов и типов.
- [ ] В папке entities/ есть общий index.ts для экспорта всех сущностей.
- [ ] Все экспорты организованы через индексные файлы.
- [ ] Для каждого GET-метода создан отдельный SWR-хук (см. правила API-хуков).
- [ ] Нет дублирования кода и неиспользуемых файлов.
## Чек-лист для использования API
- [ ] Импортируется только нужный метод через публичные экспорты (index.ts).
- [ ] Все вызовы API обёрнуты в try...catch.
- [ ] Используются только строго типизированные методы.
- [ ] Не происходит обращения к Axios напрямую — только через client.
- [ ] Нет дублирования логики и неиспользуемого кода.

View File

@@ -1,21 +0,0 @@
---
title: Общие принципы
---
# Общие принципы
## Стек технологий и библиотеки
- Использовать **TypeScript** для всех файлов логики и компонентов.
- Использовать **FSD (Feature-Sliced Design)**: разделять код на features, entities, processes, widgets, shared.
- Использовать **React** (функциональные компоненты, хуки).
- Использовать **Mantine UI** для UI-компонентов.
- Использовать **Axios** в качестве клиента для работы с API.
- Использовать **SWR** для data fetching (GET-запросы).
- Использовать **Zustand** для глобального состояния.
- Использовать **i18n** для локализации.
- Использовать **Vitest** для тестирования.
- Использовать **PostCSS модули** для стилизации.
- Использовать **BEM** для именований классов в стилях
- Использовать **Mobile First** подход для написания стилей.
- Использовать **Context7** примеров использования библиотек.
- Использовать **i18n** (i18next) для локализации всех пользовательских текстов.

View File

@@ -1,22 +0,0 @@
---
title: Архитектура
---
# Архитектура
## Архитектура проекта
В проекте используется FSD (Feature-Sliced Design) архитектура.
- **FSD-границы**
- Не нарушать границы слоёв (например, feature не может импортировать из widgets).
- Бизнес-логика должна быть вынесена в хуки или сервисы.
- **Импорты**
- Внутри слоя — относительные импорты.
- Между слоями — абсолютные импорты.
- **Требования**
- Не смешивать логику разных слоёв.
- Не хранить бизнес-логику в UI-компонентах.
- **Именование**
- Файлы и папки kebab-case.
---

View File

@@ -1,74 +0,0 @@
---
title: Стиль кода
---
# Стиль кода
## Отступы
Используем 2 пробела для отступов во всём проекте. Не используем табы.
## Кавычки
Используем **одинарные кавычки** для строк в JavaScript/TypeScript, и **двойные кавычки** для атрибутов в JSX/TSX.
**Пример:**
```ts
// JavaScript/TypeScript
const message = 'Привет, мир!';
const name = 'ProjectName';
```
```tsx
// JSX/TSX
<input type="text" placeholder="Введите имя" />
<button title="Сохранить">Сохранить</button>
```
## Строгая типизация
всегда указывать типы для пропсов, возвращаемых значений, параметров функций.
## Ранние возвраты
(early return) для повышения читаемости.
## Мемоизация
Старайся оптимизировать код если это возможно.
## Документирование
Документируем ТОЛЬКО ОПИСАНИЕ (функций, компонентов, типов и их полей).
## any, unknown
запрещено использовать без крайней необходимости.
## Классы в TSX
Для стилизации компонентов используем CSS-модули и методологию BEM. Классы подключаются через объект стилей, импортированный из соответствующего `.module.css` файла.
> Объект стилей всегда импортируется с именем `s` (сокращённо от style), а не `styles`.
**Пример:**
```tsx
import s from './my-component.module.css';
export const MyComponent = () => (
<div className={s['my-component']}>
<button className={s['my-component__button']}>Кнопка</button>
<span className={s['my-component__text']}>Текст</span>
<button className={s['my-component__button'] + ' ' + s._active}>
Активная кнопка
</button>
</div>
);
```
- Имя класса всегда берётся из объекта `s`.
- Для модификаторов используется отдельный класс с нижним подчёркиванием (например, `s._active`).
- Не используйте строковые литералы с классами напрямую — только через объект `s`.

View File

@@ -1,18 +0,0 @@
---
title: Именование
---
# Именование
## Именование файлов и папок
- Папка компонента: kebab-case, совпадает с названием компонента, пример: `component-name`.
- React-компонент: kebab-case, совпадает с названием компонента, пример: `component-name.tsx`.
- Стили: kebab-case, шаблон: `<style-name>.module.css`, пример: `style-name.module.css`.
- Интерфейсы: kebab-case, шаблон: `<interface-name>.interface.ts`, пример: `interface-name.interface.ts`.
- Типы: kebab-case, шаблон: `<type-name>.type.ts`, пример: `type-name.type.ts`.
- Enum: kebab-case, шаблон: `<enum-name>.enum.ts`, пример: `enum-name.enum.ts`.
- Схемы: kebab-case, шаблон: `<schema-name>.schema.ts`, пример: `schema-name.schema.ts`.
- Локализация: kebab-case, пример: `ru.json`, `en.json`.
- Утилиты: kebab-case, шаблон: `<util-name>.util.ts`, пример: `util-name.util.ts`
- React Hooks: kebab-case, шаблон: `use-<hook-name>.hook.ts`, пример: `use-hook-name.hook.ts`
- Хранилища состояния компонента: kebab-case, шаблон: `<store-name>.store.ts`, пример: `store-name.store.ts`

View File

@@ -1,69 +0,0 @@
---
title: Документирование
---
# Документирование
## Правило для документирования кода
- Документировать разрешено только описание (назначение) функций, компонентов, типов, интерфейсов, enum и их полей.
- Строго запрещено документировать параметры, возвращаемые значения, типы пропсов, аргументы, возвращаемые значения функций, компоненты, хуки и т.д.
- В интерфейсах, типах и enum разрешено документировать только смысл (описание) каждого поля или значения.
- В React-компонентах, функциях, хранилищах, схемах, утилитах разрешено документировать только назначение (описание), без детализации параметров и возвращаемых значений.
- Описание должно быть кратким, информативным и реально помогать понять структуру и бизнес-логику.
- Не допускается избыточная или дублирующая очевидное документация.
- В конце описания всегда ставить точку.
**Примеры правильного документирования**
```tsx
/**
* Список задач пользователя.
*/
export const TodoList = memo(() => { ... });
/**
* Интерфейс задачи.
*/
export interface TodoItem {
/** Уникальный идентификатор задачи. */
id: string;
/** Текст задачи. */
text: string;
/** Статус выполнения задачи. */
completed: boolean;
}
/**
* Перечисление фильтров задач.
*/
export enum TodoFilter {
/** Все задачи. */
All = 'all',
/** Только активные задачи. */
Active = 'active',
/** Только выполненные задачи. */
Completed = 'completed',
}
```
**Примеры неправильного документирования**
```ts
// ❌ Не нужно:/
/**
* @param id - идентификатор задачи
* @returns объект задачи
*/
// ❌ Не нужно:/
/**
* @param props - пропсы компонента
* @returns JSX.Element
*/
// ❌ Не нужно:/
/**
* id — идентификатор задачи
* text — текст задачи
* completed — статус выполнения
*/
```

View File

@@ -1,187 +0,0 @@
---
title: Типизация
---
# Типизация
## Общие правила типизации
> Данный раздел определяет единые требования к типизации для всего проекта. Соблюдение этих правил обеспечивает читаемость, предсказуемость и безопасность кода.
- Использовать только строгую типизацию TypeScript для всех файлов логики, компонентов, хуков, API, сторов и утилит.
- Всегда явно указывать типы для:
- Пропсов компонентов
- Параметров функций и методов
- Возвращаемых значений функций и методов
- Всех переменных состояния (в том числе в store)
- Всех значимых переменных и констант, если их тип не очевиден из присваивания
- Не использовать `any` и `unknown` без крайней необходимости. Если использование неизбежно — обязательно добавить комментарий с обоснованием.
- Все интерфейсы, типы и enum всегда размещать в папке `types/` на своём уровне абстракции (например, `features/todo/types/`).
- Для DTO всегда использовать отдельную папку `dto/` на уровне сущности или слоя.
- Для сложных структур использовать отдельные интерфейсы или типы, размещая их в соответствующих файлах в папке `types/`.
- Для DTO, enum, схем и других сущностей — всегда создавать отдельные типы/интерфейсы с осмысленными именами.
- Ключи enum всегда писать ЗАГЛАВНЫМИ_БУКВАМИ (SCREAMING_SNAKE_CASE).
- Не использовать неявное приведение типов и не полагаться на автоматический вывод, если это может снизить читаемость или безопасность.
- Для массивов и объектов всегда указывать тип элементов/ключей.
- Для возвращаемых значений асинхронных функций всегда указывать тип Promise.
- Типизацию коллбеков и функций, передаваемых в пропсы, указывать инлайн, не выносить в отдельные типы.
- Для типизации внешних библиотек использовать официальные типы или создавать собственные декларации при необходимости.
- Не использовать устаревшие или не рекомендуемые паттерны типизации (например, `Function`, `Object`, `{}`).
---
### Примеры
#### Интерфейс и типы для сущностей (всегда в папке types/)
```ts
// features/todo/types/todo-item.interface.ts
/**
* Интерфейс задачи.
*/
export interface TodoItem {
/** Уникальный идентификатор задачи. */
id: string;
/** Текст задачи. */
text: string;
/** Статус выполнения задачи. */
completed: boolean;
}
```
#### Типизация enum (всегда в папке types/)
```ts
// features/todo/types/todo-status.enum.ts
/**
* Перечисление статусов задачи.
*/
export enum TodoStatus {
/** Активная задача. */
ACTIVE = 'active',
/** Выполненная задача. */
COMPLETED = 'completed',
}
```
#### Типизация пропсов компонента
```ts
import { FC, memo } from 'react';
import { TodoItem } from './types/todo-item.interface';
/**
* Список задач.
*/
export interface TodoListProps {
/** Массив задач. */
items: TodoItem[];
}
export const TodoList: FC<TodoListProps> = memo(({ items }) => (
<ul>
{items.map((item) => (
<li key={item.id}>{item.text}</li>
))}
</ul>
));
```
#### Типизация функций и коллбеков (инлайн)
```ts
/**
* Функция фильтрации задач.
*/
export const getCompletedTodos = (items: TodoItem[]): TodoItem[] => {
return items.filter((t) => t.completed);
};
/**
* Колбэк для обработки клика (инлайн).
*/
const handleClick = (id: string): void => {
console.log('Clicked:', id);
};
```
#### Типизация асинхронных функций
```ts
/**
* Получить задачи с сервера.
*/
export const fetchTodos = async (): Promise<TodoItem[]> => {
const response = await fetch('/api/todos');
return response.json();
};
```
#### Типизация состояния в store (интерфейс в types/)
```ts
// features/todo/types/todo-store.interface.ts
/**
* Состояние хранилища задач.
*/
export interface TodoStoreState {
/** Массив задач. */
items: TodoItem[];
/** Добавить задачу. */
addTodo: (item: TodoItem) => void;
/** Удалить задачу. */
removeTodo: (id: string) => void;
}
```
#### Типизация DTO (всегда в папке dto/)
```ts
// features/todo/dto/create-todo.dto.ts
/**
* DTO для создания задачи.
*/
export interface CreateTodoDto {
/** Текст задачи. */
text: string;
}
// features/todo/dto/todo-response.dto.ts
/**
* DTO ответа сервера.
*/
export interface TodoResponseDto {
/** Созданная задача. */
todo: TodoItem;
}
```
#### Типизация внешних библиотек
```ts
import type { AxiosResponse } from 'axios';
export const getData = async (): Promise<AxiosResponse<TodoItem[]>> => {
// ...
};
```
### Чек-лист проверки типизации
- [ ] Все пропсы компонентов явно типизированы через интерфейс или тип в папке `types/`.
- [ ] Все параметры и возвращаемые значения функций и методов явно типизированы.
- [ ] Все переменные состояния (в том числе в store) имеют явные типы.
- [ ] Все интерфейсы, типы и enum размещены в папке `types/` на своём уровне абстракции.
- [ ] Ключи всех enum написаны ЗАГЛАВНЫМИ_БУКВАМИ (SCREAMING_SNAKE_CASE).
- [ ] Все DTO размещены в папке `dto/` на своём уровне абстракции.
- [ ] Не используется `any` и `unknown` без крайней необходимости и поясняющего комментария.
- [ ] Для сложных структур используются отдельные интерфейсы или типы.
- [ ] Для массивов и объектов указан тип элементов/ключей.
- [ ] Для асинхронных функций указан тип Promise с конкретным типом результата.
- [ ] Типы коллбеков и функций, передаваемых в пропсы, указаны инлайн.
- [ ] Не используются устаревшие типы (`Function`, `Object`, `{}`).
- [ ] Для внешних библиотек используются официальные типы или собственные декларации.
- [ ] Нет неявного приведения типов, все типы читаемы и прозрачны.

View File

@@ -1,12 +0,0 @@
---
title: Локализация
---
# Локализация
## Правила использования локализации
- Все пользовательские тексты должны быть вынесены в локализационные файлы.
- Для каждого компонента создавать папку `locales/` с файлами `ru.json`, `en.json` и т.д.
- Новые namespace обязательно регистрировать в экземпляре i18n (см. `app/i18n.ts`).
- В коде использовать только функцию перевода из i18n, не использовать "жёстко" прописанные строки.

View File

@@ -1,57 +1,53 @@
# NextJS Style Guide # Style Guide
Rules and standards for NextJS and TypeScript development: architecture, typing, styles, components, API, and infrastructure. Репозиторий с правилами и стандартами фронтенд-разработки. Исходники документации собираются в разные форматы под разные фреймворки.
## Documentation Structure ## Структура
### Processes ```text
src/ # Исходники — только .md файлы
├── base/ # Общие правила (не поставляется отдельно)
│ ├── basics/ # Базовые: стиль кода, именование, типизация
│ ├── applied/ # Прикладные: компоненты, стили, хуки, API
│ └── triggers/ # Триггеры: создание компонента, стилизация и т.д.
└── nextjs/ # Next.js — самостоятельная единица
├── applied/ # Next.js-специфичные: page-level, project-structure
├── triggers/ # Next.js-специфичные триггеры: create-page, create-layout
├── DEVELOP.md # Точка входа для агента-разработчика
└── REVIEW.md # Точка входа для агента-ревьювера
**What to do** in a specific situation — step-by-step instructions. scripts/ # Скрипты и манифесты сборки
├── build-ai.js # Скрипт сборки
└── nextjs.build.js # Манифест: какие файлы, куда, как называются
| Section | Answers the question | dist/ # Собранные версии (gitignore)
|---------|---------------------| ├── ai/{framework}/ # Для AI-агентов
| Getting Started | What tools to install before starting development? | └── vitepress/{framework}/ # Для людей (планируется)
| Creating an App | How to create a new project, where to get a template? | ```
| Creating Pages | How to add a page: routing and screen? |
| Creating Components | How to generate components using templates? |
| Styling | What to use: Mantine, tokens, or PostCSS? |
| Data Fetching | How to fetch data: SWR, codegen, sockets? |
| State Management | When and how to create a store (Zustand)? |
| Localization | How to add translations and work with i18next? |
### Basic Rules ## Сборка
**What the code should look like** — standards not tied to a specific technology. ```bash
npm run build:ai # Собрать все фреймворки
```
| Section | Answers the question | ## Манифест
|---------|---------------------|
| Tech Stack | What stack do we use? |
| Architecture | How are FSD layers, dependencies, and public API structured? |
| Code Style | How to format code: indentation, quotes, imports, early return? |
| Naming | How to name files, variables, components, hooks? |
| Documentation | How to write JSDoc: what to document and what not? |
| Typing | How to type: type vs interface, any/unknown? |
### Applied Sections Каждый фреймворк имеет манифест `scripts/{framework}.build.js`. Ключ — путь в выходной папке, значение — путь исходника в `src/`.
**How a specific area works** — rules, structure, and code examples for specific technologies and tools. Скрипт только копирует файлы по манифесту. Никакой генерации.
| Section | Answers the question | ## Добавление раздела
|---------|---------------------|
| Project Structure | How are folders and files organized by FSD? |
| Components | How is a component structured: files, props, clsx? |
| Page-level Components | How to define layout, page, loading, error, not-found? |
| Templates & Code Generation | How do templates work: syntax, variables, modifiers? |
| Styles | How to write CSS: PostCSS Modules, nesting, media, tokens? |
| Images | _(not filled)_ |
| SVG Sprites | _(not filled)_ |
| Video | _(not filled)_ |
| API | _(not filled)_ |
| Stores | _(not filled)_ |
| Hooks | _(not filled)_ |
| Fonts | _(not filled)_ |
| Localization | _(not filled)_ |
## For Assistants 1. Создать `.md` в `src/base/` (общий) или `src/{framework}/` (специфичный).
2. Добавить frontmatter: `title`, `scope`, `keywords`, `when`.
3. Добавить путь в манифест `scripts/{framework}.build.js`.
4. Обновить точку входа (`DEVELOP.md` и/или `REVIEW.md`).
5. `npm run build:ai`.
Full documentation in a single MD file: https://gromlab.ru/docs/frontend-style-guide/raw/branch/main/generated/en/RULES.md ## Добавление фреймворка
1. Создать `src/{framework}/` с `.md` файлами и точками входа.
2. Создать `scripts/{framework}.build.js`.
3. `npm run build:ai`.

View File

@@ -1,60 +0,0 @@
# NextJS Style Guide
Правила и стандарты разработки на NextJS и TypeScript: архитектура, типизация, стили, компоненты, API и инфраструктурные разделы.
## Для ассистентов
Полная документация в одном MD файле: https://gromlab.ru/docs/nextjs-style-guide/raw/branch/main/generated/ru/RULES.md
## Структура документации
### Workflow
**Что делать и в каком порядке** — пошаговые инструкции.
| Раздел | Отвечает на вопрос |
|--------|-------------------|
| Начало работы | Что нужно знать перед началом разработки? |
| Создание проекта | Как начать новый проект? |
| Генерация кода | Какие модули должны генерироваться из шаблонов? |
| Добавление страницы | Как добавить новую страницу в проект? |
| Добавление UI-модуля | Как создать компонент, фичу, виджет, сущность или layout? |
| Стилизация | Как стилизовать компоненты в проекте? |
| Получение данных | Как получать данные с сервера? |
| Управление состоянием | Как работать с состоянием? |
| Локализация | Как добавлять переводы и подключать локализацию? |
### Базовые правила
**Каким должен быть код** — стандарты, не привязанные к конкретной технологии.
| Раздел | Отвечает на вопрос |
|--------|-------------------|
| Технологии и библиотеки | Какой стек используем? |
| Архитектура | Как устроены слои FSD, зависимости, публичный API? |
| Стиль кода | Как оформлять код: отступы, кавычки, импорты, early return? |
| Именование | Как называть файлы, переменные, компоненты, хуки? |
| Документирование | Как писать JSDoc: что документировать, а что нет? |
| Типизация | Как типизировать: type vs interface, any/unknown? |
### Прикладные разделы
**Как это настроить и использовать** — конфигурация, структура и примеры кода для конкретных областей.
| Раздел | Отвечает на вопрос |
|--------|-------------------|
| Настройка VS Code | Как настроить редактор для проекта? |
| Структура проекта | Как организованы папки и файлы по FSD? |
| Компоненты | Как устроен компонент: файлы, пропсы, clsx? |
| Page-level компоненты | Как описывать layout, page, loading, error, not-found? |
| Шаблоны и генерация кода | Как работают шаблоны, синтаксис и инструменты генерации? |
| Стили | Как писать CSS: PostCSS Modules, вложенность, медиа, токены? |
| Изображения | _(не заполнен)_ |
| SVG-спрайты | _(не заполнен)_ |
| Видео | _(не заполнен)_ |
| API | _(не заполнен)_ |
| Stores | _(не заполнен)_ |
| Хуки | _(не заполнен)_ |
| Шрифты | _(не заполнен)_ |
| Локализация | _(не заполнен)_ |

View File

@@ -1,107 +0,0 @@
import path from "path";
import fs from "fs";
// Явный порядок файлов внутри каждого языка
const fileOrder = [
// index
"index.md",
// workflow
"workflow.md",
// basics
"basics/tech-stack.md",
"basics/naming.md",
"basics/architecture.md",
"basics/code-style.md",
"basics/documentation.md",
"basics/typing.md",
// applied
"applied/project-structure.md",
"applied/components.md",
"applied/page-level.md",
"applied/templates-generation.md",
"applied/styles.md",
"applied/images-sprites.md",
"applied/svg-sprites.md",
"applied/video.md",
"applied/api.md",
"applied/stores.md",
"applied/hooks.md",
"applied/fonts.md",
"applied/localization.md",
"applied/vscode.md",
];
// Удалить frontmatter из содержимого md-файла
const stripFrontmatter = (content) =>
content.replace(/^---[\s\S]*?---\n*/m, "");
// Сдвинуть уровень заголовков на 1 вниз (h1→h2, h2→h3, ...)
// Не трогает заголовки внутри блоков кода
const shiftHeadings = (content) => {
const lines = content.split("\n");
let inCodeBlock = false;
return lines
.map((line) => {
if (line.startsWith("```")) inCodeBlock = !inCodeBlock;
if (inCodeBlock) return line;
if (/^#{1,5}\s/.test(line)) return "#" + line;
return line;
})
.join("\n");
};
// Собрать RULES.md с мета-якорями для каждого файла
const buildRules = (lang) => {
const srcDir = `./docs/${lang}`;
const outDir = `./generated/${lang}`;
const outFile = path.join(outDir, "RULES.md");
if (!fs.existsSync(srcDir)) {
console.log(`Пропуск ${lang}: папка ${srcDir} не найдена`);
return;
}
fs.mkdirSync(outDir, { recursive: true });
const parts = [];
for (const file of fileOrder) {
const filePath = path.join(srcDir, file);
if (!fs.existsSync(filePath)) continue;
const raw = fs.readFileSync(filePath, "utf8");
const content = stripFrontmatter(raw).trim();
if (!content) continue;
// Мета-якорь: путь VitePress без расширения
const route = "/" + file.replace(/\.md$/, "");
// index.md остаётся без сдвига (его h1 — главный заголовок документа)
const processed = file === "index.md" ? content : shiftHeadings(content);
parts.push(`<!-- ${route} -->\n${processed}`);
}
fs.writeFileSync(outFile, parts.join("\n\n"), "utf8");
console.log(`RULES.md (${lang}) создан: ${outFile}`);
};
// Собираем RULES.md для обоих языков
buildRules("ru");
buildRules("en");
// Генерируем README из index.md
const buildReadme = (lang, outFile) => {
const indexPath = `./docs/${lang}/index.md`;
if (!fs.existsSync(indexPath)) {
console.log(`Пропуск README (${lang}): ${indexPath} не найден`);
return;
}
const content = stripFrontmatter(fs.readFileSync(indexPath, "utf8"));
fs.writeFileSync(outFile, content, "utf8");
console.log(`${outFile} создан из ${indexPath}`);
};
buildReadme("en", "./README.md");
buildReadme("ru", "./README_RU.md");

View File

@@ -1,5 +0,0 @@
---
title: API
---
# API

View File

@@ -1,7 +0,0 @@
---
title: Components
---
# Components
Rules for creating UI components across all FSD layers.

View File

@@ -1,5 +0,0 @@
---
title: Fonts
---
# Fonts

View File

@@ -1,5 +0,0 @@
---
title: Hooks
---
# Hooks

View File

@@ -1,5 +0,0 @@
---
title: Images
---
# Images

View File

@@ -1,5 +0,0 @@
---
title: Localization
---
# Localization

View File

@@ -1,7 +0,0 @@
---
title: Page-level Components
---
# Page-level Components
Next.js App Router special files used by the framework by convention: `layout.tsx`, `page.tsx`, `loading.tsx`, `error.tsx`, `not-found.tsx`, `template.tsx`.

View File

@@ -1,7 +0,0 @@
---
title: Project Structure
---
# Project Structure
Base project structure and principles of module organization at folder and file level.

View File

@@ -1,5 +0,0 @@
---
title: Stores
---
# Stores

View File

@@ -1,7 +0,0 @@
---
title: Styles
---
# Styles
CSS writing rules: PostCSS Modules, nesting, media queries, variables, formatting.

View File

@@ -1,5 +0,0 @@
---
title: SVG Sprites
---
# SVG Sprites

View File

@@ -1,7 +0,0 @@
---
title: Templates & Code Generation
---
# Templates & Code Generation
Template tools, syntax, and examples for code generation.

View File

@@ -1,5 +0,0 @@
---
title: Video
---
# Video

View File

@@ -1,7 +0,0 @@
---
title: Architecture
---
# Architecture
Architecture based on FSD (Feature-Sliced Design) and strict module boundaries.

View File

@@ -1,7 +0,0 @@
---
title: Code Style
---
# Code Style
Unified code formatting rules: indentation, line breaks, quotes, import order, and readability.

View File

@@ -1,7 +0,0 @@
---
title: Documentation
---
# Documentation
Documentation should help understand the purpose of an entity, not duplicate its types or obvious details.

View File

@@ -1,7 +0,0 @@
---
title: Naming
---
# Naming
Naming should be predictable, concise, and reflect the meaning of the entity.

View File

@@ -1,7 +0,0 @@
---
title: Tech Stack
---
# Tech Stack
Base technology stack and libraries used in projects.

View File

@@ -1,7 +0,0 @@
---
title: Typing
---
# Typing
Typing is required for all public interfaces, functions, and components.

View File

@@ -1,57 +0,0 @@
# NextJS Style Guide
Rules and standards for NextJS and TypeScript development: architecture, typing, styles, components, API, and infrastructure.
## Documentation Structure
### Processes
**What to do** in a specific situation — step-by-step instructions.
| Section | Answers the question |
|---------|---------------------|
| Getting Started | What tools to install before starting development? |
| Creating an App | How to create a new project, where to get a template? |
| Creating Pages | How to add a page: routing and screen? |
| Creating Components | How to generate components using templates? |
| Styling | What to use: Mantine, tokens, or PostCSS? |
| Data Fetching | How to fetch data: SWR, codegen, sockets? |
| State Management | When and how to create a store (Zustand)? |
| Localization | How to add translations and work with i18next? |
### Basic Rules
**What the code should look like** — standards not tied to a specific technology.
| Section | Answers the question |
|---------|---------------------|
| Tech Stack | What stack do we use? |
| Architecture | How are FSD layers, dependencies, and public API structured? |
| Code Style | How to format code: indentation, quotes, imports, early return? |
| Naming | How to name files, variables, components, hooks? |
| Documentation | How to write JSDoc: what to document and what not? |
| Typing | How to type: type vs interface, any/unknown? |
### Applied Sections
**How a specific area works** — rules, structure, and code examples for specific technologies and tools.
| Section | Answers the question |
|---------|---------------------|
| Project Structure | How are folders and files organized by FSD? |
| Components | How is a component structured: files, props, clsx? |
| Page-level Components | How to define layout, page, loading, error, not-found? |
| Templates & Code Generation | How do templates work: syntax, variables, modifiers? |
| Styles | How to write CSS: PostCSS Modules, nesting, media, tokens? |
| Images | _(not filled)_ |
| SVG Sprites | _(not filled)_ |
| Video | _(not filled)_ |
| API | _(not filled)_ |
| Stores | _(not filled)_ |
| Hooks | _(not filled)_ |
| Fonts | _(not filled)_ |
| Localization | _(not filled)_ |
## For Assistants
Full documentation in a single MD file: https://gromlab.ru/docs/frontend-style-guide/raw/branch/main/generated/en/RULES.md

View File

@@ -1,7 +0,0 @@
---
title: Creating an App
---
# Creating an App
How to create a new application: choosing a project template and initialization.

View File

@@ -1,7 +0,0 @@
---
title: Creating Components
---
# Creating Components
Generating components using templates, working with child components.

View File

@@ -1,7 +0,0 @@
---
title: Creating Pages
---
# Creating Pages
Page creation pattern: routing (page.tsx) and screen.

View File

@@ -1,7 +0,0 @@
---
title: Data Fetching
---
# Data Fetching
How to fetch data: SWR, API client codegen, sockets.

View File

@@ -1,7 +0,0 @@
---
title: Getting Started
---
# Getting Started
Setting up the environment and installing tools before starting development.

View File

@@ -1,7 +0,0 @@
---
title: Localization
---
# Localization
How to add translations and work with i18next.

View File

@@ -1,7 +0,0 @@
---
title: State Management
---
# State Management
When and how to create a store (Zustand), what to store locally vs globally.

View File

@@ -1,7 +0,0 @@
---
title: Styling
---
# Styling
Styling tools priority and rules for their application.

View File

View File

@@ -1,5 +0,0 @@
---
title: SVG-спрайты
---
# SVG-спрайты

View File

@@ -1,471 +0,0 @@
---
title: Архитектура
---
# Архитектура
Раздел описывает архитектуру проекта: из каких слоёв состоит приложение,
как организован код внутри слоёв и какие правила управляют зависимостями.
## Что нужно знать
SLM Design (Scoped Layered Module Design) — архитектурный подход
к проектированию фронтенд-приложений, предложенный Громовым Сергеем в 2026 г.
Вырос на основе:
- [Feature-Sliced Design](https://feature-sliced.design) — слои и направление зависимостей
- Screaming Architecture — структура говорит сама за себя
- Colocation Principle — код рядом с местом использования
Переосмыслив эти подходы, SLM Design отличается от FSD в трёх аспектах:
где живёт код (колокация), как он организован (модули)
и как масштабируется (подъём при переиспользовании).
## Терминология
Архитектура оперирует четырьмя ключевыми понятиями:
- **Слой** — содержит модули
- **Модуль** — содержит сегменты
- **Компонент** — содержит сегменты
- **Сегмент** — папка внутри модуля или компонента, группирующая код по назначению: UI-элементы (`ui/`), хуки (`hooks/`), типы (`types/`), стили (`styles/`) и другие
Модуль и компонент устроены одинаково — оба имеют сегменты. Разница в том, где они живут и обязателен ли UI.
```text
Слой
└── Модуль
├── Сегменты (hooks/, stores/, types/, styles/, lib/...)
└── ui/
└── Компонент
├── Сегменты (hooks/, stores/, types/, styles/, lib/...)
└── ui/
└── Компонент → ...
```
### Слой
Архитектурный уровень. Содержит только модули. Определяет назначение кода и правила зависимостей.
### Модуль
Единица первого уровня слоя, объединённая по смыслу. Может содержать компонент, логику, типы, стили — или любую комбинацию. Имеет публичный API (`index.ts`) и внутреннюю структуру из сегментов.
Модуль — не обязательно UI. Feature `analytics` может быть только стором и сервисом. Entity `session` может быть только типами и хуком.
Модуль не может содержать вложенных модулей. Вложенные единицы с UI размещаются в сегменте `ui/` как компоненты.
### Компонент
Вложенная единица внутри сегмента `ui/` модуля (или другого компонента). Публичный `.tsx` файл обязателен. Именуется без суффикса слоя.
Компонент может иметь собственные сегменты (`hooks/`, `styles/`, `types/` и т.д.), `index.ts` и свой `ui/` с ещё более вложенными компонентами.
Отличия от модуля:
| | Модуль | Компонент |
|--|--------|-----------|
| Где живёт | В корне слоя | В `ui/` модуля или другого компонента |
| Публичный `.tsx` | С суффиксом слоя, опционален | Без суффикса, обязателен |
| Может не иметь UI | Да | Нет |
Пример:
```text
features/auth-by-email/ # модуль
├── auth-by-email.feature.tsx # публичный .tsx модуля (с суффиксом, опционален)
├── ui/ # сегмент: компоненты
│ ├── login-form/ # компонент
│ │ ├── login-form.tsx # публичный .tsx компонента (без суффикса, обязателен)
│ │ ├── ui/ # вложенные компоненты
│ │ │ └── password-field/
│ │ │ └── password-field.tsx
│ │ ├── hooks/
│ │ │ └── use-validation.hook.ts
│ │ ├── styles/
│ │ │ └── login-form.module.css
│ │ └── index.ts
│ └── reset-password/ # компонент
│ ├── reset-password.tsx
│ └── index.ts
├── hooks/
│ └── use-auth.hook.ts
├── stores/
│ └── auth.store.ts
└── index.ts
```
### Сегмент
Техническая папка внутри модуля или компонента, группирующая код по назначению. Набор не фиксирован — включаются только те сегменты, которые нужны.
| Сегмент | Назначение |
|---------|-----------|
| `ui/` | Вложенные компоненты |
| `hooks/` | React-хуки |
| `stores/` | Сторы состояния |
| `types/` | Интерфейсы, типы, enums, DTO |
| `styles/` | Стили |
| `lib/` | Утилиты |
| `services/` | Внешние источники данных |
| `helpers/` | Вспомогательные функции |
| `config/` | Константы, конфигурация |
## Ключевой принцип
> Модуль живёт на самом низком уровне, где он используется.
> Поднимается выше только при переиспользовании в 2+ местах.
Если модуль используется только в одном месте — он остаётся на текущем уровне.
Как только он начинает использоваться в 2+ местах — выносится на уровень выше.
В крайнем случае — в `shared/`, где он доступен всем.
## Слои
Каждый нижний слой не знает о существовании верхних. Импорты идут строго сверху вниз.
```
app → layouts → screens → widgets → features → entities → shared
```
| Слой | Что лежит | Импортирует |
|------|-----------|-------------|
| **App** | Роутинг, провайдеры, глобальные стили. Композиция layout + screen для маршрута. | Все слои ниже |
| **Layouts** | Каркас страницы, общий для группы маршрутов. | widgets, features, entities, shared |
| **Screens** | Контент конкретной страницы. | widgets, features, entities, shared |
| **Widgets** | Составные блоки с данными/логикой, переиспользуемые в 2+ местах. | features, entities, shared |
| **Features** | Пользовательское действие или интерактивный сценарий. | entities, shared |
| **Entities** | Бизнес-сущность с отображением и типами. | shared |
| **Shared** | Переиспользуемые компоненты, утилиты, стили без бизнес-логики. | ничего |
Принципы:
- Импорты строго сверху вниз
- Модули одного слоя не знают друг о друге
- Layout получает контекстно-зависимые блоки через пропсы от app, а не импортирует их сам
- `entities/` и `features/` создаются осознанно — это не результат «вынесения» компонента из screen
### App
Точка входа приложения: роутинг (Next.js App Router), провайдеры, глобальные стили.
Находится на самом высоком уровне абстракции — может импортировать любой слой ниже.
Никакой бизнес-логики — только композиция.
```text
app/
├── layout.tsx # RootLayout: провайдеры, глобальные стили
├── page.tsx # Главная: MainLayout + HomeScreen
├── knv-new/
│ └── page.tsx # КНВ: MainLayout + KnvScreen
└── catalog/
└── page.tsx # Каталог: MainLayout + CatalogScreen
```
```tsx
// app/knv-new/page.tsx
import { MainLayout } from '@/layouts/main'
import { KnvScreen } from '@/screens/knv'
export default function KnvNewPage() {
return (
<MainLayout>
<KnvScreen />
</MainLayout>
)
}
```
Если layout требует разный контент в зависимости от страницы — app передаёт его через пропсы:
```tsx
// app/knv-new/page.tsx
import { MainLayout } from '@/layouts/main'
import { KnvScreen } from '@/screens/knv'
import { KnvHeader } from '@/widgets/knv-header'
export default function KnvNewPage() {
return (
<MainLayout header={<KnvHeader />}>
<KnvScreen />
</MainLayout>
)
}
```
### Layouts
Каркас страницы — общие элементы, одинаковые для группы маршрутов (header, footer, sidebar).
Если компонент внутри layout начинает использоваться в 2+ местах — он выносится в `widgets/` или `shared/ui/`.
```text
src/layouts/
└── main/
├── main.layout.tsx
├── ui/
│ ├── header/
│ │ └── header.tsx
│ └── footer/
│ └── footer.tsx
└── index.ts
```
### Screens
Контент конкретной страницы. Собирает локальные секции и переиспользуемые модули из нижних слоёв.
Если компонент внутри screen начинает использоваться в 2+ местах — он выносится в `widgets/` или `shared/ui/`.
```text
src/screens/
└── knv/
├── knv.screen.tsx
├── ui/
│ ├── hero-section/
│ │ └── hero-section.tsx
│ ├── products-section/
│ │ └── products-section.tsx
│ └── diseases-section/
│ └── diseases-section.tsx
└── index.ts
```
### Widgets
Составные блоки с данными и логикой, переиспользуемые в 2+ местах.
Если блок с логикой нужен только в одном месте — это компонент внутри `screens/{name}/ui/` или `layouts/{name}/ui/`, а не widget.
```text
src/widgets/
└── popular-products-slider/
├── popular-products-slider.widget.tsx
├── ui/
│ └── slider-card/
│ └── slider-card.tsx
├── hooks/
│ └── use-products.hook.ts
└── index.ts
```
### Features
Пользовательское действие или интерактивный сценарий: авторизация, заказ, добавление в корзину.
Feature создаётся осознанно, когда есть действие пользователя с бизнес-логикой. Компонент опционален — feature может экспортировать хуки, сторы, компоненты или всё вместе.
```text
src/features/
└── auth-by-email/
├── auth-by-email.feature.tsx
├── ui/
│ ├── login-form/
│ │ └── login-form.tsx
│ └── reset-password/
│ └── reset-password.tsx
├── hooks/
│ └── use-auth.hook.ts
├── stores/
│ └── auth.store.ts
└── index.ts
```
### Entities
Бизнес-сущность с отображением и типами: препарат, заболевание, врач, пользователь.
Entity создаётся осознанно, когда появляется бизнес-сущность. Компонент опционален — entity может быть только типами и хуком.
Отличие от `shared/ui/`: entity-компонент знает о бизнес-домене (принимает `Product`, а не абстрактные пропсы).
```text
src/entities/
├── product/
│ ├── product.entity.tsx
│ ├── ui/
│ │ └── product-card/
│ │ └── product-card.tsx
│ ├── types/
│ │ └── product.type.ts
│ └── index.ts
├── session/
│ ├── types/
│ │ └── session.type.ts
│ ├── hooks/
│ │ └── use-session.hook.ts
│ └── index.ts
```
### Shared
Переиспользуемые компоненты, утилиты, стили без бизнес-логики. Не знает о бизнес-домене — работает с абстрактными данными.
Структурирован как набор сегментов:
```text
src/shared/
├── ui/
│ ├── icon/
│ │ └── icon.tsx
│ ├── carousel/
│ │ ├── carousel.tsx
│ │ ├── ui/
│ │ │ ├── carousel-slide/
│ │ │ │ └── carousel-slide.tsx
│ │ │ └── carousel-dots/
│ │ │ └── carousel-dots.tsx
│ │ └── index.ts
│ ├── container/
│ └── button/
├── lib/
│ ├── format-date.ts
│ └── cn.ts
├── styles/
│ ├── variables.css
│ └── media.css
└── sprites/
```
## Модуль
### Структура
```text
{name}/
├── {name}.{суффикс}.tsx # компонент (опционален)
├── ui/ # вложенные компоненты
├── hooks/ # хуки
├── stores/ # сторы
├── types/ # типы, интерфейсы, enums
├── styles/ # стили
├── lib/ # утилиты
├── services/ # внешние источники данных
├── helpers/ # вспомогательные функции
├── config/ # константы, конфигурация
└── index.ts # публичный API
```
### Именование компонента
Суффикс слоя получают **только модули первого уровня слоя** — те, что лежат непосредственно в корне слоя. Все компоненты (в `ui/`, любой глубины) именуются без суффикса. Без исключений.
| Слой | Суффикс | Пример |
|------|---------|--------|
| Layouts | `.layout.tsx` | `main.layout.tsx` |
| Screens | `.screen.tsx` | `knv.screen.tsx` |
| Widgets | `.widget.tsx` | `popular-products-slider.widget.tsx` |
| Features | `.feature.tsx` | `auth-by-email.feature.tsx` |
| Entities | `.entity.tsx` | `product.entity.tsx` |
Примеры:
```text
features/auth-by-email/auth-by-email.feature.tsx # модуль первого уровня → суффикс
features/auth-by-email/ui/login-form/login-form.tsx # компонент в ui/ → без суффикса
shared/ui/carousel/carousel.tsx # компонент в shared → без суффикса
```
### Правила импорта
Три уровня правил:
**Между слоями** — импорты строго сверху вниз:
```
app → layouts → screens → widgets → features → entities → shared
```
**Внутри модуля (не shared)** — сегменты доступны друг другу и компонентам. Компоненты внутри одного `ui/` не импортируют друг друга:
```text
features/auth-by-email/
├── ui/
│ ├── login-form/ # НЕ может импортировать reset-password
│ └── reset-password/ # НЕ может импортировать login-form
```
Если двум компонентам нужен общий код — он поднимается на уровень выше:
```text
features/auth/ui/login-form/ui/email-input/ # нужен соседу
→ features/auth/ui/email-input/ # поднимаем на уровень
→ shared/ui/email-input/ # если нужен за пределами фичи
```
Компоненты наследуют правила зависимостей **родительского слоя**:
- Компонент внутри `features/auth/ui/login-form/` может импортировать `entities/` и `shared/` — как и сам feature
- Компонент внутри `widgets/hero/ui/hero-stats/` может импортировать `features/`, `entities/`, `shared/` — как и сам widget
**Shared** — без ограничений на внутренние импорты. Компоненты в `shared/ui/` могут импортировать друг друга (`button` использует `icon`), `ui/` может использовать `lib/` и другие сегменты. Shared — фундамент, его компоненты строятся друг на друге.
Правила импорта между слоями enforceable через ESLint — настройка границ слоёв и запрет обратных зависимостей.
## Жизненный цикл модуля
Модуль не проектируется «на вырост». Он рождается на самом низком уровне
и поднимается только когда появляется реальная потребность.
Пример пути компонента `product-card`:
1. **Начало:** `screens/catalog/ui/product-card/` — нужен только на странице каталога.
2. **Переиспользование:** появился на странице поиска — выносим выше.
Куда именно зависит от природы:
- Составной блок с данными и логикой → `widgets/product-card/`
- Представление бизнес-сущности → `entities/product/ui/product-card/`
- Абстрактный UI без бизнес-логики → `shared/ui/product-card/`
Основной триггер подъёма — переиспользование в 2+ местах.
Но если очевидно что модуль будет переиспользоваться — разумно разместить его на нужном уровне сразу.
Как происходит подъём на практике:
1. Разработчик обнаруживает что компонент нужен в другом месте
2. Определяет целевой слой по природе компонента (widget / entity / shared)
3. Перемещает папку, обновляет импорты, добавляет суффикс если это модуль первого уровня слоя
4. Ревью подтверждает что подъём обоснован
Подъём — это обычный рефакторинг в рамках задачи, а не отдельная активность.
## Граничные случаи
| Ситуация | Решение | Почему |
|----------|---------|--------|
| Фильтр каталога только на одной странице, но с хуками и стором | Модуль в `screens/catalog/` с сегментами `hooks/`, `stores/` | Не feature — feature это действие пользователя с бизнес-логикой (авторизация, заказ), а не UI с состоянием |
| Компонент используется в 2 местах на одной странице | Остаётся в `screens/{name}/ui/` | Переиспользование внутри одного screen — не повод выносить в widget |
| Entity без UI (только типы и хук) | Нормально | Модуль не обязан иметь UI. `entities/session/` с типами и хуком — валидный модуль |
| Компонент нужен и в layout, и в screen | Выносить в `widgets/` или `shared/ui/` | Два разных слоя используют один компонент → переиспользование → подъём |
| Модуль screen содержит бизнес-логику (хуки, стор, сервисы) | Нормально | Это не значит что он должен стать feature. Модуль с логикой внутри screen — обычное дело, пока он не переиспользуется |
| Компонент в `shared/ui/button` хочет использовать `shared/ui/icon` | Разрешено | Shared — исключение: внутренние импорты без ограничений. Это фундамент, его компоненты строятся друг на друге |
## Запрещено
- **Не создавать feature без бизнес-логики** — кнопка без состояния и сайд-эффектов это компонент в `ui/`, а не feature
- **Не класть доменные типы в shared** — если тип знает о Product, Disease, User — он живёт в `entities/`, не в `shared/`
- **Не создавать entity или feature как результат «вынесения»** — они создаются осознанно: появилась бизнес-сущность → entity, появилось действие пользователя → feature
- **Не импортировать соседние компоненты в `ui/` (кроме shared)** — если двум компонентам нужен общий код, он поднимается на уровень выше
- **Не хранить в shared «помойку для всего»** — shared содержит переиспользуемые компоненты и утилиты без бизнес-логики, а не код который «непонятно куда положить»
## Почему так, а не иначе
### Почему `ui/` а не `modules/`
Внутри сегмента `ui/` всегда лежат единицы с обязательным UI (компоненты). Название точно отражает содержимое. `modules/` был нейтральнее, но скрывал природу вложенных единиц и создавал путаницу — модуль внутри модуля размывал понятие «модуль как единица слоя».
### Почему модуль и компонент — разные понятия
Модуль — единица первого уровня слоя, может не иметь UI. Компонент — вложенная единица с обязательным UI. Разделение снимает вопрос «а если нет `.tsx` — это всё ещё компонент?» и делает название сегмента `ui/` честным.
### Почему shared без ограничений на внутренние импорты
Shared — фундамент. Его компоненты строятся друг на друге: `button` использует `icon`, `carousel` использует `button`. Запрещать это — бороться с реальностью. Поднимать некуда — shared уже нижний слой.
### Почему нет слоя pages
Роутинг живёт в `app/` (Next.js App Router). Отдельный слой `pages` конфликтовал бы с файловой структурой Next.js и дублировал ответственность `app/`.
### Почему компоненты в одном `ui/` не импортируют друг друга (кроме shared)
Независимые компоненты легко выносить в другой слой при переиспользовании. Если компонент A зависит от соседа B — при подъёме A придётся тянуть B. Это усложняет рефакторинг и нарушает принцип колокации.

View File

@@ -1,60 +0,0 @@
# NextJS Style Guide
Правила и стандарты разработки на NextJS и TypeScript: архитектура, типизация, стили, компоненты, API и инфраструктурные разделы.
## Для ассистентов
Полная документация в одном MD файле: https://gromlab.ru/docs/nextjs-style-guide/raw/branch/main/generated/ru/RULES.md
## Структура документации
### Workflow
**Что делать и в каком порядке** — пошаговые инструкции.
| Раздел | Отвечает на вопрос |
|--------|-------------------|
| Начало работы | Что нужно знать перед началом разработки? |
| Создание проекта | Как начать новый проект? |
| Генерация кода | Какие модули должны генерироваться из шаблонов? |
| Добавление страницы | Как добавить новую страницу в проект? |
| Добавление UI-модуля | Как создать компонент, фичу, виджет, сущность или layout? |
| Стилизация | Как стилизовать компоненты в проекте? |
| Получение данных | Как получать данные с сервера? |
| Управление состоянием | Как работать с состоянием? |
| Локализация | Как добавлять переводы и подключать локализацию? |
### Базовые правила
**Каким должен быть код** — стандарты, не привязанные к конкретной технологии.
| Раздел | Отвечает на вопрос |
|--------|-------------------|
| Технологии и библиотеки | Какой стек используем? |
| Архитектура | Как устроены слои FSD, зависимости, публичный API? |
| Стиль кода | Как оформлять код: отступы, кавычки, импорты, early return? |
| Именование | Как называть файлы, переменные, компоненты, хуки? |
| Документирование | Как писать JSDoc: что документировать, а что нет? |
| Типизация | Как типизировать: type vs interface, any/unknown? |
### Прикладные разделы
**Как это настроить и использовать** — конфигурация, структура и примеры кода для конкретных областей.
| Раздел | Отвечает на вопрос |
|--------|-------------------|
| Настройка VS Code | Как настроить редактор для проекта? |
| Структура проекта | Как организованы папки и файлы по FSD? |
| Компоненты | Как устроен компонент: файлы, пропсы, clsx? |
| Page-level компоненты | Как описывать layout, page, loading, error, not-found? |
| Шаблоны и генерация кода | Как работают шаблоны, синтаксис и инструменты генерации? |
| Стили | Как писать CSS: PostCSS Modules, вложенность, медиа, токены? |
| Изображения | _(не заполнен)_ |
| SVG-спрайты | _(не заполнен)_ |
| Видео | _(не заполнен)_ |
| API | _(не заполнен)_ |
| Stores | _(не заполнен)_ |
| Хуки | _(не заполнен)_ |
| Шрифты | _(не заполнен)_ |
| Локализация | _(не заполнен)_ |

View File

@@ -1,87 +0,0 @@
---
title: Workflow
---
# Workflow
Порядок действий при разработке — от создания проекта до реализации фич.
## Создание проекта
Инициализация нового проекта из готового шаблона.
1. Создать проект из шаблона:
```bash
npx tiged git@gromlab.ru:templates/nextjs.git my-app
cd my-app
npm install
```
2. Проект готов к разработке — стек, структура FSD, конфигурация
редактора и шаблоны генерации уже настроены.
## Генерация кода
Создание модулей из шаблонов `.templates/` вместо ручного создания файлов.
1. Определить тип модуля и соответствующий шаблон:
| Модуль | Слой | Шаблон |
|------------|--------------|-------------|
| Компонент | `shared/ui/` | `component` |
| Фича | `features/` | `feature` |
| Виджет | `widgets/` | `widget` |
| Сущность | `entities/` | `entity` |
| Layout | `layouts/` | `layout` |
| Экран | `screens/` | `screen` |
| Стор | `model/` | `store` |
2. Сгенерировать модуль из шаблона.
3. Если подходящего шаблона нет — сначала создать шаблон, затем использовать.
Ручное создание файловой структуры модулей запрещено.
## Добавление страницы
Создание нового маршрута: экран + точка входа для роутинга.
1. Сгенерировать экран из шаблона `screen` в `src/screens/`.
2. Заполнить экран логикой и стилями.
3. Создать `page.tsx` в нужном маршруте `src/app/`.
`page.tsx` — тонкая обёртка: только `metadata` и рендер экрана.
Логика, стили и хуки размещаются в экране, не в `page.tsx`.
## Добавление UI-модуля
Создание компонента, фичи, виджета, сущности или layout.
1. Сгенерировать модуль из соответствующего шаблона в целевой слой.
2. Заполнить модуль логикой и стилями.
3. Дочерние компоненты — генерировать из шаблона `component` в папку `ui/`
внутри родителя.
Дочерние компоненты не экспортируются через `index.ts` родителя.
## Стилизация
Выбор инструмента стилизации по приоритету.
1. Использовать Mantine-компоненты и их пропсы.
2. Если Mantine не покрывает — использовать CSS-токены
(`--color-*`, `--space-*`, `--radius-*`).
3. Если нужна кастомная стилизация — PostCSS Modules.
Инлайн-стили (`style`), магические значения и глобальные стили
вне `app/styles/` запрещены.
## Получение данных
*Раздел в разработке* — SWR, генерация API-клиентов, сокеты.
## Управление состоянием
*Раздел в разработке* — когда создавать стор, что хранить локально и глобально.
## Локализация
*Раздел в разработке* — переводы и i18next.

View File

@@ -1,32 +0,0 @@
---
title: Генерация кода
---
# Генерация кода
Как создавать модули в проекте с помощью шаблонов — какие модули покрыты генерацией и когда стоит создавать новые шаблоны.
## Какие модули генерируются из шаблонов
| Модуль | Слой | Шаблон |
|---|---|---|
| Компонент | `shared/ui/` | `component` |
| Фича | `features/` | `feature` |
| Виджет | `widgets/` | `widget` |
| Сущность | `entities/` | `entity` |
| Layout | `layouts/` | `layout` |
| Экран | `screens/` | `screen` |
| Стор | `model/` | `store` |
## Что нужно знать
В проекте принято создавать модули из шаблонов `.templates/`. Шаблоны задают единообразную файловую структуру и сокращают рутину — не нужно вручную создавать папки, файлы типов, стилей и экспорты.
Если для нужного модуля нет подходящего шаблона — стоит сначала создать шаблон, а затем использовать его.
## Когда создавать новый шаблон
- Повторяющаяся структура появляется больше одного раза.
- Существующий шаблон не покрывает нужный тип модуля.
Инструменты и синтаксис шаблонов — [Шаблоны и генерация кода](/applied/templates-generation).

View File

@@ -1,31 +0,0 @@
---
title: Создание проекта
---
# Создание проекта
Как начать новый проект, соответствующий стандартам этого руководства.
## Что нужно знать
Новый проект создаётся из готового шаблона. Шаблон содержит настроенный стек, структуру FSD, конфигурацию редактора и шаблоны генерации кода — проект готов к разработке сразу после установки зависимостей.
### Создание из шаблона
```bash
npx tiged git@gromlab.ru:templates/nextjs.git my-app
cd my-app
npm install
```
## Что входит в шаблон
- Next.js + TypeScript (App Router)
- Mantine UI + PostCSS Modules
- Biome (линтинг и форматирование)
- Zustand, SWR
- Структура FSD (`screens/`, `widgets/`, `features/`, `entities/`, `shared/`)
- Шаблоны генерации (`.templates/`)
- Конфигурация VS Code (`.vscode/`)
- CSS-токены (цвета, отступы, радиусы, медиа)
- Open Graph метаданные

View File

@@ -1,22 +0,0 @@
---
title: Добавление UI-модуля
---
# Добавление UI-модуля
Как создать компонент, фичу, виджет, сущность или layout в проекте.
## Что нужно знать
Все UI-модули создаются только из шаблонов `.templates/`. Ручное создание файловой структуры запрещено. Если подходящего шаблона нет — сначала создать шаблон в `.templates/`, затем использовать его.
## Порядок действий
1. [Сгенерировать](/applied/templates-generation) модуль из соответствующего шаблона в целевой слой.
2. Заполнить модуль логикой и стилями.
## Дочерние компоненты
Если модулю нужны внутренние подкомпоненты — [генерировать](/applied/templates-generation) их из шаблона `component` в папку `ui/` внутри родительского модуля. Дочерние компоненты не экспортируются через `index.ts` родителя.
Правила написания компонентов — [Компоненты](/applied/components).

View File

@@ -1,27 +0,0 @@
---
title: Добавление страницы
---
# Добавление страницы
Как добавить новую страницу в проект по стандартам этого руководства.
## Что нужно знать
Страница в проекте — это два файла: экран в `src/screens/` (вся логика, стили, зависимости) и `page.tsx` в `src/app/` (точка входа для роутинга Next.js). Экран генерируется из шаблона, `page.tsx` создаётся вручную.
## Порядок действий
1. [Сгенерировать](/applied/templates-generation) экран из шаблона `screen` в папку `src/screens/`.
2. Заполнить экран логикой и стилями.
3. Создать `page.tsx` в нужном маршруте `src/app/`. Файл страницы должен быть тонким — только `metadata` и рендер экрана. Никакой логики, стилей и хуков в `page.tsx` не размещается — всё это живёт в экране.
## Правила
- Ручное создание файловой структуры экрана запрещено — только [генерация](/applied/templates-generation) из шаблона.
- Логика, стили и зависимости размещаются в экране, не в `page.tsx`.
- Каждая страница содержит `metadata` с `title` и `description`.
Примеры `page.tsx` и `metadata` — [Page-level компоненты](/applied/page-level).

View File

@@ -1,7 +0,0 @@
---
title: Получение данных
---
# Получение данных
Как получать данные с сервера — SWR, генерация API-клиентов, сокеты.

View File

@@ -1,7 +0,0 @@
---
title: Локализация
---
# Локализация
Как добавлять переводы и подключать локализацию через i18next.

View File

@@ -1,7 +0,0 @@
---
title: Управление состоянием
---
# Управление состоянием
Как работать с состоянием — когда создавать стор, что хранить локально и глобально.

View File

@@ -1,23 +0,0 @@
---
title: Стилизация
---
# Стилизация
Как стилизовать компоненты в проекте — приоритет инструментов и правила их применения.
## Приоритет стилизации
Основной UI-фреймворк проекта — **Mantine**. При стилизации компонентов придерживаться следующего приоритета:
1. **Mantine-компоненты и их пропсы** — в первую очередь использовать встроенные возможности Mantine (пропсы, `classNames`, `styles`).
2. **Глобальные CSS-токены** (`--color-*`, `--space-*`, `--radius-*`) — для значений, которые не покрываются Mantine.
3. **PostCSS Modules** — когда Mantine не покрывает задачу и нужна кастомная стилизация.
## Что запрещено
- **Инлайн-стили** — использование атрибута `style` в компонентах строго запрещено.
- **Магические значения** — произвольные цвета, отступы и скругления запрещены, использовать токены.
- **Глобальные стили** вне `app/styles/` запрещены.
Правила написания CSS, вложенность, медиа-запросы и токены — [Стили](/applied/styles).

View File

@@ -1,137 +0,0 @@
<!-- /index -->
# NextJS Style Guide
Rules and standards for NextJS and TypeScript development: architecture, typing, styles, components, API, and infrastructure.
## Documentation Structure
### Processes
**What to do** in a specific situation — step-by-step instructions.
| Section | Answers the question |
|---------|---------------------|
| Getting Started | What tools to install before starting development? |
| Creating an App | How to create a new project, where to get a template? |
| Creating Pages | How to add a page: routing and screen? |
| Creating Components | How to generate components using templates? |
| Styling | What to use: Mantine, tokens, or PostCSS? |
| Data Fetching | How to fetch data: SWR, codegen, sockets? |
| State Management | When and how to create a store (Zustand)? |
| Localization | How to add translations and work with i18next? |
### Basic Rules
**What the code should look like** — standards not tied to a specific technology.
| Section | Answers the question |
|---------|---------------------|
| Tech Stack | What stack do we use? |
| Architecture | How are FSD layers, dependencies, and public API structured? |
| Code Style | How to format code: indentation, quotes, imports, early return? |
| Naming | How to name files, variables, components, hooks? |
| Documentation | How to write JSDoc: what to document and what not? |
| Typing | How to type: type vs interface, any/unknown? |
### Applied Sections
**How a specific area works** — rules, structure, and code examples for specific technologies and tools.
| Section | Answers the question |
|---------|---------------------|
| Project Structure | How are folders and files organized by FSD? |
| Components | How is a component structured: files, props, clsx? |
| Page-level Components | How to define layout, page, loading, error, not-found? |
| Templates & Code Generation | How do templates work: syntax, variables, modifiers? |
| Styles | How to write CSS: PostCSS Modules, nesting, media, tokens? |
| Images | _(not filled)_ |
| SVG Sprites | _(not filled)_ |
| Video | _(not filled)_ |
| API | _(not filled)_ |
| Stores | _(not filled)_ |
| Hooks | _(not filled)_ |
| Fonts | _(not filled)_ |
| Localization | _(not filled)_ |
## For Assistants
Full documentation in a single MD file: https://gromlab.ru/docs/frontend-style-guide/raw/branch/main/generated/en/RULES.md
<!-- /basics/tech-stack -->
## Tech Stack
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
Architecture based on FSD (Feature-Sliced Design) and strict module boundaries.
<!-- /basics/code-style -->
## Code Style
Unified code formatting rules: indentation, line breaks, quotes, import order, and readability.
<!-- /basics/documentation -->
## Documentation
Documentation should help understand the purpose of an entity, not duplicate its types or obvious details.
<!-- /basics/typing -->
## Typing
Typing is required for all public interfaces, functions, and components.
<!-- /applied/project-structure -->
## Project Structure
Base project structure and principles of module organization at folder and file level.
<!-- /applied/components -->
## Components
Rules for creating UI components across all FSD layers.
<!-- /applied/page-level -->
## Page-level Components
Next.js App Router special files used by the framework by convention: `layout.tsx`, `page.tsx`, `loading.tsx`, `error.tsx`, `not-found.tsx`, `template.tsx`.
<!-- /applied/templates-generation -->
## Templates & Code Generation
Template tools, syntax, and examples for code generation.
<!-- /applied/styles -->
## Styles
CSS writing rules: PostCSS Modules, nesting, media queries, variables, formatting.
<!-- /applied/images-sprites -->
## Images
<!-- /applied/svg-sprites -->
## SVG Sprites
<!-- /applied/video -->
## Video
<!-- /applied/api -->
## API
<!-- /applied/stores -->
## Stores
<!-- /applied/hooks -->
## Hooks
<!-- /applied/fonts -->
## Fonts
<!-- /applied/localization -->
## Localization

File diff suppressed because it is too large Load Diff

166
notes
View File

@@ -1,153 +1,23 @@
ФЛОУ # TODO
- после создания компонента, заменить шаблонный коментарий документа на реальный.
## Триггеры: классификация и расширение
Проблема, неочевидность слоев (наследие FSD) Текущий список триггеров слабо проработан. Нужно:
1. Классифицировать триггеры по группам:
- Создание — новые модули, компоненты, страницы
- Ресурсы — ассеты (иконки, шрифты, изображения, видео)
- Данные — API, сторы, серверные данные, формы
- Навигация — роутинг, middleware, редиректы
- Модификация — рефакторинг, перенос, удаление
- Инфраструктура — зависимости, переводы, настройка окружения
Архитектурные слои проекта 2. Добавить недостающие триггеры. Примеры пробелов:
Каждый нижний слой не знает о существовании верхних. Импорты идут только сверху вниз. - Создание: утилита/хелпер, тип/интерфейс, контекст
pages → layouts → screens → widgets → features → entities → shared - Данные: создать форму, добавить валидацию
--- - Навигация: динамический роут, middleware, редирект
1. Pages (pages/) - Модификация: рефакторинг компонента, перенос модуля, удаление модуля
Точка входа маршрута. Только связывает layout и screen. - Обработка ошибок: error boundary, fallback UI, error.tsx, not-found.tsx, loading.tsx
Правила: - Авторизация: защита страницы, проверка прав
- Никакой логики, стилей, разметки кроме композиции
- Один page = один layout + один screen
Пример:
// pages/knv-new.js
import { KnvScreen } from 'src/screens/knv'
import { MainLayout } from 'src/layouts/main'
const KnvNewPage = () => (
<MainLayout>
<KnvScreen />
</MainLayout>
)
---
2. Layouts (src/layouts/)
Каркас страницы — общие элементы, которые одинаковы на всех страницах в рамках этого layout.
Содержит в ui/: header, footer, sidebar — дочерние компоненты, которые привязаны к layout и не переиспользуются отдельно.
Критерий: компонент одинаков на всех страницах, использующих этот layout? → layouts/{name}/ui/
Пример:
src/layouts/main/
├── main.layout.tsx # <Header /> + children + <Footer />
├── ui/
│ ├── header/ # всегда одинаковый на всех страницах
│ └── footer/ # всегда одинаковый на всех страницах
---
3. Screens (src/screens/)
Контент конкретной страницы. Собирает свои секции и переиспользуемые widgets/features/entities.
Содержит в ui/: блоки, которые существуют только на этой странице и не переиспользуются.
Критерий: компонент используется только на одной странице? → screens/{name}/ui/
Пример:
src/screens/knv/
├── knv.screen.tsx
├── ui/
│ ├── hero-section/ # hero только на главной КНВ
│ ├── products-section/ # секция препаратов только на главной
│ ├── diseases-section/ # секция заболеваний только на главной
│ └── doctor-section/ # секция врачей только на главной
Каждая секция внутри может использовать shared/ui компоненты:
// screens/knv/ui/products-section/products-section.widget.tsx
import { Carousel } from 'src/shared/ui/carousel'
import { ProductCard } from './ui/product-card' // локальный, пока не переиспользуется
Когда локальный компонент начинает использоваться на 2+ страницах — выносим в entities/ или shared/ui.
---
4. Widgets (src/widgets/)
Составные блоки с данными/логикой, которые переиспользуются на 2+ страницах.
Критерий: блок с бизнес-логикой + данными используется на нескольких страницах? → widgets/
Пример: Слайдер «Популярные препараты» с загрузкой данных из API, который показывается и на главной, и на странице заболевания, и в каталоге:
src/widgets/
├── popular-products-slider/
│ ├── popular-products-slider.widget.tsx # Carousel + ProductCard + useProducts()
│ ├── hooks/
│ │ └── use-products.hook.ts # запрос данных
Не widget: секция «Подобрать врача» которая есть только на главной → screens/knv/ui/
---
5. Features (src/features/)
Пользовательское действие или интерактивный сценарий. Содержит бизнес-логику взаимодействия.
Критерий: это действие пользователя (отправить форму, авторизоваться, добавить в корзину)? → features/
Примеры:
src/features/
├── auth/ # авторизация (форма + логика + стор)
│ ├── auth.feature.tsx
│ ├── hooks/
│ │ └── use-auth.hook.ts
│ └── stores/
│ └── auth.store.ts
├── order-drug/ # заказ препарата (кнопка + модалка + API)
│ ├── order-drug.feature.tsx
│ └── hooks/
│ └── use-order.hook.ts
Не feature: отображение карточки препарата без взаимодействия → entities/ или shared/ui
---
6. Entities (src/entities/)
Бизнес-сущность с её отображением и типами. Привязана к домену (препарат, заболевание, врач, пользователь).
Критерий: это представление бизнес-объекта, которое переиспользуется в разных контекстах? → entities/
Примеры:
src/entities/
├── product/ # Препарат
│ ├── ui/
│ │ └── product-card/ # карточка препарата (каталог, слайдеры, поиск)
│ ├── types/
│ │ └── product.type.ts # { id, name, mnn, indication }
│ └── index.ts
├── disease/ # Заболевание
│ ├── ui/
│ │ └── disease-card/
│ ├── types/
│ │ └── disease.type.ts
│ └── index.ts
Отличие от shared/ui: entity-компонент знает о бизнес-домене (принимает Product, а не абстрактные пропсы). shared/ui Button не знает ничего о бизнесе.
---
7. Shared (src/shared/)
Переиспользуемые компоненты, утилиты, стили без бизнес-логики.
Критерий: компонент не знает о бизнес-домене, работает с абстрактными данными? → shared/
src/shared/
├── ui/ # UI-компоненты
│ ├── carousel/ # принимает children, не знает о препаратах
│ ├── container/
│ ├── section/
│ └── icon-svg/
├── styles/ # CSS-переменные, media
│ ├── variables.css
│ └── media.css
├── sprites/ # SVG-спрайты
└── lib/ # утилиты, хелперы
---
Сводная таблица принятия решений
Вопрос Да → Нет ↓
Это точка входа маршрута? pages/ ↓
Одинаков на всех страницах layout? layouts/{name}/ui/ ↓
Используется только на одной странице? screens/{name}/ui/ ↓
Составной блок с данными на 2+ страницах? widgets/ ↓
Это действие пользователя с логикой? features/ ↓
Привязан к бизнес-сущности? entities/ ↓
Абстрактный UI без бизнес-логики? shared/ui/ —
3. Обновить секцию "Триггеры" в DEVELOP.md — перейти на новые группы.
И еще размышлений
Что у нас по факту
Мы взяли FSD и добавили:
- Слой Layouts — каркас страницы
- Слой Screens — контент страницы с локальными компонентами
- Правило scope — компонент живёт максимально близко к месту использования, и поднимается на уровень выше только при переиспользовании
Это не FSD в чистом виде. Но и не что-то принципиально новое.
Существующие названия
Feature-Sliced Design (FSD) — то от чего отталкиваемся, но расходимся в деталях.
Screaming Architecture (Robert C. Martin) — структура проекта "кричит" о том, что он делает. Открываешь screens/knv/ui/ — видишь КНВ. Открываешь widgets/ — видишь глобальное. Это близко к нашему подходу.
Colocation Principle — держи код рядом с тем, где он используется. Именно этот принцип отличает нас от FSD: page-specific компоненты лежат внутри screen, а не в глобальном widgets/.
Как назвать
Я бы не стал придумывать новое название. Это:
> FSD с принципом колокации (FSD + Colocation)
Или проще — адаптированный FSD. Суть отличия укладывается в одно правило:
> Компонент живёт на самом низком уровне, где он используется. Поднимается выше только при переиспользовании на 2+ страницах.
Если хочется краткое название для внутренней документации — можно SLD (Scoped Layer Design), подчёркивая что каждый компонент привязан к scope (shared → entity → feature → widget → screen → layout → page).

4
package-lock.json generated
View File

@@ -1,11 +1,11 @@
{ {
"name": "nextjs-style-guide", "name": "frontend-style-guide",
"version": "0.0.0", "version": "0.0.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "nextjs-style-guide", "name": "frontend-style-guide",
"version": "0.0.0", "version": "0.0.0",
"devDependencies": { "devDependencies": {
"vitepress": "^1.6.3" "vitepress": "^1.6.3"

View File

@@ -1,10 +1,10 @@
{ {
"name": "nextjs-style-guide", "name": "frontend-style-guide",
"private": true, "private": true,
"type": "module", "type": "module",
"version": "0.0.0", "version": "0.0.0",
"scripts": { "scripts": {
"docs": "node ./concat-md.js", "build:ai": "node ./scripts/build-ai.js",
"dev": "vitepress dev .", "dev": "vitepress dev .",
"build": "vitepress build .", "build": "vitepress build .",
"serve": "vitepress serve ." "serve": "vitepress serve ."

88
scripts/build-ai.js Normal file
View File

@@ -0,0 +1,88 @@
import fs from "fs";
import path from "path";
import { pathToFileURL } from "url";
const SRC_DIR = "./src";
const DIST_DIR = "./dist/ai";
const SCRIPTS_DIR = "./scripts";
// ---------------------------------------------------------------------------
// Сборка по манифесту
// ---------------------------------------------------------------------------
async function buildForFramework(framework) {
const manifestPath = path.join(SCRIPTS_DIR, `${framework}.build.js`);
if (!fs.existsSync(manifestPath)) {
console.error(`Манифест не найден: ${manifestPath}`);
process.exit(1);
}
const manifest = (await import(pathToFileURL(path.resolve(manifestPath)).href)).default;
const outDir = path.join(DIST_DIR, framework);
// Очищаем выходную директорию
if (fs.existsSync(outDir)) {
fs.rmSync(outDir, { recursive: true, force: true });
}
console.log(`\nСборка: ${manifest.name} (${framework})`);
console.log(`Выход: ${outDir}\n`);
const errors = [];
let count = 0;
for (const [destRelative, srcRelative] of Object.entries(manifest.files)) {
const srcPath = path.join(SRC_DIR, srcRelative);
const destPath = path.join(outDir, destRelative);
if (!fs.existsSync(srcPath)) {
errors.push(` [!] Не найден: ${srcRelative}`);
continue;
}
fs.mkdirSync(path.dirname(destPath), { recursive: true });
fs.copyFileSync(srcPath, destPath);
console.log(` ${destRelative}`);
count++;
}
if (errors.length > 0) {
console.log(`\nОшибки:`);
errors.forEach((e) => console.log(e));
}
console.log(`\nГотово: ${outDir} (${count} файлов)`);
}
// ---------------------------------------------------------------------------
// Определяем что собирать
// ---------------------------------------------------------------------------
let frameworks = fs
.readdirSync(SCRIPTS_DIR)
.filter((f) => f.endsWith(".build.js"))
.map((f) => f.replace(".build.js", ""));
if (frameworks.length === 0) {
console.error("Не найдено ни одного манифеста *.build.js в scripts/");
process.exit(1);
}
// --framework=nextjs
const fwArg = process.argv.find((a) => a.startsWith("--framework="));
if (fwArg) {
const fw = fwArg.split("=")[1];
if (frameworks.includes(fw)) {
frameworks = [fw];
} else {
console.error(`Фреймворк "${fw}" не найден. Доступные: ${frameworks.join(", ")}`);
process.exit(1);
}
}
for (const fw of frameworks) {
await buildForFramework(fw);
}
console.log("\nВсе сборки завершены.");

69
scripts/nextjs.build.js Normal file
View File

@@ -0,0 +1,69 @@
/**
* Манифест сборки стайлгайда для Next.js.
*
* Ключ — путь файла в dist/ai/nextjs/.
* Значение — путь исходника относительно src/.
*
* Скрипт только копирует. Никакой генерации.
*/
export default {
name: "Next.js",
files: {
// ── Точки входа ─────────────────────────────────────────────
"DEVELOP.md": "nextjs/DEVELOP.md",
// ── Базовые правила ─────────────────────────────────────────
"basics/architecture.md": "base/basics/architecture.md",
"basics/code-style.md": "base/basics/code-style.md",
"basics/documentation.md": "base/basics/documentation.md",
"basics/naming.md": "base/basics/naming.md",
"basics/tech-stack.md": "base/basics/tech-stack.md",
"basics/typing.md": "base/basics/typing.md",
// ── Прикладные разделы ──────────────────────────────────────
"applied/components.md": "base/applied/components.md",
"applied/styles.md": "base/applied/styles.md",
"applied/templates-generation.md": "base/applied/templates-generation.md",
"applied/hooks.md": "base/applied/hooks.md",
"applied/stores.md": "base/applied/stores.md",
"applied/api.md": "base/applied/api.md",
"applied/fonts.md": "base/applied/fonts.md",
"applied/localization.md": "base/applied/localization.md",
"applied/images-sprites.md": "base/applied/images-sprites.md",
"applied/svg-sprites.md": "base/applied/svg-sprites.md",
"applied/video.md": "base/applied/video.md",
"applied/vscode.md": "base/applied/vscode.md",
"applied/page-level.md": "nextjs/applied/page-level.md",
"applied/project-structure.md": "nextjs/applied/project-structure.md",
// ── Триггеры: разработка / создание ─────────────────────────
"triggers/develop/create-component.md": "base/triggers/develop/create-component.md",
"triggers/develop/create-feature.md": "base/triggers/develop/create-feature.md",
"triggers/develop/create-widget.md": "base/triggers/develop/create-widget.md",
"triggers/develop/create-entity.md": "base/triggers/develop/create-entity.md",
"triggers/develop/create-hook.md": "base/triggers/develop/create-hook.md",
"triggers/develop/create-store.md": "base/triggers/develop/create-store.md",
"triggers/develop/create-page.md": "nextjs/triggers/develop/create-page.md",
"triggers/develop/create-layout.md": "nextjs/triggers/develop/create-layout.md",
"triggers/develop/create-project.md": "nextjs/triggers/develop/create-project.md",
"triggers/develop/generate-module.md": "base/triggers/develop/generate-module.md",
// ── Триггеры: разработка / стилизация и ресурсы ─────────────
"triggers/develop/style-component.md": "base/triggers/develop/style-component.md",
"triggers/develop/add-icon.md": "base/triggers/develop/add-icon.md",
"triggers/develop/add-image.md": "base/triggers/develop/add-image.md",
"triggers/develop/add-video.md": "base/triggers/develop/add-video.md",
"triggers/develop/add-font.md": "base/triggers/develop/add-font.md",
// ── Триггеры: разработка / данные и состояние ───────────────
"triggers/develop/add-api-request.md": "base/triggers/develop/add-api-request.md",
"triggers/develop/connect-store.md": "base/triggers/develop/connect-store.md",
"triggers/develop/add-server-data.md": "nextjs/triggers/develop/add-server-data.md",
// ── Триггеры: разработка / инфраструктура ───────────────────
"triggers/develop/add-localization.md": "base/triggers/develop/add-localization.md",
"triggers/develop/add-dependency.md": "base/triggers/develop/add-dependency.md",
"triggers/develop/setup-vscode.md": "base/triggers/develop/setup-vscode.md",
},
};

5
src/base/applied/api.md Normal file
View File

@@ -0,0 +1,5 @@
---
scope: applied
keywords: [api, запрос, fetch, SWR, эндпоинт, REST, клиент]
when: "Работа с API: запросы, клиенты, обработка ответов"
---

View File

@@ -1,7 +1,9 @@
--- ---
title: Компоненты title: Компоненты
scope: applied
keywords: [компонент, props, jsx, ui, clsx, cl, React, FC]
when: "Создание или редактирование React-компонентов: структура, пропсы, стили"
--- ---
# Компоненты # Компоненты
Правила написания React-компонентов: файловая структура модуля, типизация пропсов, документирование и реализация. Раздел охватывает компоненты всех слоёв — от `shared/ui` до `screens`. Правила написания React-компонентов: файловая структура модуля, типизация пропсов, документирование и реализация. Раздел охватывает компоненты всех слоёв — от `shared/ui` до `screens`.
@@ -110,3 +112,7 @@ export const Container = (props: ContainerProps) => {
```ts ```ts
export { Container } from './container' export { Container } from './container'
``` ```
## Дочерние компоненты
Если модулю нужны внутренние подкомпоненты — генерировать их из шаблона `component` в папку `ui/` внутри родительского модуля. Дочерние компоненты не экспортируются через `index.ts` родителя.

View File

@@ -0,0 +1,5 @@
---
scope: applied
keywords: [шрифт, font, next/font, подключение шрифта, woff]
when: "Подключение и настройка шрифтов"
---

View File

@@ -0,0 +1,5 @@
---
scope: applied
keywords: [хук, hook, use, кастомный хук, useState, useEffect]
when: "Создание или использование кастомных хуков"
---

View File

@@ -0,0 +1,5 @@
---
scope: applied
keywords: [изображение, картинка, image, next/image, public, оптимизация]
when: "Работа с изображениями: подключение, оптимизация"
---

View File

@@ -0,0 +1,5 @@
---
scope: applied
keywords: [i18n, локализация, перевод, язык, i18next, namespace]
when: "Локализация: добавление переводов, работа с i18next"
---

View File

@@ -0,0 +1,5 @@
---
scope: applied
keywords: [стор, store, zustand, состояние, глобальное состояние]
when: "Работа с глобальным состоянием: создание стора, подписка"
---

View File

@@ -1,7 +1,9 @@
--- ---
title: Стили title: Стили
scope: applied
keywords: [css, postcss, модули, css modules, токены, медиа-запросы, вложенность, класс]
when: "Стилизация: CSS Modules, PostCSS, переменные, медиа-запросы"
--- ---
# Стили # Стили
Раздел описывает правила написания CSS: PostCSS Modules, вложенность, медиа-запросы, переменные, форматирование. Раздел описывает правила написания CSS: PostCSS Modules, вложенность, медиа-запросы, переменные, форматирование.
@@ -267,3 +269,17 @@ title: Стили
- Желательно не писать комментарии в CSS. - Желательно не писать комментарии в CSS.
- Исключение — нетривиальные хаки и обходные решения, к которым стоит оставить пояснение. - Исключение — нетривиальные хаки и обходные решения, к которым стоит оставить пояснение.
## Приоритет стилизации
Основной UI-фреймворк проекта — **Mantine**. При стилизации компонентов придерживаться следующего приоритета:
1. **Mantine-компоненты и их пропсы** — в первую очередь использовать встроенные возможности Mantine (пропсы, `classNames`, `styles`).
2. **Глобальные CSS-токены** (`--color-*`, `--space-*`, `--radius-*`) — для значений, которые не покрываются Mantine.
3. **PostCSS Modules** — когда Mantine не покрывает задачу и нужна кастомная стилизация.
## Что запрещено
- **Инлайн-стили** — использование атрибута `style` в компонентах строго запрещено.
- **Магические значения** — произвольные цвета, отступы и скругления запрещены, использовать токены.
- **Глобальные стили** вне `app/styles/` запрещены.

View File

@@ -0,0 +1,7 @@
---
title: SVG-спрайты
scope: applied
keywords: [svg, спрайт, иконка, icon, sprite]
when: "Работа с SVG-иконками и спрайтами"
---
# SVG-спрайты

View File

@@ -1,7 +1,9 @@
--- ---
title: Шаблоны и генерация кода title: Шаблоны и генерация кода
scope: applied
keywords: [шаблон, генерация, template, scaffold, plop, hygen, .templates]
when: "Генерация кода из шаблонов, создание новых шаблонов"
--- ---
<!-- @formatter:off --> <!-- @formatter:off -->
::: v-pre ::: v-pre
@@ -154,3 +156,20 @@ npx @gromlab/create <шаблон> <имя> <путь>
::: :::
## Какие модули генерируются из шаблонов
| Модуль | Слой | Шаблон |
|---|---|---|
| Компонент | `shared/ui/` | `component` |
| Фича | `features/` | `feature` |
| Виджет | `widgets/` | `widget` |
| Сущность | `entities/` | `entity` |
| Layout | `layouts/` | `layout` |
| Экран | `screens/` | `screen` |
| Стор | `model/` | `store` |
## Когда создавать новый шаблон
- Повторяющаяся структура появляется больше одного раза.
- Существующий шаблон не покрывает нужный тип модуля.

View File

@@ -0,0 +1,5 @@
---
scope: applied
keywords: [видео, video, плеер, mp4]
when: "Встраивание и работа с видео"
---

View File

@@ -1,7 +1,9 @@
--- ---
title: Настройка VS Code title: Настройка VS Code
scope: applied
keywords: [vscode, редактор, расширение, настройка, extension, .vscode]
when: "Настройка VS Code: расширения, settings.json, сниппеты"
--- ---
# Настройка VS Code # Настройка VS Code
Каждый проект содержит папку `.vscode/` с конфигурацией редактора. Это гарантирует, что все участники команды работают с одинаковыми настройками форматирования, линтинга и расширениями. Каждый проект содержит папку `.vscode/` с конфигурацией редактора. Это гарантирует, что все участники команды работают с одинаковыми настройками форматирования, линтинга и расширениями.

View File

@@ -0,0 +1,665 @@
---
title: Архитектура
scope: basics
keywords: [SLM Design, слой, модуль, сегмент, архитектура, FSD, scoped layered module]
when: "Организация кода: слои, модули, зависимости между модулями"
---
<!-- /index -->
# SLM Design
Scoped Layered Module Design — модульная архитектура фронтенд-приложений. Код организован по слоям ответственности, а модуль содержит всё, что ему нужно: компоненты, хуки, сторы, типы, стили.
## Преимущества
### Вертикальная организация домена
Бизнес-домен не разбивается по техническим слоям — сценарии, сущности, типы и UI живут в одном модуле. Это сокращает время навигации и упрощает сопровождение: все изменения домена локализованы.
### Dependency Injection без фреймворков
Cross-domain зависимости в бизнес-слое реализуются через фабрики — модуль декларирует что ему нужно, а точка использования предоставляет зависимости. Домены изолированы без DI-контейнеров, провайдеров и шин событий.
### Разделение ответственности без перегрузки слоёв
Сервисы приложения (`infrastructure/`), UI-кит (`ui/`) и общие ресурсы (`shared/`) — три разных слоя с разной природой. Ни один слой не превращается в свалку разнородного кода.
### Горизонтальная инкапсуляция
Вложенные модули (`parts/`) и направление зависимостей позволяют нескольким разработчикам работать над одной областью приложения параллельно, не затрагивая код друг друга.
### Колокация по умолчанию
Код начинает жизнь рядом с местом использования и поднимается в общие слои только при реальной потребности. Глобальные слои не засоряются преждевременными абстракциями.
### Явное разделение каркаса и контента
Каркас группы маршрутов (`layouts/`) и контент конкретной страницы (`screens/`) — независимые слои с собственной ответственностью.
### Масштабирование через группировку
При росте проекта слои не теряют структуру — модули группируются по естественным признакам: бизнес-домены по субдоменам, страницы по разделам, UI-компоненты по уровню абстракции (примитивы и композиции).
## Происхождение
SLM Design вырос на основе:
- **Feature-Sliced Design** — слоистая структура, публичный API модуля, направление зависимостей
- **Vertical Slice Architecture** — модуль как вертикальный срез, содержащий всё необходимое
- **Screaming Architecture** — структура проекта «кричит» о назначении: открыл `business/auth` — видишь авторизацию
- **Colocation Principle** — код живёт рядом с местом использования
## Пример структуры проекта
```text
src/
├── app/
├── layouts/
│ ├── main/
│ └── dashboard/
├── screens/
│ ├── home/
│ ├── products/
│ ├── product-detail/
│ └── about/
├── widgets/
│ ├── page-heading/
│ ├── hero-section/
│ └── promo-banner/
├── business/
│ ├── auth/
│ ├── catalog/
│ ├── orders/
│ └── chat/
├── infrastructure/
│ ├── theme/
│ ├── i18n/
│ ├── backend-api/
│ └── logger/
├── ui/
│ ├── button/
│ ├── input/
│ ├── modal/
│ ├── toast/
│ └── dropdown/
└── shared/
├── lib/
├── types/
└── styles/
```
## Принципы
- **Домен — единое целое.** Всё, что относится к домену, живёт в одном модуле.
- **Колокация.** Код рождается рядом с местом использования и поднимается только при необходимости.
- **Зависимости однонаправлены.** Импорты только сверху вниз, только через публичный API.
- **Архитектура — каркас, не клетка.** Правила фиксируют направление зависимостей и структуру модуля, остальное определяет команда.
<!-- /reference/layers -->
## Слои
Раздел описывает слои SLM: что такое слой, какие бывают, как между ними направлены зависимости и какие правила действуют на каждом.
### Определение
**Слой — уровень организации кода внутри `src/`. Каждый слой отвечает за свою область (каркас страницы, бизнес-логика, UI-кит) и задаёт правила для кода внутри: направление импортов, именование, допустимые связи между модулями.**
### Группы слоёв
Слои делятся на три группы:
| Группа | Слои | Описание |
|--------|------|----------|
| Композиция | `app`, `layouts`, `screens`, `widgets` | Собирают интерфейс из готовых блоков: маршруты, каркасы, страницы |
| Ядро | `business`, `infrastructure`, `ui` | Реализация продукта: бизнес-домены, техсервисы, UI-кит |
| Фундамент | `shared` | Общие ресурсы: утилиты, хелперы, стили, конфиги |
### Направление зависимостей
Любой импорт между модулями — только через публичный API.
```
app → [ layouts | screens ] → widgets → business → infrastructure → ui → shared
```
- `layouts` и `screens` — параллельные слои, не импортируют друг друга
- Модули одного слоя в группе «Композиция» изолированы друг от друга
- Модули одного слоя `infrastructure` и `ui` могут импортировать друг друга через публичный API
- Модули `business` — cross-domain зависимости по коду через фабрику, `import type` напрямую
- Импорт типов (`import type`) в «Ядре» разрешён в обоих направлениях
### Слой App
Точка входа приложения. Отвечает за запуск, роутинг и композицию маршрутов из layout и screen.
В отличие от остальных слоёв, `app/` не содержит модулей SLM. Здесь живут только инфраструктурные файлы, которые не могут быть никаким другим слоем: файлы фреймворка роутинга, точка запуска и код инициализации.
#### Требования
- Не содержит модулей SLM — только файлы фреймворка, роутинг, инициализация
- Содержит: файлы маршрутов, bootstrap, обработку ошибок верхнего уровня (404, error boundary), подключение глобальных стилей и ассетов
- Провайдеры и гарды — только подключает готовые из нижних слоёв, не реализует
- Не содержит бизнес-логику, UI-компоненты, хуки, сторы, сервисы
- Никем не импортируется
### Слой Layouts
Каркас страницы: общие элементы, одинаковые для группы маршрутов (header, footer, sidebar).
```text
src/layouts/
├── main/
├── dashboard/
└── auth/
```
#### Требования
- Содержит только модули
- Не содержит бизнес-логику
- Контекстно-зависимые блоки принимает через пропсы от `app`, не импортирует напрямую
### Слой Screens
Контент конкретной страницы: собирает её из модулей нижних слоёв.
```text
src/screens/
├── home/
├── products/
├── product-detail/
├── about/
└── contacts/
```
Когда количество страниц затрудняет навигацию — вводится группировка по разделам. Группа — папка для организации, не модуль (без `index.ts`).
```text
src/screens/
├── shop/
│ ├── home/
│ ├── products/
│ ├── product-detail/
│ └── cart/
├── account/
│ ├── profile/
│ ├── settings/
│ └── order-history/
└── info/
├── about/
├── contacts/
└── faq/
```
#### Требования
- Содержит только модули
- Не содержит бизнес-логику
- Локальные одноразовые секции живут внутри screen-модуля, не выносятся в `widgets`/`business`
### Слой Widgets
Составной блок интерфейса, который компонует модули ядра, но не принадлежит конкретному бизнес-домену. Widget появляется когда блок используется в нескольких screens или layouts.
Если блок принадлежит домену — он живёт в `business/{area}/`, даже если переиспользуется. Если блок нужен только в одном месте — это `screens/{name}/parts/` или `layouts/{name}/parts/`, а не widget.
```text
src/widgets/
├── page-heading/
├── hero-section/
├── onboarding-checklist/
├── promo-banner/
└── error-boundary/
```
#### Требования
- Не принадлежит конкретному бизнес-домену. Если блок доменный — он живёт в `business/`
- Используется в нескольких screens или layouts
### Слой Business
Бизнес-домены приложения: auth, catalog, orders, checkout, chat. Каждый домен — отдельный модуль со своими типами, логикой, UI и сервисами.
Слой входит в группу «Ядро». Импортирует `infrastructure/`, `ui/`, `shared/`. Cross-domain зависимости по коду реализуются через фабрику. `import type` между доменами разрешён напрямую.
Business объединяет то, что в FSD разделено на `features` и `entities`: пользовательские сценарии и бизнес-сущности живут вместе, внутри одного домена. Внутри домена сегменты разделяют ответственность: `types/` — доменная модель, `hooks/` и `services/` — сценарии и логика, `mappers/` — трансформация данных, `parts/` — составные блоки.
```text
src/business/
├── auth/
├── catalog/
├── orders/
├── checkout/
└── chat/
```
Когда количество доменов затрудняет навигацию — вводится группировка по субдоменам. Группа — папка для организации, не модуль (без `index.ts`).
```text
src/business/
├── commerce/
│ ├── catalog/
│ ├── cart/
│ ├── orders/
│ └── checkout/
└── communication/
├── chat/
└── notifications/
```
#### Требования
- Один модуль = один бизнес-домен
- Циклические зависимости между доменами запрещены
- Импорт кода между доменами — через фабрику. `import type` — напрямую
- Доменные типы (`User`, `Product`) живут здесь, не в `shared/`
### Слой Infrastructure
Техсервисы приложения: theme, i18n, API-адаптеры, logger, realtime. Каждый сервис — отдельный модуль.
Слой входит в группу «Ядро». Импортирует `infrastructure/`, `ui/`, `shared/`.
Отличие от `shared/`: infrastructure — инфраструктура приложения (сервисы, темы, адаптеры к API), `shared/` — общие ресурсы (утилиты, хелперы, стили, конфиги).
```text
src/infrastructure/
├── theme/
├── i18n/
├── backend-api/
├── maps-api/
├── logger/
├── feature-flags/
└── realtime/
```
#### Требования
- Один модуль = один техсервис
- Импортирует `infrastructure/`, `ui/`, `shared/`
### Слой UI
UI-кит без бизнес-логики: button, carousel, toast, modal.
Слой входит в группу «Ядро». Импортирует `ui/` и `shared/`.
Компоненты строятся друг на друге: `button` использует `icon`, `carousel` использует `button`.
```text
src/ui/
├── button/
├── input/
├── icon/
├── carousel/
├── modal/
├── toast/
├── dropdown/
├── tabs/
└── tooltip/
```
Когда количество компонентов затрудняет навигацию — вводится группировка на примитивы и композиции. Примитивы (`button`, `icon`, `input`) не импортируют композиции. Композиции (`carousel`, `modal`, `dropdown`) строятся на примитивах.
```text
src/ui/
├── primitives/
│ ├── button/
│ ├── input/
│ ├── icon/
│ └── badge/
└── composites/
├── carousel/
├── modal/
├── dropdown/
├── tabs/
└── tooltip/
```
#### Требования
- Не содержит бизнес-логику
- Импортирует только `ui/` и `shared/`
### Слой Shared
Общие ресурсы: утилиты, хелперы, стили, конфиги. Не знает о бизнес-домене.
Слой входит в группу «Фундамент» — ни о ком не знает, никого не импортирует.
Отличие от `infrastructure/`: infrastructure — инфраструктура приложения (сервисы, темы, адаптеры к API), `shared/` — общие ресурсы (утилиты, хелперы, стили, конфиги).
Отличие от `ui/`: UI-компоненты (button, carousel, modal) живут в слое `ui/`, а не здесь.
```text
src/shared/
├── lib/
├── types/
├── styles/
└── sprites/
```
#### Требования
- Не имеет runtime-состояния
<!-- /reference/modules -->
## Модули
Раздел описывает модули SLM: что такое модуль, из чего он состоит и как взаимодействует с остальным кодом.
### Определение
**Модуль — универсальный строительный блок архитектуры. Живёт на слое и содержит всё необходимое для своей работы: компоненты, хуки, сторы, сервисы, типы, стили. Набор содержимого не фиксирован — включаются только нужные части.**
### Модуль vs компонент
**Компонент** — один `.tsx` файл. Не имеет своих сегментов, использует сегменты родительского модуля. Живёт в корне или `ui/` сегменте модуля.
**Модуль** — папка, которая может содержать корневой компонент, сегменты (`hooks/`, `types/`, `styles/`, `ui/`, `parts/` и т.д.) и публичный API (`index.ts`).
```text
auth/
├── ui/
│ ├── auth-guard.tsx
│ └── logout-button.tsx
├── parts/
│ ├── login-form/
│ ├── registration-form/
│ └── restore-form/
├── hooks/
├── stores/
├── types/
├── auth.tsx # корневой компонент (опционален)
└── index.ts
```
### Структура
Модуль состоит из сегментов. Ни один сегмент не обязателен — модуль может состоять даже из одного `index.ts` с реэкспортом типов.
```text
{module-name}/
├── {module-name}.tsx # корневой компонент (опционален)
├── ui/ # компоненты модуля (только .tsx)
├── parts/ # вложенные модули (со своими сегментами)
├── hooks/ # хуки
├── stores/ # сторы состояния
├── services/ # внешние источники данных
├── mappers/ # трансформация данных между форматами
├── types/ # типы
├── styles/ # стили
├── lib/ # утилиты модуля
├── config/ # константы
└── index.ts # публичный API
```
Подробное описание каждого сегмента — в разделе [Сегменты](/reference/segments).
### Публичный API
Модуль экспортирует наружу только то, что нужно другим. Всё остальное — внутреннее.
```ts
// business/auth/index.ts
export type { User, Session } from './types/user.types'
export { useAuth } from './hooks/use-auth.hook'
export { AuthGuard } from './ui/auth-guard'
```
Импорт в обход `index.ts` запрещён:
```ts
// Плохо
import { validateToken } from '@/business/auth/lib/tokens'
// Хорошо
import { useAuth } from '@/business/auth'
```
### Фабрика
Если модуль зависит от кода другого бизнес-домена — он экспортирует фабрику. Фабрика декларирует необходимые зависимости и возвращает API модуля. Точка использования (screen, widget, layout) предоставляет зависимости при вызове.
Модуль без cross-domain зависимостей экспортирует API напрямую. Типы всегда экспортируются напрямую — `import type` не является runtime-зависимостью.
#### Модуль без зависимостей — прямой экспорт:
```ts
// business/auth/index.ts
export { useAuth } from './hooks/use-auth'
export { useCurrentUser } from './hooks/use-current-user'
export type { User, Session } from './types'
```
#### Модуль с зависимостями — фабрика:
```ts
// business/chat/types/deps.ts
import type { User } from '@/business/auth'
export interface ChatDeps {
useCurrentUser: () => User | null
}
```
```ts
// business/chat/index.ts
import type { ChatDeps } from './types/deps'
export function chatFactory(deps: ChatDeps) {
return {
useMessages: (roomId: string) => {
const user = deps.useCurrentUser()
// ...
},
useSendMessage: (roomId: string) => {
const user = deps.useCurrentUser()
return (text: string) => { /* ... */ }
},
useChatRooms: () => {
const user = deps.useCurrentUser()
// ...
},
ChatBadge: ({ count }: { count: number }) => { /* ... */ },
}
}
export type { Message, ChatRoom } from './types'
export type { ChatDeps } from './types/deps'
```
#### Использование на странице:
```tsx
// screens/support/support.tsx
import { useCurrentUser } from '@/business/auth'
import { chatFactory } from '@/business/chat'
const chat = chatFactory({ useCurrentUser })
export function SupportScreen() {
const { useMessages, useSendMessage, ChatBadge } = chat
const messages = useMessages('support')
const sendMessage = useSendMessage('support')
return (
<div>
<ChatBadge count={messages.length} />
{messages.map(m => <MessageBubble key={m.id} {...m} />)}
<MessageInput onSend={sendMessage} />
</div>
)
}
```
### Жизненный цикл
Модуль рождается на самом низком уровне использования и поднимается выше только при реальной потребности.
- Нужен на одной странице → `screens/{name}/parts/`
- Появился в 2+ местах → поднимается по природе:
- абстрактный UI → `ui/`
- блок с данными/логикой → `widgets/`
- представление бизнес-домена → `business/{area}/parts/`
Подъём — обычный рефакторинг в рамках задачи, а не отдельная активность.
<!-- /reference/segments -->
## Сегменты
Раздел описывает сегменты SLM: что такое сегмент, какие бывают и что в каждом из них лежит.
### Определение
**Сегмент — папка внутри модуля, которая группирует файлы по назначению. Набор сегментов не фиксирован — модуль включает только те, которые ему нужны. Команда сама определяет какие сегменты используются в проекте — архитектура даёт рекомендацию.**
### Обзор
| Сегмент | Содержимое |
|---------|------------|
| `ui/` | Компоненты модуля — только `.tsx` файлы |
| `parts/` | Вложенные модули со своими сегментами |
| `hooks/` | React-хуки |
| `stores/` | Сторы состояния |
| `services/` | Работа с внешними источниками данных |
| `mappers/` | Трансформация данных между форматами |
| `types/` | TypeScript-типы и интерфейсы |
| `styles/` | Стили |
| `lib/` | Утилиты и хелперы модуля |
| `config/` | Константы и конфигурация |
### Сегмент ui/
Компоненты, принадлежащие модулю. Содержит только `.tsx` файлы — без своих сегментов, стилей, типов, хуков. Использует сегменты родительского модуля.
```text
auth/
├── ui/
│ ├── auth-provider.tsx
│ ├── auth-guard.tsx
│ └── logout-button.tsx
├── types/
├── hooks/
└── index.ts
```
Если компоненту нужны собственные сегменты — это уже не `ui/`, а `parts/`.
### Сегмент parts/
Вложенные модули со своими сегментами. Каждый элемент `parts/` — полноценный модуль: папка с компонентом, хуками, стилями, типами и т.д.
```text
home/
├── parts/
│ ├── hero-section/
│ │ ├── hero-section.tsx
│ │ ├── styles/
│ │ └── parts/
│ │ └── top-banner/
│ │ └── top-banner.tsx
│ └── features-section/
│ ├── features-section.tsx
│ └── hooks/
├── home.screen.tsx
└── index.ts
```
Отличие от `ui/`: элемент `parts/` — модуль со своими сегментами. Элемент `ui/` — компонент, один `.tsx` файл.
Вложенность `parts/` инкапсулирует область разработки горизонтально: каждый разработчик работает в своём `parts/`-модуле, не затрагивая чужие. Это снижает конфликты при параллельной разработке.
Если вложенный модуль обрастает своими `parts/` — это сигнал, что он достаточно самостоятельный для подъёма на уровень выше.
### Сегмент hooks/
React-хуки модуля. Инкапсулируют логику, состояние, подписки, побочные эффекты.
```text
hooks/
├── use-auth.hook.ts
├── use-session.hook.ts
└── use-permissions.hook.ts
```
### Сегмент stores/
Сторы состояния модуля. Конкретная реализация зависит от выбранного стейт-менеджера (Zustand, MobX, Redux и т.д.).
```text
stores/
├── auth.store.ts
└── session.store.ts
```
### Сегмент services/
Работа с внешними источниками данных: API-вызовы, запросы, подписки.
```text
services/
├── auth.service.ts
└── token.service.ts
```
### Сегмент mappers/
Функции трансформации данных из одного формата в другой: DTO в доменный тип, доменный тип в DTO, доменный тип в ViewModel.
```text
mappers/
├── map-user.ts
├── map-product.ts
└── map-order-to-dto.ts
```
### Сегмент types/
TypeScript-типы и интерфейсы модуля. Доменные типы, DTO, пропсы компонентов.
```text
types/
├── user.type.ts
└── session.type.ts
```
### Сегмент styles/
Стили модуля. Формат зависит от выбранного подхода (CSS Modules, SCSS, CSS-in-JS и т.д.).
```text
styles/
├── auth.module.css
└── login-form.module.css
```
### Сегмент lib/
Утилиты и хелперы, специфичные для модуля. Чистые функции без побочных эффектов.
```text
lib/
├── validate-email.ts
└── format-phone.ts
```
Отличие от `shared/lib/`: здесь лежат утилиты, нужные только этому модулю. Общие утилиты — в `shared/lib/`.
### Сегмент config/
Константы и конфигурация модуля: маршруты, лимиты, дефолтные значения.
```text
config/
├── routes.ts
└── constants.ts
```

View File

@@ -1,7 +1,9 @@
--- ---
title: Стиль кода title: Стиль кода
scope: basics
keywords: [форматирование, импорт, отступ, кавычки, early return, точка с запятой, линтер]
when: "Написание или ревью любого кода: форматирование, импорты, структура файла"
--- ---
# Стиль кода # Стиль кода
Раздел описывает единые правила оформления кода: отступы, переносы, кавычки, порядок импортов и базовую читаемость. Раздел описывает единые правила оформления кода: отступы, переносы, кавычки, порядок импортов и базовую читаемость.

View File

@@ -1,7 +1,9 @@
--- ---
title: Документирование title: Документирование
scope: basics
keywords: [JSDoc, комментарий, документирование, описание функции, описание компонента]
when: "Документирование кода: JSDoc для функций, компонентов, типов"
--- ---
# Документирование # Документирование
Этот раздел описывает правила документирования кода: когда и как писать Этот раздел описывает правила документирования кода: когда и как писать

View File

@@ -1,7 +1,9 @@
--- ---
title: Начало работы title: Начало работы
scope: workflow
keywords: [начало, onboarding, настройка, установка, первый запуск]
when: "Первый запуск проекта, знакомство со стеком"
--- ---
# Начало работы # Начало работы
Что нужно знать перед началом разработки в проекте. Что нужно знать перед началом разработки в проекте.

View File

@@ -1,7 +1,9 @@
--- ---
title: Именование title: Именование
scope: basics
keywords: [camelCase, kebab-case, PascalCase, имя файла, имя переменной, имя компонента, имя хука]
when: "Создание файлов, переменных, компонентов, хуков — выбор имени"
--- ---
# Именование # Именование
Этот раздел описывает соглашения об именовании в проекте. Единые правила делают код предсказуемым и упрощают навигацию по проекту. Этот раздел описывает соглашения об именовании в проекте. Единые правила делают код предсказуемым и упрощают навигацию по проекту.

View File

@@ -1,7 +1,9 @@
--- ---
title: Технологии и библиотеки title: Технологии и библиотеки
scope: basics
keywords: [стек, React, TypeScript, Next.js, Mantine, библиотека, зависимость]
when: "Выбор библиотеки или технологии, проверка допустимости зависимости"
--- ---
# Технологии и библиотеки # Технологии и библиотеки
Этот раздел описывает базовый стек технологий и библиотек, принятый в проекте. Этот раздел описывает базовый стек технологий и библиотек, принятый в проекте.

View File

@@ -1,7 +1,9 @@
--- ---
title: Типизация title: Типизация
scope: basics
keywords: [type, interface, generic, any, unknown, enum, типизация, пропсы]
when: "Типизация кода: выбор type vs interface, работа с generic, запрет any"
--- ---
# Типизация # Типизация
Этот раздел описывает правила типизации: как типизировать компоненты, функции и работу с `any`/`unknown`. Этот раздел описывает правила типизации: как типизировать компоненты, функции и работу с `any`/`unknown`.

View File

@@ -0,0 +1,35 @@
---
title: Добавить API-запрос
---
# Добавить API-запрос
Инструкция по добавлению запроса к серверу: создание клиента, хука, обработка ответа.
## Прочитай перед началом
- applied/api.md — правила API-слоя: клиенты, эндпоинты, обработка ошибок
- basics/typing.md — типизация запросов и ответов
## Шаги
1. Определи подход:
- Клиентские данные → SWR / хук
- Серверные данные → серверный компонент (RSC)
2. Опиши типы запроса и ответа.
3. Создай или расширь API-клиент (→ applied/api.md).
4. Создай хук для использования в компоненте (→ triggers/develop/create-hook.md).
## Смежные триггеры
- triggers/develop/create-hook.md — хук для запроса
- triggers/develop/create-component.md — компонент, использующий данные
## Проверь себя
- [ ] Типы запроса и ответа описаны
- [ ] Хук для использования в компоненте создан
- [ ] Обработка ошибок реализована

View File

@@ -0,0 +1,24 @@
---
title: Добавить зависимость
---
# Добавить зависимость
Инструкция по добавлению новой npm-зависимости в проект. Проверь допустимость перед установкой.
## Прочитай перед началом
- basics/tech-stack.md — разрешённый стек, допустимые библиотеки
## Шаги
1. Проверь, что библиотека не дублирует уже используемую (→ basics/tech-stack.md).
2. Проверь, что библиотека входит в разрешённый список или обоснуй необходимость.
3. Установи как `dependency` или `devDependency` в зависимости от назначения.
## Проверь себя
- [ ] Библиотека не дублирует уже используемую
- [ ] Библиотека входит в разрешённый список (→ basics/tech-stack.md)

View File

@@ -0,0 +1,28 @@
---
title: Подключить шрифт
---
# Подключить шрифт
Инструкция по подключению и настройке шрифта в проекте.
## Прочитай перед началом
- applied/fonts.md — правила подключения шрифтов: форматы, загрузка, CSS-переменные
## Шаги
1. Подготовь файлы шрифта (woff2).
2. Подключи шрифт по правилам (→ applied/fonts.md).
3. Зарегистрируй CSS-переменную для шрифта.
## Смежные триггеры
- triggers/develop/style-component.md — использование шрифта в стилях
## Проверь себя
- [ ] Файл шрифта в формате woff2
- [ ] CSS-переменная для шрифта зарегистрирована

View File

@@ -0,0 +1,29 @@
---
title: Добавить иконку
---
# Добавить иконку
Инструкция по добавлению SVG-иконки в проект через спрайт-систему.
## Прочитай перед началом
- applied/svg-sprites.md — правила SVG-спрайтов: структура, именование, использование
## Шаги
1. Подготовь SVG-файл: убери лишние атрибуты, оптимизируй.
2. Добавь SVG в спрайт по правилам (→ applied/svg-sprites.md).
3. Используй иконку в компоненте через компонент-обёртку.
## Смежные триггеры
- triggers/develop/create-component.md — если нужен компонент-обёртка для иконки
- triggers/develop/style-component.md — стилизация иконки (размер, цвет)
## Проверь себя
- [ ] SVG оптимизирован — убраны лишние атрибуты
- [ ] Иконка добавлена в спрайт по правилам (→ applied/svg-sprites.md)

View File

@@ -0,0 +1,30 @@
---
title: Добавить изображение
---
# Добавить изображение
Инструкция по добавлению и использованию растровых изображений в проекте.
## Прочитай перед началом
- applied/images-sprites.md — правила работы с изображениями: оптимизация, форматы, подключение
## Шаги
1. Определи тип изображения:
- Статическое (логотип, декор) → `public/`
- Динамическое (контентное) → URL из API
2. Оптимизируй изображение (формат, размер, сжатие).
3. Подключи в компоненте по правилам (→ applied/images-sprites.md).
## Смежные триггеры
- triggers/develop/create-component.md — если нужен компонент-обёртка для изображения
## Проверь себя
- [ ] Изображение оптимизировано (формат, размер, сжатие)
- [ ] Подключено по правилам (→ applied/images-sprites.md)

View File

@@ -0,0 +1,28 @@
---
title: Добавить перевод
---
# Добавить перевод
Инструкция по добавлению локализации: создание ключей перевода и подключение в компоненте.
## Прочитай перед началом
- applied/localization.md — правила локализации: namespace, ключи, форматирование
## Шаги
1. Определи namespace для переводов (→ applied/localization.md).
2. Добавь ключи перевода в файлы локализации.
3. Подключи переводы в компоненте (→ applied/localization.md).
## Смежные триггеры
- triggers/develop/create-component.md — если компонент ещё не создан
## Проверь себя
- [ ] Ключи перевода добавлены в файлы локализации
- [ ] Namespace определён (→ applied/localization.md)

View File

@@ -0,0 +1,27 @@
---
title: Добавить видео
---
# Добавить видео
Инструкция по встраиванию видео в проект.
## Прочитай перед началом
- applied/video.md — правила работы с видео: форматы, плеер, оптимизация
## Шаги
1. Определи тип видео:
- Локальное → `public/`
- Внешнее (YouTube, Vimeo) → embed
2. Подключи видео по правилам (→ applied/video.md).
## Смежные триггеры
- triggers/develop/create-component.md — если нужен компонент-обёртка для видео
## Проверь себя
- [ ] Видео подключено по правилам (→ applied/video.md)

Some files were not shown because too many files have changed in this diff Show More