# Конфигурация проекта projects-frontend

Документ описывает, как конфигурируется микрофронтенд `projects-frontend`: переменные сборки, способы запуска, параметры Docker/nginx, Helm-чарта и CI.

## Способы конфигурирования

`projects-frontend` — это клиентский микрофронтенд (React 17 + MobX, сборка Webpack 5, Module Federation). У приложения **нет runtime-конфигурации и файла `.env`**: всё поведение, зависящее от окружения, определяется **на этапе сборки** одной переменной `BUILD_ENV`.

Разбор выполняется в `configWebpack/config/build.config.ts` (`extractBuildOptions`): значение `process.env.BUILD_ENV` (одно из `local` / `stage` / `prod` / `preprod` / `contour`, по умолчанию `prod`) определяет режим сборки (`development`/`production`) и «endpoint». Полученный `endPoint` через `DefinePlugin` (`configWebpack/buildPlugins.ts`) подставляется в бандл как глобальная константа `__ENDPOINT__`:

```js
new DefinePlugin({ __ENDPOINT__: JSON.stringify(endPoint) })
```

Константа `__ENDPOINT__` используется в рантайме бандла для выбора:

- карты хостов API — `src/shared/api/http-service.ts` (`const endpoint = (__ENDPOINT__ as TypeEnvironment) || "prod"`) поверх `src/shared/api/hosts.ts`;
- URL удалённого модуля timeline — `src/widgets/remote-timeline/ui/timelineProxy.tsx`;
- локального провайдера разработки — `src/app/bootstrap.tsx` (`__ENDPOINT__ === "local" ? <LocalDevProvider /> : <div />`).

Отдельного конфиг-файла (yaml/env) у приложения нет.

## Переменные сборки и запуска

| Переменная | Где используется | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `BUILD_ENV` | `webpack.config.ts`, `configWebpack/config/build.config.ts`, `Dockerfile` (build-arg) | `prod` | Целевое окружение сборки: `local`/`stage`/`prod`/`preprod`/`contour`. Определяет режим (`development`/`production`), карту хостов и URL удалённых модулей |
| `NPM_NEXUS_TOKEN` | `.npmrc`, `Dockerfile` (build-arg) | — | Токен доступа к приватному npm-реестру Nexus (`https://nexus.infra.sarex.io/repository/npm/`) для установки пакетов `@sarex-team/*` |
| `PORT` | `webpack.config.ts` | `9001` | Порт dev-сервера Webpack |

Версия Node фиксирована в `.nvmrc` — `v16.0.0`. Приватный реестр и авторизация заданы в `.npmrc`:

```
@sarex-team:registry=https://nexus.infra.sarex.io/repository/npm/
//nexus.infra.sarex.io/repository/npm/:_authToken=${NPM_NEXUS_TOKEN}
```

### npm-скрипты (`package.json`)

| Команда | Действие |
| --- | --- |
| `npm run dev` | Локальная разработка: `BUILD_ENV=local webpack serve --config webpack.config.ts` |
| `npm run build-module` | Сборка модуля: `webpack --config webpack.config.ts` (окружение — из `BUILD_ENV`) |
| `npm run build:start` | Раздача собранного бандла: `serve -s ./dist -l 9001` |
| `npm run lint` | Форматирование Prettier: `npx prettier --write .` |

## Сборка Webpack и Module Federation

Точка входа — `src/app/index.ts` (`webpack.config.ts`). Для всех окружений, кроме `local`, добавляется `ModuleFederationPlugin`:

- `name`: `srx_projects`;
- `filename`: `module/remoteEntry.js`;
- `exposes`: `./ProjectsPage` → `./src/app/App.tsx`;
- `shared` (singleton, `requiredVersion: false`): `react`, `react-dom`, `@material-ui/core`, `@sarex-team/sdk-js`.

Плагины (`configWebpack/buildPlugins.ts`): `HtmlWebpackPlugin`, `DefinePlugin`. В режиме `local` дополнительно `ProgressPlugin`, `ForkTsCheckerWebpackPlugin`, `ReactRefreshWebpackPlugin`; вне `local` — `MiniCssExtractPlugin` (хеши в именах файлов).

### Dev-сервер (`configWebpack/buildDevServer.ts`)

HTTPS, порт `9001`, `historyApiFallback`, `hot`. Прокси на stage-окружение с `pathRewrite`:

| Префикс | Target |
| --- | --- |
| `/sarex-backend` | `https://stage.sarex.io` |
| `/sarex-gateway` | `https://stage-api.sarex.io/gateway` |
| `/sarex-documentations` | `https://stage-api.sarex.io/documentations` |
| `/sarex-api` | `https://stage-api.sarex.io` |

Заголовки CORS dev-сервера разрешают любой origin, методы `GET, POST, PUT, DELETE, PATCH, OPTIONS` и заголовки `X-Requested-With, content-type, Authorization`.

## Docker

Многоступенчатая сборка (`Dockerfile`):

1. **Стадия сборки** (`node:16`): установка зависимостей (`npm i` с `NPM_NEXUS_TOKEN`), `npm run lint`, `BUILD_ENV=$BUILD_ENV npm run build-module` → `dist`.
2. **Стадия раздачи** (`nginx:1.19.6`): копирование `dist` в `/dist` и `nginx/nginx.conf` в `/etc/nginx/nginx.conf`.

Build-args: `BUILD_ENV`, `NPM_NEXUS_TOKEN`.

### nginx (`nginx/nginx.conf`)

Статика раздаётся с `root /dist` на порту `80`. Особенности:

- `location = /ping` → возвращает `200 {"result": "ok"}` (используется как liveness/readiness-проба);
- `location = /module/remoteEntry.js` → `Cache-Control: no-store, no-cache, must-revalidate…`, `expires off` (точка входа Module Federation не кешируется);
- `gzip on`, логи в `stdout`/`stderr`.

