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

Документ описывает способы конфигурирования микрофронтенда аутентификации `auth-flow-frontend` (React + webpack), а также все переменные сборки, деплоя и рантайма.

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

В отличие от бэкенд-сервисов, приложение **не читает `.env` и не использует dotenv**. Это статический фронтенд, собираемый webpack, поэтому конфигурация распределена по трём уровням:

1. **Сборка (build-time).** Переменная `ENDPOINT` определяет окружение. Её значение подставляется в код на этапе сборки через `webpack.DefinePlugin` (`webpack.config.ts`) — заменяет обращения `process.env.ENDPOINT` и `process.env.IS_DEV` на строковые литералы. Выбор режима (`development`/`production`) и флага `isDev` выполняется в `webpack/build.config.ts`.
2. **Установка зависимостей.** Пакеты `@sarex-team/*` тянутся из приватного npm-реестра (`.npmrc` → `nexus.infra.sarex.io`). Для доступа нужен токен `NPM_NEXUS_TOKEN`.
3. **Рантайм (runtime).** Параметры OIDC-провайдера — `authority` и `client_id` — читаются из `localStorage` (`src/config/zitadel.ts`) по ключам `STORAGE.AUTHORITY` и `STORAGE.CLIENT_ID` из `@sarex-team/sdk-js`. Их задаёт хостовое приложение, а не сборка.

Источники переменных по способам запуска:

| Способ запуска | Откуда берутся переменные |
| --- | --- |
| Локально (dev) | `npm run dev` → `ENDPOINT=local webpack serve`. Dev-сервер на `https://localhost:9000` |
| Локально (build) | `npm run build` → `webpack --config webpack.config.ts` (по умолчанию `ENDPOINT=prod`, см. `build.config.ts`) |
| Docker | `Dockerfile`: build-args `ENDPOINT` и `NPM_NEXUS_TOKEN`; сборка dist → отдача через nginx |
| Kubernetes (Helm) | `.helm/values.yaml` (чарт `universal-chart`): блок `services.frontend`, `global.env` |
| CI/CD (GitLab) | `.gitlab-ci.yml`: `workflow.rules` (ветка/тег → `STAND`, `ENDPOINT`, `CHART_VERSION`), `BUILD_ARGS`, `HELM_SET_ARGS` |

## Переменные сборки (build-time)

Подставляются в код на этапе сборки; в рантайме это уже константы.

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `ENDPOINT` | enum | `prod` (в `build.config.ts`, если не задана) | Окружение сборки: `local`/`stage`/`prod`/`preprod`/`contour`. Определяет `mode` (`development` для `local`, иначе `production`) и `isDev` |
| `IS_DEV` | bool | — (вычисляется) | `true`, если `ENDPOINT === 'local'`. Включает dev-роуты (`/login`, `/logout`, `/`). Задаётся автоматически через `DefinePlugin`, вручную указывать не нужно |
| `NPM_NEXUS_TOKEN` | string | — | Токен авторизации в приватном npm-реестре `@sarex-team` (`.npmrc`). Обязателен для `npm i` |

> `mode` по окружениям (`webpack/build.config.ts`): `local` → `development`, `stage`/`prod`/`preprod`/`contour` → `production`. Неизвестное значение `ENDPOINT` приводит к ошибке сборки.

## Переменные рантайма (localStorage)

Читаются в браузере во время работы приложения; задаются хостовым приложением, не сборкой.

| Ключ | Источник | Назначение |
| --- | --- | --- |
| `STORAGE.AUTHORITY` | `@sarex-team/sdk-js` | URL issuer'а Zitadel (`authority` OIDC). Обязателен — при отсутствии `src/config/zitadel.ts` бросает `Error("Authority or client ID is not set")` |
| `STORAGE.CLIENT_ID` | `@sarex-team/sdk-js` | `client_id` OIDC-клиента. Обязателен (та же проверка) |
| `sarex_logout` (`LOGOUT_STORAGE_KEY`) | `src/config/logout.ts` | Состояние логаута между вкладками (`{ logoutAt, owner, reason }`). Снимается только валидным токеном в `setTokensInfo` |
| access / refresh / id токены | `storage` из `@sarex-team/sdk-js` | Устанавливаются в `setTokensInfo` (`storage.setAccessToken`/`setRefreshToken`/`setIdentityToken`) после успешного колбэка |

