Вкладка «Слоты» масштабирована под ~20k слотов/мес без торможения:
- wktCache: контур слота парсится один раз (кэш по slotKey), не на каждый ререндер сцены
- виртуализация таблицы (@tanstack/react-virtual): в DOM только видимое окно строк
- автоподбор покрытия: проброс coverageStrategy (GREEDY/CONTINUOUS) в request-cover,
результат — преднабор брони (solver не дублируется, используется бэкендный)
- мультивыбор: Shift-диапазон по отсортированному списку, «все сутки»/«видимые»,
счётчик охвата выбора
- бронь крупных наборов чанками (по 200) + подтверждение выше 500 + прогресс
- отмена расчёта (AbortController), мягкая подсказка перегруза карты
- чистая логика выбора/чанкинга вынесена в slotSelection.ts + юнит-тесты
Тесты: 70/70 (17 новых). tsc -b и vite build чисто.
- новая вкладка: заявки интервала на карте, выбор заявки кликом/инспектором,
расчёт слотов покрытия, бронирование и снятие брони
- выбор заявки без выпадающего списка (не масштабируется на ~10к): все заявки
на карте, панель справа с кнопкой «Выбрать», имя выбранной заявки в тулбаре,
кнопка «Сброс», фильтр заявок по интервалу
- бронь отмечаем по ответу POST booking/request (by-request отдаёт слот в чужом
cycle-фрейме — ключ не совпадал, бейдж «бронь» не появлялся)
- подсветка и автоскролл активной строки по клику на слот (ручной scrollBy)
- меню выбора при плотном наложении слотов (SlotPickMenu); контур заявки
pickable:false, чтобы не «съедать» меню; панель не закрывается при выборе
- фильтр отображения по суткам (SlotDaySelector)
- gateway: маршрут slots (/api/pcp-slots/**)
- карточка полосы обзора (swath): КА и виток в инспекторе
При первой правке плана ensureDraft→createDraft(replace) падал 409, если по КА
уже есть открытый черновик на это окно (осиротевший с прошлой сессии — авто-отмена
best-effort). В UI это показывалось голым «Conflict» (на стенде не подхвачен
include-message у tgu).
Теперь на 409 от createDraft редактор подхватывает существующий черновик того же
КА с тем же окном (adoptExistingDraft через fetchDraftPlans, сверка окна ±2 c) и
продолжает в нём; если подходящего нет — читаемое сообщение со ссылкой на вкладку
«Планы» вместо «Conflict».
Обобщил ComplexInfoPanel в общий MapObjectInspector (tgu-map-2d): карточки для
всех типов объектов — заявка, включение комплексного плана, ячейка тепловой карты,
маршрут planWorks, станция, маркер КА, линия; список с раскрытием при наложении.
Вкладка «Карта» переведена на enableObjectChooser + onObjectsAtPoint + правый
инспектор — заменила разрозненные Tgu2DMapRequestsPanel/Tgu2DMapStationPanel (удалены)
и объектную часть нижней плашки (Tgu2DMapDetails ужат до контекста плана). Вкладка
«Комплексный план» использует тот же инспектор.
RequestAtPoint переехал в tgu-requests/RequestDetailsPanel (нужен вкладке «Заявки»).
Чекбокс «Тепловая карта» — фоновый слой-заливка ячеек сетки заданий по важности
(cool→hot), источник GET /api/pcp-request/v1/cells/priority-map (cellsApi + drawHeatmap).
Heatmap — полноценный слой MapPolygon (layer "heatmap", importance/cellNum), участвует
в spatial-индексе и chooser, рисуется под контурами плана/заявок.
Клик по объекту открывает правый инспектор ComplexInfoPanel (по аналогии с редактором):
карточки ячейки приоритета, включения комплексного плана и заявки; при наложении —
список объектов под точкой клика с раскрытием. При включённой тепловой карте ячейка
всегда идёт первой в списке и раскрыта по умолчанию.
Бэклог #44 отмечен сделанным.
Кнопка предлагала replace-черновик для уже стартовавшего плана, хотя бэк
(CreateDraftUseCase.createReplaceDraft) возвращает 422 «окно выдачи заморожено».
Гард canCreateDraftFromPlan теперь требует startInFuture (зеркалит редактор);
для стартовавших eligible-планов вместо кнопки — amber-подсказка про fork-forward.
Запросы tguApi.ts (platforms/plans/decision/dismiss/restore/confirm-layin)
и flight-line переведены с прокси /api/tgu-planning через умирающий
pcp-ui-service на прямые вызовы pcp-tgu-service (/api/pcp-tgu, decision и
confirm-layin — на тест-контроллер /test/tgu/*) и pcp-ballistics-service.
flight-line перенесён в ballisticsApi.ts. editorApi.ts modes переведён с
/api/current-plans на /api/pcp-mission. UX-перевод ошибок решения уже жил во
фронте (errorMessage в tguApi.ts), серверная обвязка ui-service дублировала.
Из config-repo/pcp-gateway-service.yaml снят маршрут ui-catch-all: не-матчнутый
/api/** теперь отдаёт 404 на gateway, а не уходит в pcp-ui-service.
Шаг 8 (вывод сервиса из эксплуатации: compose/helm/CI/реестр + удаление кода)
отложен до проверки репойнта на живом стенде; сервис пока задеплоен без
маршрутов. См. docs/план-перевода-с-pcp-ui-service.md и задачу #40 бэклога.
CORS-политика (allowedOriginPatterns:* + allowCredentials) переезжает в единый
globalcors на pcp-gateway-service. После сворачивания фронта на gateway браузер
ходит к бэкендам только через него (same-origin via Vite/nginx), поэтому
per-service CORS в pcp-ui-service/WebConfig.kt стал мёртвым грузом. globalcors
оставлен как страховка от cross-origin напрямую к gateway.
Откат регрессии 0ec8c30: в профиле dev datasource снова берётся из
SPRING_DATASOURCE_URL/USERNAME/PASSWORD (профиль local оставлен параметрическим).
dynamic-plan и tgu переведены на тот же механизм + добавлены helm extraEnv
с in-cluster postgres и кредами из секретов pcp-dynamic-plan-db / pcp-tgu-db.
Run pipeline + RUN_ALL=true прогоняет test/build/package всех бэкендов
независимо от changes; deploy:dev остаётся ручным. Обычный пуш по-прежнему
собирает только изменившийся сервис. pcp-tgu-ui-service source-guard-нут
(только push), чтобы не попадать в RUN_ALL/web-пайплайны.
Merge 0ec8c30 затёр ${SPRING_DATASOURCE_URL/USERNAME/PASSWORD} на конкретный
postgres в shared-профиле, из-за чего падал тест RequestServiceConfigTest
(shared datasource keeps environment placeholders) и красился CI.
Плейсхолдеры восстановлены; local-профиль остаётся с конкретным postgres.
Дашборд «Группировка» наполняется из плана: режимы SURVEY/DROP → интервалы
съёмки и сброса с контуром и станцией, окна ЗРВ выделены в отдельную «связь»
(раньше показывались как сброс). Заполнение бортового накопителя считается
из объёмов маршрутов (volumeMb) с модельной ёмкостью 500 ГБ
(ONBOARD_CAPACITY_MB) — memAt по таймлайну, подсветка контура/линии сброса
на карте.
Бэкенд считает геометрию видимости/маршрута только в |крен| ≤ 45°,
поэтому предел снижен с 89° до 45°. Введён общий clampRoll (зажим +
округление до 0.1°), применён при ручной правке крена (кнопки ±,
прямой ввод) и при загрузке сохранённого маршрута в окно построения
(легаси-маршрут вне ±45° зажимается).
Сброс рисуется приглушённо-малиновым (rgba(214,96,138,0.82), ширина 5)
поверх трассы: контрастно к бирюзовым виткам, не сливается с заявками
и контурами съёмки.
Зафиксирована диагностика: корень — оптические полосы Emissio в каталоге
(satellite_slot_angle) уходят до 50.42°, slots-service берёт центр полосы
без зажима по 45°. Версия «логика локации» проверена и отклонена.
RS1 (#29): планировщик истечения заявок — RequestExpiryService
(@Scheduled + FOR UPDATE SKIP LOCKED, мультиинстанс-safe), refreshStatus
вызывается и при создании заявки.
RS7 (#35): единый топик pcp.request.status.v1 → geoportal (COMPLETED/EXPIRED
в payload), замена orphan pcp.request.completed.v1; эмиссия из matching и
expiry через тот же outbox; backoff/next_attempt_at/cap для outbox FAILED.
RS3 (#31): DefaultErrorHandler + DeadLetterPublishingRecoverer
(DLQ pcp.route.georeference-dlq.v1), bounded retry, контрактные ошибки в DLQ.
RS6 (#34): проброс coverageRequiredPercent из API, разведение терминов
покрытие/важность.
Доки: бэклог, аудит сервиса заданий, карты взаимодействий.
RS2 (#30) отложено до #28, RS5 (#33) — до роста требований к точности.
Объём режима = скорость × длительность, Мбайт: съёмка 120 Мбайт/с (12 ГБ / 100 с), сброс — канал 1200 Мбит/с ÷ 8. Единый источник — ModeDataRates в pcp-types-lib. Хранится колонкой volume_mb (Flyway V10 mission-planing, V9 complex-mission, бэкфилл из duration), заполняется на всех путях построения через @PrePersist/@PreUpdate. DTO отдают вычисляемое read-only поле (та же формула). Фронт pcp-tgu-ops-ui показывает объём в редакторе (инспектор, построенный маршрут) и в сводке комплексного плана.
Тестовый эндпоинт загрузки платформ принимает root-array НСИ в теле запроса (@RequestBody List<NsiPlatformDto>) вместо пути к файлу; маршрут load-from-file переименован в load-manual.
Добавлены docs/бэклог-pcp-tgu-ops-ui.md, бриф дашборда состояния группировки
и прототипы docs/ui-prototypes/tgu-ops/; удалён устаревший
docs/задачи для pcp-tgu-ops-ui.txt.
application.yaml/yml всех сервисов и config-repo переведены с 192.168.60.x
на localhost (дефолты CONFIG_SERVER_URI и пр.); обновлены примеры в
changeIpInCurrentFolder.sh и create_pcp_databases.sh.