## Helm-чарт (`.helm`)

Чарт `projects-frontend` (`Chart.yaml`, `type: application`, `version: 0.1.0`, `appVersion: 1.16.0`) разворачивает статику как `Deployment` + `Service` (`templates/static.yaml`) и публикует её через Istio `VirtualService` (`templates/mesh-config.yaml`).

Значения задаются в `values-<env>.yaml` (блок `static`):

| Параметр | `stage` | `preprod` | `production` |
| --- | --- | --- | --- |
| `static.host` | `stage-modules.sarex.io` | `modules.preprod.sarex.io` | `modules.sarex.io` |
| `static.replicas` | `1` | `2` | `2` |
| `static.path` | `/projects/static/` | `/projects/static/` | `/projects/static/` |
| `static.image` | `sarex/projects-frontend-static:latest` | то же | то же |
| `static.port` / `static.service_port` | `80` / `80` | `80` / `80` | `80` / `80` |
| `static.requests` | `memory: 100Mi`, `cpu: 100m` | то же | то же |
| `imagePullSecrets` | `dockerhub` | `dockerhub` | `dockerhub` |

Общее для всех окружений: `static.name: projects-frontend-static`, `static.service_name: projects-frontend-static-service`, `static.version: stable`. Пробы `livenessProbe`/`readinessProbe` бьют в `/ping` (`templates/static.yaml`).

`VirtualService` (`templates/mesh-config.yaml`): хост `static.host`, шлюз `gateway/modules-gateway`, матч по префиксу `static.path` (`/projects/static/`) с `rewrite` на `/`. Политика CORS: `allowOrigins` по регулярке `(https://.*\.sarex\.io)|(https://localhost:.*)`, `allowMethods: [GET, POST, PUT, PATCH, HEAD, DELETE]`, `allowHeaders: [Authorization, Content-Type]`, `maxAge: 24h`.

## CI/CD (`.gitlab-ci.yml`)

Пайплайн подключает общие шаблоны из `generic/common-ci` (`universal-pipeline-*`, `common-security-scan`, `common-build`) и переключает окружение по ветке/тегу через `workflow.rules`:

| Условие | STAND | Namespace | `BUILD_ENV` |
| --- | --- | --- | --- |
| ветка `master` | `preprod` | `projects-preprod` | `preprod` |
| ветка `stage` | `stage` | `projects-stage` | `stage` |
| тег (`CI_COMMIT_TAG`) | `prod` | `projects-prod` | `prod` |

Ключевые переменные пайплайна (общие для всех окружений): `RELEASE_NAME`/`CHART_NAME` = `projects-frontend`, `IMAGE_PATH` = `static.image`, `HELM_SET_ARGS` = `--set static.image=${IMAGE_NAME}`, `BUILD_ARGS` = `--build-arg BUILD_ENV=<env> --build-arg NPM_NEXUS_TOKEN=${NPM_NEXUS_TOKEN}`, `DOCKERFILE_PATH` = `Dockerfile`. Флаги этапов: `ENABLE_LINTER` (`false`), `ENABLE_BUILD_CHART`, `ENABLE_BUILD_IMAGE`, `ENABLE_STATE_UPDATE`, `ENABLE_DEPLOY` (`true`). `CHART_VERSION` задаётся как `0.0.1-<env>`. Стадии: `linter → test → unittest → prebuild-secscan → build → state-update → deploy`.

## Замечания и потенциальные проблемы

- **Нет runtime-конфигурации.** Всё, что зависит от окружения, «зашивается» в бандл на этапе сборки через `BUILD_ENV`/`__ENDPOINT__`. Пересборка под другое окружение обязательна — переопределить хосты в рантайме нельзя.
- **Значение по умолчанию `BUILD_ENV=prod`.** Если переменная не задана при сборке, собирается production-вариант (`build.config.ts`, `webpack.config.ts`, `http-service.ts`). Для локальной разработки нужно явно `BUILD_ENV=local` (скрипт `npm run dev` это делает).
- **Окружение `contour` неполно сконфигурировано.** Оно перечислено в `build.config.ts` и типах, но в `src/shared/api/hosts.ts` карта хостов для `contour` отсутствует, а URL удалённого модуля timeline для `contour` пуст (`timelineProxy.tsx`). Сборка с `BUILD_ENV=contour` не сможет разрешить хосты API.
- **README не совпадает с `package.json`.** В `README.md` указаны `nvm use 16.0.0` и `npm run start:local`, однако скрипта `start:local` в `package.json` нет — локальный запуск выполняется командой `npm run dev`. `.nvmrc` фиксирует `v16.0.0`.
- **Версии чарта расходятся.** В `Chart.yaml` — `version: 0.1.0` / `appVersion: 1.16.0`, тогда как в CI `CHART_VERSION` задаётся как `0.0.1-<env>`. Значения не синхронизированы.
- **Приватный реестр.** Установка зависимостей требует валидный `NPM_NEXUS_TOKEN` (`.npmrc`); без него `npm i` (в т.ч. в Docker-сборке) завершится ошибкой авторизации.

## Минимальный набор для локального запуска

1. `nvm use` (Node `v16.0.0` из `.nvmrc`).
2. Экспортировать `NPM_NEXUS_TOKEN` (доступ к Nexus) и выполнить `npm i`.
3. `npm run dev` — соберёт с `BUILD_ENV=local` и поднимет HTTPS dev-сервер на `https://localhost:9001` (запросы к backend проксируются на stage через `/sarex-backend`, `/sarex-gateway`, `/sarex-documentations`, `/sarex-api`).
