# Конфигурация проекта stamp-verification-frontend Документ описывает, как конфигурируется и разворачивается модуль **stamp-verification-frontend** — публичная статическая страница проверки штампа (QR) на документе. ## Что это за сервис `stamp-verification-frontend` — это статический фронтенд (обычный HTML + ванильный JavaScript + `moment.js`), который раздаётся через **nginx**. По QR-коду со штампа на PDF пользователь попадает на страницу с параметрами `?id=&page_number=`, страница запрашивает данные документа у 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:///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.=${IMAGE_NAME}`), `universal-chart.global.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:`, `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=&page_number=1 ``` Для реальных данных нужен доступный backend `documentations` (по умолчанию для не-prod хоста используется `https://stage-api.sarex.io`).