## Конфигурация OIDC (Zitadel)

Задаётся в `src/config/zitadel.ts` (`configZitadel: ZitadelConfig`), клиент создаётся через `createZitadelAuth`.

| Параметр | Значение | Назначение |
| --- | --- | --- |
| `authority` | из `localStorage` (`STORAGE.AUTHORITY`) | Issuer Zitadel |
| `client_id` | из `localStorage` (`STORAGE.CLIENT_ID`) | Идентификатор клиента |
| `response_type` | `code` | Authorization Code Flow |
| `scope` | `openid profile email offline_access urn:zitadel:iam:user:metadata` | Запрашиваемые области |
| `redirect_uri` | `${window.location.origin}/auth/callback` | URL возврата после логина |
| `post_logout_redirect_uri` | `${window.location.origin}/login` | URL после логаута |
| `redirectMethod` | `replace` | Замена записи в истории браузера |
| `revokeTokensOnSignout` | `false` | Не отзывать токены при выходе |
| `automaticSilentRenew` | `false` | Фоновое обновление токенов выключено |
| `validateSubOnSilentRenew` | `false` | — |
| `silentRequestTimeoutInSeconds` | `100` | Таймаут silent-запроса |

## Роуты приложения

Определены в `src/config/urls.ts`, диспетчеризация в `src/App.tsx`.

| Роут | Константа | Доступность | Назначение |
| --- | --- | --- | --- |
| `/auth/callback` | `CALLBACK` | всегда | Обработка OIDC-колбэка (по умолчанию для неизвестных путей) |
| `/auth/error` | `ERROR` | всегда | Страница ошибки аутентификации |
| `/login` | `LOGIN` | только dev | Dev-страница входа |
| `/logout` | `LOGOUT` | только dev | Dev-страница выхода |
| `/` | `HOME` | только dev | Dev-навигация |

> В production разрешены только `/auth/callback` и `/auth/error` (`ALLOWED_PATHS`); в dev дополнительно `/login`, `/logout`, `/` (`ALLOWED_PATHS_DEV`). Неразрешённый путь заменяется на `/auth/callback` (`history.replaceState`).

## Сборка (webpack)

`webpack.config.ts` + `webpack/build.config.ts`.

| Параметр | Значение | Примечание |
| --- | --- | --- |
| `entry` | `src/index.tsx` | Точка входа |
| `output.path` | `dist/` | |
| `output.filename` | `index.js` | |
| `output.publicPath` | `/` (dev) или `/auth/callback/` (prod) | Зависит от `isDev` |
| loader | `esbuild-loader`, target `es2015` | Для `.tsx?/.jsx?` |
| `devServer` | `https`, `port: 9000`, `hot`, `historyApiFallback`, `open` | Только dev |
| plugins | `HtmlWebpackPlugin` (`public/index.html`), `DefinePlugin` (`ENDPOINT`, `IS_DEV`) | |

Node-версия для разработки: `v20.0.0` (`.nvmrc`; в `package.json` заявлено `v20.0.0`, реальная база образа — `node:20`).

## Docker

`Dockerfile` — двухстадийная сборка.

| Стадия | База | Действия |
| --- | --- | --- |
| build | `cr.yandex/crp3ccidau046kdj8g9q/node:20` | `npm i` (с `NPM_NEXUS_TOKEN`), `npm run build` (с `ENDPOINT`) |
| runtime | `cr.yandex/crp3ccidau046kdj8g9q/nginx:latest` | Копирует `/app/dist/` → `/dist/`, `nginx/nginx.conf` → `/etc/nginx/nginx.conf` |

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

## Nginx

`nginx/nginx.conf` — отдача статики и healthcheck.

| Локация | Поведение |
| --- | --- |
| `= /auth/callback/index.js` | `alias /dist/index.js` |
| `^~ /auth/callback` | `try_files $uri $uri/ /index.html`; заголовки `Cache-Control: no-store,...`, кеш отключён |
| `= /ping` | `200 {"result": "ok"}` (healthcheck) |

