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

Документ описывает, как конфигурируется и разворачивается модуль **stamp-verification-frontend** — публичная статическая страница проверки штампа (QR) на документе.

## Что это за сервис

`stamp-verification-frontend` — это статический фронтенд (обычный HTML + ванильный JavaScript + `moment.js`), который раздаётся через **nginx**. По QR-коду со штампа на PDF пользователь попадает на страницу с параметрами `?id=<qrId>&page_number=<n>`, страница запрашивает данные документа у backend-сервиса `documentations` и отображает информацию о версии, авторе, дате загрузки, статусе согласования и ссылке на документ в Sarex.

Ключевое отличие от backend-сервисов: **у приложения нет разбора переменных окружения**. Здесь нет `pydantic-settings`, нет `.env`, нет секций конфигурации. Всё «runtime»-поведение либо статично, либо определяется по хосту в браузере (`window.location.host`). Конфигурируется только **сборка и деплой** (Docker, Helm/`universal-chart`, GitLab CI).

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

| Слой | Где задаётся | Что настраивает |
| --- | --- | --- |
| Runtime (браузер) | `static/js/index.js` | Выбор базового URL API по `window.location.host`; параметры запроса берутся из query-строки (`id`, `page_number`, `v`) |
| Веб-сервер | `nginx.conf` | Порт прослушивания `8080`, корень `/dist`, health-check `GET /ping` → `200 {"result": "ok"}`, gzip, логи в stdout/stderr |
| Образ | `Dockerfile` | Базовый образ `nginx:mainline-alpine-otel`, копирование `static/` и `index.html` в `/dist`, `EXPOSE 8080` |
| Helm | `.helm/values.yaml`, `.helm/Chart.yaml` | Значения чарта-зависимости `universal-chart` (deployment, image, service, imagePullSecrets) |
| CI/CD | `.gitlab-ci.yml` | Выбор окружения по ветке/тегу, имя релиза/чарта, `HELM_SET_ARGS` |
| IaC (kustomize) | `iac/apps/stamp-verification/**` | Namespace, Deployment, Service и оверлеи кластеров (этот репозиторий) |

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

## Runtime-поведение (`static/js/index.js`)

Скрипт выполняется на `DOMContentLoaded`. Логика:

- читает query-параметры: `id` (идентификатор QR), `page_number`, `v` (пока не используется);
- запрос выполняется только если заданы одновременно `id` и `page_number`;
- выбирает базовый URL API:

  | `window.location.host` | Базовый URL API | Окружение |
  | --- | --- | --- |
  | `stamp-verification.sarex.io` | `api.sarex.io` | prod |
  | любой другой (напр. `stamp-verification.stage.sarex.io`) | `stage-api.sarex.io` | stage |

- делает `fetch` `GET https://<apiBaseUrl>/documentations/api/v1/public/qr/{id}/document_info?number_page={page_number}` с `mode: cors`, `credentials: include`, `cache: no-cache`;
- по ответу заполняет поля страницы (название, версия, номер страницы, автор, дата загрузки), блок изменений (changelog), индикаторы актуальности/аннулирования версии, статус согласования и ссылку на документ.

Локаль дат — `ru` (`moment.locale("ru")`), формат отображения даты — `DD.MM.YYYY / HH:mm`.

Полный перечень внешних вызовов см. в `ENDPOINTS.md`, контракт эндпоинта — в `openapi.yaml`.

## nginx (`nginx.conf`)

| Параметр | Значение | Назначение |
| --- | --- | --- |
| `listen` | `8080` | Порт HTTP |
| `root` | `/dist` | Корень статики (туда Dockerfile кладёт `static/` и `index.html`) |
| `location = /ping` | `return 200 '{"result": "ok"}'` | Health-check для k8s-проб/балансировщика |
| `access_log` | `/dev/stdout` | Логи доступа в stdout |
| `error_log` | `stderr warn` | Логи ошибок в stderr |
| `gzip` | `on` | Сжатие ответов |
| `expires` | `off` | Без заголовков кеширования |

## Docker (`Dockerfile`, `docker-compose.yml`)

Образ на базе `nginx:mainline-alpine-otel`. Сборка копирует `nginx.conf` в `/etc/nginx/nginx.conf`, каталог `static` и `index.html` в `/dist`, выставляет права на `/var` и `/run`, объявляет `EXPOSE 8080` и запускает `nginx -g "daemon off;"`. Build-time аргументов нет (`BUILD_ARGS=""`).

`docker-compose.yml` — только для локального прогона (`image: sarex/landing:latest`, публикует порт `8000:8000`; обратите внимание, что nginx внутри слушает `8080` — маппинг в compose оставлен историческим).

## Helm / universal-chart (`.helm/`)

`Chart.yaml` подключает зависимость `universal-chart` (`oci://cr.yandex/crp3ccidau046kdj8g9q/charts`, версия `0.1.7`). Значения задаются в `values.yaml` под ключом `universal-chart` и разбиты по окружениям через суффиксы (`_default`, `stage`, `preprod`, `production`).

