From 8d16a2acab5711ac06b14c9091ebef1fe754b113 Mon Sep 17 00:00:00 2001 From: "S.Gromov" Date: Fri, 30 Jan 2026 02:10:51 +0300 Subject: [PATCH] sync --- .cursorrules | 1211 -------------------------------------------------- README.md | 2 +- index.md | 2 +- 3 files changed, 2 insertions(+), 1213 deletions(-) delete mode 100644 .cursorrules diff --git a/.cursorrules b/.cursorrules deleted file mode 100644 index 22eb064..0000000 --- a/.cursorrules +++ /dev/null @@ -1,1211 +0,0 @@ - - - -## Для ассистента - -- Всегда используй Русский язык для общения и генерации документации/комментариев/коммитов. -- Всегда следуй этим правилам при генерации кода и ответах. -- Всегда пиши план действий перед генерацией кода. -- Всегда спрашивай разрешения у пользователя перед генерацией кода. -- Всегда проверяй, что код соответствует линтингу и форматированию. -- Всегда сверяйся с чек-листом при генерации кода. -- Не предлагай решения, которые противоречат этим правилам этого файла. -- Если не уверен — уточни у пользователя, не гадай, не придумывай. - ---- - - - - -## Обязательность чек-листов - -- Все чек-листы, приведённые в правилах, обязательны к исполнению. -- Ассистент обязан сверяться с чек-листом при выполнении любой задачи, связанной с кодом. -- Нельзя сокращать, игнорировать или опускать пункты чек-листа — каждый пункт должен быть выполнен или явно отмечен как невыполнимый с объяснением причины. -- В каждом ответе, связанном с генерацией или изменением кода, ассистент обязан ссылаться на соответствующий чек-лист и подтверждать его выполнение. - ---- - - - - -## Общие принципы - -- Использовать **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. -- [ ] Нет дублирования логики и неиспользуемого кода. diff --git a/README.md b/README.md index 59fad15..07b40bb 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Код-стайл для фронтенд-проектов на React/NextJS и TypeScript +# Frontend Style Guide для проектов на React/Next.js и TypeScript Этот репозиторий содержит документацию с правилами разработки фронтенд-проектов на React/NextJS и TypeScript. diff --git a/index.md b/index.md index e0e2343..4bc5ed0 100644 --- a/index.md +++ b/index.md @@ -11,4 +11,4 @@ ## Для ассистентов Для передачи ассистенту используйте сконкатенированную версию документации: -https://gromlab.ru/docs/react-ts. +https://gromlab.ru/docs/frontend-style-guide/raw/branch/main/RULES.md