diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..7a57d68 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,18 @@ +## Ссылка на задачу или issue (обязательно) + + +## Описание (обязательно) + + +## Чек лист (обязательно) +- [ ] Код соответствует рекомендациям и требованиям проекта. +- [ ] Анализатор проверил на предмет ошибок и предупреждений. +- [ ] Название ПР соответствует [требованиям проекта](../tools/rfc/RFC-documentation.md). +- [ ] В документации отражены внесенные изменения. +- [ ] Добавлены необходимые тесты, если требуется. + +## Скриншоты (желательно) +
+ Показать + +
\ No newline at end of file diff --git a/CODEOWNERS b/CODEOWNERS index 7e9c3e6..e90983b 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,3 +1 @@ -.github/* @ns @sna2021 -**/.gitlab-ci.yml @ns @sna2021 - +Friflex LCC \ No newline at end of file diff --git a/README copy.md b/README copy.md deleted file mode 100644 index cbdd835..0000000 --- a/README copy.md +++ /dev/null @@ -1,16 +0,0 @@ -# friflex_starter - -A new Flutter project. - -## Getting Started - -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) - -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. diff --git a/README.md b/README.md index 16b56d1..c025037 100644 --- a/README.md +++ b/README.md @@ -1 +1,30 @@ -# friflex_starter \ No newline at end of file +#### Приложение [ProjectName] + +## Структура проекта + - проект архитектурно делится на три слоя: data, domain и presentation; + - все [features] реализуются в отдельных папках, с внутренним делением на слои; + +## Основные пакеты и реализации (обновляется при добавлении или изменении) + - управление роутингом: [go_router](https://pub.dev/packages/go_router); + - основной state manager: [flutter_bloc](https://pub.dev/packages/flutter_bloc); + - di: ручная реализация через InheritedWidget; + - работа с ресурсами: [flutter_gen](https://pub.dev/packages/flutter_gen); + - анализатор: используем [friflex_lint_rules](https://pub.friflex.com/packages/friflex_lint_rules), с правилами написания кода от компании.; + - для хранения защищенных данных - [flutter_secure_storage](https://pub.dev/packages/flutter_secure_storage); + - для хранения данных - [shared_preferences](https://pub.dev/packages/shared_preferences); + - для работы с API - [dio](https://pub.dev/packages/dio); + +## Инструкция по запуску проекта + - [Инструкция по запуску проекта](./tools/rfc/RFC-build.md) + +## Стиль написания кода + - [Стиль написания кода](./tools/rfc/RFC-codestyle.md) + +## Внесение изменений в код + - [Внесение изменений в код](./tools/rfc/RFC-gitflow.md) + +## Структура проекта + - [Структура проекта](./tools/rfc/RFC-projects_structure.md) + +## Ведение документации и комментариев в проекте + - [Ведение документации и комментариев в проекте](./tools/rfc/RFC-documentation.md) \ No newline at end of file diff --git a/tools/.sh b/tools/.sh new file mode 100644 index 0000000..439dcbf --- /dev/null +++ b/tools/.sh @@ -0,0 +1,3 @@ +format code + +dart format --output=none --set-exit-if-changed . \ No newline at end of file diff --git a/tools/res/images/developing.jpg b/tools/res/images/developing.jpg new file mode 100644 index 0000000..0edfd74 Binary files /dev/null and b/tools/res/images/developing.jpg differ diff --git a/tools/res/images/release.jpg b/tools/res/images/release.jpg new file mode 100644 index 0000000..cae7d61 Binary files /dev/null and b/tools/res/images/release.jpg differ diff --git a/tools/rfc/RFC-build.md b/tools/rfc/RFC-build.md new file mode 100644 index 0000000..79f1ba9 --- /dev/null +++ b/tools/rfc/RFC-build.md @@ -0,0 +1,2 @@ +# Инструкция по запуску + \ No newline at end of file diff --git a/tools/rfc/RFC-codestyle.md b/tools/rfc/RFC-codestyle.md new file mode 100644 index 0000000..d5c7bde --- /dev/null +++ b/tools/rfc/RFC-codestyle.md @@ -0,0 +1,124 @@ +# Стиль кода + +Мы придерживаемся рекомендаций, описанных в +[Effective Dart](https://dart.dev/guides/language/effective-dart/design) + +Перед каждым PR необходимо отформатировать код и проверить анализатор на отсутствие сообщений. + +## Именование + +### Интерфейсы +Утверждены два вида объявления интерфейсов: +1. Все интерфейсы в приложении должны начинаться с заглавной буквы "**I**". + +Например: **IAuthRepository**, **IProfileRepository**, **IMainRunner** и т.д. + +Таким образом, сразу видно, что работаешь с интерфейсом. +Пример: +```dart +/// Интерфейс - **IUserRepository** +abstract interface class IUserRepository {} +/// Основная реализация (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 +``` +или +```dart +final userName; +``` +## Виджеты +Виджеты именуются 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 diff --git a/tools/rfc/RFC-documentation.md b/tools/rfc/RFC-documentation.md new file mode 100644 index 0000000..13336c5 --- /dev/null +++ b/tools/rfc/RFC-documentation.md @@ -0,0 +1,113 @@ +# Ведение документации и комментариев + +## Документация + +### Основные правила ведения документации в проекте: +- документация оформляется над описываемым объектом с использованием '///'; +- документацией необходимо покрывать все классы, конструкторы, поля, геттеры, сеттеры, методы, фабрики, все кастомные объекты; +- документация должна: + - указывать на назначение объекта; + - содержать исчерпывающее описание объекта; + - быть краткой и емкой; + - быть понятной для любого разработчика. + +## Шаблоны и примеры документации объектов + +### Документация классов: +```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 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 необходимо оставлять на тех участках кода, которые требуют дальнейшей доработки; +- если известно, в рамках какой задачи будет доработан помечаемый участок кода, ссылку на задаче необходимо оставить в скобках. \ No newline at end of file diff --git a/tools/rfc/RFC-gitflow.md b/tools/rfc/RFC-gitflow.md new file mode 100644 index 0000000..648be57 --- /dev/null +++ b/tools/rfc/RFC-gitflow.md @@ -0,0 +1,60 @@ +# Ведение проекта в git + +## Создание commits/pull-request +- язык описания PR - Русский; +- описание должно отражать краткую суть изменений; +- коммит/PR должен содержать: + - исчерпывающую информацию об изменениях; + - ссылку на задачу в таск-трекер; + - Перечисление deprecated-кода (если есть). +### Типы коммитов согласно convention +* **feat**: — новая функция +* **fix**: — исправление ошибок +* **refactor**: — Изменение кода, которое не исправляет ошибку и не добавляет функции (рефакторинг кода). +* **build**: — изменения, влияющие на систему сборки или внешние зависимости (примеры областей (scope): android, ios, linux и так далее). +* **docs**: — изменения только в документации +* **chore** - добавление/обновление/настройка инструментов и библиотек (пример: pubspec.yaml). +* **test**: — добавление недостающих тестов или исправление существующих тестов. +* **ci**: — изменения в файлах конфигурации и скриптах CI (примеры областей: папка CI). + +### Правила именования веток + +Имена веток должны соответствовать convention, чтобы обеспечить консистентность и читаемость. + +- Ветки feature должны начинаться с `feat/`. +- Ветки hotfix должны начинаться с `fix/` и так далее +- Используйте номер задачи из таск-трекера в имени ветки. +- Добавьте краткое описание задачи, используя snake_case или kebab-case. + +Пример: + +* `feat/PRIME-123_authentication` +* `fix/PRIME-456_typo_in_button` +* `fix/PRIME-456-typo-in-button` + +## Схема разработки новой features +![](./tools/res/images/developing.jpg) + +## Создание релиза +![](./tools/res/images/release.jpg) + +### Добавление новых features + - создаем ветку feat/(уникальный номер задачи) (название feature), +Пример: PRIME-17 Добавить_локальный_репозиторий; + - вносим изменения; + - делаем коммит только на то, что касается изменений связанных с этой задачей; + - по завершению задачи - создаем Pull Request с названием по правилам https://commitlint.io/. + Пример: feat(app,di,auth,scripts,pubspec): PRIME-17 Добавить локальный репозиторий. + Где, PRIME- это обязательный префикс(с помощью него автоматически подтягивается ссылка на задачу), число 17 это уникальный номер задачи из трекера. + В описание к PR добавляем ссылку на задачу и описание внесенных изменений, и пояснения(если требуется); + - после завершения CodeReview создаем squash commit в ветку main (название коммит(а), должно быть такое же как название pull request) ; + - после того как ветка с новой feature попало в main - удаляем ветку; + +### Создание release + - создаем ветку из main (release/release_0.0.1+1); + - добавляем в changelog.md описание изменений в этой версии (обычно это список коммитов, от предыдущей версии): + - делаем сборки, отправляем на тестирование; + - получаем баг-лист от тестировщиков, делаем фиксы; + - отправляем на следующий раунд тестирования и.т.д; + - после проверки и получения разрешение от другого разработчика - создаем tag c номером версии (0.0.1+1), создаем релиз, фиксируем версию и squash commit в ветку main и development; + - после того как release попал в main - удаляем ветку; diff --git a/tools/rfc/RFC-projects_structure.md b/tools/rfc/RFC-projects_structure.md new file mode 100644 index 0000000..f2cf9fa --- /dev/null +++ b/tools/rfc/RFC-projects_structure.md @@ -0,0 +1,75 @@ +# Структура проекта + +Рекомендуемая структура проекта (может отличатся в зависимости от проекта и согласований) + +- **/** - папка проекта +- **/assets** - директория расположения графических ресурсов +- **/tools/** - все необходимые инструменты для проекта + - **/docs** - документация проекта +- **/android** - папка, содержащая нативный код для Android +- **/aurora** - папка, содержащая нативный код для Aurora +- **/ios** - папка, содержащая нативный код для IOS +- **/env** - папка, с внешними переменными окружения +- **/lib** - код на Dart, Flutter-приложение + - **/app** - содержит основные настройки нашего приложения + - **/impls** - реализация интерфейсов + - **/interfaces** - объявление интерфейсов + - **/data** - общие поставщики данных + - **/domain** - общий слой + - **/presentation** - общий слой + - **/di** - файлы конфигурации зависимостей. + - **/routing** - все, что касается роутинга + - **/features** - фичи приложения, для каждой фичи создается отдельная папка + - **/feature_name** - подробнее см в разделе Структура feature папок + - **/data** + - **/domain** + - **/presentation** + - **/gen** - для сгенерированных файлов + - **/targets** - таргеты для сборок + - **/prod.dart** - сборка для prod + - **/dev.dart** - сборка разработки на моковых репозиториях + - **/stage.dart** - сборка для stage окружения + + +## Пример структуры feature папок + +- **/data** - слой данных + - **/dto** - реализация DTO ( [data transfer object](https://ru.wikipedia.org/wiki/DTO) ) + - **/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 (слой представления) + - сomponents - 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. \ No newline at end of file