## Для ассистента - Всегда используй Русский язык для общения и генерации документации/комментариев/коммитов. - Всегда следуй этим правилам при генерации кода и ответах. - Всегда пиши план действий перед генерацией кода. - Всегда спрашивай разрешения у пользователя перед генерацией кода. - Всегда проверяй, что код соответствует линтингу и форматированию. - Всегда сверяйся с чек-листом при генерации кода. - Не предлагай решения, которые противоречат этим правилам этого файла. - Если не уверен — уточни у пользователя, не гадай, не придумывай. --- ## Обязательность чек-листов - Все чек-листы, приведённые в правилах, обязательны к исполнению. - Ассистент обязан сверяться с чек-листом при выполнении любой задачи, связанной с кодом. - Нельзя сокращать, игнорировать или опускать пункты чек-листа — каждый пункт должен быть выполнен или явно отмечен как невыполнимый с объяснением причины. - В каждом ответе, связанном с генерацией или изменением кода, ассистент обязан ссылаться на соответствующий чек-лист и подтверждать его выполнение. --- ## Общие принципы - Использовать **TypeScript** для всех файлов логики и компонентов. - Использовать **FSD (Feature-Sliced Design)**: разделять код на features, entities, processes, widgets, shared. - Использовать **TSDoc** для документации функций, компонентов, типов, аргументов, возвращаемых значений. - Использовать **React** (функциональные компоненты, хуки). - Использовать **Mantine UI** для UI-компонентов. - Использовать **Axios** для работы с API. - Использовать **SWR** для data fetching (GET-запросы). - Использовать **Zod** для валидации форм. - Использовать **Zustand** для глобального состояния. - Использовать **i18n** для локализации. - Использовать **Vitest** для тестирования. - Использовать **PostCSS модули** для стилизации. - Использовать **BEM** для именований классов в стилях - Использовать **Mobile First** подход для написания стилей. - Использовать **Context7** примеров использования библиотек. - Использовать **i18n** (i18next) для локализации всех пользовательских текстов. --- ## Архитектура проекта В проекте используется FSD (Feature-Sliced Design) архитектура. - **FSD-границы** - Не нарушать границы слоёв (например, feature не может импортировать из widgets). - Бизнес-логика должна быть вынесена в хуки или сервисы. - **Импорты** - Внутри слоя — относительные импорты. - Между слоями — абсолютные импорты. - **Требования** - Не смешивать логику разных слоёв. - Не хранить бизнес-логику в UI-компонентах. - **Именование** - Файлы и папки kebab-case. --- ## 5. Стиль кода - **Строгая типизация**: всегда указывать типы для пропсов, возвращаемых значений, параметров функций. - **Ранние возвраты** (early return) для повышения читаемости. - **Мемоизация**: Старайся оптимизировать код если это возможно. - **Документирование**: Документируем ТОЛЬКО ОПИСАНИЕ (функций, компонентов, типов и их полей). - **any, unknown** запрещено использовать без крайней необходимости. --- ## Именование файлов и папок - Папка компонента: kebab-case, совпадает с названием компонента, пример: `component-name`. - React-компонент: kebab-case, совпадает с названием компонента, пример: `component-name.tsx`. - Стили: kebab-case, шаблон: `.module.css`, пример: `style-name.module.css`. - Интерфейсы: kebab-case, шаблон: `.interface.ts`, пример: `interface-name.interface.ts`. - Типы: kebab-case, шаблон: `.type.ts`, пример: `type-name.type.ts`. - Enum: kebab-case, шаблон: `.enum.ts`, пример: `enum-name.enum.ts`. - Схемы: kebab-case, шаблон: `.schema.ts`, пример: `schema-name.schema.ts`. - Локализация: kebab-case, пример: `ru.json`, `en.json`. - Утилиты: kebab-case, шаблон: `.util.ts`, пример: `util-name.util.ts` - React Hooks: kebab-case, шаблон: `use-.hook.ts`, пример: `use-hook-name.hook.ts` - Хранилища состояния компонента: kebab-case, шаблон: `.store.ts`, пример: `store-name.store.ts` ## Правило для документирования кода - Документировать разрешено только описание (назначение) функций, компонентов, типов, интерфейсов, enum и их полей. - Строго запрещено документировать параметры, возвращаемые значения, типы пропсов, аргументы, возвращаемые значения функций, компоненты, хуки и т.д. - В интерфейсах, типах и enum разрешено документировать только смысл (описание) каждого поля или значения. - В React-компонентах, функциях, хранилищах, схемах, утилитах разрешено документировать только назначение (описание), без детализации параметров и возвращаемых значений. - Описание должно быть кратким, информативным и реально помогать понять структуру и бизнес-логику. - Не допускается избыточная или дублирующая очевидное документация. - В конце описания всегда ставить точку. **Примеры правильного документирования** ```tsx /** * Список задач пользователя. */ export const TodoList = memo(() => { ... }); /** * Интерфейс задачи. */ export interface TodoItem { /** Уникальный идентификатор задачи. */ id: string; /** Текст задачи. */ text: string; /** Статус выполнения задачи. */ completed: boolean; } /** * Перечисление фильтров задач. */ export enum TodoFilter { /** Все задачи. */ All = 'all', /** Только активные задачи. */ Active = 'active', /** Только выполненные задачи. */ Completed = 'completed', } ``` **Примеры неправильного документирования** ```ts // ❌ Не нужно:/ /** * @param id - идентификатор задачи * @returns объект задачи */ // ❌ Не нужно:/ /** * @param props - пропсы компонента * @returns JSX.Element */ // ❌ Не нужно:/ /** * id — идентификатор задачи * text — текст задачи * completed — статус выполнения */ ``` ## Общие правила типизации > Данный раздел определяет единые требования к типизации для всего проекта. Соблюдение этих правил обеспечивает читаемость, предсказуемость и безопасность кода. - Использовать только строгую типизацию TypeScript для всех файлов логики, компонентов, хуков, API, сторов и утилит. - Всегда явно указывать типы для: - Пропсов компонентов - Параметров функций и методов - Возвращаемых значений функций и методов - Всех переменных состояния (в том числе в store) - Всех значимых переменных и констант, если их тип не очевиден из присваивания - Не использовать `any` и `unknown` без крайней необходимости. Если использование неизбежно — обязательно добавить комментарий с обоснованием. - Все интерфейсы, типы и enum всегда размещать в папке `types/` на своём уровне абстракции (например, `features/todo/types/`). - Для DTO всегда использовать отдельную папку `dto/` на уровне сущности или слоя. - Для сложных структур использовать отдельные интерфейсы или типы, размещая их в соответствующих файлах в папке `types/`. - Для DTO, enum, схем и других сущностей — всегда создавать отдельные типы/интерфейсы с осмысленными именами. - Ключи enum всегда писать ЗАГЛАВНЫМИ_БУКВАМИ (SCREAMING_SNAKE_CASE). - Не использовать неявное приведение типов и не полагаться на автоматический вывод, если это может снизить читаемость или безопасность. - Для массивов и объектов всегда указывать тип элементов/ключей. - Для возвращаемых значений асинхронных функций всегда указывать тип Promise. - Типизацию коллбеков и функций, передаваемых в пропсы, указывать инлайн, не выносить в отдельные типы. - Для типизации внешних библиотек использовать официальные типы или создавать собственные декларации при необходимости. - Не использовать устаревшие или не рекомендуемые паттерны типизации (например, `Function`, `Object`, `{}`). --- ### Примеры #### Интерфейс и типы для сущностей (всегда в папке types/) ```ts // features/todo/types/todo-item.interface.ts /** * Интерфейс задачи. */ export interface TodoItem { /** Уникальный идентификатор задачи. */ id: string; /** Текст задачи. */ text: string; /** Статус выполнения задачи. */ completed: boolean; } ``` #### Типизация enum (всегда в папке types/) ```ts // features/todo/types/todo-status.enum.ts /** * Перечисление статусов задачи. */ export enum TodoStatus { /** Активная задача. */ ACTIVE = 'active', /** Выполненная задача. */ COMPLETED = 'completed', } ``` #### Типизация пропсов компонента ```ts import { FC, memo } from 'react'; import { TodoItem } from './types/todo-item.interface'; /** * Список задач. */ export interface TodoListProps { /** Массив задач. */ items: TodoItem[]; } export const TodoList: FC = memo(({ items }) => (
    {items.map((item) => (
  • {item.text}
  • ))}
)); ``` #### Типизация функций и коллбеков (инлайн) ```ts /** * Функция фильтрации задач. */ export const getCompletedTodos = (items: TodoItem[]): TodoItem[] => { return items.filter((t) => t.completed); }; /** * Колбэк для обработки клика (инлайн). */ const handleClick = (id: string): void => { console.log('Clicked:', id); }; ``` #### Типизация асинхронных функций ```ts /** * Получить задачи с сервера. */ export const fetchTodos = async (): Promise => { const response = await fetch('/api/todos'); return response.json(); }; ``` #### Типизация состояния в store (интерфейс в types/) ```ts // features/todo/types/todo-store.interface.ts /** * Состояние хранилища задач. */ export interface TodoStoreState { /** Массив задач. */ items: TodoItem[]; /** Добавить задачу. */ addTodo: (item: TodoItem) => void; /** Удалить задачу. */ removeTodo: (id: string) => void; } ``` #### Типизация DTO (всегда в папке dto/) ```ts // features/todo/dto/create-todo.dto.ts /** * DTO для создания задачи. */ export interface CreateTodoDto { /** Текст задачи. */ text: string; } // features/todo/dto/todo-response.dto.ts /** * DTO ответа сервера. */ export interface TodoResponseDto { /** Созданная задача. */ todo: TodoItem; } ``` #### Типизация внешних библиотек ```ts import type { AxiosResponse } from 'axios'; export const getData = async (): Promise> => { // ... }; ``` ### Чек-лист проверки типизации - [ ] Все пропсы компонентов явно типизированы через интерфейс или тип в папке `types/`. - [ ] Все параметры и возвращаемые значения функций и методов явно типизированы. - [ ] Все переменные состояния (в том числе в store) имеют явные типы. - [ ] Все интерфейсы, типы и enum размещены в папке `types/` на своём уровне абстракции. - [ ] Ключи всех enum написаны ЗАГЛАВНЫМИ_БУКВАМИ (SCREAMING_SNAKE_CASE). - [ ] Все DTO размещены в папке `dto/` на своём уровне абстракции. - [ ] Не используется `any` и `unknown` без крайней необходимости и поясняющего комментария. - [ ] Для сложных структур используются отдельные интерфейсы или типы. - [ ] Для массивов и объектов указан тип элементов/ключей. - [ ] Для асинхронных функций указан тип Promise с конкретным типом результата. - [ ] Типы коллбеков и функций, передаваемых в пропсы, указаны инлайн. - [ ] Не используются устаревшие типы (`Function`, `Object`, `{}`). - [ ] Для внешних библиотек используются официальные типы или собственные декларации. - [ ] Нет неявного приведения типов, все типы читаемы и прозрачны. ## Правила использования локализации - Все пользовательские тексты должны быть вынесены в локализационные файлы. - Для каждого компонента создавать папку `locales/` с файлами `ru.json`, `en.json` и т.д. - Новые namespace обязательно регистрировать в экземпляре i18n (см. `app/i18n.ts`). - В коде использовать только функцию перевода из i18n, не использовать "жёстко" прописанные строки. ## Сторы (Stores) > В этом разделе собраны основные правила и рекомендации по созданию и оформлению сторов. Следуйте этим принципам, чтобы обеспечить чистую архитектуру, удобство поддержки и единый стиль работы с состоянием в проекте. > В проекте для организации состояния используется только библиотека Zustand. ### Структура - Store размещается в файле `.store.ts` в папке `stores/` на своём уровне абстракции согласно архитектуре проекта. - Интерфейс состояния описывается в этом же файле с суффиксом `State` (PascalCase). - Для каждого store создаётся отдельный хук доступа (например, `useTodoStore`). - Для глобальных сторов используйте только `shared/store`. ### Именование - Соблюдайте [правила именования файлов и папок](#правила-именования-файлов-и-папок): - Файл store — `.store.ts` (kebab-case). - Имя интерфейса состояния — PascalCase с суффиксом `State`. - Имя хука — camelCase с префиксом `use`. ### Требования - В store допускается только хранение состояния и методы управления им, без бизнес-логики, асинхронных операций и side-effects (см. раздел "Правила организации и использовалья Store"). - Для методов, изменяющих состояние через set, если используется функция — тело функции в фигурных скобках, return с новой строки после стрелки. - Не дублируйте логику между сторами. ### Типизация - Всегда указывайте типы для всех полей состояния и методов. - Не используйте неявное приведение типов и не полагайтесь на автоматический вывод, если это может снизить читаемость или безопасность. ### Документирование - Документируйте только назначение store и смысл полей, строго по [правилам документирования кода](#правило-для-документирования-кода). ### Экспорт - Экспортируйте хук доступа к store и интерфейс состояния через `index.ts` слоя/компонента. ### Примеры ```ts import { create } from 'zustand'; import { TodoItem } from './types/todo-item.interface'; /** * Состояние хранилища задач. */ export interface TodoStoreState { /** Массив задач. */ items: TodoItem[]; /** Добавить задачу. */ addTodo: (item: TodoItem) => void; /** Удалить задачу. */ removeTodo: (id: string) => void; } /** * Хук для доступа к хранилищу задач. */ export const useTodoStore = create((set) => ({ items: [], addTodo: (item) => set((state) => { return { items: [...state.items, item], }; }), removeTodo: (id) => set((state) => { return { items: state.items.filter((t) => t.id !== id), }; }), })); ``` ### Чек-лист - [ ] Store размещён в `stores/.store.ts` на своём уровне абстракции согласно архитектуре проекта. - [ ] Именование файлов и сущностей соответствует [правилам именования файлов и папок](#правила-именования-файлов-и-папок). - [ ] Все поля и методы строго типизированы (см. [общие правила типизации](#общие-правила-типизации)). - [ ] В store только состояние и методы управления им, без бизнес-логики и side-effects. - [ ] Для методов, изменяющих состояние через set, используется функция с return с новой строки. - [ ] Документировано только назначение store и смысл полей (см. [правила документирования кода](#правило-для-документирования-кода)). - [ ] Нет неиспользуемого или невалидного кода. - [ ] Экспорт через индексный файл. ## Правила оформления и стилизации CSS-кода - **Препроцессоры** Используй PostCSS и модули для стилизации. - **Архитектура написания стилей** Используй подход **Mobile First** Используй CSS переменные для стилизации. Используй Custom Media Queries для адаптивных стилей. Используй BEM для именования классов. Между каждым CSS-правилом (селектором) должен быть один пустой сброс строки, пример: ```css .todo-list { max-width: 600px; padding: var(--space-3); @media (--md) { max-width: 800px; } } .todo-list__text { font-size: 18px; @media (--md) { font-size: 22px; } } ``` Запрещено писать правила подряд без пустой строки: ```css /* Так делать нельзя! */ .todo-list { ... } .todo-list__text { ... } ``` - **Методология именования классов** Использовать методологию **BEM** для именования классов. - Блок: kebab-case, пример `.user-bar { }` - Елемент: kebab-case, соеденный с блоком двойным нижним подчеркиванием, пример `.user-bar__slide { }` - Модификатор: kebab-case, отдельный самостоятельный класс, **не соединяется** с блоком/елементом, имя модификатора всегда начинается с нижнего подчеркивания, пример: `._red { }` - **Единицы измерения** Используй `px` как основная единица измирения, так-же допускается использовать остальные единицы измерения если того требует реализуемый дизайн. - **Импорт стилей** Стили компонента должны импортироваться только внутри соответствующего компонента. Запрещено импортировать стили одного компонента в другой. Запрещено импортировать `css переменные` в файлы стилей, они доступны глобально. Запрещено импортировать `custom media` в файлы стилей, они доступны глобально. - **Переменные** Все значения переменных нужно писать в `/shared/styles` или в Mantine ThemeProvider. Все что не является цветами, брекпоинтами, отступами, скруглением допускаются использоваться в компонентах. Обязательное создавай CSS перменные для: - "Цветов", пример: `--color-danger: red;`. - "Брекпоинты", описываем в (Сustom media) пример: `@custom-media --md (min-width: 62em);`. - "Отспупы (--space)", , пример: `--space-1: 4px;`, `--space-2: 8px;`, `--space-3: 12px;` итд.. - "Скругление углов (--radius)", пример: `--radius-1: 4px;`,`--radius-2: 8px;`,`--radius-3: 12px;` итд.. - **Вложенность селекторов** Запрещено использовать вложенность селекторов. Разрешено использовать вложенность только для: - Псевдо-классов `:hover`, `:active` итд.. - Псевдо-елементов `::before`, `::after` - Медиа запросов `@media` - Классы **модификаторы** по методологии BEM Каждый вложенный селектор отделяется 1 пустой строкой. - **Медиа запросы** Строго запрещено использовать `@media` без вложения в селектор. Строго запрещено использовать в теле `@media` любые селекторы. Разрешено использовать только Custom Media Queries (например, `@media (--md) {}`). Запрещено использовать любые произвольные значения breakpoints (например, max-width: 768px). **Пример как правильно писать @media** ```css .todo-list { max-width: 600px; padding: 24px; @media (--md) { max-width: 800px; } } .todo-list__text { font-size: 18px; @media (--md) { font-size: 22px; } } ``` **Пример как неправильно писать @media** ```css // Медиа запрос не вложен в селектор @media (--md) { .todo-list { max-width: 600px; padding: 24px; } .todo-list__text { font-size: 18px; } } // Используется стандартный `min-width: 992px` вмето Custom Media Queries @media (min-width: 992px) { // Внутри @media запроса используются селекторы .todo-list { max-width: 600px; padding: 24px; } .todo-list__text { font-size: 18px; } } ``` - **Глобальные стили и сбросы** Все глобальные стили (например, сбросы) должны располагаться в отдельном файле, например, `src/app/styles/global.css`. - **Использование Mantine и PostCSS** Для стандартных визуальных компонентов (кнопки, инпуты, layout, grid, notifications и т.д.) использовать только Mantine и его ThemeProvider. Запрещено использовать в Mantine компонентах его props/styling, вмето этого нужно добавлять кастомные стили PostCSS. Кастомные стили допускаются только в случае, если требуемый дизайн невозможно реализовать средствами Mantine. При написании кастомных стилей стараться использовать переменные и токены Mantine, если это возможно. - **Порядок CSS-свойств** В стилях рекомендуется придерживаться логического порядка свойств: 1. Позиционирование (position, top, left, z-index и т.д.) 2. Блочная модель (display, width, height, margin, padding и т.д.) 3. Оформление (background, border, box-shadow и т.д.) 4. Текст (font, color, text-align и т.д.) 5. Прочее (transition, animation и т.д.) - **Комментарии** В стилях запрещено использовать комментарии. - **Дублирования** Не дублировать стили между компонентами. Общие стили выносить в shared/styles или использовать переменные. - **Примеры кода стилей** Пример как хорошо: ```css /* Блок BEM */ .user-bar { display: none; color: black; /* Медиа запрос custom media и отделяется 1 пустой строкой */ @media (--md) { display: flex; } } /* Елемент BEM отделяется 1 пустой строкой*/ .user-bar__button-next { background-color: #f0f0f0; /* Псевдо-класс отделяется 1 пустой строкой*/ &:hover { background-color: #e0e0e0; } /* Модификатор BEM отделяется 1 пустой строкой*/ &._blue { background-color: #2b2bbe; } /* Модификатор BEM отделяется 1 пустой строкой*/ &._green { background-color: #29c53d; } } ``` Пример как плохо писать: ```css .user-bar { display: none; color: black; &__button { &_next { background-color: #f0f0f0; &:hover { background-color: #e0e0e0; } &._blue { background-color: #2b2bbe; } &._green { background-color: #29c53d; } } } } @media (min-width: 992px) { .user-bar { display: flex; } } ``` **Чек лист для проверки стилизации.** - [ ] Используется PostCSS и CSS-модули для стилизации. - [ ] Применён подход Mobile First. - [ ] Именование классов строго по BEM: - [ ] Модификатор — отдельный класс, начинается с нижнего подчёркивания (например, `._red`, `._active`) - [ ] Все CSS-переменные (цвета, брейкпоинты, отступы, скругления) определены только в `/shared/styles` или через Mantine ThemeProvider. - [ ] Для медиа-запросов используются только custom media переменные из `/shared/styles/media.css`. - [ ] Соблюдается правила вложености селекторов. - [ ] Соблюдается правила отступов селекторов. - [ ] Глобальные стили (reset) вынесены в отдельный файл, остальные стили — модульные. - [ ] Для стандартных UI-элементов используются только компоненты Mantine, кастомные стили — только при необходимости. - [ ] В Mantine-компонентах не используются props/styling для стилизации, только PostCSS. - [ ] Кастомные стили используют переменные и токены Mantine, если это возможно. - [ ] В стилях нет комментариев. - [ ] Стили компонента импортируются только внутри соответствующего компонента. - [ ] Нет импорта стилей одного компонента в другой. - [ ] Нет импорта файлов переменных и custom media — они доступны глобально. - [ ] Нет дублирования стилей между компонентами, общие стили вынесены в shared/styles или используются переменные. ## Правила создания и работы с компонентами. ### 1. Структура компонента Ассистент при создании/рефакторинге компонента должен **строго** придерживаться следующей структуры файлов и папок: ``` component-name/ index.ts component-name.tsx styles/ component-name.module.css locales/ ru.json en.json types/ component-name.interface.ts component-name.type.ts component-name.enum.ts schemas/ schema-name.schema.ts utils/ util-name.util.ts hooks/ use-hook-name.hook.ts stores/ store-name.store.ts ui/ ... # вложенные компоненты для component-name ``` Пояснения к структуре компонента: **Обязательные файлы** обязательны для всех компонентов, даже если они пустые. - component-name/: Папка компонента корень для всего компонента. - index.ts: экспортирует главный компонент, интерфейс и всё, что может быть переиспользовано. - component-name.tsx: главный компонент. - styles/component-name.module.css: стили компонента. - locales/ru.json: локализация на русском языке. - locales/en.json: локализация на английском языке. - types/component-name.interface.ts: интерфейс пропсов компонента. **Не обязательные файлы** добавляются только при необходимости - types/component-name.type.ts: типы компонента. - types/component-name.enum.ts: enum компонента. - schemas/schema-name.schema.ts: схемы валидации. - utils/util-name.util.ts: утилиты компонента. - hooks/use-hook-name.hook.ts: хуки компонента. - stores/store-name.store.ts: хранилища состояния компонента. - ui/: Папка для вложенных компонентов. ### Требования к компоненту - Использовать `memo()` для всех компонентов, которые принимают пропсы. - Использовать `useMemo` для всех вычислений, которые передаются в пропсы других компонентов. - Использовать `useCallback` для всех функций/методов, которые передаются в пропсы других компонентов. ### Требования к вложенным компонентам - Вложенный компонент — это полноценный компонент, который обязан полностью соблюдать все правила, описанные для компонентов (структура, именование, документация, типизация, стилизация и т.д.). - Все вложенные компоненты размещаются только в папке ui/ основного компонента. **Пояснение** Нет необходимости повторять структуру и требования — вложенный компонент подчиняется тем же правилам, что и любой другой компонент, только располагается в папке ui/ родительского компонента. ### Требования к локализации - Все добавленные локализации обязательно подключать в экземпляр `app/i18n` (чтобы новые namespace были доступны для i18next). --- ### Чек-лист для создания нового компонента - [ ] Главный компонент размещён в корне и назван по правилу PascalCase. - [ ] Создан файл стилей в папке `styles/`, имя в kebab-case, используется BEM. - [ ] Все классы применяются через `className={styles['component-name']}`. - [ ] Создана папка `locales/` с файлами `ru.json` и `en.json`. - [ ] Создан файл интерфейса пропсов в папке `types/`, даже если интерфейс пустой. - [ ] Создан файл `index.ts` с экспортом главного компонента и интерфейса. - [ ] Внутренние компоненты (если есть) размещены в папке `ui/`. - [ ] Все важные части кода документированы по TSDoc (см. раздел 16). - [ ] Остальные файлы (schemas, дополнительные типы, enum) добавлены только при необходимости. - [ ] Именование файлов и папок соответствует правилам (см. выше). - [ ] Нет неиспользуемого или невалидного кода. - [ ] Для компонентов с пропсами используется `React.memo`. - [ ] Для вычислений, передаваемых в пропсы, используется `useMemo`. - [ ] Для функций, передаваемых в пропсы, используется `useCallback`. - [ ] Все тексты вынесены в локализационные файлы и используются через i18n. - [ ] Новые namespace подключены в экземпляр i18n. ## Хуки (React Hooks) > В проекте для создания пользовательских хуков используется только React (функциональные компоненты и хуки). > В этом разделе собраны основные правила и рекомендации по созданию и оформлению хуков. Следуйте этим принципам, чтобы обеспечить чистую архитектуру, переиспользуемость и единый стиль работы с хуками в проекте. ### Рекомендации по использованию сторонних хуков - Если есть возможность, используйте хуки Mantine в компонентах и кастомных хуках для работы с состоянием, темизацией, медиа-запросами и другими возможностями библиотеки. - Не дублируйте функциональность, уже реализованную в Mantine. ### Структура - Каждый хук размещается в отдельном файле с именем `use-.hook.ts` в папке `hooks/` на своём уровне абстракции согласно архитектуре проекта. - Имя хука — в стиле camelCase с префиксом `use` (например, `useTodoFilter`). - Для сложных возвращаемых структур использовать отдельные типы или интерфейсы, размещая их в папке `types/` на своём уровне абстракции. ### Именование - Соблюдайте [правила именования файлов и папок](#правила-именования-файлов-и-папок): - Файл хука — `use-.hook.ts` (kebab-case). - Имя хука — camelCase с префиксом `use`. ### Требования - Хук должен быть строго типизирован: все параметры, возвращаемые значения и внутренние переменные должны иметь явные типы. - Не хранить бизнес-логику, связанную с несколькими слоями — хук должен быть изолирован в рамках своего слоя/feature. - Не дублировать логику между хуками — общие части выносить в shared. - Не использовать side-effects вне useEffect/useLayoutEffect. - Для мемоизации возвращаемых значений и функций использовать useMemo и useCallback. - Не использовать устаревшие или неразрешённые паттерны React. ### Типизация - Всегда явно указывать типы для всех параметров, возвращаемых значений и состояния внутри хука. - Не используйте неявное приведение типов и не полагайтесь на автоматический вывод, если это может снизить читаемость или безопасность. ### Документирование - Документируйте только назначение хука (описание), строго по [правилам документирования кода](#правило-для-документирования-кода). ### Экспорт - Экспортируйте хук только именованным экспортом через `index.ts` слоя/компонента. ### Примеры ```ts import { useMemo } from 'react'; import { TodoItem } from '../types/todo-item.interface'; import { TodoStatus } from '../types/todo-status.enum'; /** * Хук фильтрации задач по статусу. */ export const useTodoFilter = (items: TodoItem[], filter: TodoStatus): TodoItem[] => { return useMemo(() => { if (filter === TodoStatus.ALL) return items; if (filter === TodoStatus.ACTIVE) return items.filter((t) => !t.completed); return items.filter((t) => t.completed); }, [items, filter]); }; ``` ### Чек-лист - [ ] Хук размещён в файле `use-.hook.ts` в папке `hooks/` на своём уровне абстракции согласно архитектуре проекта. - [ ] Именование файлов и сущностей соответствует [правилам именования файлов и папок](#правила-именования-файлов-и-папок). - [ ] Все параметры, возвращаемые значения и внутренние переменные строго типизированы. - [ ] Вся бизнес-логика изолирована в рамках слоя/feature. - [ ] Нет дублирования логики между хуками. - [ ] Для мемоизации используется useMemo/useCallback. - [ ] Не используются side-effects вне useEffect/useLayoutEffect. - [ ] Документировано только назначение хука (см. [правила документирования кода](#правило-для-документирования-кода)). - [ ] Нет неиспользуемого или невалидного кода. - [ ] Экспорт только именованный через индексный файл. ## Хуки API (React Hooks) > В проекте для работы с API-хуками используется только React и библиотека SWR для получения данных (GET-запросы). > В этом разделе собраны основные правила и рекомендации по созданию и оформлению хуков для работы с API. Следуйте этим принципам, чтобы обеспечить чистую архитектуру, переиспользуемость и единый стиль работы с API-хуками в проекте. ### Описание и назначение API-хуков API-хуки предназначены для получения данных с сервера (GET-запросы) и используются в компонентах или других хуках. В проекте для этого применяется библиотека SWR, которая обеспечивает кэширование, автоматическое обновление и удобную работу с асинхронными запросами. **Fetcher** — это функция, которую использует SWR для выполнения запроса к API. В проекте fetcher обычно экспортируется из файла клиента (например, `backendFetcher` из `shared/api/backend/client.ts`) и инкапсулирует логику обращения к конкретному API-клиенту. **API-клиент** — это отдельный модуль (папка), отвечающий за взаимодействие с конкретным внешним или внутренним API. API-клиент включает: - инициализацию экземпляра HTTP-клиента (например, Axios), - настройку базового URL, интерцепторов и общих обработчиков ошибок, - организацию всех сущностей и методов для работы с этим API (например, users, auth, orders и т.д.), - экспорт всех функций, типов и fetcher через индексные файлы. Каждый API-клиент размещается в папке `src/shared/api//` и имеет собственную структуру согласно архитектуре проекта. ### Структура - Каждый API-хук размещается в отдельном файле с именем `use-.hook-api.ts` в папке `hooks/api//` на своём уровне абстракции согласно архитектуре проекта. - Имя хука — в стиле camelCase с префиксом `use` (например, `useGetUser`). - Для сложных возвращаемых структур используйте отдельные типы или интерфейсы, размещая их в папке `types/` на своём уровне абстракции. ### Именование - Соблюдайте [правила именования файлов и папок](#правила-именования-файлов-и-папок): - Файл хука — `use-.hook-api.ts` (kebab-case). - Имя хука — camelCase с префиксом `use`. ### Требования - Хук должен быть строго типизирован: все параметры, возвращаемые значения и внутренние переменные должны иметь явные типы. - Для получения данных используйте только SWR. - Не дублируйте логику между хуками — общие части выносите в shared. - Не используйте side-effects вне useEffect/useLayoutEffect. ### Типизация - Всегда явно указывайте типы для всех параметров, возвращаемых значений и состояния внутри хука. - Придерживайтесь [общих правил типизации проекта](#общие-правила-типизации). - Не используйте неявное приведение типов и не полагайтесь на автоматический вывод, если это может снизить читаемость или безопасность. ### Документирование - Документируйте только назначение хука (описание), строго по [правилам документирования кода](#правило-для-документирования-кода). ### Экспорт - Экспортируйте хук только именованным экспортом через `index.ts` слоя/компонента. ### Пример API хука ```ts // use-get-me.hook-api.ts import useSWR from 'swr'; import { backendFetcher } from 'shared/api/backend/client'; import { UserDto } from 'shared/api/backend/entities/users/get-me.api'; /** * Хук для получения информации о текущем пользователе. */ export const useGetMe = () => { const { data, error, isLoading } = useSWR('/users/me', backendFetcher); return { data, error, isLoading, }; }; ``` #### Пример использования хука в компоненте ```tsx import React from 'react'; import { useGetMe } from 'shared/hooks/api/backend/use-get-me.hook-api'; export const UserInfo: React.FC = () => { const { data, error, isLoading } = useGetMe(); if (isLoading) { return
Загрузка...
; } if (error) { return
Ошибка загрузки данных
; } if (!data) { return
Нет данных о пользователе
; } return (
Имя: {data.name}
Email: {data.email}
); }; ``` ### Чек-лист для создания API-хука - [ ] Для каждого GET-запроса создан отдельный хук. - [ ] Хук размещён в `hooks/api//use-.hook-api.ts` на своём уровне абстракции согласно архитектуре проекта. - [ ] Именование файлов и сущностей соответствует [правилам именования файлов и папок](#правила-именования-файлов-и-папок). - [ ] Используется SWR для получения данных. - [ ] Все параметры, возвращаемые значения и внутренние переменные строго типизированы. - [ ] Нет дублирования логики между хуками. - [ ] Не используются side-effects вне useEffect/useLayoutEffect. - [ ] Документировано только назначение хука (см. [правила документирования кода](#правило-для-документирования-кода)). - [ ] Нет неиспользуемого или невалидного кода. - [ ] Экспорт только именованный через индексный файл. --- ### Чек-лист для использования API-хука - [ ] Импортируется только нужный хук через публичные экспорты (`index.ts`). - [ ] Использование хука строго по назначению (только для получения данных). - [ ] Если требуется получить данные через GET-запрос в компоненте — обязательно используется соответствующий API-хук. **Запрещено вызывать GET-методы API напрямую в компонентах, только через хуки.** - [ ] Обработка состояний загрузки, ошибки и данных реализована корректно. - [ ] Не происходит дублирования логики, связанной с получением данных. - [ ] Нет неиспользуемого или невалидного кода. ## API > В этом разделе собраны основные правила и рекомендации по созданию, оформлению и использованию API-клиентов и функций для работы с сервером. Следуйте этим принципам, чтобы обеспечить единый стиль, безопасность и удобство поддержки API-слоя в проекте. ### Описание и назначение API-клиента API-клиент — это модуль (папка), отвечающий за взаимодействие с конкретным внешним или внутренним API. В проекте для HTTP-запросов используется только Axios. API-клиент инкапсулирует: - инициализацию экземпляра Axios, - настройку базового URL, интерцепторов, обработчиков ошибок, - организацию всех сущностей и методов для работы с этим API (например, users, auth, orders и т.д.), - экспорт всех функций, типов и fetcher через индексные файлы. Каждый API-клиент размещается в папке `src/shared/api//` и имеет собственную структуру согласно архитектуре проекта. --- ### Использование методов API - Все методы API должны использоваться строго внутри блока `try...catch`. - При вызове методов API всегда используйте полный путь, например: `await api.backend.createUser({ email, password });` - Запрещено вызывать методы API вне блока `try...catch` даже в тестах, утилитах и других вспомогательных функциях. --- ### Структура клиента ```text src/shared/api/backend/ │ ├── client.ts ├── index.ts └── entities/ ├── users/ │ ├── get-me.api.ts │ ├── create-user.api.ts │ ├── update-user.api.ts │ └── index.ts ├── auth/ │ ├── login.api.ts │ ├── register.api.ts │ └── index.ts └── index.ts ``` ### Описание ключевых элементов - **client.ts** Экземпляр Axios с настройками, интерцепторами, экспортом fetcher для SWR. - **index.ts** Главная точка экспорта: экспортирует client, fetcher, все сущности и их методы. - **entities/** Папка для бизнес-сущностей (например, users, auth, orders и т.д.). - **/** Папка для отдельной сущности. Имя — в kebab-case, отражает бизнес-область (например, users, auth). - **.api.ts** Файл для каждой операции (CRUD, спец. действия). Внутри: - DTO (интерфейсы запроса/ответа) - Функция, реализующая запрос через client - **index.ts (внутри /)** Экспортирует все методы и типы этой сущности. - **index.ts (внутри entities/)** Экспортирует все сущности (users, auth и т.д.). --- ### Именование - Соблюдайте [правила именования файлов и папок](#правила-именования-файлов-и-папок): - Файл клиента — `client.ts`. - Файл функции — `-.api.ts` (например, `create-user.api.ts`). - DTO — в папке `dto/` (например, `create-user.dto.ts`). - Все функции и типы экспортируются через индексные файлы на каждом уровне (сущность, entities, клиент). --- ### Требования - Для каждого действия (CRUD, спец. действия) — отдельная функция и файл. - Все функции используют общий экземпляр Axios из `client.ts`. - Все функции строго типизированы (используются DTO). - DTO объявляется в отдельном файле в папке `dto/` перед функцией, которая его использует. - Для каждого GET метода обязательно должен быть создан API-хук. - Все API-хуки должны создаваться строго по [документации раздела "Хуки для API"](#хуки-для-api-api-hooks). --- ### Типизация - Все функции и DTO строго типизированы. - Все интерфейсы, типы и enum размещены в папке `types/` на своём уровне абстракции. - Все DTO размещены в папке `dto/` на своём уровне абстракции. - Придерживайтесь [общих правил типизации проекта](#общие-правила-типизации). --- ### Документирование - Документируйте только назначение функций и DTO, строго по [правилам документирования кода](#правило-для-документирования-кода). - В описании указывается только смысл функции/типа. --- ### Экспорт - Все функции и типы экспортируются через индексные файлы на каждом уровне (сущность, entities, клиент). --- ### Примеры #### Пример клиента API ```ts // client.ts import axios, { AxiosInstance } from "axios"; export { AxiosError, isAxiosError } from 'axios'; export type { AxiosResponse } from 'axios'; /** * Экземпляр HTTP-клиента для работы с backend API. */ export const backendHttpClient: AxiosInstance = axios.create({ baseURL: '/api', timeout: 10000, }); // Интерцептор запроса backendHttpClient.interceptors.request.use( (config) => { // Здесь можно добавить авторизационные заголовки или другую логику return config; }, (error) => Promise.reject(error) ); // Интерцептор ответа backendHttpClient.interceptors.response.use( (response) => response, (error) => { // Здесь можно обработать ошибки (например, показать уведомление) return Promise.reject(error); } ); ``` #### Пример DTO ```ts // dto/create-user.dto.ts /** * DTO для создания пользователя. */ export interface CreateUserDto { /** Email пользователя. */ email: string; /** Пароль пользователя. */ password: string; } ``` #### Пример API-функции ```ts // create-user.api.ts import { backendHttpClient } from '../client'; import { CreateUserDto } from './dto/create-user.dto'; /** * Создать пользователя. */ export const createUser = (data: CreateUserDto) => backendHttpClient.post('/users', data); ``` #### Пример index.ts (в папке сущности) ```ts export * from './create-user.api'; export * from './get-user.api'; ``` #### Пример использования API-функции в компоненте ```tsx import React, { useState } from 'react'; import { api } from 'shared/api'; export const CreateUserForm: React.FC = () => { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { await api.backend.createUser({ email, password }); console.log('Пользователь создан!'); } catch { console.log('Ошибка создания пользователя'); } }; return (
setEmail(e.target.value)} placeholder="Email" required /> setPassword(e.target.value)} placeholder="Пароль" required />
); }; ``` --- ### Чек-лист для создания клиента - [ ] Новый клиент размещён в src/shared/api//. - [ ] В корне клиента есть client.ts (экземпляр Axios) и index.ts (главный экспорт). - [ ] Все бизнес-сущности размещены в entities/, каждая — в отдельной папке. - [ ] Для каждой операции создан отдельный файл .api.ts с DTO и функцией. - [ ] DTO объявлен непосредственно перед функцией. - [ ] В каждой папке сущности есть свой index.ts для экспорта методов и типов. - [ ] В папке entities/ есть общий index.ts для экспорта всех сущностей. - [ ] Все экспорты организованы через индексные файлы. - [ ] Для каждого GET-метода создан отдельный SWR-хук (см. правила API-хуков). - [ ] Нет дублирования кода и неиспользуемых файлов. ### Чек-лист для использования API - [ ] Импортируется только нужный метод через публичные экспорты (index.ts). - [ ] Все вызовы API обёрнуты в try...catch. - [ ] Используются только строго типизированные методы. - [ ] Не происходит обращения к Axios напрямую — только через client. - [ ] Нет дублирования логики и неиспользуемого кода.