| Ключ (`universal-chart.services.frontend.*`) | Значение (`_default`) | Назначение |
| --- | --- | --- |
| `deployment.enabled` | `true` | Создавать Deployment |
| `deployment.name` | `stamp-verification-frontend` | Имя Deployment |
| `deployment.port` | `8080` | Порт контейнера |
| `deployment.replicaCount` | `1` | Число реплик |
| `image.name` | `cr.yandex/crp3ccidau046kdj8g9q/stamp-verification-frontend:latest` | Образ |
| `image.pullPolicy` | `IfNotPresent` | Политика загрузки образа |
| `service.enabled` | `true` | Создавать Service |
| `service.name` | `frontend-service` | Имя Service |
| `service.port` | `8080` (в `production` — `80`) | Порт сервиса |
| `service.targetPort` | `8080` | Целевой порт |
| `service.type` | `ClusterIP` | Тип сервиса |
| `imagePullSecrets.name` | `dockerhub` | Секрет для доступа к реестру |

`global.env` (`_default`) выбирает активный набор значений по окружению.

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

Пайплайн подключает общие шаблоны `generic/common-ci` (`common-security-scan.yaml`, `universal-pipeline.yaml`, ref `apps-business`). Общие переменные: `SERVICE_NAME=stamp-verification-frontend`, `DOCKERFILE_PATH=Dockerfile`, `BUILD_ARGS=""`, `CI_TRIGGER_SOURCE=app`.

Окружение переключается правилами `workflow.rules`:

| Условие | STAND | NAMESPACE | CHART_VERSION | K8S_HUSTLER_BRANCH |
| --- | --- | --- | --- | --- |
| `merge_request_event` | — | — | — | `ENABLE_BUILD_IMAGE="false"` (только проверки, без сборки образа) |
| ветка `stage` | `stage` | `documentations` | `0.0.1-stage` | `universal-chart-stage` |
| ветка `master` | `preprod` | `stamp-verification-preprod` | `0.0.1-preprod` | `universal-chart-preprod` |
| тег (`CI_COMMIT_TAG`) | `production` | `stamp-verification-prod` | `0.0.1-prod` | `universal-chart-production` |
| иначе | `when: never` | | | |

Для каждого деплой-окружения `HELM_SET_ARGS` передаёт: образ (`universal-chart.services.frontend.image.name.<env>=${IMAGE_NAME}`), `universal-chart.global.env=<env>` и метаданные коммита (`commitSha`, `gitlabUri`, `gitlabJobUrl`, `owner`).

## Инфраструктура (kustomize, этот репозиторий)

Каталог `iac/apps/stamp-verification/` содержит kustomize-манифесты (альтернатива/дополнение к Helm-деплою из CI):

- `base/namespace.yaml` — namespace `stamp-verification` с `istio-injection: enabled`;
- `base/deployment.yaml` — Deployment `frontend` (образ `cr.yandex/crp3ccidau046kdj8g9q/stamp-verification-frontend:<sha>`, `imagePullPolicy: IfNotPresent`, `containerPort: 80`, requests `cpu: 25m`/`memory: 100Mi`, `imagePullSecrets: regcred`);
- `base/service.yaml` — Service `frontend-service` (`ClusterIP`, `port: 80` → `targetPort: 80`);
- `base/kustomization.yaml` — сборка base (namespace + deployment + service);
- `yc-k8s-test/kustomization.yaml` — оверлей кластера (`resources: ../base`, патчи закомментированы);
- `yc-k8s-test/replicas.yaml` — заготовка патча реплик (`replicas: 1`).

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

- **Захардкоженный JWT.** В `static/js/index.js` в заголовок `Authorization: Bearer …` вшит истёкший (2023 г.) токен. Публичный эндпоинт `/public/qr/...` не должен требовать пользовательский токен — строку следует удалить. Держать секреты в статике недопустимо.
- **Рассогласование портов.** nginx и Helm/`universal-chart` используют порт **8080**, а kustomize-манифесты в этом репозитории (`base/deployment.yaml`, `base/service.yaml`) — порт **80**. Нужно привести к одному значению (образ слушает 8080), иначе проброс/пробы могут не сходиться.
- **Дублирование деплоя.** Приложение может разворачиваться и через Helm (CI, чарт `universal-chart`), и через kustomize (этот репозиторий). Следует зафиксировать единый источник истины, чтобы образ/порт/namespace не расходились.
- **NAMESPACE для stage.** На ветке `stage` деплой идёт в namespace `documentations` (общий), тогда как preprod/prod — в выделенные `stamp-verification-*`. Это осознанное решение или наследие — стоит проверить.
- **Конфиг только по хосту.** Выбор prod/stage жёстко завязан на строку `stamp-verification.sarex.io`. Любой новый прод-домен потребует правки кода, а не конфигурации.
- **Mock-данные в бандле.** В `index.js` присутствуют объекты `mockData`/`mockChangeLog` — тестовые данные, оставшиеся в продовом бандле. На поведение не влияют (не используются), но их стоит убрать.

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

Отдельная конфигурация не требуется — приложение статично:

```
# сборка и запуск образа
docker build -t stamp-verification-frontend .
docker run --rm -p 8080:8080 stamp-verification-frontend
# проверка
curl http://localhost:8080/ping        # {"result": "ok"}
# страница: http://localhost:8080/?id=<qrId>&page_number=1
```

Для реальных данных нужен доступный backend `documentations` (по умолчанию для не-prod хоста используется `https://stage-api.sarex.io`).
