mirror of
https://github.com/smmarty/friflex_flutter_starter.git
synced 2025-12-22 09:30:45 +00:00
docs(cursorrules,copilot-instructions): обновить правила разработки и нструкции для AI-агента (#41)
This commit is contained in:
427
.github/copilot-instructions.md
vendored
427
.github/copilot-instructions.md
vendored
@@ -1,63 +1,390 @@
|
||||
Инструкция для AI-агента (ревью Flutter-кода)
|
||||
# Правила разработки Flutter проекта
|
||||
|
||||
Вы — строгий ревьюер кода Flutter-приложения по принципам **Clean Architecture**.
|
||||
Ваша задача — проводить ревью кода, выявлять ошибки и давать корректные рекомендации.
|
||||
Bloc и Cubit должны находиться в слое domain.
|
||||
Контекст (справочно, не включать в ответ):
|
||||
- Архитектура: три слоя (presentation, domain, data), каждый в своей папке.
|
||||
- State management: flutter_bloc.
|
||||
- Навигация: go_router.
|
||||
- HTTP: dio.
|
||||
- Анализатор: flutter_lint_rules.
|
||||
- Feature-first структура: lib/features/<feature_name>/{data,domain,presentation}.
|
||||
Этот файл содержит правила и стандарты разработки для проекта. Все правила обязательны к соблюдению при написании кода.
|
||||
|
||||
---
|
||||
## Обзор запроса на вытягивание
|
||||
1. В начале ответа укажите решение: **«Принять»** или **«Отклонить»**.
|
||||
2. Укажите оценку: **Оценка: X/100** (X — фактический балл).
|
||||
3. Кратко и строгим тоном перечислите ключевые проблемы:
|
||||
- Архитектура (слои `presentation`, `domain`, `data`).
|
||||
- Принципы **DRY, KISS, SOLID**.
|
||||
- Разделение ответственности (BLoC, репозитории, DTO, UI).
|
||||
- Безопасность (`dio`, SSL, валидация данных).
|
||||
- Кодстайл и соглашения (`flutter_lint_rules`).
|
||||
- Цикломатическая сложность: избегать чрезмерно сложных функций и классов (оптимально ≤ 10).
|
||||
|
||||
4. При необходимости предоставьте исправленный фрагмент кода или улучшенное решение.
|
||||
5. Ответ должен быть в **Markdown** и полностью на **русском языке**.
|
||||
**ВАЖНО:** Перед каждым PR необходимо отформатировать код (`dart format .`) и проверить анализатор на отсутствие сообщений (`dart analyze`).
|
||||
|
||||
---
|
||||
|
||||
## Критерии оценки
|
||||
- **Чистая архитектура**: корректное разделение слоёв, отсутствие Flutter-зависимостей в `domain`.
|
||||
- **KISS**: минимальная сложность и читаемость решений.
|
||||
- **DRY**: отсутствие дублирования логики, использование утилит/виджетов.
|
||||
- **SOLID**: правильная декомпозиция классов и интерфейсы вместо жёстких связей.
|
||||
- **Безопасность**: корректная работа с API, валидация данных.
|
||||
- **Кодстайл**: именование, структура файлов и папок.
|
||||
- **Цикломатическая сложность**: методы и классы должны быть простыми, без избыточных ветвлений.
|
||||
# Стиль кода
|
||||
|
||||
## Именование
|
||||
|
||||
---
|
||||
### Интерфейсы
|
||||
|
||||
## Пример ответа
|
||||
**Отклонить**
|
||||
**Оценка: 58/100**
|
||||
- Нарушен принцип DRY: HTTP-запрос продублирован в двух репозиториях.
|
||||
- BLoC перегружен бизнес-логикой (трансформация DTO → Entity должна быть в `data`).
|
||||
- Domain-слой содержит зависимость от Flutter — это недопустимо.
|
||||
- Отсутствует обработка ошибок и валидация данных в `dio`.
|
||||
Все интерфейсы в приложении должны начинаться с заглавной буквы "**I**".
|
||||
|
||||
Примеры: **IAuthRepository**, **IProfileRepository**, **IMainRunner** и т.д.
|
||||
|
||||
Таким образом, сразу видно, что работаешь с интерфейсом.
|
||||
|
||||
Пример:
|
||||
|
||||
**Исправленный фрагмент:**
|
||||
```dart
|
||||
// Вместо дублирования запроса используем общий DataSource
|
||||
class UserRemoteDataSource {
|
||||
final Dio dio;
|
||||
UserRemoteDataSource(this.dio);
|
||||
/// Интерфейс - **IUserRepository**
|
||||
abstract interface class IUserRepository {}
|
||||
|
||||
Future<UserEntity> fetchUser(String id) async {
|
||||
final response = await dio.get('/users/$id');
|
||||
return UserDto.fromJson(response.data).toEntity();
|
||||
}
|
||||
/// Основная реализация (prod и stage окружения)
|
||||
class UserRepository implements IUserRepository {}
|
||||
|
||||
/// Иная реализация (мок, локальное хранилище) должна содержать
|
||||
/// постфикс функциональности:
|
||||
/// - Network - сетевое взаимодействие.
|
||||
/// - Local - локальное хранилище.
|
||||
/// - Mock - мок репозиторий.
|
||||
class UserRepositoryLocal implements IUserRepository {}
|
||||
```
|
||||
|
||||
### Классы - Репозитории
|
||||
|
||||
Репозитории должны содержать в конце название источника данных (если используется мок или локальное хранилище). Основная реализация не должна содержать постфикса.
|
||||
|
||||
Примеры:
|
||||
- Интерфейс - **IAuthRepository**
|
||||
- Основная реализация (prod и stage окружения) - **AuthRepository**
|
||||
- Мок (мок данные) - **AuthRepositoryMock**
|
||||
- Локальное хранилище (например бд или просто имитация данных) - **AuthRepositoryLocal**
|
||||
|
||||
### Файлы
|
||||
|
||||
Используется snake_case. Название файла должно иметь следующую структуру: `[раздел]_[тип].dart`
|
||||
|
||||
Примеры: `user_details_screen.dart`, `shop_entity.dart`
|
||||
|
||||
### Классы
|
||||
|
||||
Название классов UpperCamelCase. Для создания приватных классов используем префикс `_`. Название класса в конце должно содержать в себе тип.
|
||||
|
||||
Примеры: **UserEntity**, **AdultDialog**
|
||||
|
||||
## Методы
|
||||
|
||||
Название метода в начале должно содержать в себе действие (глагол):
|
||||
|
||||
- fetch
|
||||
- put
|
||||
- update
|
||||
- delete
|
||||
- и так далее
|
||||
|
||||
Примеры:
|
||||
|
||||
```dart
|
||||
int fetchFirstElement() {}
|
||||
```
|
||||
|
||||
```dart
|
||||
void updateFirstElement() {}
|
||||
```
|
||||
|
||||
**ВАЖНО:** Название метода не должно содержать в себе `And`/`Or`, и метод соответственно не должен выполнять подобную логику.
|
||||
|
||||
## Переменные и константы
|
||||
|
||||
Константы именуются также lowerCamelCase.
|
||||
|
||||
Примеры:
|
||||
|
||||
```dart
|
||||
const String carItem = 'default';
|
||||
```
|
||||
|
||||
или
|
||||
|
||||
```dart
|
||||
final String userName = 'user';
|
||||
```
|
||||
|
||||
## Виджеты
|
||||
|
||||
Виджеты именуются UpperCamelCase. В названии виджетов не должно содержаться слово `widget`.
|
||||
|
||||
### Экраны
|
||||
|
||||
Экраны, используемые в роутинге, именуются с постфиксом `Screen`.
|
||||
|
||||
Пример: **ShopListScreen**
|
||||
|
||||
### Содержимое экрана
|
||||
|
||||
Виджеты, отображающие содержимое экрана, именуются с постфиксом `View`.
|
||||
|
||||
Пример: **ShopListView**
|
||||
|
||||
### Глобальные виджеты
|
||||
|
||||
Глобальные виджеты именуются с приставкой `App`.
|
||||
|
||||
Пример: **AppButton**
|
||||
|
||||
## Структура класса
|
||||
|
||||
Объявления элементов класса должны располагаться в следующем порядке:
|
||||
|
||||
1. **Constructors**
|
||||
- constructors
|
||||
- named-constructors
|
||||
- factory-constructors
|
||||
2. **Static**
|
||||
- public-static-methods
|
||||
- private-static-methods
|
||||
- public-static-const-fields
|
||||
- private-static-const-fields
|
||||
- public-static-final-fields
|
||||
- private-static-final-fields
|
||||
- public-static-fields
|
||||
- private-static-fields
|
||||
3. **Fields**
|
||||
- public-final-fields
|
||||
- private-final-fields
|
||||
- public-fields
|
||||
- private-fields
|
||||
4. **Getters/Setters**
|
||||
- public-getters-setters
|
||||
- private-getters-setters
|
||||
5. **Methods**
|
||||
- overridden-methods
|
||||
- public-methods
|
||||
- protected-methods
|
||||
- private-methods
|
||||
|
||||
---
|
||||
|
||||
# Ведение документации и комментариев
|
||||
|
||||
## Документация
|
||||
|
||||
### Основные правила ведения документации в проекте
|
||||
|
||||
- Документация оформляется над описываемым объектом с использованием `///`
|
||||
- Документацией необходимо покрывать все классы, конструкторы, поля, геттеры, сеттеры, методы, фабрики, все кастомные объекты
|
||||
- Документация должна:
|
||||
- указывать на назначение объекта
|
||||
- содержать исчерпывающее описание объекта
|
||||
- быть краткой и емкой
|
||||
- быть понятной для любого разработчика
|
||||
|
||||
### Шаблоны и примеры документации объектов
|
||||
|
||||
#### Документация классов
|
||||
|
||||
```dart
|
||||
/// {@template new_class}
|
||||
/// Класс для {описание назначения и реализуемого функционала в классе}.
|
||||
/// {@endtemplate}
|
||||
class NewClass {}
|
||||
```
|
||||
|
||||
Пример:
|
||||
|
||||
```dart
|
||||
/// {@template app_button}
|
||||
/// Класс для реализации кастомизированной кнопки.
|
||||
/// {@endtemplate}
|
||||
class AppButton {}
|
||||
```
|
||||
|
||||
#### Документация конструкторов и фабрик
|
||||
|
||||
Если конструктор один, то достаточно указать `{@macro new_class}`. `{@macro new_class}` дублирует на конструктор указанную в рамках описания класса документацию, поэтому описание класса должно в таком случае включать все передаваемые в конструктор параметры.
|
||||
|
||||
Если конструкторов несколько, описания должны отражать их отличия друг от друга. Фабрики описываются по такому же принципу.
|
||||
|
||||
```dart
|
||||
/// {@macro new_class}
|
||||
const NewClass();
|
||||
|
||||
/// Создает {описание создаваемого фабрикой объекта}.
|
||||
/// Принимает:
|
||||
/// - [json] - {описание параметра}
|
||||
factory NewClass.fromJson(Map<String, dynamic> json) {}
|
||||
```
|
||||
|
||||
#### Документация полей классов
|
||||
|
||||
В классе необходимо описывать каждое поле по отдельности. Если поле ссылается на другое поле или зависит от него, необходимо это указывать в описании.
|
||||
|
||||
```dart
|
||||
/// Возраст пользователя.
|
||||
final int age;
|
||||
|
||||
/// Индикатор совершеннолетия пользователя. Принимает значение true, когда [age] больше 18 лет.
|
||||
final bool isAdult;
|
||||
```
|
||||
|
||||
#### Документация геттеров/сеттеров
|
||||
|
||||
```dart
|
||||
/// Получения доступа к {описание данных, которые получает геттер}
|
||||
int get newGetter => ...
|
||||
|
||||
/// Установка значения для {описание работы сеттера}
|
||||
set newSetter(int setterValue) => ...
|
||||
```
|
||||
|
||||
#### Документация методов
|
||||
|
||||
Методы должны описывать их основное назначение. Если метод сложный, требуется указывать дополнительное описание его работы ниже через пропущенную строку. Если метод принимает какие-либо параметры, каждый параметр должен быть описан по отдельности списком с прямой ссылкой. Если метод возвращает какие-либо значения, они должны быть описаны. Желательно указать, что вернет метод в случае возникновения ошибки.
|
||||
|
||||
```dart
|
||||
/// Метод для {описание назначения метода}.
|
||||
/// {описание особенностей работы метода}.
|
||||
/// Принимает:
|
||||
/// - [param] - {описание назначения параметра}.
|
||||
void newMethod({required String param}) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Пример:
|
||||
|
||||
```dart
|
||||
/// Метод для расчета температуры.
|
||||
/// Принимает:
|
||||
/// - [grad] - параметр необходим для расчета температуры.
|
||||
/// Возвращает:
|
||||
/// - температуру в градусах.
|
||||
/// При ошибке расчета возвращается null.
|
||||
int? calcTemperature({required int grad}) {
|
||||
// Реализация
|
||||
}
|
||||
```
|
||||
|
||||
## Комментарии
|
||||
|
||||
### Основные правила комментирования кода в проекте
|
||||
|
||||
- Комментарии оформляются над описываемым участком кода с использованием `//`
|
||||
- Комментировать необходимо те участки кода, которые действительно нуждаются в дополнительном описании
|
||||
- Комментарий не должен повторять легко читаемые участки кода
|
||||
|
||||
Примеры неправильного использования:
|
||||
|
||||
```dart
|
||||
if (flag != true) // не нужно описывать как "Если значение не равно true..."
|
||||
```
|
||||
|
||||
Примеры правильного использования:
|
||||
|
||||
```dart
|
||||
if (isAurora) {
|
||||
// Так как Аврора не может открывать WebView,
|
||||
// то заменяем на открытие внешнего браузера
|
||||
}
|
||||
```
|
||||
|
||||
## TODO
|
||||
|
||||
### Основные правила создания TODO в проекте
|
||||
|
||||
- TODO оформляются согласно условиям форматирования линтера с указанием имени разработчика, кто находится в контексте проблемы и сможет ее прокомментировать
|
||||
- TODO необходимо оставлять на тех участках кода, которые требуют дальнейшей доработки
|
||||
- Если известно, в рамках какой задачи будет доработан помечаемый участок кода, ссылку на задачу необходимо оставить в скобках
|
||||
|
||||
Пример:
|
||||
|
||||
```dart
|
||||
// TODO(username): Оптимизировать алгоритм сортировки
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Ведение проекта в git
|
||||
|
||||
## Создание commits/pull-request
|
||||
|
||||
- Язык описания PR - Русский
|
||||
- Описание должно отражать краткую суть изменений
|
||||
- Коммит/PR должен содержать:
|
||||
- исчерпывающую информацию об изменениях
|
||||
- ссылку на задачу в таск-трекер
|
||||
- Перечисление deprecated-кода (если есть)
|
||||
|
||||
### Типы коммитов согласно convention
|
||||
|
||||
- **feat**: — новая функция
|
||||
- **fix**: — исправление ошибок
|
||||
- **refactor**: — Изменение кода, которое не исправляет ошибку и не добавляет функции (рефакторинг кода)
|
||||
- **build**: — изменения, влияющие на систему сборки или внешние зависимости (примеры областей (scope): android, ios, linux и так далее)
|
||||
- **docs**: — изменения только в документации
|
||||
- **chore**: — добавление/обновление/настройка инструментов и библиотек (пример: pubspec.yaml)
|
||||
- **test**: — добавление недостающих тестов или исправление существующих тестов
|
||||
- **ci**: — изменения в файлах конфигурации и скриптах CI (примеры областей: папка CI)
|
||||
|
||||
# Структура проекта
|
||||
|
||||
Рекомендуемая структура проекта (может отличаться в зависимости от проекта и согласований)
|
||||
|
||||
- **/** - папка проекта
|
||||
- **/assets** - директория расположения графических ресурсов
|
||||
- **/tools/** - все необходимые инструменты для проекта
|
||||
- **/docs** - документация проекта
|
||||
- **/env** - папка, с внешними переменными окружения
|
||||
- **/lib** - код на Dart, Flutter-приложение
|
||||
- **/app** - содержит основные настройки нашего приложения
|
||||
- **/data** - общие поставщики данных
|
||||
- **/domain** - общий слой
|
||||
- **/presentation** - общий слой
|
||||
- **/di** - файлы конфигурации зависимостей
|
||||
- **/router** - все, что касается роутинга
|
||||
- **/features** - фичи приложения, для каждой фичи создается отдельная папка
|
||||
- **/feature_name** - подробнее см в разделе Структура feature папок
|
||||
- **/data**
|
||||
- **/domain**
|
||||
- **/presentation**
|
||||
- **/gen** - для сгенерированных файлов
|
||||
- **/targets** - таргеты для сборок
|
||||
- **/prod.dart** - сборка для prod
|
||||
- **/dev.dart** - сборка разработки на моковых репозиториях
|
||||
- **/stage.dart** - сборка для stage окружения
|
||||
|
||||
## Пример структуры feature папок
|
||||
|
||||
- **/data** - слой данных
|
||||
- **/dto** - реализация DTO (data transfer object)
|
||||
- **/repository** - реализации репозиториев
|
||||
- **/domain** - слой бизнес логики
|
||||
- **/entity** - модели которые используются для работы в domain/presentation слоях
|
||||
- **/repository** - интерфейсы репозиториев, которые используются в domain слое
|
||||
- **/state** - state-management
|
||||
- **/service** - реализации сервисов
|
||||
- **/presentation** - слой представления
|
||||
- **/screens** - все экраны должны заканчиваться на Screen, например UserProfileScreen
|
||||
- **/components** - виджеты, которые необходимы для работы в presentation слое. Например: SuperButton, AppTextFields итд
|
||||
|
||||
## Пояснение к структуре feature папок
|
||||
|
||||
### Data (слой данных)
|
||||
|
||||
Этот слой является поставщиком данных.
|
||||
|
||||
- **Repository** - сущность, которая реализует внутри себя предоставление данных. Должен реализовывать какой либо интерфейс репозитория из domain слоя
|
||||
- **DTO** - Dto(Data Transfer Object) модели, и модели с которыми происходит работа в data слое. Например: UserDto
|
||||
|
||||
### Domain (слой бизнес логики)
|
||||
|
||||
- **Entity** - должны быть в максимально удобном виде для работы внутри Domain и Presentation. Например: UserEntity, ShopEntity
|
||||
- **State** - управления состоянием - state manager
|
||||
- **Service** - различные сервисы, для выполнения различных задач
|
||||
- **interfaces** - интерфейсы репозиториев, которые используются в domain слое
|
||||
|
||||
### Presentation (слой представления)
|
||||
|
||||
- **components** - widget'ы которые реализуют работу какого либо визуального компонента (Buttons, TextFields, Lists, итд). Например: ShopList, RateButton. Модальные окна
|
||||
- **screens** - widget'ы которые представляют собой экран приложения. Например: UserInfoScreen
|
||||
|
||||
## Основные правила общения объектов между папками
|
||||
|
||||
### В рамках всего приложения
|
||||
|
||||
- Объекты внутри фичи должны быть инкапсулированы и не могут использоваться в других feature
|
||||
- Если есть необходимость использовать объект в нескольких feature, его нужно вынести в папку app и использовать как глобальный для всего приложения
|
||||
- Сервис, который должен быть использован в нескольких feature, создается как отдельная feature
|
||||
- Если создаваемый сервис является платформно-зависимым, его необходимо выносить в app_services. В приложении должен быть только интерфейс
|
||||
|
||||
### В рамках одной feature
|
||||
|
||||
- Объекты data слоя не должны ничего знать про объекты слоя presentation. Имеют доступ к объектам entity из domain слоя для преобразования DTO в Entity
|
||||
- Объекты domain слоя не должны ничего знать про объекты слоя data, используемый экземпляр репозитория передается в объекты domain слоя через интерфейс репозитория, расположенного в этом же domain слое
|
||||
- Объекты domain слоя не должны ничего знать про слой presentation, не должны использовать компоненты библиотек ui, material, cupertino, widget и прочих, не должны использовать context
|
||||
- Объекты presentation слоя не должны ничего знать про объекты слоя data, все взаимодействия непосредственно через объекты слоя domain
|
||||
|
||||
Reference in New Issue
Block a user