Files
dc-observatio/services/pcp-tgu-ui-service
Дмитрий Соловьев 1f44c1a5bb feat(tgu-ui): #50 слой поддержки решений по слотам + выбор полосами
Поверх ручного бронирования — информационный слой (достаточность судит оператор).

M1 покрытие: coverage.ts (растровое Monte-Carlo % покрытия заявки, чистые функции
  + coverage.test.ts), CoveragePanel (живой % + бар), слой coverage на карте
  (drawCoverage, union контуров, клип по заявке).
M2 эргономика: сортировка списка по вкладу в покрытие (жадный маргинальный прирост),
  по крену; колонка «Вклад» (+N%).
M3 конфликты: бейдж держателя BUSY-слота (заявка + важность) из holders в SlotDTO.

Выбор полосами (TASK_slot-strip-selection it.1): slotStrips.ts (groupStrips —
  same-roll цепочки по-КА, ε=0.01 с якорным креном, тотальный порядок) +
  slotStrips.test.ts; toggleStripSelection в slotSelection.ts; чип «полоса ×N» в
  строке, рельс по StripId в сортировке «время», подсветка полосы при наведении.
  Физику выполнимости не дублируем на фронте — это backend validate (it.2).

Смежный баг: anchorIndexRef (якорь Shift-выбора) сбрасывается при смене видимого
набора (фильтры/окно суток), не только сортировки.
2026-06-17 09:06:25 +03:00
..

pcp-tgu-ui-service

Фронтенд «ТГУ — Операции». Сервис собран с нуля на чистой базе исходного pcp-tgu-ops-ui (React + Vite, своя тёмная тема), в которую добавлены только две вещи с платформы NStart:

  1. Авторизация — headless-ядро @nstart/auth (New Start ID / Keycloak): токен, login, logout, refresh. Без @nstart/ui — UI-компоненты библиотеки (ProfilePage/UserPanel) намеренно не подключены, экраны ТГУ остаются на своём UI.
  2. Сборка и деплой — платформенный контракт: hardened Dockerfile (non-root, healthcheck), runtime-config (config.js из APP_*), docker-bake.hcl, .gitlab-ci.yml (build → trivy/semgrep → push в registry), nginx.conf.

В отличие от pcp-tgu-ops-ui-template, здесь нет демо-страниц шаблона, @nstart/ui, Tailwind, i18n и борьбы тем — только рабочий ТГУ + auth + контур сборки/деплоя.

Авторизация (headless)

  • Режим выбирается переменной authMode (anonymous | new-start-id).
  • anonymous (дефолт): приложение открывается сразу, токена нет, заголовок Authorization не добавляется — поведение как у исходного сервиса.
  • new-start-id: вход редиректом на New Start ID; токен подставляется в каждый запрос src/api/* через мост apiFetch + AuthTokenBridge. В шапке появляется кнопка «Выйти».
  • Конфиг входа берётся из src/config/env.ts (runtime APP_* имеют приоритет над build VITE_*).

Конфигурация окружения

Назначение DEV (npm run dev) PROD (Docker)
источник .env (VITE_*) APP_* контейнера → config.js
api VITE_API_URL APP_API_URL
режим auth VITE_AUTH_MODE APP_AUTH_MODE
New Start ID VITE_NEW_START_ID_* APP_NEW_START_ID_*

Доступ к приватному реестру @nstart/*: scope @nstart:registry=... должен быть в ~/.npmrc (или в конфиге CI-раннера). Проектный .npmrc задаёт только min-release-age=7.

Запуск

cp .env.example .env     # режим anonymous, открывается сразу
npm install              # нужен доступ к repo.nstart.cloud (scope @nstart)
npm run dev              # http://localhost:5174
npm run build            # tsc -b + vite build
npm run test             # vitest

Прод-прокси (осталось настроить)

В nginx.conf активный /api/ — заглушка (127.0.0.1:8000), а блоки pcp-* закомментированы (зеркало server.proxy из vite.config.ts). Подставьте реальные UPSTREAM_* кластера и раскомментируйте, либо вынесите маршрутизацию на gateway/ingress.