`listen 80`, `root /dist`, логи в stdout/stderr, `gzip on`.

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

Деплой через зонтичный чарт `universal-chart` (`oci://cr.yandex/crp3ccidau046kdj8g9q/charts`, версия `0.1.7`; `Chart.yaml` приложения — `auth-flow-frontend` `1.0.0`). Значения задаются с ключами по окружениям (`_default`/`stage`/`preprod`/`production`).

| Параметр | Значение | Назначение |
| --- | --- | --- |
| `global.env` | `stage` (`_default` в файле) | Активное окружение чарта |
| `services.frontend.enabled` | `true` | Включение сервиса |
| `deployment.name._default` | `auth-flow-frontend` | Имя деплоймента |
| `deployment.replicaCount` | `_default: 1`, `production: 2` | Число реплик |
| `deployment.port._default` | `80` | Порт контейнера |
| `deployment.revisionHistoryLimit._default` | `5` | Хранимые ревизии |
| `deployment.resources.requests` | `memory: 128Mi`, `cpu: 100m` | Реквесты ресурсов |
| `deployment.probes.liveness/readiness` | `httpGet` `/` : `80` | Пробы |
| `image.name._default` | `cr.yandex/crp3ccidau046kdj8g9q/auth-flow-frontend` | Образ |
| `image.pullPolicy._default` | `IfNotPresent` | |
| `imagePullSecrets.name._default` | `dockerhub` (enabled `false`) | Секрет реестра |
| `service` | `ClusterIP`, port/targetPort `80`, portName `http`, имя `auth-flow-frontend-service` | Service |
| `envs` | `[]` | Переменные окружения контейнера (пусто) |
| `volumes._default` | `[]` | Тома |
| `commitSha`/`gitlabUri`/`gitlabJobUrl`/`owner` | заполняются из CI (`owner` по умолчанию `team-abc`) | Метаданные |

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

Подключает общие шаблоны `generic/common-ci` (`common-security-scan.yaml`, `universal-pipeline.yaml` ref `apps-business`).

Базовые переменные: `SERVICE_NAME=auth-flow-frontend`, `DOCKERFILE_PATH=./Dockerfile`, `CI_TRIGGER_SOURCE=app`.

Переключение окружения по `workflow.rules`:

| Условие | STAND | ENDPOINT | CHART_VERSION | K8S_HUSTLER_BRANCH |
| --- | --- | --- | --- | --- |
| `merge_request_event` | — | — | — (`ENABLE_BUILD_IMAGE=false`) | — |
| ветка `stage` | `stage` | `stage` | `0.0.1-stage` | `universal-chart-stage` |
| тег (`CI_COMMIT_TAG`) | `production` | `prod` | `0.0.1-prod` | `universal-chart-production` |

> Правило для ветки `master` → `preprod` присутствует, но **закомментировано**. `NAMESPACE` для всех окружений — `platform`, `RELEASE_NAME`/`CHART_NAME` — `${SERVICE_NAME}`.

`BUILD_ARGS` прокидывают `--build-arg ENDPOINT=<env>` и `--build-arg NPM_NEXUS_TOKEN=${NPM_NEXUS_TOKEN}`. `HELM_SET_ARGS` устанавливают `universal-chart.services.frontend.image.name.<env>`, `global.env`, а также `commitSha`, `gitlabUri`, `gitlabJobUrl`, `owner`.

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

- **Обязательные runtime-параметры.** Если в `localStorage` нет `AUTHORITY` или `CLIENT_ID`, `src/config/zitadel.ts` бросает ошибку при инициализации — приложение не стартует. Эти значения должен положить хостовый сервис до загрузки микрофронтенда.
- **Нет `.env`.** Приложение не читает dotenv; `process.env.ENDPOINT`/`IS_DEV` существуют только на этапе сборки (замена через `DefinePlugin`). Значение `ENDPOINT` задаётся только через CLI/`--build-arg`/CI.
- **publicPath в prod** — `/auth/callback/`: приложение обслуживается nginx под префиксом `/auth/callback`, что согласовано с `redirect_uri` OIDC.
- **`silentRenew` отключён** намеренно (`automaticSilentRenew: false`) — обновление токенов не выполняется в фоне.
