diff --git a/ai/nextjs-style-guide/DEVELOP.md b/ai/nextjs-style-guide/DEVELOP.md
new file mode 100644
index 0000000..265090d
--- /dev/null
+++ b/ai/nextjs-style-guide/DEVELOP.md
@@ -0,0 +1,103 @@
+---
+title: Гид для агента
+description: Что AI-агент обязан прочитать перед началом работы, а что — по задаче.
+---
+
+# Обязательное чтение перед началом работы
+
+Этот документ определяет **строгий порядок действий агента перед выполнением любых задач**.
+
+## Общее правило
+
+Перед началом работы над **любой задачей** агент **обязан ознакомиться с базовой документацией проекта**.
+
+Нарушение этого порядка считается ошибкой.
+
+---
+
+## Порядок обязательного чтения
+
+Агент должен читать документацию **строго в следующем порядке**:
+
+### 1. Архитектура (КРИТИЧЕСКИ ВАЖНО)
+
+* [Архитектура: Обзор](./basics/architecture/index.md)
+* [Архитектура: Слои](./basics/architecture/reference/layers.md)
+* [Архитектура: Модули](./basics/architecture/reference/modules.md)
+* [Архитектура: Сегменты](./basics/architecture/reference/segments.md)
+
+**Архитектура — это самое важное в проекте.**
+
+Агент обязан:
+
+* строго понимать архитектурный подход (SLM)
+* соблюдать архитектуру **на 100% без отклонений**
+* не предлагать решений, нарушающих архитектурные принципы
+* не упрощать архитектуру даже ради скорости выполнения задачи
+
+Любое нарушение архитектуры недопустимо.
+
+---
+
+### 2. Базовые правила
+
+После архитектуры необходимо изучить:
+
+* [Технологии и библиотеки](./basics/tech-stack.md)
+* [Именование](./basics/naming.md)
+* [Стиль кода](./basics/code-style.md)
+* [Документирование](./basics/documentation.md)
+* [Типизация](./basics/typing.md)
+
+Агент обязан применять эти правила во всех решениях.
+
+---
+
+## Использование карты документации
+
+Для поиска дополнительных сведений агент должен использовать:
+
+* [MAP.md](./MAP.md)
+
+MAP.md содержит ссылки на все прикладные и вспомогательные разделы.
+
+Агент может:
+
+* переходить к нужным разделам через MAP.md
+* уточнять детали реализации
+* искать примеры и частные случаи
+
+---
+
+## Запрещено
+
+Агенту запрещено:
+
+* начинать выполнение задачи без изучения архитектуры
+* игнорировать базовые правила
+* принимать решения, противоречащие архитектуре
+* придумывать собственные подходы, если они не описаны в документации
+
+---
+
+## Ожидаемое поведение агента
+
+Перед выполнением задачи агент должен:
+
+1. Изучить архитектуру
+2. Изучить базовые правила
+3. При необходимости открыть MAP.md и найти релевантные разделы
+4. Только после этого приступать к решению задачи
+
+---
+
+## Приоритеты
+
+При принятии решений агент должен руководствоваться следующим приоритетом:
+
+1. **Архитектура**
+2. Базовые правила
+3. Документация из MAP.md
+4. Задача пользователя
+
+Если задача противоречит архитектуре — задача должна быть переосмыслена, а не выполнена напрямую.
diff --git a/ai/nextjs-style-guide/MAP.md b/ai/nextjs-style-guide/MAP.md
new file mode 100644
index 0000000..2f022c8
--- /dev/null
+++ b/ai/nextjs-style-guide/MAP.md
@@ -0,0 +1,66 @@
+# Карта документации
+
+Список всех разделов архива с относительными ссылками. Точка входа
+— `DEVELOP.md` рядом с этим файлом.
+
+## Подсказки
+
+- [Подсказки](./workflow.md) — Короткие ответы на типовые вопросы и решения для спорных ситуаций.
+
+## Базовые правила
+
+- [Технологии и библиотеки](./basics/tech-stack.md) — Какие библиотеки и инструменты используются в проекте.
+- [Именование](./basics/naming.md) — Как называть переменные, файлы и прочие сущности в коде.
+- [Архитектура: Обзор](./basics/architecture/index.md) — Архитектурный подход проекта: что такое SLM и как он устроен.
+- [Архитектура: Слои](./basics/architecture/reference/layers.md) — Из каких слоёв состоит SLM-архитектура и как они связаны.
+- [Архитектура: Модули](./basics/architecture/reference/modules.md) — Что такое модуль в SLM-архитектуре и как он устроен.
+- [Архитектура: Сегменты](./basics/architecture/reference/segments.md) — Что такое сегмент модуля в SLM-архитектуре и какие они бывают.
+- [Стиль кода](./basics/code-style.md) — Как оформляется код в проекте.
+- [Документирование](./basics/documentation.md) — Что и как документировать в коде.
+- [Типизация](./basics/typing.md) — Как типизируется код в проекте.
+
+## Создание проекта
+
+- [Из шаблона](./creating-project/from-template.md) — Создание нового проекта на основе готового шаблона.
+- [По гайду вручную](./creating-project/manual.md) — Поэтапное создание нового проекта без использования шаблона.
+- [Чистый Next.js](./creating-project/nextjs.md) — Установка Next.js без лишнего шаблона — голый каркас под дальнейшую сборку.
+
+## Работа с данными
+
+- [Введение](./data/index.md) — Какие источники данных используются в проекте и как с ними работать.
+- [REST](./data/rest/index.md) — Как правильно работать с REST API в проекте.
+- [REST: Создание клиента](./data/rest/clients/index.md) — Как выбрать способ создания REST-клиента и где размещать его части.
+- [REST: Создание клиента: Автогенерация из OpenAPI](./data/rest/clients/auto.md) — Генерация REST-клиента из OpenAPI-спецификации через @gromlab/api-codegen.
+- [REST: Создание клиента: Ручное создание](./data/rest/clients/manual.md) — Создание REST-клиента вручную, когда OpenAPI нет или он неполный.
+- [REST: Создание клиента: GET-хуки REST-клиента](./data/rest/clients/hooks.md) — Прозрачные SWR-обёртки над GET-методами REST-клиента.
+- [REST: Использование: Стратегии получения данных](./data/rest/strategies/index.md) — Как выбрать способ получения REST-данных в зависимости от места и сценария.
+- [REST: Использование: Серверный await](./data/rest/strategies/server-await.md) — Получение REST-данных на сервере прямым await метода клиента.
+- [REST: Использование: Параллельные серверные запросы](./data/rest/strategies/parallel-server-requests.md) — Как запускать независимые REST-запросы на сервере без waterfall.
+- [REST: Использование: Передача промиса ниже](./data/rest/strategies/pass-promise-down.md) — Как запускать серверный REST-запрос выше и ожидать его во вложенном server-компоненте.
+- [REST: Использование: Начальные данные для клиентских хуков](./data/rest/strategies/client-hooks-initial-data.md) — Как передать серверный промис в SWR fallback, чтобы клиентские GET-хуки получили начальные данные.
+- [REST: Использование: Клиентский GET-хук](./data/rest/strategies/client-get-hook.md) — Получение REST-данных в Client Components через готовые GET-хуки REST-клиента.
+- [REST: Использование: Business-композиция](./data/rest/strategies/business-composition.md) — Когда REST-данные нужно объединить или интерпретировать в бизнес-модуле.
+- [Realtime](./data/realtime.md) — Работа с push-данными от сервера: подписки и события.
+
+## Прикладные разделы
+
+- [Структура проекта](./applied/project-structure.md) — Из чего состоит проект и где что лежит.
+- [Страницы](./applied/page-level.md) — Как работать со страницами и другими файлами роутинга Next.js App Router.
+- [Компонент](./applied/component.md) — Как создавать React-компоненты внутри SLM-модулей.
+- [Модуль](./applied/module.md) — Как создавать и организовывать SLM-модули в проекте.
+- [Стили: Настройка](./applied/styles/styles-setup.md) — Подготовка стилевой основы проекта: токены, медиа-запросы, глобальные стили.
+- [Стили: Использование](./applied/styles/styles-usage.md) — Как пишутся стили в проекте.
+- [SVG-спрайты](./applied/svg-sprites/svg-sprites-intro.md) — Что такое SVG-спрайты и какие проблемы они решают.
+- [SVG-спрайты: Настройка](./applied/svg-sprites/svg-sprites-setup.md) — Подключение SVG-спрайтов в новом проекте.
+- [SVG-спрайты: Использование](./applied/svg-sprites/svg-sprites-usage.md) — Как добавлять и использовать SVG-иконки в коде.
+- [Изображения](./applied/images.md) — Как подключать изображения через Next.js Image в проекте.
+- [Шрифты](./applied/fonts.md) — Как подключать шрифты через Next.js Font в проекте.
+- [Алиасы импортов](./applied/aliases.md) — Какие алиасы импортов есть в проекте и как ими пользоваться.
+- [Шаблоны генерации](./applied/templates/templates-intro.md) — Что такое шаблоны кодогенерации и какие проблемы они решают.
+- [Шаблоны генерации: Настройка](./applied/templates/templates-setup.md) — Первичная установка шаблонов кодогенерации в проект.
+- [Шаблоны генерации: Создание шаблонов](./applied/templates/templates-create.md) — Структура шаблонов, синтаксис переменных и примеры.
+- [Шаблоны генерации: Использование](./applied/templates/templates-usage.md) — Генерация файлов из шаблонов через VS Code плагин и CLI.
+- [Biome](./applied/biome.md) — Установка и настройка линтера-форматтера в новом проекте.
+- [PostCSS](./applied/postcss.md) — Установка и настройка CSS-процессора в новом проекте.
+- [VS Code](./applied/vscode.md) — Единые настройки редактора и расширений для команды.
+- [Локализация](./applied/localization.md) — Как организовать локализацию как infrastructure-модуль.
diff --git a/ai/nextjs-style-guide/VERSION b/ai/nextjs-style-guide/VERSION
new file mode 100644
index 0000000..2ff96d1
--- /dev/null
+++ b/ai/nextjs-style-guide/VERSION
@@ -0,0 +1,2 @@
+e835210
+2026-04-30T13:02:04.343Z
diff --git a/ai/nextjs-style-guide/applied/aliases.md b/ai/nextjs-style-guide/applied/aliases.md
new file mode 100644
index 0000000..da6ccab
--- /dev/null
+++ b/ai/nextjs-style-guide/applied/aliases.md
@@ -0,0 +1,77 @@
+---
+title: Алиасы импортов
+description: Какие алиасы импортов есть в проекте и как ими пользоваться.
+keywords: [алиасы, aliases, paths, tsconfig, импорты, baseUrl, app, layouts, screens, widgets, business, infrastructure, ui, shared]
+---
+
+# Алиасы импортов
+
+Какие алиасы импортов есть в проекте и как ими пользоваться.
+
+## Конфиг
+
+`tsconfig.json` в корне проекта:
+
+```json
+{
+ "compilerOptions": {
+ "paths": {
+ "app/*": ["./src/app/*"],
+ "layouts/*": ["./src/layouts/*"],
+ "screens/*": ["./src/screens/*"],
+ "widgets/*": ["./src/widgets/*"],
+ "business/*": ["./src/business/*"],
+ "infrastructure/*": ["./src/infrastructure/*"],
+ "ui/*": ["./src/ui/*"],
+ "shared/*": ["./src/shared/*"]
+ }
+ }
+}
+```
+
+Восемь алиасов — ровно по числу слоёв. Других алиасов в проекте нет.
+
+## Правила
+
+- **Каждый импорт между модулями — через алиас слоя.** Относительные пути (`../../`) запрещены за пределами своего модуля.
+- **Внутри одного модуля** допустимы относительные импорты (`./model`, `./ui/button`) — это часть инкапсуляции модуля.
+- **Префикс `@/` не используется.** Имя слоя — само по себе адрес.
+- **Направление импортов** определяется архитектурой, не алиасами. Алиас разрешает импорт технически, но не отменяет правила слоёв (→ [Слои](../basics/architecture/reference/layers.md)).
+
+**Хорошо**
+
+```ts
+import { Button } from 'ui/button'
+import { useUser } from 'business/user'
+import { formatDate } from 'shared/utils/date'
+```
+
+**Плохо**
+
+```ts
+// Относительный путь между модулями
+import { Button } from '../../../ui/button'
+
+// Префикс @/, которого нет в paths
+import { Button } from '@/ui/button'
+
+// Алиас на src — не предусмотрен
+import { Button } from 'src/ui/button'
+```
+
+## Внутри модуля
+
+Внутри своего модуля — относительные пути:
+
+```ts
+// src/ui/button/button.tsx
+import styles from './button.module.css'
+import { Icon } from './icon'
+```
+
+Не использовать алиас на самого себя:
+
+```ts
+// Плохо — алиас вместо относительного пути внутри модуля
+import { Icon } from 'ui/button/icon'
+```
diff --git a/ai/nextjs-style-guide/applied/biome.md b/ai/nextjs-style-guide/applied/biome.md
new file mode 100644
index 0000000..b8a8483
--- /dev/null
+++ b/ai/nextjs-style-guide/applied/biome.md
@@ -0,0 +1,81 @@
+---
+title: Biome
+description: Установка и настройка линтера-форматтера в новом проекте.
+keywords: [biome, линтер, форматтер, lint, format, biome.json, "@biomejs/biome", замена eslint, замена prettier]
+---
+
+# Biome
+
+Установка и настройка линтера-форматтера в новом проекте.
+
+## Требования
+
+- Node.js 18+.
+- Проект без установленного ESLint и Prettier (они конфликтуют с Biome).
+
+## Установка
+
+1. Установить пакет:
+
+ ```bash
+ npm install --save-dev --save-exact @biomejs/biome
+ ```
+
+2. Инициализировать конфиг:
+
+ ```bash
+ npx @biomejs/biome init
+ ```
+
+ В корне появится `biome.json` с дефолтными настройками.
+
+3. Привести `biome.json` к стандартному виду — добавить override для `*.css` (см. «Стандартный `biome.json`»). Делается сразу после `init`, до первого запуска `lint`/`check`.
+
+4. Добавить скрипты в `package.json`:
+
+ ```json
+ {
+ "scripts": {
+ "lint": "biome lint .",
+ "format": "biome format --write .",
+ "check": "biome check --write ."
+ }
+ }
+ ```
+
+ | Скрипт | Что делает |
+ |--------|-----------|
+ | `lint` | Проверка правил без правок |
+ | `format` | Автоформатирование всех файлов |
+ | `check` | Lint + format + organize imports в один проход (основная команда) |
+
+## Стандартный `biome.json`
+
+Дефолтный `biome.json`, созданный `biome init`, кастомизируется ровно одним блоком — `overrides` для `*.css` с отключённым правилом `suspicious/noUnknownAtRules`. Этот override **обязателен по умолчанию во всех проектах**, независимо от того, подключены ли уже стили: проектный CSS-стек использует `@custom-media` и другие нестандартные at-правила, которые Biome не распознаёт; без override `npm run lint` падает.
+
+Фрагмент, который добавляется в `biome.json`:
+
+```jsonc
+{
+ "overrides": [
+ {
+ "includes": ["**/*.css"],
+ "linter": {
+ "rules": {
+ "suspicious": {
+ "noUnknownAtRules": "off"
+ }
+ }
+ }
+ }
+ ]
+}
+```
+
+Если в `biome.json` уже есть массив `overrides` — добавить элемент в него; не дублировать массив.
+
+Прочая настройка правил Biome — отдельная задача, не входит в стандартный канон.
+
+## Интеграция с VS Code
+
+Расширение `biomejs.biome` и автоформатирование при сохранении настраиваются в [VS Code](./vscode.md).
diff --git a/ai/nextjs-style-guide/applied/component.md b/ai/nextjs-style-guide/applied/component.md
new file mode 100644
index 0000000..4e825c3
--- /dev/null
+++ b/ai/nextjs-style-guide/applied/component.md
@@ -0,0 +1,201 @@
+---
+title: Компонент
+description: Как создавать React-компоненты внутри SLM-модулей.
+---
+
+# Компонент
+
+Как создавать React-компоненты внутри SLM-модулей.
+
+## Назначение
+
+Компонент — минимальная UI-единица проекта. Это один `.tsx` файл без собственной папки, сегментов и публичного API.
+
+Компонент может использовать стили, типы, хуки и другие ресурсы родительского модуля. Наличие связанных файлов в `styles/` или `types/` не превращает компонент в модуль.
+
+## Компонент или модуль
+
+Классификация определяется границей владения:
+
+- `component` — один `.tsx` файл внутри модуля;
+- `module` — папка с `index.ts`, сегментами и собственной публичной границей.
+
+```text
+user/
+├── ui/
+│ └── user-avatar.tsx # компонент
+├── styles/
+│ └── user-avatar.module.css # ресурс родительского модуля
+├── types/
+│ └── user-avatar.type.ts # ресурс родительского модуля
+└── user.tsx # корневой компонент модуля
+```
+
+`user-avatar.tsx` остаётся компонентом, потому что у него нет собственной папки, `index.ts` и сегментов.
+
+## Где размещать
+
+Компонент размещается внутри модуля:
+
+- В корне модуля, если это главная UI-сущность модуля.
+- В `ui/`, если это вспомогательный компонент модуля.
+
+```text
+user/
+├── ui/
+│ └── user-avatar.tsx
+├── styles/
+│ ├── user.module.css
+│ └── user-avatar.module.css
+├── types/
+│ ├── user.type.ts
+│ └── user-avatar.type.ts
+├── user.tsx
+└── index.ts
+```
+
+`user.tsx` — корневой компонент модуля. `ui/user-avatar.tsx` — вспомогательный компонент этого же модуля.
+
+## Что запрещено
+
+- Заворачивать компонент в папку: `ui/header/header.tsx`.
+- Создавать для компонента отдельный `index.ts`.
+- Создавать собственные сегменты внутри папки компонента: `ui/header/styles/`, `ui/header/types/`, `ui/header/hooks/` и т.п.
+- Декларировать внутри `.tsx` сторы, сервисы, API-клиенты, мапперы или утилиты. Для этого есть сегменты родительского модуля.
+- Размещать бизнес-правила прямо в компоненте. Компонент может использовать готовые зависимости модуля, но не определяет их.
+- Размещать компонент в `parts/` напрямую. `parts/` содержит только модули.
+
+**Плохо**
+
+```text
+user/
+└── ui/
+ └── user-avatar/
+ ├── styles/
+ │ └── user-avatar.module.css
+ ├── user-avatar.tsx
+ └── index.ts
+```
+
+**Хорошо**
+
+```text
+user/
+├── ui/
+│ └── user-avatar.tsx
+├── styles/
+│ └── user-avatar.module.css
+└── types/
+ └── user-avatar.type.ts
+```
+
+## Стили и типы
+
+Компонент использует ресурсы родительского модуля.
+
+`styles/` и `types/` рядом с корневым компонентом — это сегменты модуля, а не собственные папки `.tsx` файла.
+
+- CSS Module компонента лежит в `styles/` родительского модуля и называется по компоненту: `user-avatar.module.css`.
+- Если у компонента есть CSS Module, его корневой класс всегда называется `.root`.
+- Типы компонента лежат в `types/` родительского модуля и называются по компоненту: `user-avatar.type.ts`.
+- Локальный `type Props` внутри `.tsx` не используется. Типы пропсов всегда выносятся в `types/` родительского модуля.
+- Экспорт типа из `types/` не делает его публичным API. Публичным он становится только при реэкспорте из `index.ts` модуля.
+
+Причина `.root`: в DevTools проще находить корневой DOM-узел компонента и отличать его от внутренних элементов.
+
+## Реализация
+
+- Компоненты объявляются через `const`.
+- `React.FC` не используется.
+- JSDoc-комментарий обязателен для компонента.
+- Пропсы деструктурируются в теле компонента.
+- `className` объединяется с `styles.root` через `cl()`.
+- Побочные эффекты и состояние выносятся в хуки модуля, если перестают быть тривиальными.
+- Компонент возвращает JSX и не содержит orchestration-код страницы или бизнес-домена.
+
+`user/types/user-avatar.type.ts`
+
+```ts
+import type { ImageProps } from 'next/image'
+
+/**
+ * Параметры UserAvatar.
+ */
+export type UserAvatarParams = {}
+
+/** Пропсы базового изображения. */
+type RootAttrs = ImageProps
+
+export type UserAvatarProps = RootAttrs & UserAvatarParams
+```
+
+`user/ui/user-avatar.tsx`
+
+```tsx
+import cl from 'clsx'
+import Image from 'next/image'
+import type { UserAvatarProps } from '../types/user-avatar.type'
+import styles from '../styles/user-avatar.module.css'
+
+/**
+ * Аватар пользователя.
+ *
+ * Используется для:
+ * - отображения пользователя в карточке
+ * - отображения пользователя в шапке профиля
+ */
+export const UserAvatar = (props: UserAvatarProps) => {
+ const { className, ...imageProps } = props
+
+ return
+}
+```
+
+`user/styles/user-avatar.module.css`
+
+```css
+.root {
+ display: block;
+ border-radius: 50%;
+}
+```
+
+## Когда нужен модуль
+
+Решение о выделении модуля остаётся за разработчиком. Поднимать компонент в модуль стоит, если он становится самостоятельной областью:
+
+- получает свои вложенные компоненты;
+- получает свои хуки, стор или сервисы;
+- получает внутренние мапперы или утилиты;
+- требует собственного публичного API;
+- начинает переиспользоваться вне родительского модуля;
+- становится отдельной зоной параллельной разработки.
+
+Пример: страница — это screen-модуль, а самостоятельные секции страницы — вложенные модули в `parts/`.
+
+```text
+screens/home/
+├── parts/
+│ ├── hero-section/
+│ │ ├── styles/
+│ │ │ └── hero-section.module.css
+│ │ ├── types/
+│ │ │ └── hero-section.type.ts
+│ │ ├── hero-section.tsx
+│ │ └── index.ts
+│ └── features-section/
+│ ├── styles/
+│ │ └── features-section.module.css
+│ ├── types/
+│ │ └── features-section.type.ts
+│ ├── features-section.tsx
+│ └── index.ts
+├── styles/
+│ └── home.module.css
+├── types/
+│ └── home.type.ts
+├── home.screen.tsx
+└── index.ts
+```
+
+`hero-section` и `features-section` — модули, потому что это самостоятельные части страницы со своей структурой и публичной точкой входа.
diff --git a/ai/nextjs-style-guide/applied/fonts.md b/ai/nextjs-style-guide/applied/fonts.md
new file mode 100644
index 0000000..981276b
--- /dev/null
+++ b/ai/nextjs-style-guide/applied/fonts.md
@@ -0,0 +1,128 @@
+---
+title: Шрифты
+description: Как подключать шрифты через Next.js Font в проекте.
+---
+
+# Шрифты
+
+Как подключать шрифты через Next.js Font в проекте.
+
+## Назначение
+
+Шрифты подключаются через `next/font`. Это стандартный способ Next.js: шрифты загружаются без ручных ``, `@font-face` и настройки preconnect.
+
+Шрифт подключается в точке инициализации приложения, а в CSS используется через переменную.
+
+## Google Fonts
+
+```tsx
+// src/app/layout.tsx
+import type { ReactNode } from 'react'
+import { Inter } from 'next/font/google'
+import 'shared/styles/global.css'
+
+const inter = Inter({
+ subsets: ['latin', 'cyrillic'],
+ variable: '--font-main',
+ display: 'swap',
+})
+
+type RootLayoutProps = {
+ children: ReactNode
+}
+
+export default function RootLayout({ children }: RootLayoutProps) {
+ return (
+
+
{children}
+
+ )
+}
+```
+
+```css
+/* src/shared/styles/global.css */
+body {
+ font-family: var(--font-main), system-ui, sans-serif;
+}
+```
+
+## Локальные шрифты
+
+Каждый локальный шрифт размещается в отдельной папке внутри `src/shared/fonts/`. В этой же папке лежит `.font.ts`, где объявляется `localFont`.
+
+```text
+src/shared/fonts/
+└── roboto/
+ ├── roboto.font.ts
+ ├── Roboto-Regular.woff2
+ ├── Roboto-Italic.woff2
+ ├── Roboto-Bold.woff2
+ └── Roboto-BoldItalic.woff2
+```
+
+```ts
+// src/shared/fonts/roboto/roboto.font.ts
+import localFont from 'next/font/local'
+
+export const roboto = localFont({
+ src: [
+ {
+ path: './Roboto-Regular.woff2',
+ weight: '400',
+ style: 'normal',
+ },
+ {
+ path: './Roboto-Italic.woff2',
+ weight: '400',
+ style: 'italic',
+ },
+ {
+ path: './Roboto-Bold.woff2',
+ weight: '700',
+ style: 'normal',
+ },
+ {
+ path: './Roboto-BoldItalic.woff2',
+ weight: '700',
+ style: 'italic',
+ },
+ ],
+ variable: '--font-main',
+ display: 'swap',
+})
+```
+
+`app/` импортирует готовый объект шрифта и только подключает его к документу:
+
+```tsx
+// src/app/layout.tsx
+import type { ReactNode } from 'react'
+import { roboto } from 'shared/fonts/roboto/roboto.font'
+import 'shared/styles/global.css'
+
+type RootLayoutProps = {
+ children: ReactNode
+}
+
+export default function RootLayout({ children }: RootLayoutProps) {
+ return (
+
+ {children}
+
+ )
+}
+```
+
+Путь в `localFont` указывается относительно `.font.ts`, поэтому файлы шрифта импортируются коротко: `./Roboto-Regular.woff2`.
+
+Если шрифтов несколько, у каждого своя папка и свой `.font.ts`.
+
+## Правила
+
+- Использовать `next/font/google` или `next/font/local`.
+- Не подключать шрифты через ручные `` и `@font-face` без необходимости.
+- Подключать шрифты один раз — в корневом layout через готовый объект шрифта.
+- Использовать CSS-переменные `variable`, а не жёстко прописывать семейство в каждом компоненте.
+- Локальные файлы шрифтов хранить в `src/shared/fonts/{font-name}/` рядом с `{font-name}.font.ts`.
+- Не объявлять `localFont` внутри `src/app/layout.tsx`; layout только импортирует готовый шрифт.
diff --git a/ai/nextjs-style-guide/applied/images.md b/ai/nextjs-style-guide/applied/images.md
new file mode 100644
index 0000000..448efd8
--- /dev/null
+++ b/ai/nextjs-style-guide/applied/images.md
@@ -0,0 +1,95 @@
+---
+title: Изображения
+description: Как подключать изображения через Next.js Image в проекте.
+---
+
+# Изображения
+
+Как подключать изображения через Next.js Image в проекте.
+
+## Назначение
+
+Изображения рендерятся через компонент `Image` из `next/image`. Это сохраняет единый API для размеров, `alt`, lazy-loading и `priority`, даже если оптимизация изображений отключена.
+
+В проекте оптимизация Next.js Image отключается через `unoptimized`, чтобы сборка и рантайм не зависели от встроенного image optimizer.
+
+## Настройка
+
+Отключение оптимизации задаётся глобально в `next.config.ts`:
+
+```ts
+import type { NextConfig } from 'next'
+
+const nextConfig: NextConfig = {
+ images: {
+ unoptimized: true,
+ },
+}
+
+export default nextConfig
+```
+
+После этого `unoptimized` не нужно повторять на каждом `Image`.
+
+## Использование
+
+Статические изображения, доступные по URL, размещаются в `public/`:
+
+```text
+public/
+└── images/
+ └── user-avatar.png
+```
+
+```tsx
+import Image from 'next/image'
+
+export const UserAvatar = () => {
+ return (
+
+ )
+}
+```
+
+## Правила
+
+- Использовать `Image` из `next/image`, не обычный ``.
+- Для контентных изображений всегда писать осмысленный `alt`.
+- Для декоративных изображений использовать `alt=""`.
+- Указывать `width` и `height`, если изображение не использует `fill`.
+- При `fill` задавать `sizes` и контролировать размеры родителя стилями.
+- `priority` ставить только для изображений первого экрана.
+- SVG-иконки не оформлять как изображения — для них используется раздел [SVG-спрайты](./svg-sprites/svg-sprites-intro.md).
+
+## Пример с `fill`
+
+```tsx
+import Image from 'next/image'
+import styles from '../styles/article-card-cover.module.css'
+
+export const ArticleCardCover = () => {
+ return (
+
+
+
+ )
+}
+```
+
+```css
+.root {
+ position: relative;
+ aspect-ratio: 16 / 9;
+ overflow: hidden;
+}
+```
diff --git a/ai/nextjs-style-guide/applied/localization.md b/ai/nextjs-style-guide/applied/localization.md
new file mode 100644
index 0000000..c65b7f6
--- /dev/null
+++ b/ai/nextjs-style-guide/applied/localization.md
@@ -0,0 +1,81 @@
+---
+title: Локализация
+description: Как организовать локализацию как infrastructure-модуль.
+---
+
+# Локализация
+
+Как организовать локализацию как infrastructure-модуль.
+
+## Назначение
+
+Локализация — инфраструктурная подсистема приложения. Она отвечает за текущую локаль, словари, форматирование переводов и API для компонентов.
+
+Код локализации живёт в `src/infrastructure/i18n/`. Компоненты и модули не читают словари напрямую — они используют публичный API infrastructure-модуля.
+
+## Структура
+
+```text
+src/infrastructure/i18n/
+├── config/
+│ └── i18n.config.ts
+├── dictionaries/
+│ ├── ru.ts
+│ └── en.ts
+├── hooks/
+│ └── use-translation.hook.ts
+├── providers/
+│ └── i18n-provider.tsx
+├── types/
+│ └── i18n.type.ts
+└── index.ts
+```
+
+Набор сегментов может отличаться, но публичная точка входа остаётся одна — `infrastructure/i18n`.
+
+## Подключение
+
+`app/` только подключает готовый провайдер локализации. Реализация провайдера, словари и конфиг остаются в `infrastructure/i18n/`.
+
+```tsx
+// src/app/layout.tsx
+import type { ReactNode } from 'react'
+import { I18nProvider } from 'infrastructure/i18n'
+
+type RootLayoutProps = {
+ children: ReactNode
+}
+
+export default function RootLayout({ children }: RootLayoutProps) {
+ return (
+
+
+ {children}
+
+
+ )
+}
+```
+
+## Использование
+
+Компоненты получают переводы через готовый API модуля локализации:
+
+```tsx
+import { useTranslation } from 'infrastructure/i18n'
+
+export const ProfileTitle = () => {
+ const { t } = useTranslation()
+
+ return
{t('profile.title')}
+}
+```
+
+## Правила
+
+- Локализация живёт в `infrastructure/i18n/`.
+- `app/` только подключает готовый provider и передаёт locale.
+- Словари не импортируются напрямую в компоненты, screens или business-модули.
+- Ключи переводов не собираются динамически из строк, если это ломает типизацию и поиск.
+- Тексты интерфейса не хардкодятся в переиспользуемых компонентах, если они должны переводиться.
+- Форматирование дат, чисел и валют должно проходить через API локализации или отдельные утилиты infrastructure-модуля.
diff --git a/ai/nextjs-style-guide/applied/module.md b/ai/nextjs-style-guide/applied/module.md
new file mode 100644
index 0000000..5e6ca5c
--- /dev/null
+++ b/ai/nextjs-style-guide/applied/module.md
@@ -0,0 +1,162 @@
+---
+title: Модуль
+description: Как создавать и организовывать SLM-модули в проекте.
+---
+
+# Модуль
+
+Как создавать и организовывать SLM-модули в проекте.
+
+## Назначение
+
+Модуль — основной строительный блок SLM-архитектуры. Это папка с публичным API (`index.ts`) и опциональными сегментами: компонентами, стилями, типами, хуками, сторами, сервисами и вложенными модулями.
+
+Если UI-сущность остаётся одним `.tsx` файлом и использует ресурсы родительского модуля — это [компонент](./component.md), а не модуль. Связанные файлы в `styles/` и `types/` родителя не создают новую модульную границу.
+
+Архитектурное определение: [Модули SLM](../basics/architecture/reference/modules.md). Список сегментов: [Сегменты SLM](../basics/architecture/reference/segments.md).
+
+## Когда нужен модуль
+
+Создавайте модуль, если сущности нужны:
+
+- публичный API;
+- хуки, сторы, сервисы, мапперы или утилиты;
+- вложенные части;
+- переиспользование вне родительского модуля;
+- самостоятельная ответственность на слое.
+
+Если понадобилась папка вокруг компонента — это сигнал, что нужен модуль.
+
+## Где размещать
+
+Модуль размещается на самом низком уровне использования.
+
+- Нужен только одному модулю — размещается в `parts/` родителя.
+- Нужен одной странице — размещается в `screens/{name}/parts/`.
+- Нужен одному layout — размещается в `layouts/{name}/parts/`.
+- Переиспользуется между страницами или layout — поднимается в `widgets/`.
+- Представляет бизнес-домен — размещается в `business/`.
+- Является UI-китом — размещается в `ui/`.
+
+`app/` не содержит модулей. Это слой файлового роутинга и инициализации.
+
+## Структура
+
+Минимальный UI-модуль:
+
+```text
+user/
+├── user.tsx
+└── index.ts
+```
+
+Модуль расширяется сегментами только при реальной потребности:
+
+```text
+user/
+├── ui/
+│ └── user-avatar.tsx
+├── parts/
+│ └── user-posts/
+│ ├── user-posts.tsx
+│ └── index.ts
+├── styles/
+│ ├── user.module.css
+│ └── user-avatar.module.css
+├── types/
+│ ├── user.type.ts
+│ └── user-avatar.type.ts
+├── user.tsx
+└── index.ts
+```
+
+Корневой компонент опционален. Business- и infrastructure-модули могут состоять только из хуков, сервисов, типов и публичного API.
+
+## `ui/` и `parts/`
+
+`ui/` содержит только компоненты: отдельные `.tsx` файлы без собственных сегментов.
+
+`parts/` содержит только модули: каждая запись внутри `parts/` — папка с собственным `index.ts`. Отдельные `.tsx`, стили, хуки или произвольные файлы в `parts/` не кладутся.
+
+```text
+user/
+├── ui/
+│ └── user-avatar.tsx # компонент
+└── parts/
+ └── user-posts/ # модуль
+ ├── styles/
+ │ └── user-posts.module.css
+ ├── user-posts.tsx
+ └── index.ts
+```
+
+Если компоненту в `ui/` понадобились стили или типы, они добавляются в `styles/` и `types/` родительского модуля. Если компоненту нужны собственные хуки, вложенные части или публичная граница — он переносится в `parts/` как модуль.
+
+## Публичный API
+
+`index.ts` — единственная точка входа в модуль. Внешние импорты внутренних файлов запрещены.
+
+```ts
+// user/index.ts
+export { User } from './user'
+export type { UserProps } from './types/user.type'
+```
+
+```ts
+// Плохо: импорт в обход публичного API.
+import { UserPosts } from 'screens/user/parts/user-posts/user-posts'
+
+// Хорошо: импорт через публичный API родительского модуля.
+import { User } from 'screens/user'
+```
+
+Вложенный модуль имеет свой `index.ts`, но наружу родителя экспортируется только при необходимости.
+
+## Именование
+
+Базовые правила описаны в разделе [Именование](../basics/naming.md).
+
+- Папка модуля — `kebab-case`: `user-posts/`.
+- Файл корневого компонента повторяет имя папки: `user-posts/user-posts.tsx`.
+- Корневые модули слоёв наследуют роль слоя в имени файла: `screens/profile/profile.screen.tsx`, `layouts/main/main.layout.tsx`.
+- Корневой компонент именуется в `PascalCase`: `UserPosts`.
+- Если имя без контекста слишком общее, добавляется префикс родителя или роль слоя: `ProfileUserPosts`, `ProfileScreen`, `MainLayout`.
+
+## Примеры
+
+### Screen-модуль
+
+```text
+screens/profile/
+├── ui/
+│ └── profile-heading.tsx
+├── parts/
+│ └── activity-feed/
+│ ├── styles/
+│ │ └── activity-feed.module.css
+│ ├── activity-feed.tsx
+│ └── index.ts
+├── styles/
+│ ├── profile.module.css
+│ └── profile-heading.module.css
+├── types/
+│ ├── profile.type.ts
+│ └── profile-heading.type.ts
+├── profile.screen.tsx
+└── index.ts
+```
+
+### Business-модуль без корневого компонента
+
+```text
+business/auth/
+├── hooks/
+│ └── use-auth.hook.ts
+├── services/
+│ └── auth.service.ts
+├── stores/
+│ └── auth.store.ts
+├── types/
+│ └── auth.type.ts
+└── index.ts
+```
diff --git a/ai/nextjs-style-guide/applied/page-level.md b/ai/nextjs-style-guide/applied/page-level.md
new file mode 100644
index 0000000..27ffea9
--- /dev/null
+++ b/ai/nextjs-style-guide/applied/page-level.md
@@ -0,0 +1,186 @@
+---
+title: Файлы роутинга
+description: Как работать со страницами и другими файлами роутинга Next.js App Router.
+---
+
+# Файлы роутинга
+
+Как работать со страницами и другими файлами роутинга Next.js App Router.
+
+## Назначение
+
+`src/app/**` — точка входа приложения и слой файлового роутинга Next.js.
+
+Файлы роутинга не реализуют интерфейс. Они описывают маршрут: читают параметры, получают данные первого рендера, подготавливают кеш или состояние и передают результат в screen.
+
+Границы слоя описаны в [Архитектура → Слои → App](../basics/architecture/reference/layers.md#слой-app).
+
+## Граница ответственности
+
+| Область | Где живёт |
+|---|---|
+| Файлы маршрутов (`page.tsx`, `layout.tsx`, `loading.tsx`, `error.tsx`, `not-found.tsx`) | `src/app/**` |
+| Параметры маршрута, `metadata`, `redirect()`, `notFound()` | `src/app/**` |
+| Серверные запросы для первого рендера | `src/app/**`, через готовые клиенты и сервисы нижних слоёв |
+| Прогрев SWR-кеша, начальное состояние, подключение провайдеров | `src/app/**`, только через готовые обёртки из нижних слоёв |
+| UI страницы | `screens/` |
+| Каркас страницы: header, footer, sidebar | `layouts/` |
+| Провайдеры, сторы, хуки, API-клиенты, сервисы | нижние слои (`screens/`, `business/`, `infrastructure/`, `shared/`) |
+| CSS Modules и стили компонентов | рядом с компонентами, не в `src/app/**` |
+
+## Что можно делать в `page.tsx`
+
+- Экспортировать `metadata` или `generateMetadata`.
+- Читать `params` и `searchParams`.
+- Нормализовать и валидировать параметры маршрута.
+- Делать серверные запросы для первого рендера через готовые клиенты или сервисы.
+- Вызывать `redirect()` и `notFound()`.
+- Готовить начальные данные для screen.
+- Готовить SWR `fallback` и передавать его в готовый провайдер.
+- Подключать готовый провайдер стора страницы и передавать начальное состояние.
+- Рендерить screen или композицию из готовых обёрток и screen.
+
+## Что запрещено
+
+- Писать UI-разметку страницы прямо в файле роутинга.
+- Создавать локальные компоненты внутри `src/app/**`.
+- Добавлять CSS Modules, стили компонентов, `components/`, `styles/`, `hooks/`, `stores/`, `services/` внутри `src/app/**`.
+- Реализовывать провайдеры, сторы, хуки, API-клиенты или сервисы в файлах роутинга.
+- Размещать бизнес-логику, мапперы и правила предметной области в файлах роутинга.
+- Вызывать `useSWR` и доменные клиентские хуки в файлах роутинга.
+
+## Страницы
+
+Страница объявляется через `export default function`. Для серверных запросов используется `async function`.
+
+```tsx
+import type { Metadata } from 'next'
+import { ProfileScreen } from 'screens/profile'
+
+export const metadata: Metadata = {
+ title: 'Профиль',
+ description: 'Страница профиля пользователя',
+}
+
+type ProfilePageProps = {
+ params: Promise<{ id: string }>
+}
+
+export default async function ProfilePage({ params }: ProfilePageProps) {
+ const { id } = await params
+
+ return
+}
+```
+
+## Данные первого рендера
+
+Если данные нужны до первого рендера, `page.tsx` получает их на сервере и передаёт в screen. Сам запрос выполняется через готовый клиент или сервис нижнего слоя.
+
+```tsx
+import { notFound } from 'next/navigation'
+import { userApi } from 'infrastructure/backend-api'
+import { UserScreen } from 'screens/user'
+
+type UserPageProps = {
+ params: Promise<{ id: string }>
+}
+
+export default async function UserPage({ params }: UserPageProps) {
+ const { id } = await params
+ const user = await userApi.users.get(id)
+
+ if (!user) {
+ notFound()
+ }
+
+ return
+}
+```
+
+Если данные нужны нескольким клиентским SWR-хукам, файл роутинга может обернуть дерево в `SWRConfig` и передать `fallback`. Запросы стартуют на сервере, а клиентские хуки получают данные из кеша.
+
+Ключи `fallback` должны совпадать с ключами внутри GET-хуков REST-клиента. Для array-key используется `unstable_serialize`.
+
+```tsx
+import type { ReactNode } from 'react'
+import { SWRConfig, unstable_serialize } from 'swr'
+import {
+ backendApi,
+ getCurrentUserKey,
+ getPostListKey,
+} from 'infrastructure/backend-api'
+
+type FeedLayoutProps = {
+ children: ReactNode
+}
+
+export default async function FeedLayout({ children }: FeedLayoutProps) {
+ const userPromise = backendApi.user.getCurrent()
+ const postsPromise = backendApi.posts.list()
+
+ return (
+
+ {children}
+
+ )
+}
+```
+
+Подробнее о стратегиях запросов и начальных данных для клиентских хуков: [REST → Стратегии получения данных](../data/rest/strategies/index.md), [REST → Начальные данные для клиентских хуков](../data/rest/strategies/client-hooks-initial-data.md).
+
+## Инициализация состояния
+
+Файл роутинга может подключить готовый провайдер стора страницы, если состояние зависит от маршрута или данных первого рендера. Реализация стора и провайдера не размещается в `src/app/**`.
+
+```tsx
+import { ProfileScreen, ProfileStoreProvider } from 'screens/profile'
+
+type ProfilePageProps = {
+ params: Promise<{ id: string }>
+}
+
+export default async function ProfilePage({ params }: ProfilePageProps) {
+ const { id } = await params
+
+ return (
+
+
+
+ )
+}
+```
+
+## Layout
+
+`layout.tsx` подключает готовую инициализацию приложения: глобальные стили, провайдеры и верхнеуровневые обёртки из нижних слоёв.
+
+Вёрстка layout-каркаса выносится в слой `layouts/`. Реализация провайдеров, стилей и UI не размещается в `app/`.
+
+## Error и Not Found
+
+`error.tsx` и `not-found.tsx` делегируют разметку готовым screen или widget. В файле роутинга остаётся только адаптация API Next.js к пропсам нижнего слоя.
+
+```tsx
+'use client'
+
+import { ErrorScreen } from 'screens/error'
+
+type ErrorPageProps = {
+ error: Error & { digest?: string }
+ reset: () => void
+}
+
+const ErrorPage = ({ error, reset }: ErrorPageProps) => {
+ return
+}
+
+export default ErrorPage
+```
diff --git a/ai/nextjs-style-guide/applied/postcss.md b/ai/nextjs-style-guide/applied/postcss.md
new file mode 100644
index 0000000..38c6283
--- /dev/null
+++ b/ai/nextjs-style-guide/applied/postcss.md
@@ -0,0 +1,70 @@
+---
+title: PostCSS
+description: Установка и настройка CSS-процессора в новом проекте.
+keywords: [postcss, postcss.config.mjs, postcss-custom-media, postcss-nesting, autoprefixer, postcss-global-data, csstools, "@custom-media", "@nest", css-процессор]
+---
+
+# PostCSS
+
+Установка и настройка CSS-процессора в новом проекте.
+
+## Зачем PostCSS
+
+Подключаем ради двух вещей:
+
+- **Вложенность** — `&:hover`, `&::before`, `&._active` и `@media` внутри селектора. Без процессора нативный CSS не покрывает всех нужных кейсов вложенности.
+- **`@custom-media`** — единые breakpoints проекта (`@media (--md)`) вместо магических `min-width`. Определяются в одном месте, переиспользуются везде.
+
+Autoprefixer и `@csstools/postcss-global-data` идут довеском под эти две задачи.
+
+## Требования
+
+- Next.js 14+ (App Router).
+- Node.js 18+.
+
+CSS Modules поддерживаются Next.js из коробки — отдельной установки не требуют.
+
+## Установка
+
+1. Установить PostCSS-плагины как devDependencies:
+
+ ```bash
+ npm install -D postcss-custom-media postcss-nesting autoprefixer @csstools/postcss-global-data
+ ```
+
+2. Создать `postcss.config.mjs` в корне проекта (см. «Конфиг»).
+
+## Конфиг
+
+Файл `postcss.config.mjs` в корне проекта.
+
+```js
+// postcss.config.mjs
+export default {
+ plugins: {
+ '@csstools/postcss-global-data': {
+ files: ['src/shared/styles/media.css'],
+ },
+ 'postcss-custom-media': {},
+ 'postcss-nesting': {},
+ autoprefixer: {},
+ },
+}
+```
+
+### Разбор плагинов
+
+| Плагин | Назначение |
+|--------|------------|
+| `@csstools/postcss-global-data` | Подгружает определения `@custom-media` из `src/shared/styles/media.css` перед обработкой каждого CSS-модуля. Семантика — «глобальный файл определений, который не импортируется в исходники» |
+| `postcss-custom-media` | Поддержка `@custom-media --md (...)` и использования `@media (--md) {}`. Определения берутся из файла, который подгрузил `postcss-global-data` |
+| `postcss-nesting` | Нативная CSS-вложенность: `&:hover`, `&::before`, `&._active` |
+| `autoprefixer` | Добавление вендорных префиксов по browserslist |
+
+### Почему внешний файл с `@custom-media`, а не `@import`
+
+`@custom-media` — глобальные определения, одинаковые для всего проекта. Держим их в `src/shared/styles/media.css`. `@csstools/postcss-global-data` подгружает этот файл перед каждым модулем, а `postcss-custom-media` заменяет `@media (--md)` на конкретные `@media (min-width: ...)` на этапе сборки. Сами определения в бандл не попадают.
+
+Опция `importFrom` у `postcss-custom-media` удалена в v10+; её роль теперь выполняет `@csstools/postcss-global-data`.
+
+Импортировать `media.css` в файлы компонентов **не нужно** и запрещено правилами (см. [Использование стилей](./styles/styles-usage.md), раздел «Импорт стилей»).
diff --git a/ai/nextjs-style-guide/applied/project-structure.md b/ai/nextjs-style-guide/applied/project-structure.md
new file mode 100644
index 0000000..02d50f4
--- /dev/null
+++ b/ai/nextjs-style-guide/applied/project-structure.md
@@ -0,0 +1,101 @@
+---
+title: Структура проекта
+description: Из чего состоит проект и где что лежит.
+---
+
+# Структура проекта
+
+Из чего состоит проект и где что лежит.
+
+## Корень репозитория
+
+```text
+project-root/
+├── .templates/ # Шаблоны для генерации модулей
+├── .vscode/ # Настройки и рекомендуемые расширения VS Code
+├── public/ # Статика, доступная по прямому URL
+├── src/ # Исходный код приложения
+├── .env.example # Переменные окружения проекта (шаблон)
+├── .env # Переменные окружения проекта (не коммитить)
+├── .gitignore
+├── AGENTS.md # Инструкции для AI-агентов
+├── biome.json # Линтер и форматтер (вместо ESLint + Prettier)
+├── next.config.ts # Конфигурация Next.js
+├── package.json # Зависимости и скрипты
+├── postcss.config.mjs # Конфигурация PostCSS
+└── tsconfig.json # Конфигурация TypeScript
+```
+
+## Папка `public/`
+
+Хранит статические файлы, которые отдаются по прямому URL без обработки сборщиком:
+
+```text
+public/
+└── og-image.png
+```
+
+Компоненты, стили и другой исходный код здесь не размещаются.
+
+## Папка `src/`
+
+```text
+src/
+├── app/ # Роутинг Next.js и точка входа приложения
+├── layouts/ # Каркасы страниц (header, footer, sidebar)
+├── screens/ # Контент конкретной страницы
+├── widgets/ # Составные блоки интерфейса, не привязанные к домену
+├── business/ # Бизнес-домены (auth, catalog, orders)
+├── infrastructure/ # Техсервисы (theme, i18n, API-адаптеры)
+├── ui/ # UI-кит без бизнес-логики
+└── shared/ # Общие ресурсы (утилиты, типы, стили)
+```
+
+Принципы организации слоёв описаны в разделе [Архитектура](../basics/architecture/).
+
+### Папка `app/`
+
+Точка входа приложения и файловый роутинг Next.js (`layout.tsx`, `page.tsx`, route-сегменты).
+`app/` подключает готовую инициализацию из нижних слоёв, но не реализует провайдеры, стили, UI-компоненты, хуки, сторы или сервисы.
+
+Подробнее о границах слоя: [Архитектура → Слои → App](../basics/architecture/reference/layers.md#слой-app).
+
+```text
+src/app/
+├── layout.tsx # Корневой layout
+└── page.tsx # Главная страница
+```
+
+## Папка `.templates/`
+
+Содержит шаблоны для генерации кода. Каждый подкаталог — шаблон отдельного типа модуля:
+
+```text
+.templates/
+├── component/ # Шаблон компонента
+├── screen/ # Шаблон экрана
+├── layout/ # Шаблон layout
+├── widget/ # Шаблон виджета
+├── module/ # Шаблон бизнес-модуля
+└── store/ # Шаблон стора
+```
+
+Подробнее о генерации описано в разделе [Шаблоны генерации](./templates/templates-intro.md).
+
+## Конфигурационные файлы
+
+| Файл | Назначение |
+|---|---|
+| `next.config.ts` | Настройки Next.js: редиректы, переменные окружения, webpack |
+| `tsconfig.json` | Настройки TypeScript: пути, строгость, таргет |
+| `biome.json` | Правила линтера и форматтера Biome |
+| `postcss.config.mjs` | Подключение PostCSS-плагинов (CSS Modules, custom media) |
+| `package.json` | Зависимости, версии, npm-скрипты |
+| `AGENTS.md` | Инструкции для AI-агентов, работающих в проекте |
+
+## Переменные окружения
+
+- `.env` — переменные окружения проекта, запрещено коммитить
+- `.env.example` — шаблон, коммитится в репозиторий
+
+Переменные с префиксом `NEXT_PUBLIC_` доступны в клиентском коде. Остальные доступны только на сервере.
diff --git a/src/infrastructure/.gitkeep b/ai/nextjs-style-guide/applied/stores.md
similarity index 100%
rename from src/infrastructure/.gitkeep
rename to ai/nextjs-style-guide/applied/stores.md
diff --git a/ai/nextjs-style-guide/applied/styles/styles-setup.md b/ai/nextjs-style-guide/applied/styles/styles-setup.md
new file mode 100644
index 0000000..64ea0e9
--- /dev/null
+++ b/ai/nextjs-style-guide/applied/styles/styles-setup.md
@@ -0,0 +1,176 @@
+---
+title: Настройка стилей
+description: "Подготовка стилевой основы проекта: токены, медиа-запросы, глобальные стили."
+keywords: [variables.css, media.css, global.css, shared/styles, токены, переменные, custom-media, breakpoints, подключение стилей, базовые стили, инициализация]
+---
+
+# Настройка стилей
+
+Подготовка стилевой основы проекта: токены, медиа-запросы, глобальные стили.
+
+## Требования
+
+- Установлен PostCSS или любой другой pre/post-процессор с поддержкой `@custom-media`.
+
+## Файлы
+
+Состав глобальных стилей — три файла:
+
+| Файл | Роль |
+|------|------|
+| `variables.css` | Токены проекта (цвета, отступы, радиусы) |
+| `media.css` | Custom media queries (брейкпоинты по ширине и высоте) |
+| `global.css` | Точка сборки глобальных стилей: через `@import` тянет все остальные глобалы, импортируется в приложение один раз |
+
+Правила подключения:
+
+- В приложение импортируется **только** `global.css`.
+- `variables.css` и будущие глобальные файлы (резеты, темы, типографика) подключаются в `global.css` через `@import`.
+- `media.css` **не импортируется** — ни в `global.css`, ни в компоненты, ни в точку инициализации. Его читает CSS-процессор на этапе сборки (см. [PostCSS](../postcss.md)).
+
+## Корневой `font-size`
+
+Базовая единица `rem` в проекте привязана к **16px**: корневой `font-size` не переопределяется. `html { font-size: ... }` писать запрещено — пользовательская настройка размера шрифта в браузере должна работать (a11y). Все `rem`-значения в `media.css` и других стилях трактуются как `1rem = 16px по умолчанию`.
+
+Reset браузерных дефолтов (`box-sizing`, сброс `margin`, типографика) каноном не задаётся — каждый проект решает сам. Если заводится — подключается через `global.css`.
+
+## Установка
+
+### 1. Создать файлы
+
+```bash
+mkdir -p src/shared/styles
+touch src/shared/styles/variables.css src/shared/styles/media.css src/shared/styles/global.css
+```
+
+### 2. Заполнить `media.css`
+
+Файл `src/shared/styles/media.css`. Стандартный набор брейкпоинтов проекта; редактировать только при согласованном изменении шкалы.
+
+Единица — `rem` (реагирует на корневой `font-size`). Перевод исходит из дефолтного `html { font-size: 16px }`, т.е. `1rem = 16px`.
+
+```css
+/* src/shared/styles/media.css */
+
+/* Ширина — Mobile First (min-width), кроме --xs (max-width) */
+@custom-media --xs (max-width: 35.9375rem); /* 575px — до sm */
+@custom-media --sm (min-width: 36rem); /* 576px — телефон альбом / малый планшет */
+@custom-media --md (min-width: 48rem); /* 768px — планшет */
+@custom-media --lg (min-width: 62rem); /* 992px — малый десктоп */
+@custom-media --xl (min-width: 75rem); /* 1200px — десктоп */
+@custom-media --2xl (min-width: 88rem); /* 1408px — широкий десктоп */
+@custom-media --3xl (min-width: 120rem); /* 1920px — full HD+ */
+
+/* Высота — min-height */
+@custom-media --h-xs (min-height: 41.6875rem); /* 667px — iPhone SE портрет */
+@custom-media --h-sm (min-height: 43.875rem); /* 702px */
+@custom-media --h-md (min-height: 50.625rem); /* 810px — iPad портрет */
+@custom-media --h-lg (min-height: 56.25rem); /* 900px */
+@custom-media --h-xl (min-height: 62.5rem); /* 1000px */
+@custom-media --h-2xl (min-height: 68.75rem); /* 1100px */
+@custom-media --h-3xl (min-height: 75rem); /* 1200px */
+```
+
+Правила:
+
+- только `@custom-media` на верхнем уровне;
+- имена короткие, по шкале (`--xs` … `--3xl`); высотные — с префиксом `--h-`;
+- единица — `rem`, не `em`/`px`; пиксельное значение указывается комментарием;
+- значения ширины — `min-width` (Mobile First), исключение `--xs` — `max-width` (блок «строго меньше `--sm`»);
+- значения высоты — `min-height`.
+
+### 3. Заполнить `variables.css`
+
+Файл `src/shared/styles/variables.css`. Набор токенов под проект расширяется по мере роста дизайн-системы.
+
+```css
+/* src/shared/styles/variables.css */
+:root {
+ /* Цвета */
+ --color-primary: #3b82f6;
+ --color-bg: #ffffff;
+ --color-bg-hover: #f5f5f5;
+ --color-text: #1a1a1a;
+
+ /* Отступы */
+ --space-1: 4px;
+ --space-2: 8px;
+ --space-3: 12px;
+ --space-4: 16px;
+
+ /* Скругления */
+ --radius-1: 4px;
+ --radius-2: 8px;
+}
+```
+
+Правила:
+
+- все токены определяются в `:root` — без вложенных селекторов;
+- именование — `kebab-case` по ролям: `--color-*`, `--space-*`, `--radius-*`;
+- `px` — основная единица для пространственных токенов;
+- темы накладываются поверх через `[data-theme="..."] { ... }` — в отдельном файле темы или здесь же.
+
+`variables.css` напрямую в приложение не импортируется — только через `global.css`.
+
+### 4. Заполнить `global.css`
+
+Файл `src/shared/styles/global.css`. Единственный глобальный файл, импортируемый в точку инициализации приложения. Внутри — `@import` остальных глобалов относительным путём.
+
+```css
+/* src/shared/styles/global.css */
+@import './variables.css';
+
+/* Сюда же подключаются будущие глобалы через @import:
+ * @import './reset.css';
+ * @import './typography.css';
+ * @import './themes.css';
+ * media.css НЕ импортируется — он работает через PostCSS.
+ */
+```
+
+Правила:
+
+- пути в `@import` — относительные (`./variables.css`), не через алиасы; нативный CSS `@import` не понимает tsconfig-paths;
+- `media.css` в `global.css` **не импортируется**;
+- собственные глобальные правила (`html { ... }`, `body { ... }`) писать **не здесь**, а в отдельных файлах рядом (`reset.css`, `typography.css`) и подключать через `@import`. `global.css` — только точка сборки;
+- порядок `@import` определяет порядок каскада: токены первыми, дальше резеты / темы / типографика.
+
+### 5. Подключить `global.css` в layout
+
+Импорт делается **один раз** — в корневом layout приложения:
+
+```tsx
+// src/app/layout.tsx
+import 'shared/styles/global.css'
+
+import type { Metadata } from 'next'
+
+export const metadata: Metadata = {
+ title: 'App',
+ description: '',
+}
+
+export default function RootLayout({ children }: { children: React.ReactNode }) {
+ return (
+
+ {children}
+
+ )
+}
+```
+
+`variables.css` и `media.css` в layout **не импортируются напрямую** — только через `global.css` (variables) или через PostCSS на сборке (media).
+
+## Проверка установки
+
+- В `src/shared/styles/` присутствуют три файла: `variables.css`, `media.css`, `global.css`. В `src/app/` папки `styles/` нет.
+- В `src/app/layout.tsx` есть `import 'shared/styles/global.css'`. Импортов `variables.css` и `media.css` там нет.
+- В проекте **не появились** PostCSS-пакеты и `postcss.config.*` — этот раздел их не ставит.
+- `npm run build` завершается успешно.
+
+## Дальше
+
+- [PostCSS](../postcss.md) — подключить процессор, чтобы заработали `@media (--md)` и вложенность.
+- [Использование стилей](./styles-usage.md) — правила написания CSS в компонентах.
+- [SVG-спрайты](../svg-sprites/svg-sprites-setup.md) — стили иконок отдельно от глобальных.
diff --git a/ai/nextjs-style-guide/applied/styles/styles-usage.md b/ai/nextjs-style-guide/applied/styles/styles-usage.md
new file mode 100644
index 0000000..d7f1405
--- /dev/null
+++ b/ai/nextjs-style-guide/applied/styles/styles-usage.md
@@ -0,0 +1,271 @@
+---
+title: Использование стилей
+description: Как пишутся стили в проекте.
+---
+
+# Использование стилей
+
+Как пишутся стили в проекте.
+
+## Общие правила
+
+- Только **PostCSS** и **CSS Modules** для кастомной стилизации.
+- Подход **Mobile First** — стили пишутся от мобильных к десктопу.
+- Именование классов — `camelCase` (`.root`, `.buttonNext`, `.itemTitle`).
+- Корневой класс каждого CSS Module компонента всегда называется `.root` — это упрощает ориентацию в DevTools и отладку DOM.
+- Модификаторы — отдельный класс с `_`, применяется через `&._modifier`.
+
+**Хорошо**
+```css
+.submitButton {
+ padding: 8px 16px;
+
+ &._disabled {
+ opacity: 0.5;
+ }
+}
+```
+
+**Плохо**
+```css
+/* Плохо: kebab-case и вложенный элемент вместо отдельного класса. */
+.submit-button {
+ padding: 8px 16px;
+
+ &__icon {
+ margin-right: 8px;
+ }
+}
+```
+
+## Вложенность
+
+- Вложенность селекторов запрещена.
+- Исключения:
+ - Псевдоклассы: `&:hover`, `&:active`, `&:focus`, `&:disabled` и т.д.
+ - Псевдоэлементы: `&::before`, `&::after`.
+ - Медиа-запросы: `@media`.
+ - Модификаторы: `&._active`, `&._disabled`.
+- Каждый вложенный блок отделяется пустой строкой от предыдущих свойств.
+
+**Хорошо**
+```css
+.card {
+ padding: 16px;
+ background-color: var(--color-bg);
+
+ &:hover {
+ background-color: var(--color-bg-hover);
+ }
+
+ &::after {
+ content: '';
+ display: block;
+ }
+
+ &._highlighted {
+ border-color: var(--color-primary);
+ }
+
+ @media (--md) {
+ padding: 24px;
+ }
+}
+
+.cardTitle {
+ font-size: 16px;
+
+ @media (--md) {
+ font-size: 20px;
+ }
+}
+```
+
+**Плохо**
+```css
+/* Плохо: вложенность селекторов, нет пустых строк между блоками. */
+.card {
+ padding: 16px;
+ .cardTitle {
+ font-size: 16px;
+ }
+ &:hover {
+ background-color: var(--color-bg-hover);
+ }
+}
+```
+
+## Медиа-запросы
+
+- Только **Custom Media Queries**: `@media (--md) {}`.
+- Запрещены произвольные breakpoints: `@media (min-width: 768px)`.
+- `@media` пишется только **внутри** селектора.
+- Запрещено писать `@media` на верхнем уровне с селекторами внутри.
+
+**Хорошо**
+```css
+.sidebar {
+ display: none;
+
+ @media (--md) {
+ display: block;
+ }
+}
+
+.sidebarTitle {
+ font-size: 14px;
+
+ @media (--md) {
+ font-size: 18px;
+ }
+}
+```
+
+**Плохо**
+```css
+/* Плохо: @media на верхнем уровне с селекторами внутри. */
+@media (--md) {
+ .sidebar {
+ display: block;
+ }
+
+ .sidebarTitle {
+ font-size: 18px;
+ }
+}
+
+/* Плохо: произвольный breakpoint вместо custom media. */
+.sidebar {
+ @media (min-width: 992px) {
+ display: block;
+ }
+}
+```
+
+## CSS-переменные
+
+- Цвета (`--color-*`), отступы (`--space-*`), скругления (`--radius-*`) определяются в `src/shared/styles/variables.css` через `:root`.
+- Файл переменных подключается через `src/shared/styles/global.css`, который импортируется один раз в `src/app/layout.tsx`.
+- Не дублировать магические значения в компонентах.
+
+**Хорошо**
+```css
+/* src/shared/styles/variables.css */
+:root {
+ --color-primary: #3b82f6;
+ --color-bg: #ffffff;
+ --color-bg-hover: #f5f5f5;
+ --space-1: 4px;
+ --space-2: 8px;
+ --space-3: 12px;
+ --radius-1: 4px;
+ --radius-2: 8px;
+}
+```
+
+```css
+/* компонент */
+.card {
+ padding: var(--space-3);
+ border-radius: var(--radius-2);
+ background-color: var(--color-bg);
+}
+```
+
+**Плохо**
+```css
+/* Плохо: магические значения вместо переменных. */
+.card {
+ padding: 12px;
+ border-radius: 8px;
+ background-color: #ffffff;
+}
+```
+
+## Custom Media
+
+- Breakpoints определяются через Custom Media Queries в `src/shared/styles/media.css`.
+- Custom media подключаются глобально через конфиг PostCSS (плагин `postcss-custom-media`) — не импортировать в файлы стилей.
+
+```css
+/* src/shared/styles/media.css */
+@custom-media --sm (min-width: 36em);
+@custom-media --md (min-width: 62em);
+@custom-media --lg (min-width: 82em);
+```
+
+## Импорт стилей
+
+- Стили компонента импортируются только внутри своего компонента.
+- Запрещено импортировать стили одного компонента в другой.
+- Custom media не импортируются в файлы стилей — они подключаются глобально через конфиг PostCSS.
+
+## Форматирование
+
+- Пустая строка между селекторами верхнего уровня.
+- Пустая строка перед каждым вложенным блоком (медиа, псевдокласс, модификатор).
+
+**Хорошо**
+```css
+.userBar {
+ display: none;
+ color: var(--color-text);
+
+ @media (--md) {
+ display: flex;
+ }
+}
+
+.userBarButton {
+ background-color: var(--color-bg);
+
+ &:hover {
+ background-color: var(--color-bg-hover);
+ }
+
+ &._active {
+ background-color: var(--color-primary);
+ }
+}
+```
+
+**Плохо**
+```css
+/* Плохо: нет пустых строк между селекторами и вложенными блоками. */
+.userBar {
+ display: none;
+ color: var(--color-text);
+ @media (--md) {
+ display: flex;
+ }
+}
+.userBarButton {
+ background-color: var(--color-bg);
+ &:hover {
+ background-color: var(--color-bg-hover);
+ }
+ &._active {
+ background-color: var(--color-primary);
+ }
+}
+```
+
+## Единицы измерения
+
+- `px` — основная единица измерения.
+- Остальные (`em`, `rem`, `%`, `vh`/`vw`) — допускаются по необходимости дизайна.
+
+## Порядок CSS-свойств
+
+В стилях рекомендуется придерживаться логического порядка свойств:
+
+1. Позиционирование (`position`, `top`, `left`, `z-index`).
+2. Блочная модель (`display`, `width`, `height`, `margin`, `padding`).
+3. Оформление (`background`, `border`, `box-shadow`, `border-radius`).
+4. Текст (`font`, `color`, `text-align`, `line-height`).
+5. Прочее (`transition`, `animation`, `opacity`, `cursor`).
+
+## Комментарии
+
+- Желательно не писать комментарии в CSS.
+- Исключение — нетривиальные хаки и обходные решения, к которым стоит оставить пояснение.
diff --git a/ai/nextjs-style-guide/applied/svg-sprites/svg-sprites-intro.md b/ai/nextjs-style-guide/applied/svg-sprites/svg-sprites-intro.md
new file mode 100644
index 0000000..4bc1fb2
--- /dev/null
+++ b/ai/nextjs-style-guide/applied/svg-sprites/svg-sprites-intro.md
@@ -0,0 +1,31 @@
+---
+title: SVG-спрайты
+description: "Что такое SVG-спрайты и какие проблемы они решают."
+---
+
+# SVG-спрайты
+
+Что такое SVG-спрайты и какие проблемы они решают.
+
+## Проблема
+
+Иконки в проекте — это десятки и сотни SVG-файлов, которые нужно как-то доставлять в интерфейс. Подход «один `` на иконку» или инлайн SVG в каждом компоненте приводят к трём проблемам:
+
+- **Дублирование.** Инлайн SVG в нескольких компонентах — один и тот же код размазан по проекту. Изменение иконки требует правок в десяти местах.
+- **Размер бандла.** Каждый инлайн SVG — полный XML-код, который попадает в JS-бандл. Сотня иконок × средний размер SVG = сотни килобайт, которые браузер парсит как JavaScript, а не как статику.
+- **Нет управления цветом.** Инлайн SVG жёстко закрашивает иконку. Сменить цвет по состоянию (`:hover`, `._disabled`) — значит дублировать SVG или городить `currentColor`-хаки в каждом компоненте.
+
+## Решение
+
+SVG-спрайты — это единый файл-контейнер, в который собираются все иконки проекта. В коде используется один React-компонент ``, а браузер загружает спрайт как статику — один раз, с кешированием.
+
+Что дают SVG-спрайты:
+
+- **Один источник.** Каждая иконка — один SVG-файл в `src/shared/sprites/`. Обновил файл — иконка обновилась везде.
+- **Лёгкий бандл.** Спрайт отдаётся как статический файл из `public/`, не попадает в JavaScript. Типы имён иконок генерируются автоматически — автодополнение работает без ручных описаний.
+- **Цвет через CSS.** При сборке цвета в SVG заменяются на CSS-переменные. Цвет иконки меняется через `color` родителя или через переменные `--icon-color-N` — как любой другой стиль.
+
+## Состав раздела
+
+- [Настройка](./svg-sprites-setup.md) — подключение пакета, конфигурация, первая генерация.
+- [Использование](./svg-sprites-usage.md) — добавление иконок, компонент ``, управление цветом.
diff --git a/ai/nextjs-style-guide/applied/svg-sprites/svg-sprites-setup.md b/ai/nextjs-style-guide/applied/svg-sprites/svg-sprites-setup.md
new file mode 100644
index 0000000..7329443
--- /dev/null
+++ b/ai/nextjs-style-guide/applied/svg-sprites/svg-sprites-setup.md
@@ -0,0 +1,132 @@
+---
+title: Настройка SVG-спрайтов
+description: Подключение SVG-спрайтов в новом проекте.
+keywords: [svg-sprites, установка, настройка, config, пакет, "@gromlab/svg-sprites", svg-sprites.config.ts]
+---
+
+# Настройка SVG-спрайтов
+Подключение SVG-спрайтов в новом проекте.
+
+## Установка
+
+1. Установить пакет:
+
+ ```bash
+ npm install @gromlab/svg-sprites
+ ```
+
+2. Создать `svg-sprites.config.ts` в корне проекта (см. [Стандартный конфиг](#стандартныи-конфиг)).
+
+3. Создать папку входа для SVG-файлов в слое `shared`:
+
+ ```bash
+ mkdir -p src/shared/sprites/icons
+ ```
+
+ Источники спрайтов живут в `src/shared/sprites//` — это слой `shared` SLM-архитектуры (см. [Структура проекта](../project-structure.md), [Архитектура](../../basics/architecture/index.md)). В `src/` посторонних каталогов вне слоёв не заводим.
+
+4. Добавить скрипты в `package.json`:
+
+ ```json
+ {
+ "scripts": {
+ "sprite": "svg-sprites",
+ "predev": "svg-sprites",
+ "prebuild": "svg-sprites"
+ }
+ }
+ ```
+
+ Хуки `predev` и `prebuild` гарантируют, что спрайты и типы всегда актуальны перед запуском и сборкой.
+
+5. Добавить сгенерированные артефакты в `.gitignore`:
+
+ ```text
+ # Сгенерированные спрайты и React-компонент
+ /public/sprites/
+ /src/ui/svg-sprite/
+ ```
+
+ 6. Выполнить первую генерацию:
+
+ ```bash
+ npm run sprite
+ ```
+
+7. Подключить спрайт в layout. Глобальный спрайт (иконки) подключается через `` в корневом layout — браузер загрузит файл заранее и закеширует:
+
+ ```tsx
+ // src/app/layout.tsx
+ import 'shared/styles/global.css'
+
+ import type { Metadata } from 'next'
+
+ export const metadata: Metadata = {
+ title: 'App',
+ description: '',
+ }
+
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
+
+ {children}
+
+ )
+ }
+ ```
+
+ Локальные спрайты (если есть) подключаются аналогично в layout конкретной страницы или маршрута.
+
+## Стандартный конфиг
+
+Файл `svg-sprites.config.ts` в корне проекта. Это канон — отклонения только по явной причине.
+
+```ts
+// svg-sprites.config.ts
+import { defineConfig } from '@gromlab/svg-sprites'
+
+export default defineConfig({
+ output: 'public/sprites',
+ publicPath: '/sprites',
+ react: 'src/ui/svg-sprite',
+ sprites: [
+ { name: 'icons', input: 'src/shared/sprites/icons' },
+ ],
+})
+```
+
+### Фиксированные значения
+
+| Опция | Значение | Почему так |
+|-------|----------|------------|
+| `output` | `public/sprites` | Единая папка статики Next.js |
+| `publicPath` | `/sprites` | URL-путь без `public/` (Next.js раздаёт `public/` как `/`) |
+| `react` | `src/ui/svg-sprite` | Слой `ui/` из архитектуры проекта (→ [Архитектура](../../basics/architecture/index.md)) |
+| `sprites[0].name` | `icons` | Основной спрайт всегда называется `icons` |
+
+### Трансформации
+
+Все значения по умолчанию оставлять включёнными:
+
+```ts
+transform: {
+ removeSize: true,
+ replaceColors: true,
+ addTransition: true,
+}
+```
+
+Явно прописывать блок `transform` не нужно — пакет применяет эти значения по умолчанию.
+
+Отключать `replaceColors` — только для отдельного спрайта с фиксированной палитрой (например, брендовые логотипы). Делать это на уровне спрайта, не глобально.
+
+### Режим
+
+По умолчанию `mode: 'stack'` — не указывать явно. Переход на `symbol` требует обоснования: превью и примеры в пакете оптимизированы под `stack`.
+
+## Дальше
+
+- [Использование](./svg-sprites-usage.md) — добавление иконок, компонент ``, управление цветом.
diff --git a/ai/nextjs-style-guide/applied/svg-sprites/svg-sprites-usage.md b/ai/nextjs-style-guide/applied/svg-sprites/svg-sprites-usage.md
new file mode 100644
index 0000000..d984642
--- /dev/null
+++ b/ai/nextjs-style-guide/applied/svg-sprites/svg-sprites-usage.md
@@ -0,0 +1,56 @@
+---
+title: Использование SVG-спрайтов
+description: Как добавлять и использовать SVG-иконки в коде.
+keywords: [svg, спрайт, sprite, иконка, icon, SvgSprite, превью, preview, цвет, color]
+---
+
+# Использование SVG-спрайтов
+
+Как добавлять и использовать SVG-иконки в коде.
+
+## Шаги
+
+1. **Положить SVG в папку спрайта:**
+
+ ```text
+ src/shared/sprites/icons/new-icon.svg
+ ```
+
+2. **Импортировать компонент.** Компонент `` генерируется пакетом вместе с типами имён иконок — автодополнение работает без ручных описаний:
+
+ ```tsx
+ import { SvgSprite } from 'ui/svg-sprite'
+
+
+ ```
+
+3. **Посмотреть и пощупать иконку — в превью.** Пакет генерирует HTML-превью рядом со спрайтом (`public/sprites/icons.preview.html`). Там виден набор иконок, имена и поведение цвета.
+
+## Управление цветом
+
+При сборке цвета в SVG заменяются на CSS-переменные `--icon-color-N`. Управление — через обычный CSS родителя.
+
+**Моно-иконка** наследует `color` родителя (`--icon-color-1` по умолчанию `currentColor`):
+
+```css
+.button {
+ color: var(--color-primary);
+}
+```
+
+**Точечное переопределение** — через переменную:
+
+```css
+.icon-danger {
+ --icon-color-1: var(--color-danger);
+}
+```
+
+**Мульти-иконка** — переменные задаются явно, порядок виден в превью:
+
+```css
+.folder {
+ --icon-color-1: var(--color-folder-bg);
+ --icon-color-2: var(--color-folder-accent);
+}
+```
diff --git a/ai/nextjs-style-guide/applied/templates/templates-create.md b/ai/nextjs-style-guide/applied/templates/templates-create.md
new file mode 100644
index 0000000..1715c5d
--- /dev/null
+++ b/ai/nextjs-style-guide/applied/templates/templates-create.md
@@ -0,0 +1,91 @@
+---
+title: Создание шаблонов генерации
+description: "Структура шаблонов, синтаксис переменных и примеры."
+keywords: [шаблоны, templates, .templates, syntax, переменные, kebabCase, pascalCase, scaffold]
+---
+
+
+::: v-pre
+
+# Создание шаблонов генерации
+
+Структура шаблонов, синтаксис переменных и примеры.
+
+## Структура шаблонов
+
+Все шаблоны лежат в `.templates/` в корне проекта. Каждая папка — отдельный шаблон.
+
+```text
+.templates/
+├── component/ # шаблон компонента
+│ └── {{name.kebabCase}}/
+│ ├── styles/
+│ │ └── {{name.kebabCase}}.module.css
+│ ├── types/
+│ │ └── {{name.kebabCase}}.type.ts
+│ ├── {{name.kebabCase}}.tsx
+│ └── index.ts
+└── store/ # шаблон Zustand стора
+ └── {{name.kebabCase}}/
+ ├── {{name.kebabCase}}.store.ts
+ ├── {{name.kebabCase}}.type.ts
+ └── index.ts
+```
+
+## Синтаксис шаблонов
+
+### Переменные
+
+Переменные работают в именах файлов/папок и внутри файлов:
+
+```text
+{{variable}}
+```
+
+Переменные могут быть любыми. `name` — дефолтная, подставляется генератором автоматически. Если реализация требует дополнительных параметров — можно использовать произвольные наборы переменных.
+
+### Модификаторы
+
+Модификаторы меняют регистр и формат записи переменной:
+
+```text
+{{name.pascalCase}} → MyButton
+{{name.camelCase}} → myButton
+{{name.kebabCase}} → my-button
+{{name.snakeCase}} → my_button
+{{name.screamingSnakeCase}} → MY_BUTTON
+```
+
+## Как создать новый шаблон
+
+1. Создать папку в `.templates/` с именем шаблона (например `hook`).
+2. Внутри разместить файлы и папки, используя `{{name}}` и модификаторы в именах и содержимом.
+3. Шаблон сразу доступен и в расширении VS Code, и в CLI.
+
+Пример — создание шаблона для хука:
+
+```text
+.templates/
+└── hook/
+ └── {{name.kebabCase}}/
+ ├── {{name.kebabCase}}.hook.ts
+ └── index.ts
+```
+
+```ts
+// .templates/hook/{{name.kebabCase}}.hook.ts
+export const {{name.camelCase}} = () => {
+
+}
+```
+
+```ts
+// .templates/hook/index.ts
+export { {{name.camelCase}} } from './{{name.kebabCase}}.hook'
+```
+
+## Дальше
+
+- [Использование](./templates-usage.md) — генерация через VS Code плагин и CLI.
+
+:::
diff --git a/ai/nextjs-style-guide/applied/templates/templates-intro.md b/ai/nextjs-style-guide/applied/templates/templates-intro.md
new file mode 100644
index 0000000..1ae1b95
--- /dev/null
+++ b/ai/nextjs-style-guide/applied/templates/templates-intro.md
@@ -0,0 +1,32 @@
+---
+title: Шаблоны генерации
+description: "Что такое шаблоны кодогенерации и какие проблемы они решают."
+---
+
+# Шаблоны генерации
+
+Что такое шаблоны кодогенерации и какие проблемы они решают.
+
+## Проблема
+
+Каждый новый модуль в проекте — компонент, стор, бизнес-модуль — требует однотипной структуры файлов и boilerplate-кода. Ручное создание приводит к трём проблемам:
+
+- **Расхождения.** Разные разработчики создают модули по-разному: забывают `index.ts`, называют типы не по канону, пропускают стили.
+- **Время.** Создание одного компонента с типами, стилями и экспортом — 5–10 минут рутины. За спринт набегают часы.
+- **Ошибки копипасты.** Копирование существующего модуля и переименование — источник опечаток и забытых ссылок.
+
+## Решение
+
+Шаблоны кодогенерации — это папки с файлами-заготовками в `.templates/`. Вместо ручного создания файлов разработчик вызывает генератор, указывает имя — и получает готовый модуль со всей структурой, именами и boilerplate, подставленными автоматически.
+
+Что дают шаблоны:
+
+- **Единообразие.** Все модули одного типа идентичны по структуре. Канон живёт в шаблоне, а не в памяти разработчика.
+- **Скорость.** Генерация модуля — одна команда. Остальное время — на бизнес-логику.
+- **Согласованность с архитектурой.** Шаблоны учитывают SLM: правильные слои, сегменты, экспорты. Отклонение от стайлгайда требует осознанного усилия, а не случайного упущения.
+
+## Состав раздела
+
+- [Настройка](./templates-setup.md) — первичная установка: скачивание стандартного набора шаблонов в проект.
+- [Создание шаблонов](./templates-create.md) — структура файлов, синтаксис переменных, примеры.
+- [Использование](./templates-usage.md) — генерация через VS Code плагин и CLI.
diff --git a/ai/nextjs-style-guide/applied/templates/templates-setup.md b/ai/nextjs-style-guide/applied/templates/templates-setup.md
new file mode 100644
index 0000000..4365c71
--- /dev/null
+++ b/ai/nextjs-style-guide/applied/templates/templates-setup.md
@@ -0,0 +1,44 @@
+---
+title: Настройка шаблонов генерации
+description: Первичная установка шаблонов кодогенерации в проект.
+keywords: [шаблоны, templates, .templates, tiged, generator, генератор шаблонов, скачать шаблоны, scaffold]
+---
+
+# Настройка шаблонов генерации
+
+Первичная установка шаблонов кодогенерации в проект.
+
+## Установка
+
+1. Проверить, что `.templates/` отсутствует (или согласовать перезапись, если папка уже есть).
+
+2. Скачать папку из эталонного репозитория:
+
+ ```bash
+ npx tiged git@gromlab.ru:templates/nextjs-template.git/.templates .templates
+ ```
+
+3. Если `tiged` падает в default-режиме (HTTP-tarball у Gitea) — повторить с явным git-режимом:
+
+ ```bash
+ npx tiged --mode=git git@gromlab.ru:templates/nextjs-template.git/.templates .templates
+ ```
+
+4. Проверить генерацию:
+
+ ```bash
+ npx @gromlab/create component test src/ui
+ ```
+
+ После проверки — удалить тестовый модуль.
+
+## Проверка установки
+
+- В корне проекта есть папка `.templates/`.
+- Внутри `.templates/` присутствуют стандартные шаблоны (или согласованный кастомный набор).
+- Пробная генерация через `npx @gromlab/create ...` отрабатывает без ошибок.
+
+## Дальше
+
+- [Создание шаблонов](./templates-create.md) — структура файлов, синтаксис переменных, примеры.
+- [Использование](./templates-usage.md) — генерация через VS Code плагин и CLI.
diff --git a/ai/nextjs-style-guide/applied/templates/templates-usage.md b/ai/nextjs-style-guide/applied/templates/templates-usage.md
new file mode 100644
index 0000000..1d2e2d8
--- /dev/null
+++ b/ai/nextjs-style-guide/applied/templates/templates-usage.md
@@ -0,0 +1,39 @@
+---
+title: Использование шаблонов генерации
+description: Генерация файлов из шаблонов через VS Code плагин и CLI.
+keywords: [шаблоны, templates, generate, VS Code, CLI, gromlab/create, npx, scaffold]
+---
+
+# Использование шаблонов генерации
+
+Генерация файлов из шаблонов через VS Code плагин и CLI.
+
+## Через VS Code
+
+Template File Generator | gromlab ([Marketplace](https://marketplace.visualstudio.com/items?itemName=gromlab.vscode-templateFileGenerator), [Open VSX](https://open-vsx.org/extension/gromlab/vscode-templateFileGenerator)) — расширение для генерации файлов и папок из шаблонов через интерфейс редактора.
+
+1. ПКМ на целевой папке в проводнике VS Code.
+2. **Generate from template** → выбрать шаблон.
+3. Ввести имя (например `button`) — расширение подставит его во все переменные `{{name}}`.
+
+Расширение устанавливается разово на машину разработчика, не через проект.
+
+## Через CLI
+
+[@gromlab/create](https://www.npmjs.com/package/@gromlab/create) — CLI для генерации из тех же шаблонов. Используется через npx, глобальная установка не требуется.
+
+```bash
+npx @gromlab/create <шаблон> <имя> [путь]
+```
+
+Путь не обязателен — по умолчанию генерация происходит в текущую директорию.
+
+| Команда | Что создаёт |
+|---|---|
+| `npx @gromlab/create component button` | Компонент в текущей папке |
+| `npx @gromlab/create module auth src/business` | Бизнес-модуль |
+| `npx @gromlab/create widget header src/widgets` | Виджет |
+| `npx @gromlab/create layout admin src/layouts` | Layout |
+| `npx @gromlab/create store auth src/business/auth/stores` | Стор |
+
+CLI вызывается через `npx`, в `package.json` отдельно не добавляется.
diff --git a/ai/nextjs-style-guide/applied/vscode.md b/ai/nextjs-style-guide/applied/vscode.md
new file mode 100644
index 0000000..f844ead
--- /dev/null
+++ b/ai/nextjs-style-guide/applied/vscode.md
@@ -0,0 +1,88 @@
+---
+title: VS Code
+description: Единые настройки редактора и расширений для команды.
+---
+
+# VS Code
+
+Единые настройки редактора и расширений для команды.
+
+## Структура `.vscode/`
+
+```text
+.vscode/
+├── extensions.json # Рекомендуемые расширения
+└── settings.json # Настройки редактора для проекта
+```
+
+Оба файла коммитятся в репозиторий.
+
+## Расширения
+
+Файл `.vscode/extensions.json` определяет список расширений, которые VS Code предложит установить при открытии проекта.
+
+```json
+// .vscode/extensions.json
+{
+ "recommendations": [
+ "biomejs.biome",
+ "MyTemplateGenerator.mytemplategenerator",
+ "csstools.postcss"
+ ]
+}
+```
+
+| Расширение | Назначение |
+|---|---|
+| [Biome](https://marketplace.visualstudio.com/items?itemName=biomejs.biome) | Линтинг и форматирование кода. Заменяет ESLint и Prettier |
+| Template File Generator \| gromlab ([Marketplace](https://marketplace.visualstudio.com/items?itemName=gromlab.vscode-templateFileGenerator), [Open VSX](https://open-vsx.org/extension/gromlab/vscode-templateFileGenerator)) | Генерация файлов и папок из шаблонов `.templates/` через контекстное меню |
+| [PostCSS Language Support](https://marketplace.visualstudio.com/items?itemName=csstools.postcss) | Подсветка синтаксиса и автодополнение для PostCSS (`@custom-media`, `@nest` и др.) |
+
+### Зачем это нужно
+
+- Новый участник команды получает все нужные расширения одним кликом.
+- Нет разночтений: все используют одинаковый форматтер и линтер.
+- Расширения привязаны к проекту, а не к конкретному разработчику.
+
+## Настройки редактора
+
+Файл `.vscode/settings.json` переопределяет пользовательские настройки VS Code на уровне проекта.
+
+```json
+// .vscode/settings.json
+{
+ "editor.defaultFormatter": "biomejs.biome",
+ "editor.formatOnSave": true,
+ "editor.codeActionsOnSave": {
+ "source.fixAll.biome": "explicit",
+ "source.organizeImports.biome": "explicit"
+ },
+ "files.associations": {
+ "*.css": "postcss"
+ }
+}
+```
+
+### Разбор настроек
+
+| Настройка | Значение | Что делает |
+|---|---|---|
+| `editor.defaultFormatter` | `biomejs.biome` | Biome используется как единственный форматтер для всех файлов |
+| `editor.formatOnSave` | `true` | Код автоматически форматируется при каждом сохранении |
+| `codeActionsOnSave.source.fixAll.biome` | `explicit` | Biome автоматически применяет безопасные исправления при сохранении |
+| `codeActionsOnSave.source.organizeImports.biome` | `explicit` | Импорты сортируются и группируются автоматически при сохранении |
+| `files.associations` | `"*.css": "postcss"` | Все CSS-файлы открываются с подсветкой PostCSS вместо стандартного CSS |
+
+### Зачем это нужно
+
+- **Единый стиль кода** -- форматирование происходит автоматически, невозможно закоммитить неформатированный код.
+- **Автофикс при сохранении** -- распространённые ошибки линтинга исправляются без ручного вмешательства.
+- **Сортировка импортов** -- импорты всегда в одном порядке, без конфликтов при мерже.
+- **PostCSS-подсветка** -- кастомные at-правила (`@custom-media`, `@define-mixin`) подсвечиваются корректно, а не как ошибки.
+
+## Что не должно быть в `.vscode/`
+
+Не коммитятся файлы, специфичные для конкретного разработчика:
+
+- **Не коммитить**: отладочные конфигурации с локальными путями, персональные сниппеты, настройки тем оформления.
+- **Коммитить**: только `extensions.json` и `settings.json` с общими для команды настройками.
diff --git a/ai/nextjs-style-guide/basics/architecture/index.md b/ai/nextjs-style-guide/basics/architecture/index.md
new file mode 100644
index 0000000..4653ce2
--- /dev/null
+++ b/ai/nextjs-style-guide/basics/architecture/index.md
@@ -0,0 +1,100 @@
+---
+title: SLM Design
+description: "Архитектурный подход проекта: что такое SLM и как он устроен."
+---
+
+# SLM Design
+
+Архитектурный подход проекта: что такое SLM и как он устроен.
+
+## Преимущества
+
+### Вертикальная организация домена
+
+Бизнес-домен не разбивается по техническим слоям — сценарии, сущности, типы и 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.
+- **Архитектура — каркас, не клетка.** Правила фиксируют направление зависимостей и структуру модуля, остальное определяет команда.
diff --git a/ai/nextjs-style-guide/basics/architecture/reference/layers.md b/ai/nextjs-style-guide/basics/architecture/reference/layers.md
new file mode 100644
index 0000000..c9f3407
--- /dev/null
+++ b/ai/nextjs-style-guide/basics/architecture/reference/layers.md
@@ -0,0 +1,253 @@
+---
+title: Слои SLM
+description: Из каких слоёв состоит SLM-архитектура и как они связаны.
+---
+
+# Слои SLM
+
+Из каких слоёв состоит 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-состояния
diff --git a/ai/nextjs-style-guide/basics/architecture/reference/modules.md b/ai/nextjs-style-guide/basics/architecture/reference/modules.md
new file mode 100644
index 0000000..c5a424a
--- /dev/null
+++ b/ai/nextjs-style-guide/basics/architecture/reference/modules.md
@@ -0,0 +1,165 @@
+---
+title: Модули SLM
+description: Что такое модуль в SLM-архитектуре и как он устроен.
+---
+
+# Модули SLM
+
+Что такое модуль в 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
+```
+
+Подробное описание каждого сегмента — в разделе [Сегменты](./segments.md).
+
+## Публичный 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 (
+
+
+ {messages.map(m => )}
+
+
+ )
+}
+```
+
+## Жизненный цикл
+
+Модуль рождается на самом низком уровне использования и поднимается выше только при реальной потребности.
+
+- Нужен на одной странице → `screens/{name}/parts/`
+- Появился в 2+ местах → поднимается по природе:
+ - абстрактный UI → `ui/`
+ - блок с данными/логикой → `widgets/`
+ - представление бизнес-домена → `business/{area}/parts/`
+
+Подъём — обычный рефакторинг в рамках задачи, а не отдельная активность.
diff --git a/ai/nextjs-style-guide/basics/architecture/reference/segments.md b/ai/nextjs-style-guide/basics/architecture/reference/segments.md
new file mode 100644
index 0000000..45af86b
--- /dev/null
+++ b/ai/nextjs-style-guide/basics/architecture/reference/segments.md
@@ -0,0 +1,159 @@
+---
+title: Сегменты SLM
+description: Что такое сегмент модуля в SLM-архитектуре и какие они бывают.
+---
+
+# Сегменты SLM
+
+Что такое сегмент модуля в SLM-архитектуре и какие они бывают.
+
+## Определение
+
+**Сегмент — папка внутри модуля, которая группирует файлы по назначению. Набор сегментов не фиксирован — модуль включает только те, которые ему нужны. Команда сама определяет какие сегменты используются в проекте — архитектура даёт рекомендацию.**
+
+## Обзор
+
+| Сегмент | Содержимое |
+|---------|------------|
+| `ui/` | Вспомогательные компоненты модуля — только `.tsx` файлы |
+| `parts/` | Вложенные модули со своими сегментами |
+| `hooks/` | React-хуки |
+| `stores/` | Сторы состояния |
+| `services/` | Работа с внешними источниками данных |
+| `mappers/` | Трансформация данных между форматами |
+| `types/` | TypeScript-типы и интерфейсы |
+| `styles/` | Стили |
+| `lib/` | Утилиты и хелперы модуля |
+| `config/` | Константы и конфигурация |
+
+## Сегмент ui/
+
+Вспомогательные компоненты модуля. Содержит только `.tsx` файлы — без своих сегментов, стилей, типов, хуков и публичного API. Использует сегменты родительского модуля.
+
+Корневой компонент модуля в `ui/` не размещается. Он лежит в корне модуля: `{module-name}.tsx`.
+
+```text
+user/
+├── ui/
+│ ├── user-avatar.tsx
+│ └── user-status.tsx
+├── types/
+├── hooks/
+├── user.tsx
+└── index.ts
+```
+
+Если компоненту нужны собственные сегменты — это уже не `ui/`, а `parts/`.
+
+## Сегмент parts/
+
+Вложенные модули со своими сегментами. `parts/` содержит только модули: каждый элемент `parts/` — папка полноценного модуля с собственным публичным API. Отдельные `.tsx`, стили, хуки или произвольные файлы в `parts/` не размещаются.
+
+```text
+home/
+├── parts/
+│ ├── hero-section/
+│ │ ├── hero-section.tsx
+│ │ ├── styles/
+│ │ ├── parts/
+│ │ │ └── top-banner/
+│ │ │ ├── top-banner.tsx
+│ │ │ └── index.ts
+│ │ └── index.ts
+│ └── features-section/
+│ ├── features-section.tsx
+│ ├── hooks/
+│ └── index.ts
+├── 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
+```
diff --git a/ai/nextjs-style-guide/basics/code-style.md b/ai/nextjs-style-guide/basics/code-style.md
new file mode 100644
index 0000000..e47e625
--- /dev/null
+++ b/ai/nextjs-style-guide/basics/code-style.md
@@ -0,0 +1,153 @@
+---
+title: Стиль кода
+description: Как оформляется код в проекте.
+---
+
+# Стиль кода
+
+Как оформляется код в проекте.
+
+## Отступы
+
+- 2 пробела (не табы).
+
+## Длина строк
+
+- Ориентироваться на 100 символов, но превышение допустимо, если строка читается легко.
+- Переносить выражение на новые строки, когда строка становится плохо читаемой.
+- Не переносить строку внутри строковых литералов без необходимости.
+
+**Хорошо**
+```ts
+const config = createRequestConfig(
+ endpoint,
+ {
+ headers: {
+ 'X-Request-Id': requestId,
+ 'X-User-Id': userId,
+ },
+ params: {
+ page,
+ pageSize,
+ sort: 'createdAt',
+ },
+ },
+ timeoutMs,
+);
+```
+
+**Плохо**
+```ts
+// Плохо: длинная строка с вложенными структурами плохо читается.
+const config = createRequestConfig(endpoint, { headers: { 'X-Request-Id': requestId, 'X-User-Id': userId }, params: { page, pageSize, sort: 'createdAt' } }, timeoutMs);
+```
+
+## Кавычки
+
+- В JavaScript/TypeScript использовать одинарные кавычки.
+- В JSX/TSX для атрибутов использовать двойные кавычки.
+- Шаблонные строки использовать только при интерполяции или многострочном тексте.
+
+**Хорошо**
+```ts
+const label = 'Сохранить';
+const title = `Привет, ${name}`;
+```
+
+```tsx
+
+```
+
+**Плохо**
+```ts
+// Плохо: двойные кавычки в TS и конкатенация вместо шаблонной строки.
+const label = "Сохранить";
+const title = 'Привет, ' + name;
+```
+
+```tsx
+// Плохо: одинарные кавычки в JSX-атрибутах.
+
+```
+
+## Точки с запятой и запятые
+
+- Допускаются упущения точки с запятой, если код остаётся читаемым и однозначным.
+- В многострочных массивах, объектах и параметрах функции запятая в конце допускается, но не обязательна.
+
+## Импорты
+
+- В именованных импортах использовать пробелы внутри фигурных скобок.
+- Типы импортировать через `import type`.
+- `default` экспорт избегать, использовать именованные. `default` импорт допустим (например, стили CSS Modules, сторонние библиотеки).
+- Избегать импорта всего модуля через `*`.
+
+**Хорошо**
+```ts
+import { MyComponent } from 'MyComponent';
+import type { User } from '../model/types';
+import styles from './styles/button.module.css';
+```
+
+**Плохо**
+```ts
+// Плохо: отсутствие пробелов в именованном импорте.
+import type {User} from '../model/types';
+// Плохо: default экспорт.
+export default MyComponent;
+```
+
+## Ранние возвраты (early return)
+
+- Использовать ранние возвраты для упрощения чтения.
+- Избегать `else` после `return`.
+
+**Хорошо**
+```ts
+const getName = (user?: { name: string }) => {
+ if (!user) {
+ return 'Гость';
+ }
+
+ return user.name;
+};
+```
+
+**Плохо**
+```ts
+// Плохо: лишний else после return усложняет чтение.
+const getName = (user?: { name: string }) => {
+ if (user) {
+ return user.name;
+ } else {
+ return 'Гость';
+ }
+};
+```
+
+## Форматирование объектов и массивов
+
+- В многострочных объектах каждое свойство на новой строке.
+- В многострочных массивах каждый элемент на новой строке.
+- Объекты и массивы можно писать в одну строку, если длина строки не превышает 100 символов.
+- В однострочных объектах и массивах использовать пробелы после запятых.
+
+**Хорошо**
+```ts
+const roles = ['admin', 'editor', 'viewer'];
+const options = { id: 1, name: 'User' };
+
+const config = {
+ url: '/api/users',
+ method: 'GET',
+ params: { page: 1, pageSize: 20 },
+};
+```
+
+**Плохо**
+```ts
+// Плохо: нет пробелов после запятых и объект слишком длинный для одной строки.
+const roles = ['admin','editor','viewer'];
+const options = { id: 1,name: 'User' };
+const config = { url: '/api/users', method: 'GET', params: { page: 1, pageSize: 20 } };
+```
diff --git a/ai/nextjs-style-guide/basics/documentation.md b/ai/nextjs-style-guide/basics/documentation.md
new file mode 100644
index 0000000..81abcf1
--- /dev/null
+++ b/ai/nextjs-style-guide/basics/documentation.md
@@ -0,0 +1,134 @@
+---
+title: Документирование
+description: Что и как документировать в коде.
+---
+
+# Документирование
+
+Что и как документировать в коде.
+
+## Общие правила
+
+- Документировать публичные функции, компоненты, типы, интерфейсы и enum.
+- Не документировать очевидное — если название говорит само за себя, комментарий не нужен.
+- Не документировать параметры, возвращаемые значения и типы пропсов — они видны из сигнатуры.
+- Описание через пользу и назначение, а не через внутреннюю реализацию.
+- Описание завершается точкой.
+
+## Функции
+
+Для документирования функций используется шаблон. Описание механики опционально —
+добавляется когда логика нетривиальна.
+
+**Шаблон**
+```ts
+/**
+ * <Что делает функция в 1 строке>.
+ *
+ * <Опционально: описание сложной механики или важных нюансов>.
+ */
+```
+
+**Хорошо**
+```ts
+/**
+ * Форматирует цену с символом валюты.
+ */
+export const formatPrice = (value: number): string => { ... }
+
+/**
+ * Рекурсивно собирает дерево категорий из плоского списка.
+ *
+ * Группирует элементы по parentId, начиная с корневых (parentId = null).
+ * Категории без родителя попадают в корень дерева.
+ */
+export const buildCategoryTree = (categories: Category[]): CategoryTree[] => { ... }
+```
+
+**Плохо**
+```ts
+// Плохо: дублирует сигнатуру.
+/**
+ * @param value - число
+ * @returns строка с ценой
+ */
+```
+
+## Компоненты
+
+Компонент описывает своё **назначение** и **сценарии применения** — это помогает понять, когда и где его использовать, без необходимости читать реализацию.
+
+**Шаблон**
+```ts
+/**
+ * <Назначение компонента в 1 строке>.
+ *
+ * Используется для:
+ * - <сценарий 1>
+ * - <сценарий 2>
+ * - <сценарий 3>
+ */
+```
+
+**Хорошо**
+```tsx
+/**
+ * Контейнер с адаптивной максимальной шириной.
+ *
+ * Используется для:
+ * - обёртки контента страниц с ограничением ширины
+ * - центрирования блоков в лейауте
+ */
+export const Container = (props: ContainerProps) => { ... }
+```
+
+**Плохо**
+```tsx
+// Плохо: описывает реализацию, а не назначение.
+/**
+ * Рендерит div с className и htmlAttr.
+ */
+
+// Плохо: нет описания вообще.
+export const Container = (props: ContainerProps) => { ... }
+```
+
+## Типы, интерфейсы, enum
+
+Документируются назначение сущности и каждое её поле.
+
+**Хорошо**
+```ts
+/**
+ * Фильтры списка задач.
+ */
+export enum TodoFilter {
+ /** Все задачи. */
+ ALL = 'all',
+ /** Только активные. */
+ ACTIVE = 'active',
+ /** Только завершённые. */
+ COMPLETED = 'completed',
+}
+
+/**
+ * Задача пользователя.
+ */
+export interface TodoItem {
+ /** Уникальный идентификатор задачи. */
+ id: string;
+ /** Текст задачи. */
+ text: string;
+ /** Статус выполнения. */
+ completed: boolean;
+}
+```
+
+**Плохо**
+```ts
+// Плохо: описывает очевидное.
+export interface TodoItem {
+ /** id — это id */
+ id: string;
+}
+```
diff --git a/ai/nextjs-style-guide/basics/naming.md b/ai/nextjs-style-guide/basics/naming.md
new file mode 100644
index 0000000..096dffb
--- /dev/null
+++ b/ai/nextjs-style-guide/basics/naming.md
@@ -0,0 +1,146 @@
+---
+title: Именование
+description: Как называть переменные, файлы и прочие сущности в коде.
+---
+
+# Именование
+
+Как называть переменные, файлы и прочие сущности в коде.
+
+## Базовые правила
+
+| Что | Рекомендуется |
+| ---------------- | ---------------------- |
+| Папки | `kebab-case` |
+| Файлы | `kebab-case` |
+| Переменные | `camelCase` |
+| Константы | `SCREAMING_SNAKE_CASE` |
+| Классы | `PascalCase` |
+| React-компоненты | `PascalCase` |
+| Хуки | `useSomething` |
+| CSS классы | `camelCase` |
+| Ключи enum | `SCREAMING_SNAKE_CASE` |
+
+
+## Именование файлов
+
+Суффикс обозначает роль или тип файла. Пишется в единственном числе.
+Формат: `name..ts`.
+
+**Хуки**
+- `use-name.hook.ts` — файл хука, функция именуется `useName`
+
+**Логика**
+- `.store.ts` — стор
+- `.service.ts` — сервис
+
+**Корневые компоненты слоёв**
+- `.screen.tsx` — корневой компонент screen-модуля: `screens/profile/profile.screen.tsx`, компонент `ProfileScreen`
+- `.layout.tsx` — корневой компонент layout-модуля: `layouts/main/main.layout.tsx`, компонент `MainLayout`
+
+Обычные и вложенные модули не получают суффикс слоя: `ui/button/button.tsx`, `screens/profile/parts/activity-feed/activity-feed.tsx`.
+
+**Типы и контракты**
+- `.type.ts` — типы и интерфейсы
+- `.interface.ts` — интерфейсы
+- `.enum.ts` — enum
+- `.dto.ts` — внешние DTO
+- `.schema.ts` — схемы валидации
+- `.constant.ts` — константы
+- `.config.ts` — конфигурация
+
+**Утилиты**
+- `.util.ts` — утилиты
+- `.helper.ts` — вспомогательные функции
+- `.lib.ts` — библиотечный код
+
+**Тесты**
+- `.test.ts` — тесты
+- `.mock.ts` — моки
+
+**Хорошо**
+```text
+business/
+└── auth-by-email/
+ ├── ui/
+ │ └── login-form.tsx
+ ├── hooks/
+ │ └── use-auth.hook.ts
+ ├── stores/
+ │ └── auth.store.ts
+ ├── types/
+ │ └── auth.type.ts
+ ├── auth-by-email.tsx
+ └── index.ts
+```
+
+**Плохо**
+```text
+business/
+└── authByEmail/
+ ├── LoginForm.tsx
+ ├── useAuth.ts
+ ├── authStore.ts
+ └── index.ts
+```
+
+## Булевы значения
+
+- Использовать префиксы `is`, `has`, `can`, `should`.
+
+**Хорошо**
+```ts
+const isReady = true;
+const hasAccess = false;
+const canSubmit = true;
+const shouldRedirect = false;
+```
+
+**Плохо**
+```ts
+// Плохо: неясное булево значение без префикса.
+const ready = true;
+const access = false;
+const submit = true;
+```
+
+## События и обработчики
+
+- Обработчики начинать с `handle`.
+- События и колбэки начинать с `on`.
+
+**Хорошо**
+```ts
+const handleSubmit = () => { ... };
+const onSubmit = () => { ... };
+```
+
+**Плохо**
+```ts
+// Плохо: неочевидное назначение имени.
+const submitClick = () => { ... };
+```
+
+## Коллекции
+
+- Для массивов использовать имена во множественном числе.
+- Для словарей/мап — использовать суффиксы `ById`, `Map`, `Dict`.
+
+**Хорошо**
+```ts
+const users = [];
+const usersById = {} as Record;
+const userIds = ['u1', 'u2'];
+const ordersMap = new Map();
+const featureFlagsDict = { beta: true, legacy: false } as Record;
+```
+
+**Плохо**
+```ts
+// Плохо: имя не отражает, что это коллекция.
+const user = [];
+// Плохо: словарь назван как массив.
+const usersMap = [];
+// Плохо: по имени непонятно, что это словарь.
+const users = {} as Record;
+```
diff --git a/ai/nextjs-style-guide/basics/tech-stack.md b/ai/nextjs-style-guide/basics/tech-stack.md
new file mode 100644
index 0000000..484ab93
--- /dev/null
+++ b/ai/nextjs-style-guide/basics/tech-stack.md
@@ -0,0 +1,42 @@
+---
+title: Технологии и библиотеки
+description: Какие библиотеки и инструменты используются в проекте.
+---
+
+# Технологии и библиотеки
+
+Какие библиотеки и инструменты используются в проекте.
+
+## Что используем
+
+### Стек
+- `React` / `TypeScript` — основной стек для UI и приложения.
+- `Next.js` — для продуктовых сайтов.
+
+### Архитектура
+- `SLM Design` — собственная модульная архитектура проекта. Подробнее в разделе [Архитектура](./architecture/index.md).
+
+### UI компоненты
+- `Mantine UI` — базовые UI-компоненты.
+
+### Работа с данными (API)
+- `@gromlab/api-codegen` — генерация API‑клиентов и типов.
+- `SWR` — получение, кеширование, ревалидация, дедубликация.
+- `SWR (useSWRSubscription)` — сокеты, реалтайм подписки.
+
+### Store
+- `Zustand` — глобальное состояние.
+
+### Локализация
+- `i18next (i18n)` — локализация всех пользовательских текстов.
+
+### Тестирование
+- `Vitest` — тестирование.
+
+### Стили
+- `PostCSS Modules` — изоляция стилей.
+- `Mobile First` — подход к адаптивной верстке.
+- `clsx` — конкатенация CSS‑классов.
+
+### Генерация
+- `@gromlab/create` — шаблонизатор для создания слоёв и других файлов из шаблонов.
diff --git a/ai/nextjs-style-guide/basics/typing.md b/ai/nextjs-style-guide/basics/typing.md
new file mode 100644
index 0000000..c14743d
--- /dev/null
+++ b/ai/nextjs-style-guide/basics/typing.md
@@ -0,0 +1,57 @@
+---
+title: Типизация
+description: Как типизируется код в проекте.
+---
+
+# Типизация
+
+Как типизируется код в проекте.
+
+## Общие правила
+
+- Указывать типы для параметров компонентов, возвращаемых значений и параметров функций.
+- Предпочитать `type` для описания сущностей и `interface` для расширяемых контрактов.
+- Избегать `any` и `unknown` без необходимости.
+- Не использовать `ts-ignore`, кроме крайних случаев с явным комментарием причины.
+
+## Функции
+
+- Для публичных функций указывать возвращаемый тип.
+- Не полагаться на неявный вывод для важных API.
+
+**Хорошо**
+```ts
+export const formatPrice = (value: number): string => {
+ return `${value} ₽`;
+};
+```
+
+**Плохо**
+```ts
+// Плохо: нет явного возвращаемого типа.
+export const formatPrice = (value: number) => {
+ return `${value} ₽`;
+};
+```
+
+## Работа с any/unknown
+
+- `any` использовать только для временных заглушек.
+- `unknown` сужать через проверки перед использованием.
+
+**Хорошо**
+```ts
+const parse = (value: unknown): string => {
+ if (typeof value === 'string') {
+ return value;
+ }
+
+ return '';
+};
+```
+
+**Плохо**
+```ts
+// Плохо: any отключает проверку типов.
+const parse = (value: any) => value;
+```
diff --git a/ai/nextjs-style-guide/creating-project/from-template.md b/ai/nextjs-style-guide/creating-project/from-template.md
new file mode 100644
index 0000000..c549640
--- /dev/null
+++ b/ai/nextjs-style-guide/creating-project/from-template.md
@@ -0,0 +1,51 @@
+---
+title: Создание проекта из шаблона
+description: Создание нового проекта на основе готового шаблона.
+keywords: [создать проект из шаблона, шаблон, template, tiged, degit, клонировать шаблон, эталонный шаблон, быстрый старт, scaffold, новый проект]
+---
+
+# Создание проекта из шаблона
+
+Создание нового проекта на основе готового шаблона.
+
+## Что внутри
+
+Шаблон — готовый скелет проекта с применёнными правилами стайлгайда:
+
+- **Стек:** Next.js (App Router), TypeScript, React.
+- **Архитектура:** структура папок по SLM, алиасы импортов.
+- **Качество кода:** Biome (линтер и форматер), настройки VS Code.
+- **Стили:** PostCSS Modules с плагинами, токены, медиа-брейкпоинты.
+- **Ассеты:** генерация SVG-спрайтов.
+- **Кодогенерация:** шаблоны для страниц, компонентов, хуков, сторов.
+в
+## Установка
+
+1. Склонировать шаблон в родительском каталоге будущего проекта:
+
+ ```bash
+ npx tiged git@gromlab.ru:templates/nextjs.git my-app
+ ```
+
+ `tiged` копирует снимок репозитория без истории git. Имя каталога (`my-app`) заменяется на нужное.
+
+2. Установить зависимости:
+
+ ```bash
+ cd my-app
+ npm install
+ ```
+
+3. Проверить сборку:
+
+ ```bash
+ npm run build
+ ```
+
+ Сборка должна завершиться без ошибок.
+
+## Правила
+
+- **Шаблон — источник истины.** Не добавлять, не удалять и не переименовывать файлы шаблона «для приведения к канону»: шаблон уже канонический. Любое несоответствие — баг шаблона, а не проекта.
+- **Менеджер пакетов — npm.** Отклонение (pnpm, yarn, bun) — только по явному решению с пониманием, что стайлгайд этого не предусматривает.
+- **Не инициализировать git заново** автоматически. `tiged` намеренно не создаёт `.git/` — решение о репозитории принимает разработчик.
diff --git a/ai/nextjs-style-guide/creating-project/manual.md b/ai/nextjs-style-guide/creating-project/manual.md
new file mode 100644
index 0000000..fb89536
--- /dev/null
+++ b/ai/nextjs-style-guide/creating-project/manual.md
@@ -0,0 +1,90 @@
+---
+title: Создание проекта вручную
+description: Поэтапное создание нового проекта без использования шаблона.
+keywords: [создать проект, новый проект, с нуля, init, initialize, scaffold, create-next-app, начать проект, поднять проект, эталонный проект, ручная установка]
+---
+
+# Создание проекта вручную
+
+Поэтапное создание нового проекта без использования шаблона.
+
+## Состав эталонного проекта
+
+| Компонент | Роль | Раздел |
+|-----------|------|--------|
+| Next.js | Фреймворк (роутинг, сборка, SSR) | [Next.js](./nextjs.md) |
+| Алиасы | Импорты по слоям SLM | [Алиасы](../applied/aliases.md) |
+| Biome | Линтер и форматтер (замена ESLint + Prettier) | [Biome](../applied/biome.md) |
+| Стили | Глобальные токены и breakpoints | [Стили](../applied/styles/styles-setup.md) |
+| PostCSS | CSS-процессор для custom-media и вложенности | [PostCSS](../applied/postcss.md) |
+| SVG-спрайты | Иконки через ``, управление цветом | [SVG-спрайты](../applied/svg-sprites/svg-sprites-setup.md) |
+| VS Code | Настройки редактора и расширения | [VS Code](../applied/vscode.md) |
+| Шаблоны генерации | `.templates/` для `@gromlab/create` | [Шаблоны генерации](../applied/templates/templates-setup.md) |
+
+Убрать компонент из состава — значит согласованно отказаться от части стайлгайда. Частичные проекты возможны (только Next.js, Next.js + стили и т.п.), но не являются эталоном.
+
+## Канон раскладки
+
+В `src/` допустимы только слои SLM: `app/`, `layouts/`, `screens/`, `widgets/`, `business/`, `infrastructure/`, `ui/`, `shared/`. Любая другая папка в `src/` — нарушение канона ([Структура проекта](../applied/project-structure.md), [Архитектура](../basics/architecture/index.md)).
+
+В частности: `src/app/` содержит только файлы роутинга Next.js и инициализации, без каталогов `styles/`, `assets/`, `components/`.
+
+## Порядок установки
+
+Подсистемы ставятся в фиксированном порядке — он отражает зависимости между шагами.
+
+### 1. Next.js
+
+Скелет фреймворка — обязательный первый шаг, остальное опирается на него.
+
+См. [Next.js](./nextjs.md). После выполнения проверки этого раздела `npm run build` должен проходить.
+
+### 2. Алиасы
+
+Заменить дефолтный `"@/*"` в `tsconfig.json` на канонический список из восьми слой-префиксов.
+
+См. [Алиасы](../applied/aliases.md).
+
+### 3. Biome
+
+Линтер и форматтер. Подключается **до** написания кода, иначе в проекте копятся несогласованные правки.
+
+См. [Biome](../applied/biome.md).
+
+### 4. Стили (базовая инфраструктура)
+
+Файлы `variables.css`, `media.css`, `global.css` в `src/shared/styles/` и подключение `global.css` в `src/app/layout.tsx`. CSS-процессор на этом шаге не ставится.
+
+См. [Стили](../applied/styles/styles-setup.md).
+
+### 5. PostCSS
+
+CSS-процессор поверх базовых стилей: `@custom-media`, вложенность, autoprefixer. Ставится **только после шага 4** — опирается на `src/shared/styles/media.css`.
+
+См. [PostCSS](../applied/postcss.md).
+
+### 6. SVG-спрайты
+
+Пакет `@gromlab/svg-sprites`, генерация спрайт-файла и React-компонента ``.
+
+См. [SVG-спрайты](../applied/svg-sprites/svg-sprites-setup.md).
+
+### 7. VS Code
+
+Расширения и настройки редактора. Опирается на установленный Biome (форматирование при сохранении) и PostCSS (ассоциация `*.css`).
+
+См. [VS Code](../applied/vscode.md).
+
+### 8. Шаблоны генерации
+
+Папка `.templates/` для генератора модулей `@gromlab/create`.
+
+См. [Шаблоны генерации](../applied/templates/templates-setup.md).
+
+## Правила
+
+- **Порядок шагов фиксирован.** Перестановка ломает зависимости (PostCSS требует базовых стилей, VS Code — установленного Biome).
+- **Между шагами обязательна проверка** из соответствующего раздела. Не переходить дальше, пока чеклист текущего шага не пройден.
+- **Слои `src/`** (`layouts/`, `screens/`, `widgets/`, `business/`, `infrastructure/`, `ui/`) не создавать авансом. Появляются по мере первого модуля. Исключения — `src/app/` (создаётся `create-next-app`), `src/shared/styles/` (шаг 1) и `src/shared/sprites/icons/` (шаг 6).
+- **Посторонние каталоги в `src/`** (`assets/`, `utils/`, `lib/`, `components/` и т.п.) — запрещены.
+- **Подмножество шагов допустимо.** Можно ставить только Next.js и часть инструментов; полный набор — это эталон, а не обязательство.
diff --git a/ai/nextjs-style-guide/creating-project/nextjs.md b/ai/nextjs-style-guide/creating-project/nextjs.md
new file mode 100644
index 0000000..dc3b9d7
--- /dev/null
+++ b/ai/nextjs-style-guide/creating-project/nextjs.md
@@ -0,0 +1,112 @@
+---
+title: Чистая установка Next.js
+description: "Установка Next.js без лишнего шаблона — голый каркас под дальнейшую сборку."
+keywords: [next.js, create-next-app, npx, установка, инициализация, фреймворк, скаффолдинг, app router, typescript]
+---
+
+# Чистая установка Next.js
+
+Установка Next.js без лишнего шаблона — голый каркас под дальнейшую сборку.
+
+## Требования
+
+- Node.js 18.18+ (рекомендуется LTS 20+).
+- npm 10+.
+- Рабочая папка пуста, либо для установки выбрана подпапка (`create-next-app@16+` отказывается ставиться в непустую директорию).
+
+## Установка
+
+### 1. Инициализация через `create-next-app`
+
+Флаги зафиксированы и не согласовываются — это канон стайлгайда:
+
+```bash
+npx create-next-app@latest my-app \
+ --typescript \
+ --app \
+ --src-dir \
+ --import-alias "@/*" \
+ --no-eslint \
+ --no-tailwind \
+ --use-npm
+```
+
+| Флаг | Значение | Почему так |
+|------|----------|------------|
+| `--typescript` | TS включён | Стайлгайд требует TypeScript ([Типизация](../basics/typing.md)) |
+| `--app` | App Router | Pages Router не используется |
+| `--src-dir` | Код в `src/` | Архитектура SLM требует `src/` ([Структура проекта](../applied/project-structure.md)) |
+| `--import-alias "@/*"` | Placeholder | Требуется флагом; после установки `paths` полностью переписывается на слой-префиксы (см. [Алиасы](../applied/aliases.md)) |
+| `--no-eslint` | ESLint не ставится | Линтер и форматтер — Biome ([Biome](../applied/biome.md)) |
+| `--no-tailwind` | Tailwind не ставится | Стилизация — PostCSS Modules ([Стили](../applied/styles/styles-usage.md)) |
+| `--use-npm` | Пакетный менеджер — npm | Единый инструмент в проектах |
+
+### 2. Очистить дефолтный шаблон
+
+`create-next-app` генерирует демо-страницу со стилями и ассетами, а Next.js 16+ дополнительно кладёт в корень собственные `AGENTS.md` и `CLAUDE.md` — всё это удаляется.
+
+```bash
+rm src/app/page.module.css
+rm src/app/globals.css
+rm public/next.svg public/vercel.svg public/file.svg public/globe.svg public/window.svg
+rm -f AGENTS.md CLAUDE.md
+```
+
+Заменить `src/app/page.tsx` на минимальный:
+
+```tsx
+// src/app/page.tsx
+export default function HomePage() {
+ return
Home
+}
+```
+
+Очистить `src/app/layout.tsx` от импорта шрифтов и `globals.css`:
+
+```tsx
+// src/app/layout.tsx
+import type { Metadata } from 'next'
+
+export const metadata: Metadata = {
+ title: 'App',
+ description: '',
+}
+
+export default function RootLayout({ children }: { children: React.ReactNode }) {
+ return (
+
+ {children}
+
+ )
+}
+```
+
+### 3. Создать папку `src/shared/styles/`
+
+Глобальные стили в SLM-архитектуре живут в слое `shared`, а не в `src/app/` ([Структура проекта](../applied/project-structure.md)).
+
+```bash
+mkdir -p src/shared/styles
+```
+
+Остальные слои (`layouts/`, `screens/`, `widgets/`, `business/`, `infrastructure/`, `ui/`) заводятся при появлении первого модуля в них. `src/shared/styles/` — единственный подкаталог `shared/`, который заводится сразу: без него не настроить стили на следующих шагах.
+
+## Правила
+
+- **Конфликт с непустой директорией** — не удалять файлы пользователя автоматически. Ставить в подпапку или временно перенести посторонние файлы.
+- **Отклонение от канонических флагов** (pnpm, Tailwind, ESLint и т.п.) — только осознанное, с пониманием, что стайлгайд этого не предусматривает.
+- **Слои `src/`** не создавать авансом — появляются при первом модуле. Алиасы прописываются сразу на все восемь слоёв (см. [Алиасы](../applied/aliases.md)).
+- **`AGENTS.md` от Next.js** удаляется в шаге 2. Повторно не создаётся.
+- **Biome, стили, PostCSS, SVG-спрайты, VS Code** — отдельные шаги установки, не в этом разделе.
+
+## Проверка установки
+
+- В корне проекта: `next.config.ts`, `tsconfig.json`, `package.json`.
+- В `package.json`: Next.js установлен, нет `eslint`, `tailwindcss`.
+- В `src/app/` присутствуют минимальные `page.tsx` и `layout.tsx`. `globals.css`, `page.module.css` отсутствуют. Каталогов `styles/`, `assets/`, `providers/`, `components/` в `src/app/` нет.
+- Папка `src/shared/styles/` создана (пустая).
+- В `src/` из слоёв SLM присутствуют только `app/` и `shared/` (с `styles/`). Посторонних каталогов нет.
+- В `public/` удалены `next.svg`, `vercel.svg`, `file.svg`, `globe.svg`, `window.svg`.
+- В корне проекта нет `AGENTS.md` и `CLAUDE.md` от Next.js.
+- `npm run build` завершается успешно.
+- Пакетный менеджер — npm (нет `pnpm-lock.yaml`, `yarn.lock`, `bun.lockb`).
diff --git a/ai/nextjs-style-guide/data/index.md b/ai/nextjs-style-guide/data/index.md
new file mode 100644
index 0000000..906a5be
--- /dev/null
+++ b/ai/nextjs-style-guide/data/index.md
@@ -0,0 +1,60 @@
+---
+title: Источники данных
+description: Какие источники данных используются в проекте и как с ними работать.
+keywords: [данные, api, rest, realtime, клиент, swr, infrastructure, введение, карта раздела]
+---
+
+# Источники данных
+
+Какие источники данных используются в проекте и как с ними работать.
+
+## Принципы раздела
+
+- **Клиент — в `infrastructure/`.** Каждый внешний сервис — отдельный модуль слоя `infrastructure/{service-name}/`.
+- **Прямой `fetch` запрещён.** Запросы идут только через клиент модуля. Исключения — точечные и обоснованные.
+- **Источник данных диктует канал.** REST, realtime и т.п. — независимые подразделы, у каждого своя модель клиента и своё потребление.
+- **Серверные и клиентские компоненты потребляют по-разному.** Server Components — прямой `await` метода клиента, клиентские — через готовые GET-хуки REST-клиента (`useGetUserList`, `useGetPostDetail` и т.п.). SWR инкапсулирован в хуке, компонент про него не знает.
+
+## Карта раздела
+
+### REST
+
+Канал «запрос-ответ» по HTTP. Покрывает большинство API.
+
+- [REST](./rest/index.md) — обзор раздела: создание клиента и использование.
+- **Создание клиента** — как оформляется REST API в проекте:
+ - [Обзор](./rest/clients/index.md) — когда нужен клиент и как выбрать подход.
+ - [Автогенерация из OpenAPI](./rest/clients/auto.md) — для API с OpenAPI-спецификацией, через `@gromlab/api-codegen`.
+ - [Ручное создание](./rest/clients/manual.md) — для API без схемы, клиент пишется и поддерживается руками.
+ - [GET-хуки REST-клиента](./rest/clients/hooks.md) — прозрачные SWR-обёртки над GET-методами клиента.
+- **Использование** — как получать данные через готовый клиент:
+ - [Стратегии получения данных](./rest/strategies/index.md) — как выбрать способ получения данных под ситуацию.
+ - [Серверный await](./rest/strategies/server-await.md) — прямой `await` метода клиента в Server Components.
+ - [Параллельные серверные запросы](./rest/strategies/parallel-server-requests.md) — запуск независимых серверных запросов без waterfall.
+ - [Передача промиса ниже](./rest/strategies/pass-promise-down.md) — серверный стриминг через промис и `Suspense`.
+ - [Начальные данные для клиентских хуков](./rest/strategies/client-hooks-initial-data.md) — серверный промис в `SWRConfig fallback`.
+ - [Клиентский GET-хук](./rest/strategies/client-get-hook.md) — получение данных в Client Components через готовый GET-хук.
+ - [Business-композиция](./rest/strategies/business-composition.md) — доменная интерпретация и композиция REST-данных.
+
+### Realtime
+
+Канал push-данных: WebSocket, SSE, событийные шины. Транспорт не зашит в правила — важна абстракция «подписка».
+
+- [Realtime](./realtime.md) — клиент realtime в `infrastructure/`, потребление через `useSWRSubscription` или прямые подписки.
+
+## Что даёт раздел
+
+После прочтения раздела понятно:
+
+- Где живёт код работы с API и почему именно там.
+- Когда генерировать клиент автоматически, а когда писать вручную, и как структурирован каждый из вариантов.
+- Какие GET-хуки относятся к REST-клиенту и почему они живут в `infrastructure/{service-name}/hooks/`.
+- Как выбрать стратегию получения REST-данных под конкретную ситуацию.
+- Как подключать realtime-источники в общую модель работы с данными.
+- Какие правила обязательны и какие отклонения допустимы.
+
+## Что не входит в раздел
+
+- **Глобальное состояние UI** — Stores, формы, фичефлаги. Это [Stores](../applied/stores.md).
+- **Доменная логика** — как данные превращаются в сценарии бизнеса. Это слой `business/` в [Архитектуре](../basics/architecture/index.md).
+- **Хуки общего назначения** — переиспользуемые хуки UI, не привязанные к конкретному API. Отдельный прикладной раздел для них пока не ведётся.
diff --git a/ai/nextjs-style-guide/data/realtime.md b/ai/nextjs-style-guide/data/realtime.md
new file mode 100644
index 0000000..7463cfe
--- /dev/null
+++ b/ai/nextjs-style-guide/data/realtime.md
@@ -0,0 +1,79 @@
+---
+title: Realtime
+description: "Работа с push-данными от сервера: подписки и события."
+keywords: [realtime, websocket, sse, подписка, swr subscription, useSWRSubscription, push, события]
+---
+
+# Realtime
+
+Работа с push-данными от сервера: подписки и события.
+
+## Принципы
+
+- **Клиент realtime — в `infrastructure/`** отдельным модулем по имени канала. То же правило, что и для REST: никаких прямых соединений в коде приложения.
+- **Подписка — единица потребления.** Клиент даёт функцию `subscribe(topic, handler) → unsubscribe`. Внутри — конкретный транспорт.
+- **Использование на клиенте — два сценария:**
+ - **`useSWRSubscription`** — для данных, которые показываются в UI и должны кешироваться/синхронизироваться с REST.
+ - **Прямая подписка** — для побочных эффектов (тосты, нотификации, аналитика), не привязанных к рендеру.
+
+## Размещение клиента
+
+```text
+src/infrastructure/
+└── {channel-name}/
+ ├── connection.ts # установление соединения, реконнект
+ ├── subscribe.ts # subscribe(topic, handler) → unsubscribe
+ ├── types.ts
+ └── index.ts
+```
+
+## Использование через SWR
+
+```tsx
+'use client'
+
+import useSWRSubscription from 'swr/subscription'
+import { subscribe } from 'infrastructure/notifications'
+
+export function NotificationCounter() {
+ const { data: count } = useSWRSubscription(
+ ['notifications', 'count'],
+ (key, { next }) =>
+ subscribe('notifications.count', (value: number) => next(null, value)),
+ )
+
+ return {count ?? 0}
+}
+```
+
+Плюсы: кеш и дедупликация подписки между несколькими местами рендера; единая модель данных с REST.
+
+## Прямая подписка
+
+Для побочных эффектов, которые не влияют на состояние UI напрямую:
+
+```tsx
+'use client'
+
+import { useEffect } from 'react'
+import { subscribe } from 'infrastructure/notifications'
+import { showToast } from 'ui/toast'
+
+export function NotificationsToaster() {
+ useEffect(() => {
+ return subscribe('notifications.new', (notification) => {
+ showToast(notification.message)
+ })
+ }, [])
+
+ return null
+}
+```
+
+Возврат `unsubscribe` из `useEffect` обязателен — иначе утечка подписки.
+
+## Запрет прямых соединений
+
+Создавать `new WebSocket(...)`, `new EventSource(...)` или подписываться на событийные шины напрямую в коде приложения — запрещено. Все соединения проходят через клиент в `infrastructure/`.
+
+Исключения — точечные и обоснованные (например, диагностический скрипт), помечаются комментарием.
diff --git a/ai/nextjs-style-guide/data/rest/clients/auto.md b/ai/nextjs-style-guide/data/rest/clients/auto.md
new file mode 100644
index 0000000..2d4b06a
--- /dev/null
+++ b/ai/nextjs-style-guide/data/rest/clients/auto.md
@@ -0,0 +1,193 @@
+---
+title: Автогенерация из OpenAPI
+description: Генерация REST-клиента из OpenAPI-спецификации через @gromlab/api-codegen.
+keywords: [rest, openapi, api-codegen, автогенерация, generated, npx]
+---
+
+# Автогенерация из OpenAPI
+
+Автогенерация используется, когда у API есть актуальная OpenAPI-спецификация. Генератор создаёт TypeScript-клиент, типы и методы API, а разработчик вручную добавляет настройку клиента и GET-хуки.
+
+## Пример API
+
+В примерах используется Swagger Petstore:
+
+```text
+https://petstore3.swagger.io/api/v3/openapi.json
+```
+
+Имена модуля:
+
+```text
+src/infrastructure/pet-store-api/
+petStoreApi
+pet-store-api.generated.ts
+```
+
+## Скрипт генерации
+
+`@gromlab/api-codegen` не устанавливается в `devDependencies`. Используем `npx @gromlab/api-codegen@latest`, чтобы запускать свежую версию.
+
+```json
+{
+ "scripts": {
+ "codegen:pet-store-api": "npx @gromlab/api-codegen@latest -i https://petstore3.swagger.io/api/v3/openapi.json -o src/infrastructure/pet-store-api/generated -n pet-store-api.generated"
+ }
+}
+```
+
+Параметры:
+
+- `-i` — путь к OpenAPI-спецификации: URL или локальный файл.
+- `-o` — директория для сгенерированного файла.
+- `-n` — имя сгенерированного файла без `.ts`.
+
+Ключ `--swr` не используется. GET-хуки REST-клиента пишутся вручную, чтобы сохранить проектный контракт: один GET-хук = один GET-метод, без бизнес-логики и композиции.
+
+## Генерация
+
+```bash
+npm run codegen:pet-store-api
+```
+
+Ожидаемый результат:
+
+```text
+src/infrastructure/pet-store-api/generated/
+└── pet-store-api.generated.ts
+```
+
+Сгенерированный файл не правится руками и коммитится в репозиторий.
+
+## Проверка методов
+
+После генерации откройте `generated/pet-store-api.generated.ts` и проверьте фактические имена методов.
+
+Для Petstore нужны GET-операции вида:
+
+```ts
+petStoreApi.pet.findPetsByStatus(...)
+petStoreApi.pet.getPetById(...)
+```
+
+Точные сигнатуры зависят от OpenAPI-схемы и версии генератора. В рабочих задачах всегда сверяйтесь с generated-файлом.
+
+## `client.ts`
+
+Сгенерированный код не должен напрямую использоваться из приложения. Сначала создаётся настроенный инстанс клиента.
+
+```ts
+// src/infrastructure/pet-store-api/client.ts
+import { Api, HttpClient } from './generated/pet-store-api.generated'
+
+const httpClient = new HttpClient({
+ baseUrl: 'https://petstore3.swagger.io/api/v3',
+ baseApiParams: {
+ secure: false,
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ },
+})
+
+export const petStoreApi = new Api(httpClient)
+```
+
+В реальном проекте вместо строки `baseUrl` обычно берётся из env-переменной, нормализуется в `client.ts` и передаётся в `HttpClient` через конфиг.
+
+`client.ts` не содержит расширения типов, `declare module` и `Extended`-типы. Он только настраивает транспорт и экспортирует инстанс клиента.
+
+## Расширение сгенерированных типов
+
+Сгенерированный файл не правится руками. Если OpenAPI-спецификация неполная или генератор дал слишком общий тип (`object`, `unknown`, отсутствующее поле), расширения живут в `types/`.
+
+```text
+src/infrastructure/biocad-less-api/
+├── generated/
+│ └── biocad-less-api.generated.ts
+├── types/
+│ ├── term.ts
+│ └── index.ts
+├── client.ts
+└── index.ts
+```
+
+Пример расширения generated-типа:
+
+```ts
+// src/infrastructure/biocad-less-api/types/term.ts
+import type { TermRecordItem } from '../generated/biocad-less-api.generated'
+
+declare module '../generated/biocad-less-api.generated' {
+ interface TermRecordItem {
+ media?: {
+ file?: string
+ title?: string
+ url?: string
+ }
+ }
+}
+
+export type TermRecordItemExtended = Omit<
+ TermRecordItem,
+ 'categories' | 'tags' | 'fields'
+> & {
+ categories?: Array<{
+ _id?: string
+ id?: string
+ slug?: string
+ name?: string
+ }>
+ tags?: Array<{
+ _id?: string
+ id?: string
+ slug?: string
+ name?: string
+ }>
+ fields?: Record
+}
+```
+
+```ts
+// src/infrastructure/biocad-less-api/types/index.ts
+export type { TermRecordItemExtended } from './term'
+```
+
+`declare module` используется для добавления отсутствующих полей в generated-интерфейс. `Extended`-тип используется, когда нужно переопределить неточные поля, не трогая generated-файл.
+
+## Публичный API
+
+```ts
+// src/infrastructure/pet-store-api/index.ts
+export { petStoreApi } from './client'
+export type { Pet } from './generated/pet-store-api.generated'
+export * from './hooks'
+```
+
+Наружу импортируют только из `infrastructure/pet-store-api`, не из `generated/`.
+
+Если у модуля есть расширенные типы, они тоже реэкспортируются через `index.ts`:
+
+```ts
+// src/infrastructure/biocad-less-api/index.ts
+export type { TermRecordItemExtended } from './types'
+```
+
+## Регенерация
+
+При изменении OpenAPI-схемы:
+
+```bash
+npm run codegen:pet-store-api
+```
+
+Что меняется:
+
+- `generated/pet-store-api.generated.ts` — перезаписывается генератором.
+- `client.ts`, `hooks/`, `types/`, `index.ts` — не трогаются автоматически.
+
+Если после регенерации поменялись сигнатуры методов или типы, это исправляется в ручном коде модуля.
+
+## Следующий шаг
+
+После генерации и настройки `client.ts` проверьте серверный вызов метода клиента или добавьте [GET-хук REST-клиента](./hooks.md) для Client Components.
diff --git a/ai/nextjs-style-guide/data/rest/clients/hooks.md b/ai/nextjs-style-guide/data/rest/clients/hooks.md
new file mode 100644
index 0000000..83dbaae
--- /dev/null
+++ b/ai/nextjs-style-guide/data/rest/clients/hooks.md
@@ -0,0 +1,206 @@
+---
+title: GET-хуки REST-клиента
+description: Прозрачные SWR-обёртки над GET-методами REST-клиента.
+keywords: [rest, swr, get-хуки, client components, infrastructure]
+---
+
+# GET-хуки REST-клиента
+
+GET-хуки REST-клиента — прозрачные SWR-обёртки над GET-методами API-клиента. Они нужны, чтобы Client Components получали данные с кешированием, дедупликацией и ревалидацией, не работая с `useSWR` напрямую.
+
+## Где лежат
+
+GET-хуки принадлежат REST-клиенту конкретного сервиса и живут рядом с ним:
+
+```text
+src/infrastructure/
+└── pet-store-api/
+ ├── client.ts
+ ├── generated/
+ ├── hooks/
+ │ ├── use-get-pet-list.hook.ts
+ │ ├── use-get-pet-detail.hook.ts
+ │ └── index.ts
+ └── index.ts
+```
+
+## Контракт
+
+- Один GET-хук = один GET-метод клиента.
+- Имя GET-хука начинается с `useGet`: `useGetPetList`, `useGetPetDetail`.
+- Имя файла начинается с `use-get`: `use-get-pet-list.hook.ts`.
+- Хук принимает только параметры GET-метода и `config?: SWRConfiguration`.
+- Что передали хуку, то он передаёт в GET-метод.
+- Внутри только SWR-механика: key, fetcher, `useSWR`, `config`.
+- Хук возвращает тип ответа API: generated-тип или DTO из `types/`.
+- Хук не объединяет несколько запросов.
+- Хук не маппит DTO в доменную модель.
+- Хук не вычисляет бизнес-флаги: `isAuth`, `canEdit`, `hasAccess`, `hasPets`.
+- Хук не вызывает тосты, модалки, редиректы и не пишет UI-состояние.
+
+## Пример списка
+
+```ts
+// src/infrastructure/pet-store-api/hooks/use-get-pet-list.hook.ts
+import useSWR from 'swr'
+import type { SWRConfiguration } from 'swr'
+import { petStoreApi } from '../client'
+import type { Pet } from '../generated/pet-store-api.generated'
+
+export type PetStatus = 'available' | 'pending' | 'sold'
+
+export const getPetListKey = (status: PetStatus) =>
+ ['pet-store-api', 'pet', 'list', status] as const
+
+/**
+ * Получение списка питомцев по статусу.
+ */
+export const useGetPetList = (status: PetStatus | null, config?: SWRConfiguration) => {
+ const isReady = status !== null
+ const key = isReady ? getPetListKey(status) : null
+ const fetcher = () => petStoreApi.pet.findPetsByStatus({ status })
+
+ return useSWR(key, fetcher, config)
+}
+```
+
+Функция `getPetListKey` нужна, чтобы один и тот же SWR-ключ использовался внутри GET-хука и при передаче начальных данных через `SWRConfig fallback`.
+
+Пример начальных данных для клиентского хука:
+
+```tsx
+import type { ReactNode } from 'react'
+import { SWRConfig, unstable_serialize } from 'swr'
+import {
+ getPetListKey,
+ petStoreApi,
+} from 'infrastructure/pet-store-api'
+
+export default function PetsLayout({ children }: { children: ReactNode }) {
+ const petsPromise = petStoreApi.pet.findPetsByStatus({ status: 'available' })
+
+ return (
+
+ {children}
+
+ )
+}
+```
+
+Клиентский компонент при этом ничего не знает про preload/fallback и продолжает вызывать обычный хук:
+
+```tsx
+const { data: pets } = useGetPetList('available')
+```
+
+## Пример detail-запроса
+
+```ts
+// src/infrastructure/pet-store-api/hooks/use-get-pet-detail.hook.ts
+import useSWR from 'swr'
+import type { SWRConfiguration } from 'swr'
+import { petStoreApi } from '../client'
+import type { Pet } from '../generated/pet-store-api.generated'
+
+export const getPetDetailKey = (id: number) =>
+ ['pet-store-api', 'pet', 'detail', id] as const
+
+/**
+ * Получение питомца по идентификатору.
+ */
+export const useGetPetDetail = (id: number | null, config?: SWRConfiguration) => {
+ const isReady = id !== null
+ const key = isReady ? getPetDetailKey(id) : null
+ const fetcher = () => petStoreApi.pet.getPetById(id)
+
+ return useSWR(key, fetcher, config)
+}
+```
+
+## Отложенный запрос через `null`
+
+GET-хук может принимать `null` для обязательного параметра. `null` означает, что параметр ещё не готов и запрос выполнять нельзя.
+
+Внутри хука это выражается через `isReady`: если параметр не готов, ключ SWR становится `null`, и SWR не вызывает fetcher.
+
+```ts
+const isReady = id !== null
+const key = isReady ? getPetDetailKey(id) : null
+```
+
+`null` не передаётся в метод клиента. Key-функция принимает только готовые параметры, поэтому её можно безопасно использовать для начальных данных через `SWRConfig fallback`.
+
+Для числовых идентификаторов не используйте проверку `if (id)`: значение `0` тоже валидное число. Проверяйте явно: `id !== null`.
+
+## Экспорт
+
+```ts
+// src/infrastructure/pet-store-api/hooks/index.ts
+export { getPetListKey, useGetPetList } from './use-get-pet-list.hook'
+export type { PetStatus } from './use-get-pet-list.hook'
+export { getPetDetailKey, useGetPetDetail } from './use-get-pet-detail.hook'
+```
+
+```ts
+// src/infrastructure/pet-store-api/index.ts
+export { petStoreApi } from './client'
+export type { Pet } from './generated/pet-store-api.generated'
+export * from './hooks'
+```
+
+## Где заканчивается infrastructure
+
+```ts
+// Хорошо: infrastructure, прозрачный GET-хук
+const { data: pets } = useGetPetList('available')
+```
+
+```ts
+// Хорошо: business, доменная интерпретация
+export const useAvailablePets = () => {
+ const query = useGetPetList('available')
+
+ return {
+ ...query,
+ hasPets: Boolean(query.data?.length),
+ }
+}
+```
+
+`hasPets` — не часть GET-запроса, поэтому он не добавляется в `useGetPetList`.
+
+## Что запрещено
+
+```ts
+// Плохо — useSWR в компоненте
+const { data } = useSWR(
+ ['pet-store-api', 'pet', 'list', status],
+ () => petStoreApi.pet.findPetsByStatus({ status }),
+)
+
+// Плохо — несколько GET внутри infrastructure-хука
+export const usePetDashboard = () => {
+ const available = useGetPetList('available')
+ const sold = useGetPetList('sold')
+
+ return { available, sold }
+}
+
+// Плохо — бизнес-флаг внутри GET-хука REST-клиента
+export const useGetPetList = (status: PetStatus) => {
+ const query = useSWR(...)
+
+ return {
+ ...query,
+ hasPets: Boolean(query.data?.length),
+ }
+}
+```
+
+Подробное потребление таких хуков описано в стратегии [Клиентский GET-хук](../strategies/client-get-hook.md).
diff --git a/ai/nextjs-style-guide/data/rest/clients/index.md b/ai/nextjs-style-guide/data/rest/clients/index.md
new file mode 100644
index 0000000..9e2a601
--- /dev/null
+++ b/ai/nextjs-style-guide/data/rest/clients/index.md
@@ -0,0 +1,75 @@
+---
+title: Создание клиента
+description: Из чего состоит REST-клиент и какие части нужно подготовить перед использованием API.
+keywords: [rest, клиент, infrastructure, методы, openapi, get-хуки, swr]
+---
+
+# Создание клиента
+
+REST-клиент — это infrastructure-модуль, через который проект работает с внешним REST API.
+
+На этом этапе нужно подготовить клиент сервиса: создать оболочку клиента, получить методы API и добавить GET-хуки для клиентских компонентов.
+
+## Из чего состоит клиент
+
+REST-клиент состоит из трёх основных частей:
+
+1. **Клиент** — самописная оболочка над транспортом.
+2. **Методы** — сгенерированные из OpenAPI или написанные вручную вызовы API.
+3. **GET-хуки** — SWR-обёртки для GET-запросов.
+
+Эти части живут в одном REST-модуле, потому что относятся к одному внешнему сервису.
+
+## Клиент
+
+Клиент — ручной слой, который настраивает работу с API: `baseUrl`, заголовки, авторизацию, обработку ошибок и создание инстанса сервиса.
+
+Даже если методы генерируются из OpenAPI, `client.ts` остаётся ручным файлом проекта.
+
+`client.ts` — только сборочная точка клиента. В нём не размещаются DTO, `declare module`, `Extended`-типы, GET-хуки и бизнес-логика.
+
+## Методы
+
+Методы описывают конкретные запросы к API.
+
+Они появляются одним из двух способов:
+
+- генерируются из OpenAPI в `generated/`;
+- создаются вручную в `methods/`.
+
+Подробности:
+
+- [Автогенерация из OpenAPI](./auto.md)
+- [Ручное создание](./manual.md)
+
+## GET-хуки
+
+Для GET-запросов добавляются GET-хуки REST-клиента.
+
+Это прозрачные SWR-обёртки над GET-методами клиента. Они живут в `hooks/` этого же REST-модуля и нужны для использования данных в Client Components.
+
+GET-хуки именуются с префиксом `useGet`: `useGetPetList`, `useGetPetDetail`, `useGetCurrentUser`.
+
+Подробности:
+
+- [GET-хуки REST-клиента](./hooks.md)
+
+## Структура модуля
+
+```text
+src/infrastructure/{service-name}/
+├── client.ts # самописная оболочка и инстанс клиента
+├── generated/ или methods/ # методы API
+├── hooks/ # GET-хуки REST-клиента
+├── types/ # DTO, типы API и расширения типов
+├── errors/ # ошибки API, если нужны
+└── index.ts # публичный API
+```
+
+`index.ts` — единственная точка входа в REST-модуль для внешнего кода.
+
+## Что делаем дальше
+
+1. Создайте методы клиента: [Автогенерация из OpenAPI](./auto.md) или [Ручное создание](./manual.md).
+2. Добавьте GET-хуки для GET-запросов: [GET-хуки REST-клиента](./hooks.md).
+3. После создания клиента переходите к [Стратегиям получения данных](../strategies/index.md).
diff --git a/ai/nextjs-style-guide/data/rest/clients/manual.md b/ai/nextjs-style-guide/data/rest/clients/manual.md
new file mode 100644
index 0000000..f5545dc
--- /dev/null
+++ b/ai/nextjs-style-guide/data/rest/clients/manual.md
@@ -0,0 +1,187 @@
+---
+title: Ручное создание
+description: Создание REST-клиента вручную, когда OpenAPI нет или он неполный.
+keywords: [rest, ручной клиент, fetch, methods, dto, errors, infrastructure]
+---
+
+# Ручное создание
+
+Ручной REST-клиент используется, когда у API нет OpenAPI-спецификации или она недостаточно точная для автогенерации.
+
+Задача ручного клиента — дать такую же точку входа, как у автогенерированного клиента: именованный API-объект, методы по сущностям, DTO и GET-хуки рядом с клиентом.
+
+## Что нужно создать
+
+```text
+src/infrastructure/
+└── pet-project-api/
+ ├── methods/
+ │ └── posts.ts
+ ├── hooks/
+ │ └── index.ts
+ ├── types/
+ │ ├── client.ts
+ │ ├── post.ts
+ │ └── index.ts
+ ├── errors/
+ │ └── pet-project-api.error.ts
+ ├── client.ts
+ └── index.ts
+```
+
+| Файл | Роль |
+|------|------|
+| `client.ts` | Базовый транспорт и создание инстанса клиента |
+| `methods/` | Методы API по сущностям |
+| `types/` | DTO запросов, ответов и типы клиента |
+| `errors/` | Ошибки конкретного API |
+| `hooks/` | GET-хуки REST-клиента, если данные нужны в Client Components |
+| `index.ts` | Публичный API REST-модуля |
+
+## DTO и типы API
+
+DTO запросов и ответов живут в `types/`. `client.ts` не содержит DTO и доменные типы.
+
+```ts
+// src/infrastructure/pet-project-api/types/post.ts
+export type PostDto = {
+ id: string
+ slug: string
+ title: string
+}
+
+export type PostListQueryDto = {
+ limit?: number
+ category?: string
+}
+```
+
+```ts
+// src/infrastructure/pet-project-api/types/index.ts
+export type { PostDto, PostListQueryDto } from './post'
+```
+
+Типы, которые нужны только базовому транспорту, можно держать отдельно:
+
+```ts
+// src/infrastructure/pet-project-api/types/client.ts
+export type QueryParams = Record
+```
+
+## Ошибка API
+
+Ошибка API тоже относится к REST-модулю.
+
+```ts
+// src/infrastructure/pet-project-api/errors/pet-project-api.error.ts
+export class PetProjectApiError extends Error {
+ constructor(
+ public readonly status: number,
+ message: string,
+ ) {
+ super(message)
+ this.name = 'PetProjectApiError'
+ }
+}
+```
+
+## Базовый клиент
+
+`client.ts` содержит только транспортную оболочку и сборку инстанса. Прямой `fetch` живёт здесь, а не в компонентах и не в методах верхних слоёв.
+
+```ts
+// src/infrastructure/pet-project-api/client.ts
+import { PetProjectApiError } from './errors/pet-project-api.error'
+import type { QueryParams } from './types/client'
+
+export class PetProjectApiClient {
+ constructor(
+ private readonly baseUrl: string,
+ private readonly defaultHeaders: Record = {},
+ ) {}
+
+ async get(path: string, params: QueryParams = {}): Promise {
+ const base = `${this.baseUrl.replace(/\/+$/, '')}/`
+ const url = new URL(path.replace(/^\/+/, ''), base)
+
+ Object.entries(params).forEach(([key, value]) => {
+ url.searchParams.set(key, String(value))
+ })
+
+ const response = await fetch(url, {
+ headers: {
+ Accept: 'application/json',
+ ...this.defaultHeaders,
+ },
+ })
+
+ if (!response.ok) {
+ throw new PetProjectApiError(response.status, response.statusText)
+ }
+
+ return response.json() as Promise
+ }
+}
+```
+
+Это минимальный шаблон. Авторизация, дополнительные заголовки, `next.revalidate`, `post`, `formdata` и другие детали добавляются только когда они реально нужны API.
+
+## Методы API
+
+Методы группируются по сущностям в `methods/`. Они не знают про React, SWR и UI.
+
+```ts
+// src/infrastructure/pet-project-api/methods/posts.ts
+import type { PetProjectApiClient } from '../client'
+import type { PostDto, PostListQueryDto } from '../types/post'
+
+export function postsMethods(client: PetProjectApiClient) {
+ return {
+ /** GET /posts */
+ list: (query: PostListQueryDto = {}) =>
+ client.get('posts', query),
+
+ /** GET /posts/{slug} */
+ get: (slug: string) =>
+ client.get(`posts/${slug}`),
+ }
+}
+```
+
+Метод возвращает DTO в форме API. Если данным нужен доменный смысл, маппинг делается выше, в `business/`.
+
+## Публичный API
+
+`index.ts` собирает именованный API-объект и открывает наружу только публичные части модуля.
+
+```ts
+// src/infrastructure/pet-project-api/index.ts
+import { PetProjectApiClient } from './client'
+import { postsMethods } from './methods/posts'
+
+const client = new PetProjectApiClient(
+ process.env.NEXT_PUBLIC_API_URL ?? '',
+ { 'Content-Type': 'application/json' },
+)
+
+export const petProjectApi = {
+ posts: postsMethods(client),
+}
+
+export { PetProjectApiError } from './errors/pet-project-api.error'
+export type { PostDto, PostListQueryDto } from './types'
+export * from './hooks'
+```
+
+Внешний код импортирует только из `infrastructure/pet-project-api`, не из внутренних файлов модуля.
+
+## Правила
+
+- `fetch` используется только внутри базового клиента.
+- DTO запросов и ответов живут в `types/`.
+- `client.ts` не содержит DTO, GET-хуки и бизнес-логику.
+- Методы лежат в `methods/` и возвращают DTO.
+- GET-хуки добавляются отдельно в `hooks/`, если данные нужны в Client Components.
+- Доменные типы и маппинг DTO живут не в REST-клиенте, а в `business/`.
+
+Следующий шаг: [GET-хуки REST-клиента](./hooks.md) или [Стратегии получения данных](../strategies/index.md).
diff --git a/ai/nextjs-style-guide/data/rest/index.md b/ai/nextjs-style-guide/data/rest/index.md
new file mode 100644
index 0000000..db7df17
--- /dev/null
+++ b/ai/nextjs-style-guide/data/rest/index.md
@@ -0,0 +1,74 @@
+---
+title: REST
+description: Как правильно работать с REST API в проекте.
+keywords: [rest, api, данные, infrastructure, клиент, swr, стратегии]
+---
+
+# REST
+
+Раздел описывает, как правильно работать с REST API в проекте: создать клиент сервиса и выбрать способ получения данных в приложении.
+
+REST в проекте проходит через два главных этапа:
+
+1. Создание клиента.
+2. Использование.
+
+## 1. Создание клиента
+
+На этом этапе внешний API оформляется как модуль слоя `infrastructure/`.
+
+Клиент отвечает за:
+
+- генерацию или ручное описание методов API;
+- настройку `baseUrl`;
+- заголовки и авторизацию;
+- обработку ошибок;
+- кастомизацию и расширение типов;
+- GET-хуки для клиентских компонентов;
+- публичный API модуля.
+
+Если у API есть OpenAPI-спецификация — клиент генерируется автоматически. Если OpenAPI нет или он неполный — клиент создаётся вручную.
+
+GET-хуки относятся к клиенту, потому что это прозрачные SWR-обёртки над GET-методами этого клиента.
+
+Подробнее:
+
+- [Создание клиента](./clients/index.md)
+- [Автогенерация из OpenAPI](./clients/auto.md)
+- [Ручное создание](./clients/manual.md)
+- [GET-хуки REST-клиента](./clients/hooks.md)
+
+## 2. Использование
+
+После создания клиента нужно определить рендер страницы и выбрать, как получать данные в конкретном месте приложения.
+
+Раздел использования отвечает на вопросы:
+
+- как понять, можно ли сохранить static/ISR;
+- когда страница становится dynamic/SSR;
+- когда получать данные через серверный `await`;
+- когда запускать несколько серверных запросов параллельно;
+- когда передавать промис ниже по дереву;
+- когда передавать начальные данные клиентским GET-хукам;
+- когда использовать GET-хук в клиентском компоненте;
+- когда выносить композицию и бизнес-смысл в `business/`.
+
+Подробнее:
+
+- [Стратегии получения данных](./strategies/index.md)
+- [Серверный await](./strategies/server-await.md)
+- [Параллельные серверные запросы](./strategies/parallel-server-requests.md)
+- [Передача промиса ниже](./strategies/pass-promise-down.md)
+- [Начальные данные для клиентских хуков](./strategies/client-hooks-initial-data.md)
+- [Клиентский GET-хук](./strategies/client-get-hook.md)
+- [Business-композиция](./strategies/business-composition.md)
+
+## Как читать раздел
+
+Если API ещё не подключён — начните с [Создания клиента](./clients/index.md).
+
+Если клиент уже есть, но непонятно как получить данные — начните со [Стратегий получения данных](./strategies/index.md).
+
+Если данные нужны в Client Component — сначала проверьте, есть ли [GET-хук REST-клиента](./clients/hooks.md).
+
+Если в коде появляется бизнес-смысл вроде `isAuth`, `canEdit`, `hasAccess` — это уже не REST-клиент, а `business/`.
diff --git a/ai/nextjs-style-guide/data/rest/strategies/business-composition.md b/ai/nextjs-style-guide/data/rest/strategies/business-composition.md
new file mode 100644
index 0000000..5234443
--- /dev/null
+++ b/ai/nextjs-style-guide/data/rest/strategies/business-composition.md
@@ -0,0 +1,121 @@
+---
+title: Business-композиция
+description: Когда REST-данные нужно объединить или интерпретировать в бизнес-модуле.
+keywords: [rest, business, композиция, hooks, domain, isAuth]
+---
+
+# Business-композиция
+
+Business-композиция используется, когда простого GET-метода или прозрачного GET-хука недостаточно: нужно объединить несколько источников, преобразовать DTO или вычислить доменное состояние.
+
+## Когда использовать
+
+- Нужно объединить несколько GET-запросов.
+- Нужно вычислить `isAuth`, `canEdit`, `hasAccess`, `hasPets`.
+- Нужно преобразовать DTO в доменную модель.
+- Нужно спрятать бизнес-сценарий за доменным API.
+
+Такая логика не пишется в `infrastructure/`. REST-клиент остаётся прозрачным адаптером к API.
+
+## Пример поверх одного GET-хука
+
+```ts
+// src/business/pets/hooks/use-available-pets.hook.ts
+import { useGetPetList } from 'infrastructure/pet-store-api'
+
+/**
+ * Доменный список доступных питомцев.
+ */
+export const useAvailablePets = () => {
+ const query = useGetPetList('available')
+
+ return {
+ ...query,
+ hasPets: Boolean(query.data?.length),
+ }
+}
+```
+
+`useGetPetList` — infrastructure-хук. `hasPets` — бизнес-интерпретация, поэтому она появляется в `business/pets`.
+
+## Пример композиции нескольких GET-хуков
+
+```ts
+// src/business/pets/hooks/use-pets-dashboard.hook.ts
+import { useGetPetList } from 'infrastructure/pet-store-api'
+
+/**
+ * Данные dashboard по питомцам.
+ */
+export const usePetsDashboard = () => {
+ const availablePets = useGetPetList('available')
+ const pendingPets = useGetPetList('pending')
+ const soldPets = useGetPetList('sold')
+
+ return {
+ availablePets,
+ pendingPets,
+ soldPets,
+ total:
+ (availablePets.data?.length ?? 0) +
+ (pendingPets.data?.length ?? 0) +
+ (soldPets.data?.length ?? 0),
+ }
+}
+```
+
+Композиция нескольких запросов не добавляется в `infrastructure/pet-store-api/hooks/`, потому что это уже сценарий потребления данных.
+
+## Пример auth-состояния
+
+```ts
+// src/business/auth/hooks/use-auth-state.hook.ts
+import { useGetCurrentUser } from 'infrastructure/backend-api'
+
+/**
+ * Состояние авторизации текущего пользователя.
+ */
+export const useAuthState = () => {
+ const currentUser = useGetCurrentUser()
+ const user = currentUser.data
+
+ return {
+ ...currentUser,
+ user,
+ isAuth: Boolean(user),
+ }
+}
+```
+
+`isAuth` не является частью REST-клиента. Это доменный смысл результата запроса.
+
+## Где размещать
+
+```text
+src/business/
+└── pets/
+ ├── hooks/
+ │ └── use-available-pets.hook.ts
+ ├── mappers/
+ │ └── map-pet-dto-to-pet.ts
+ ├── types/
+ └── index.ts
+```
+
+Модуль `business/` экспортирует наружу готовый доменный API через `index.ts`.
+
+## Что запрещено
+
+```ts
+// Плохо — business-смысл внутри infrastructure-хука
+export const useGetPetList = (status: PetStatus) => {
+ const query = useSWR(...)
+
+ return {
+ ...query,
+ hasPets: Boolean(query.data?.length),
+ }
+}
+```
+
+REST-модуль отвечает за доступ к API. Business-модуль отвечает за смысл этих данных в продукте.
diff --git a/ai/nextjs-style-guide/data/rest/strategies/client-get-hook.md b/ai/nextjs-style-guide/data/rest/strategies/client-get-hook.md
new file mode 100644
index 0000000..be3265c
--- /dev/null
+++ b/ai/nextjs-style-guide/data/rest/strategies/client-get-hook.md
@@ -0,0 +1,89 @@
+---
+title: Клиентский GET-хук
+description: Получение REST-данных в Client Components через готовые GET-хуки REST-клиента.
+keywords: [rest, client components, swr, get-хук, client state]
+---
+
+# Клиентский GET-хук
+
+Клиентский GET-хук используется, когда данные зависят от состояния браузера: вкладки, фильтра, поиска, пагинации, модалки или действия пользователя.
+
+## Когда использовать
+
+- Запрос зависит от client state.
+- Данные не обязательны для первого HTML.
+- Пользователь меняет параметры запроса на клиенте.
+- Нужны SWR-кеширование, дедупликация и ревалидация.
+
+## Пример с вкладками
+
+```tsx
+'use client'
+
+import { useState } from 'react'
+import { useGetPetList } from 'infrastructure/pet-store-api'
+import type { PetStatus } from 'infrastructure/pet-store-api'
+
+const statuses: PetStatus[] = ['available', 'pending', 'sold']
+
+export function PetTabs() {
+ const [status, setStatus] = useState('available')
+ const { data: pets, isLoading, error } = useGetPetList(status)
+
+ return (
+
+
+ {statuses.map((item) => (
+
+ ))}
+
+
+ {isLoading &&
Загрузка...
}
+ {error &&
Ошибка загрузки
}
+
+
+ {pets?.map((pet) => (
+
{pet.name}
+ ))}
+
+
+ )
+}
+```
+
+Компонент выбирает параметр `status`, но не знает про SWR-ключ и fetcher. Запрос выполняет готовый GET-хук REST-клиента.
+
+## Если хука нет
+
+Хук добавляется в REST-модуль сервиса:
+
+```text
+src/infrastructure/pet-store-api/hooks/use-get-pet-list.hook.ts
+```
+
+Не создавайте локальный `useSWR` в компоненте.
+
+## Плохо
+
+```tsx
+// Плохо — прямой вызов клиента в useEffect
+useEffect(() => {
+ petStoreApi.pet.findPetsByStatus({ status }).then(setPets)
+}, [status])
+
+// Плохо — useSWR в компоненте
+const { data } = useSWR(
+ ['pet-store-api', 'pet', 'list', status],
+ () => petStoreApi.pet.findPetsByStatus({ status }),
+)
+```
+
+Такой код теряет единое место для ключей, дублирует fetcher и разносит инфраструктурные детали по UI.
+
+## Когда выбрать другую стратегию
+
+- Данные нужны до первого HTML — [Серверный await](./server-await.md).
+- Клиентский хук должен получить начальные данные сразу — [Начальные данные для клиентских хуков](./client-hooks-initial-data.md).
+- Нужно вычислить бизнес-состояние — [Business-композиция](./business-composition.md).
diff --git a/ai/nextjs-style-guide/data/rest/strategies/client-hooks-initial-data.md b/ai/nextjs-style-guide/data/rest/strategies/client-hooks-initial-data.md
new file mode 100644
index 0000000..1f22fa5
--- /dev/null
+++ b/ai/nextjs-style-guide/data/rest/strategies/client-hooks-initial-data.md
@@ -0,0 +1,109 @@
+---
+title: Начальные данные для клиентских хуков
+description: Как дать клиентским GET-хукам начальные REST-данные.
+keywords: [rest, swr, fallback, initial data, client hooks, unstable_serialize, isr, ssr]
+---
+
+# Начальные данные для клиентских хуков
+
+Как дать клиентским GET-хукам начальные REST-данные.
+
+Эта стратегия используется, когда данные должны быть запущены на сервере, но потребляться на клиенте через GET-хуки REST-клиента.
+
+Технически это делается через `SWRConfig fallback`: сервер передаёт промис в fallback, а клиентский хук использует тот же SWR-ключ.
+
+## Когда использовать
+
+- Внутри страницы есть Client Components с GET-хуками.
+- Нужно начать загрузку данных на сервере раньше.
+- Клиентский компонент должен остаться обычным потребителем `useGetPetList(...)`.
+- Не нужно писать отдельный prop-drilling для начальных данных.
+
+## Рендер страницы
+
+Перед этой стратегией сначала определите рендер маршрута. Серверный preload для `fallback` подчиняется тем же правилам, что и любой серверный запрос в `page.tsx` или `layout.tsx`.
+
+Если данные общие и могут обновляться по интервалу, сохраняйте static/ISR. Если preload зависит от cookie, headers, `searchParams`, `no-store` или персональных данных пользователя, маршрут становится dynamic/SSR.
+
+`SWRConfig fallback` не должен быть причиной отключать ISR на всякий случай. Он только передаёт клиентскому GET-хуку данные, которые уже были запущены на сервере.
+
+## Ключ хука
+
+```ts
+// src/infrastructure/pet-store-api/hooks/use-get-pet-list.hook.ts
+export const getPetListKey = (status: PetStatus) =>
+ ['pet-store-api', 'pet', 'list', status] as const
+```
+
+Ключ экспортируется из REST-модуля, потому что он нужен и GET-хуку, и серверному `SWRConfig fallback`.
+
+## Пример layout
+
+```tsx
+// src/app/(routes)/pets/layout.tsx
+import type { ReactNode } from 'react'
+import { SWRConfig, unstable_serialize } from 'swr'
+import {
+ getPetListKey,
+ petStoreApi,
+} from 'infrastructure/pet-store-api'
+
+type PetsLayoutProps = {
+ children: ReactNode
+}
+
+export default async function PetsLayout({ children }: PetsLayoutProps) {
+ const availablePetsPromise = petStoreApi.pet.findPetsByStatus({
+ status: 'available',
+ })
+
+ return (
+
+ {children}
+
+ )
+}
+```
+
+Если GET-хук использует array-key, ключ для `fallback` сериализуется через `unstable_serialize`.
+
+## Клиентский компонент
+
+```tsx
+'use client'
+
+import { useGetPetList } from 'infrastructure/pet-store-api'
+
+export function PetList() {
+ const { data: pets, isLoading } = useGetPetList('available')
+
+ if (isLoading) return
Загрузка...
+
+ return (
+
+ {pets?.map((pet) => (
+
{pet.name}
+ ))}
+
+ )
+}
+```
+
+Компонент не знает, что данные были запущены на сервере. Он использует обычный GET-хук REST-клиента.
+
+## Что важно
+
+- Ключ `fallback` должен совпадать с ключом GET-хука.
+- Серверный код вызывает метод клиента, а не GET-хук.
+- Клиентский компонент вызывает GET-хук, а не `useSWR` напрямую.
+- Эта стратегия не означает ручную работу с кешем в компонентах.
+
+## Когда не использовать
+
+Если данные нужны только серверному компоненту, используйте [Серверный await](./server-await.md). Если данные зависят от состояния браузера, используйте [Клиентский GET-хук](./client-get-hook.md).
diff --git a/ai/nextjs-style-guide/data/rest/strategies/index.md b/ai/nextjs-style-guide/data/rest/strategies/index.md
new file mode 100644
index 0000000..a7e6d34
--- /dev/null
+++ b/ai/nextjs-style-guide/data/rest/strategies/index.md
@@ -0,0 +1,100 @@
+---
+title: Стратегии получения данных
+description: Как выбрать получение REST-данных с учётом рендера страницы.
+keywords: [rest, стратегии, render, isr, ssr, server components, swr, promise, business]
+---
+
+# Стратегии получения данных
+
+Как выбрать получение REST-данных с учётом рендера страницы.
+
+Перед выбором стратегии должен быть создан REST-клиент сервиса. Если клиента ещё нет, начните с раздела [Создание клиента](../clients/index.md).
+
+## Сначала определите рендер страницы
+
+В Next.js выбор начинается не с `await`, `Suspense` или SWR. Сначала нужно понять, какой рендер получится у маршрута: static/ISR или dynamic/SSR.
+
+Next.js может перевести страницу в dynamic rendering автоматически, если в маршруте используются API текущего запроса. Поэтому первый вопрос такой:
+
+```text
+Можно ли сохранить ISR, или странице нужны данные на каждый request?
+```
+
+ISR — приоритет. Если данные общие для пользователей и их можно обновлять с интервалом, не переводите страницу в SSR без необходимости.
+
+SSR/dynamic rendering выбирается только когда данные действительно зависят от текущего request или должны пересчитываться на каждый запрос.
+
+## Что переводит страницу в dynamic rendering
+
+Проверьте, нужны ли странице API и настройки, которые делают маршрут динамическим:
+
+- `cookies()` — данные зависят от cookie текущего пользователя.
+- `headers()` — данные зависят от request headers.
+- `draftMode()` — нужен preview/draft-режим.
+- `searchParams` в `page.tsx` — данные зависят от query string.
+- `cache: 'no-store'` или `revalidate: 0` в методе клиента — запрос нельзя кешировать.
+- `connection()` — рендер явно ждёт request.
+- `export const dynamic = 'force-dynamic'` — SSR включён вручную.
+
+Если ничего из этого не нужно, сначала проектируйте страницу как static/ISR. Серверный `await` сам по себе не означает SSR: режим зависит от кеширования запроса и dynamic API маршрута.
+
+## Рендер перед стратегией
+
+| Рендер | Когда подходит | Что выбирать дальше |
+|--------|----------------|---------------------|
+| Static/ISR | Данные общие и могут обновляться по интервалу | Серверные стратегии: `await`, `Promise.all`, передача промиса ниже, SWR `fallback` |
+| SSR/dynamic | Данные зависят от request, пользователя или должны быть свежими на каждый запрос | Серверные стратегии с учётом блокировки первого HTML |
+| После гидрации | Данные зависят от вкладки, фильтра, поиска, пагинации или действия пользователя | Клиентский GET-хук |
+
+## Как выбрать стратегию
+
+Когда режим рендера понятен, выбирайте конкретный способ получения данных:
+
+| Ситуация после выбора рендера | Стратегия | Где читать |
+|-------------------------------|-----------|------------|
+| Данные обязательны для первого HTML, SEO, `notFound()` или `redirect()` | Серверный `await` | [Серверный await](./server-await.md) |
+| Несколько независимых данных нужны до рендера | Запуск промисов + `Promise.all` | [Параллельные серверные запросы](./parallel-server-requests.md) |
+| Часть UI можно загрузить отдельно | Передача промиса ниже + `Suspense` | [Передача промиса ниже](./pass-promise-down.md) |
+| Client Component должен получить данные сразу из SWR | Начальные данные для клиентских хуков | [Начальные данные для клиентских хуков](./client-hooks-initial-data.md) |
+| Данные зависят от client state | Клиентский GET-хук | [Клиентский GET-хук](./client-get-hook.md) |
+| Нужно объединить несколько запросов или вычислить `isAuth`, `canEdit`, `hasPets` | Business-композиция | [Business-композиция](./business-composition.md) |
+
+## Правило выбора
+
+Не выбирайте стратегию по любимому инструменту. Выбирайте её по двум вопросам:
+
+```text
+Можно ли сохранить ISR?
+Где нужны данные и что должно произойти до первого HTML?
+```
+
+Если данные можно кешировать между пользователями — сохраняйте static/ISR. Если данные request-specific — используйте SSR/dynamic rendering. Если данные зависят от состояния браузера — используйте GET-хук REST-клиента. Если простой GET превращается в доменный сценарий — переходите в `business/`.
+
+## Общие запреты
+
+```tsx
+// Плохо — SSR включён на всякий случай
+export const dynamic = 'force-dynamic'
+
+// Плохо — ISR отключён без требования к свежести на каждый request
+export const revalidate = 0
+
+// Плохо — прямой fetch в компоненте
+useEffect(() => {
+ fetch('/api/pets').then(...)
+}, [])
+
+// Плохо — useSWR в компоненте
+const { data } = useSWR(
+ ['pet-store-api', 'pet', 'list', status],
+ () => petStoreApi.pet.findPetsByStatus({ status }),
+)
+
+// Плохо — бизнес-флаг внутри GET-хука REST-клиента
+return {
+ ...query,
+ hasPets: Boolean(query.data?.length),
+}
+```
+
+Не отключайте ISR без причины. В компонентах используются готовые методы клиента или готовые хуки. SWR-ключи, fetcher и транспорт остаются внутри REST-модуля.
diff --git a/ai/nextjs-style-guide/data/rest/strategies/parallel-server-requests.md b/ai/nextjs-style-guide/data/rest/strategies/parallel-server-requests.md
new file mode 100644
index 0000000..c7c0e7f
--- /dev/null
+++ b/ai/nextjs-style-guide/data/rest/strategies/parallel-server-requests.md
@@ -0,0 +1,82 @@
+---
+title: Параллельные серверные запросы
+description: Как запускать независимые REST-запросы на сервере без waterfall.
+keywords: [rest, promise.all, параллельные запросы, server components]
+---
+
+# Параллельные серверные запросы
+
+Если серверному компоненту нужно несколько независимых данных, запускайте запросы до ожидания результата. Последовательный `await` создаёт waterfall и замедляет рендер.
+
+## Когда использовать
+
+- Запросы независимы друг от друга.
+- Все данные нужны текущему серверному компоненту перед возвратом UI.
+- Нельзя или не нужно стримить часть UI отдельно.
+
+## Хорошо
+
+```tsx
+import { petStoreApi } from 'infrastructure/pet-store-api'
+import { PetsDashboardScreen } from 'screens/pets-dashboard'
+
+export default async function PetsDashboardPage() {
+ const availablePetsPromise = petStoreApi.pet.findPetsByStatus({ status: 'available' })
+ const pendingPetsPromise = petStoreApi.pet.findPetsByStatus({ status: 'pending' })
+ const soldPetsPromise = petStoreApi.pet.findPetsByStatus({ status: 'sold' })
+
+ const [availablePets, pendingPets, soldPets] = await Promise.all([
+ availablePetsPromise,
+ pendingPetsPromise,
+ soldPetsPromise,
+ ])
+
+ return (
+
+ )
+}
+```
+
+## Плохо
+
+```tsx
+export default async function PetsDashboardPage() {
+ const availablePets = await petStoreApi.pet.findPetsByStatus({ status: 'available' })
+ const pendingPets = await petStoreApi.pet.findPetsByStatus({ status: 'pending' })
+ const soldPets = await petStoreApi.pet.findPetsByStatus({ status: 'sold' })
+
+ return (
+
+ )
+}
+```
+
+Во втором примере каждый следующий запрос ждёт предыдущий, хотя они независимы.
+
+## Зависимые запросы
+
+Если второй запрос зависит от результата первого, последовательный `await` допустим:
+
+```tsx
+export default async function OrderPage({ params }: OrderPageProps) {
+ const { id } = await params
+ const order = await petStoreApi.store.getOrderById(Number(id))
+ const pet = await petStoreApi.pet.getPetById(order.petId)
+
+ return
+}
+```
+
+Не превращайте зависимый сценарий в `Promise.all` искусственно.
+
+## Когда выбрать другую стратегию
+
+Если часть данных не обязательна для первого блока UI, можно запустить промис выше и передать его ниже: [Передача промиса ниже](./pass-promise-down.md).
diff --git a/ai/nextjs-style-guide/data/rest/strategies/pass-promise-down.md b/ai/nextjs-style-guide/data/rest/strategies/pass-promise-down.md
new file mode 100644
index 0000000..56fa7e3
--- /dev/null
+++ b/ai/nextjs-style-guide/data/rest/strategies/pass-promise-down.md
@@ -0,0 +1,62 @@
+---
+title: Передача промиса ниже
+description: Как запускать серверный REST-запрос выше и ожидать его во вложенном server-компоненте.
+keywords: [rest, promise, suspense, streaming, server components]
+---
+
+# Передача промиса ниже
+
+Серверный компонент может запустить запрос и передать промис вложенному server-компоненту. Это полезно, когда часть UI можно загрузить отдельно через `Suspense`.
+
+## Когда использовать
+
+- Верхняя часть страницы может отрендериться без этих данных.
+- Данные нужны только вложенному server-компоненту.
+- Нужна `Suspense`-граница и серверный стриминг.
+
+## Пример
+
+```tsx
+// src/app/(routes)/pets/page.tsx
+import { Suspense } from 'react'
+import { petStoreApi } from 'infrastructure/pet-store-api'
+import { PetListSection } from 'widgets/pet-list-section'
+import { PetListSkeleton } from 'widgets/pet-list-section'
+import type { Pet } from 'infrastructure/pet-store-api'
+
+export default function PetsPage() {
+ const petsPromise = petStoreApi.pet.findPetsByStatus({ status: 'available' })
+
+ return (
+
+
Питомцы
+ }>
+
+
+
+ )
+}
+
+async function AvailablePets({ petsPromise }: { petsPromise: Promise }) {
+ const pets = await petsPromise
+
+ return
+}
+```
+
+Запрос стартует в `PetsPage`, но ожидание происходит внутри `AvailablePets`. `Suspense` управляет fallback для этой части UI.
+
+## Граница стратегии
+
+Эта стратегия остаётся серверной. Не используйте её как замену GET-хукам в Client Components.
+
+Если данные должны попасть в клиентский SWR-хук, используйте [Начальные данные для клиентских хуков](./client-hooks-initial-data.md).
+
+## Что не делать
+
+```tsx
+// Плохо — передавать промис в произвольный клиентский компонент без ясной стратегии
+return
+```
+
+Для клиентского потребления есть отдельная стратегия через `SWRConfig fallback` и готовые GET-хуки REST-клиента.
diff --git a/ai/nextjs-style-guide/data/rest/strategies/server-await.md b/ai/nextjs-style-guide/data/rest/strategies/server-await.md
new file mode 100644
index 0000000..a882857
--- /dev/null
+++ b/ai/nextjs-style-guide/data/rest/strategies/server-await.md
@@ -0,0 +1,88 @@
+---
+title: Серверный await
+description: Получение REST-данных на сервере до первого HTML.
+keywords: [rest, server components, await, nextjs, isr, ssr, notFound, redirect]
+---
+
+# Серверный await
+
+Получение REST-данных на сервере до первого HTML.
+
+Серверный `await` — базовая стратегия для данных, которые нужны до рендера страницы или серверного блока.
+
+## Когда использовать
+
+- Данные нужны для первого HTML.
+- Данные влияют на `metadata`.
+- По результату запроса нужно вызвать `notFound()` или `redirect()`.
+- Компонент серверный и данные не зависят от состояния браузера.
+
+## Влияние на рендер
+
+Серверный `await` сам по себе не означает SSR. В App Router страница может остаться static/ISR, если маршрут не использует dynamic API и запросы можно кешировать.
+
+ISR — приоритет для общих данных. Если список или детальная страница могут обновляться по интервалу, сохраняйте кеширование и не добавляйте `no-store`, `revalidate: 0` или `force-dynamic` без требования.
+
+SSR/dynamic rendering нужен, когда данные зависят от текущего request: cookie, headers, `searchParams`, preview-режим или персональные данные пользователя.
+
+## Пример страницы списка
+
+```tsx
+// src/app/(routes)/pets/page.tsx
+import { petStoreApi } from 'infrastructure/pet-store-api'
+import { PetsScreen } from 'screens/pets'
+
+export default async function PetsPage() {
+ const pets = await petStoreApi.pet.findPetsByStatus({
+ status: 'available',
+ })
+
+ return
+}
+```
+
+`page.tsx` получает данные первого рендера и передаёт их ниже. UI страницы остаётся в `screens/`, а не пишется прямо в `app/`.
+
+## Пример детальной страницы
+
+```tsx
+// src/app/(routes)/pets/[id]/page.tsx
+import { notFound } from 'next/navigation'
+import { petStoreApi } from 'infrastructure/pet-store-api'
+import { PetDetailScreen } from 'screens/pet-detail'
+
+type PetPageProps = {
+ params: Promise<{ id: string }>
+}
+
+export default async function PetPage({ params }: PetPageProps) {
+ const { id } = await params
+ const pet = await petStoreApi.pet.getPetById(Number(id)).catch(() => null)
+
+ if (!pet) {
+ notFound()
+ }
+
+ return
+}
+```
+
+Обработка 404 зависит от API-клиента и класса ошибок. В примере показана идея: решение о `notFound()` принимается на уровне маршрута, а не внутри REST-клиента.
+
+## Что не делать
+
+```tsx
+// Плохо — хуки нельзя вызывать в Server Component
+const { data } = useGetPetList('available')
+
+// Плохо — прямой fetch в обход клиента
+const response = await fetch('https://petstore3.swagger.io/api/v3/pet/findByStatus')
+```
+
+Если данные нужны на сервере, вызывайте метод REST-клиента напрямую.
+
+## Когда выбрать другую стратегию
+
+- Несколько независимых запросов — [Параллельные серверные запросы](./parallel-server-requests.md).
+- Часть UI можно грузить отдельно — [Передача промиса ниже](./pass-promise-down.md).
+- Данные нужны клиентскому хуку сразу после гидрации — [Начальные данные для клиентских хуков](./client-hooks-initial-data.md).
diff --git a/ai/nextjs-style-guide/workflow.md b/ai/nextjs-style-guide/workflow.md
new file mode 100644
index 0000000..c060231
--- /dev/null
+++ b/ai/nextjs-style-guide/workflow.md
@@ -0,0 +1,8 @@
+---
+title: Подсказки
+description: Короткие ответы на типовые вопросы и решения для спорных ситуаций.
+---
+
+# Подсказки
+
+Короткие ответы на типовые вопросы и решения для спорных ситуаций.
diff --git a/public/img/sprites/icons/sprite.stack.html b/public/img/sprites/icons/sprite.stack.html
deleted file mode 100644
index df088b3..0000000
--- a/public/img/sprites/icons/sprite.stack.html
+++ /dev/null
@@ -1,161 +0,0 @@
-
-
-
-
- SVG stack preview | svg-sprite
-
-
-
-
-
-
-
-
-
-
-
-
SVG stack preview
-
This preview features an SVG stack. Please have a look at the HTML source for further details and be aware of the following constraints:
Support for SVG fragment identifiers hasn't always been that decent. For older browsers you will have to use some prolyfill like fixsvgstack.jquery.js.