# Архитектура
## Структура проекта
### Основная структура проекта
> <span :class="$style.pink">Цветом</span> отмечен узел, который может быть как файлом, так и папкой в зависимости от объема логики.
> <span :class="$style.blue">Цветом</span> отмечен узел, который обязателен в структуре проекта.
* assets
* styles
* icons
* images
* containers
* components
* store
* plugins
* services
* helpers
* <span :class="$style.pink">constants</span>
* <span :class="$style.pink">utils</span>
* <span :class="$style.pink">types</span>
* composables
* api
* guards
* <span :class="$style.pink">middlewares</span>
* <span :class="$style.pink">validations</span>
* routes
* <span :class="$style.blue">index.ts</span>
> Все файлы и папки являются опциональными и добавляются по мере необходимости, кроме файла `index.ts`. Он должен присутствовать в каждом модуле
### Детальное описание
<br>
#### index.ts
Главная точка входа в модуль. Экспортирует все, что можно использовать другими модулями за границей конкретного модуля (например, services, utils, components, guards .etc).
#### assets
Хранение ресурсов таких как изображения, шрифты, стили CSS, видео или другие файлы, которые не являются JavaScript кодом.
Может содержать папки:
* styles
* icons
* images
* и другие
#### containers
Файлы .vue, хранят основную бизнес-логику модуля или "страницы", например, запросы на сервер, подготовку данных или группировку компонентов.
Простыми словами, контейнер - это страница, которая выступает в роли обертки компонентов.
> Правила создания и работы контейнера:
> * контейнер ничего не визуализирует, за исключением файлов, таких как App.vue, которые хранят неповторяющуюся верстку (например, \<v-app>, \<v-main>)
> * контейнер группирует компоненты
> * контейнер обрабатывает и предоставляет данные для компонентов (requests, store .etc)
> * у модуля может быть один или несколько главных контейнеров (страниц)
> * название должно содержать суффикс "Container" (например, `DashboardContainer.vue`)
> * если один контейнер вложен в другой, названия дочерних контейнеров должны включать имя родительского контейнера в качестве префикса: `[Module]Container.vue --> [Module][Table]Container.vue`
> * контейнер может содержать другие контейнеры, если необходимо декомпозировать логику для удобства поддержки
> * контейнер не может переиспользовать другой контейнер
> * если "связанных" контейнеров более 2-х, необходимо сгруппировать эти файлы в папку. Название папки должно быть таким же, как название родительского контейнера, в формате PascalCase
#### components
Компоненты, в отличие от контейнеров, не хранят бизнес-логику, их задача отображать полученные данные так, как мы хотим, включая стили, без изменения этих данных.
> Правила создания и работы компоненты:
> * название может быть произвольное, но должно отображать назначение компоненты.
> * если одна компонента вложена в другую, названия дочерних компонентов должны включать имя родительской компоненты в качестве префикса:`[BigTable].vue --> [BigTable][Header].vue`
> * если "связанных" файлов более 2-х, необходимо сгруппировать эти файлы в папку. Название папки должно быть таким же, как название родительской компоненты, в формате PascalCase
> * данные компонента получает от своего контейнера или от родительской компоненты в виде пропсов
> * компонента не изменяет данные, который пришли от ее контейнера
> * если компоненте необходимо изменить данные, она вызывает emits и передает необходимые данные своему контейнеру
> * компонента может напрямую использовать state хранилища модуля, но не изменять его
#### store
Хранилище данных. В зависимости от используемой библиотеки хранит в себе state, actions и getters.
> Правила создания и работы с хранилищем:
> * хранилище должно принадлежать только одному модулю.
> * в модуле может быть несколько хранилищ, все зависит от объема данных модуля
> * если в модуле необходимо только одно хранилище, то в корне модуля создается папка `store`, внутри которого создается файл `index.ts` - это и будет основным хранилищем модуля.
> * если в модуле есть более одного хранилища, то в корне модуля создается папка `store`, внутри которой создаются файлы хранилищ. В папке `store` создается файл `index.ts` где реэкспортируются все хранилища. Названия файлов должны отражать прямое назначение хранилища.
> * для изменения state хранилища необходимо создать мутатор из обычного action. Так можно избежать нежелательный side effect из-за прямого изменения state
Пример мутатора
```ts
state: {
name: ''
},
actions: {
// Название такого action должно содержать в суффиксе "Mutator". // [!code focus]
changeNameMutator (newName: string): void { // [!code focus]
this.name = newName // [!code focus]
} // [!code focus]
}
```
> Не создавайте хранилище, если в этом нет необходимости. Каждое новое хранилище усложняет поддержку модулей.
> Возможно будет достаточно доработать логику общения между контейнерами/компонентами с помощью пропсов.
#### plugins
Папка плагинов содержит в себе файлы подключаемых плагинов, необходимых только для этого модуля.
Такими плагинами могут быть как обычные библиотеки, используемые только в этом модуле, так и обертка глобальных плагинов, таких как axios.
#### services
Сервисы хранят в себе специализированную бизнес-логику для данного модуля. В основном, это набор классов и функций необходимые для решения бизнес-задач.
Хоть изначально они создаются для конкретного модуля, их можно переиспользовать в других модулях, заранее реэкспортировав в файле `index.ts` находящегося в корне модуля.
> Правила создания и работы с сервисом:
> * если в модуле необходимо только один сервис, то в корне модуля создается папка `services`, внутри которого создается файл `index.ts` - это и будет основным сервисом модуля.
> * если в модуле необходимо более одного сервиса, то в корне модуля создается папка `services`, внутри которой создаются файлы сервисов. В папке `services` создается файл `index.ts`, где реэкспортируются все сервисы.
> * название должно содержать суффикс "service" (например, `dashboard.service.ts`)
#### helpers
Все, что помогает в разработке проекта
Может содержать папки/файлы:
* constants - константы
* utils - утилиты в виде функций
* types - типы и интерфейсы ts
#### api
API-запросы на сторонние сервисы
> Правила создания и работы с API:
> * название должно содержать суффикс "api" (например, `dashboard.api.ts`)
> * функции API не должны реализовывать бизнес-логику модуля. Их главная задача - запросить и передать данные
> * внутри функций API разрешается сериализовать данные (например, snake_case в camelCase), а также обогащать другими данными, если в функции API более одного запроса
> * функция API должна возвращать Promise
> * если в модуле нет необходимости в большом кол-ве API, то в корне модуля создается папка `api`, внутри которого создается файл `index.ts` - это и будет основным файлом API модуля
> * если в модуле необходимо декомпозировать API, то в корне модуля создается папка `api`, внутри которой создаются файлы API. В папке `api` создается файл `index.ts`, где реэкспортируются все API-файлы
#### api - errors
Обработка API ошибок происходит следующим образом:
1) Отлавливаем ошибку на уровне API-файла, в catch отправляем ошибку с текстом из ошибки запроса или своим собственным
2) В месте вызова запроса принимаем ошибку и обрабатываем/выводим в соответствии с бизнес требованием
В результате, в самом верху мы получаем ошибку, у которой точно будет поле message.
Примеры обработки ошибок
Пример обработки ошибки в API-файле
```ts
export async function getShiftInfoApi (siteId: number, params: {date: string, num: number}): Promise<AxiosResponse<TShift>> {
return await axios.post(`shift-closing/sites/${siteId}/shifts`, params)
.catch(({ response: { data: { message } } }) => { throw new Error(message ?? 'Не удалось получить информацию смены') }) // [!code focus]
}
```
Пример обработки ошибки в .vue-файле c использованием toast, альтернативой является `throw new error`.
```ts
getShiftInfo({ date: value.date, num: value.shift })
.catch((error: { message: string }) => { return $toast.error(error.message) }) // [!code focus]
```
#### guards
Все, что связано с безопасностью модуля.
Может содержать папки/файлы:
* middlewares - промежуточная защита api или routes
* validations - валидирование данных форм и полей
#### routes
Роутинг модуля. Хранит в себе файл(ы) маршрутов, которые поддерживаются в конкретном модуле.
> Правила создания и работы с routes:
> * должен экспортировать массив маршрутов, для глобального роутинга приложения
> * не должен содержать маршруты от других модулей
#### composables
Функции, использующие Composition API Vue для инкапсуляции и повторного использования логики с отслеживанием состояния.
Также может хранить кастомные хуки модуля
> Файлы хуков должны начинаться на **use**...