Files
dc-observatio/docs/architect/PCP_TGU_OPS_UI_CAPABILITY_MAP.md
Дмитрий Соловьев d7dda1e2f5 feat(tgu-ops-ui): add pass selector styles and update architecture docs
tgu-editor.css: add .map-pass-selector styles — floating panel with
semi-transparent background, range slider track, fill, tick marks, draggable
thumbs, and per-handle labels showing orbit number + UTC time.

docs: update PCP_ARCHITECTURE.md to reflect pcp-tgu-ops-ui is now a real SPA
(not a placeholder); add PCP_TGU_OPS_UI_CAPABILITY_MAP.md describing feature
areas and data sources for the TGU ops frontend.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 16:08:30 +03:00

20 KiB

pcp-tgu-ops-ui — карта возможностей и источников данных

Дата анализа: 2026-05-31.

Документ фиксирует, что сейчас умеет pcp-tgu-ops-ui: что отображает, чем управляет, какие backend endpoints вызывает и откуда реально приходят данные. Анализ выполнен по исходному коду frontend и по execution path backend endpoints до service/repository/external source.

Кратко

pcp-tgu-ops-ui — отдельная Vite/React SPA для Mission Ops/TGU. Приложение рендерит TguPlanningPage и имеет три вкладки:

  • Планы — timeline persisted TGU-планов по КА.
  • Карта 2D — карта с полигонами заявок на съемку.
  • Редактор — локальный редактор включений КА с черновиком, проверками и заглушкой сохранения.

Реально изменять состояние backend UI умеет только через отправку решения по плану: ACCEPTED или REJECTED. Редакторские правки пока не сохраняются во внешний сервис.

Общая схема

Browser
  |
  v
pcp-tgu-ops-ui SPA
  |
  |-- /api/tgu-planning/*
  |     |
  |     v
  |   pcp-ui-service :7008
  |     |
  |     v
  |   pcp-tgu-service :7011
  |     |
  |     |-- pcp_tgu DB
  |     |
  |     `-- Ordinis NSI spacecraft classifier
  |
  |-- /api/current-plans/*
  |     |
  |     v
  |   pcp-ui-service :7008
  |     |
  |     v
  |   pcp-mission-planing-service :7010
  |     |
  |     `-- mission planning DB
  |
  |-- /api/pcp-request/v1/*
  |     |
  |     v
  |   pcp-request-service :7005
  |     |
  |     `-- request DB
  |
  `-- https://*.basemaps.cartocdn.com
        |
        `-- CARTO basemap tiles

Dev proxy:

  • /api/pcp-request -> http://localhost:7005, prefix /api/pcp-request stripped.
  • /api -> http://localhost:7008.

Production nginx:

  • /api/pcp-request/ -> http://host.docker.internal:7005/.
  • /api/ -> http://host.docker.internal:7008/api/.

Endpoint inventory

UI endpoint Метод Использование в UI Backend execution path Источник
/api/tgu-planning/platforms GET список КА, подписи, поиск, редактор pcp-ui-service TguPlanningRestController.platforms() -> TguPlanningService.platforms() -> pcp-tgu-service /api/platforms -> PlatformService.loadPlatforms() in-memory cache, Ordinis NSI
/api/tgu-planning/plans?historyDays=N GET загрузка всех TGU-планов для timeline/map/editor context pcp-ui-service -> pcp-tgu-service /api/plans -> PlanQueryService.getAllPlans() -> PlannedPlanRepository.findAllByOrderByStartTime() planned_plan
/api/tgu-planning/spacecraft/{spacecraftId}/plans?historyDays=N GET есть в API-клиенте, текущая страница в основном грузит все планы pcp-ui-service -> pcp-tgu-service /api/plans/{spacecraftId} -> PlanQueryService.getPlansBySpacecraftId() planned_plan
/api/tgu-planning/plans/{planId}/decision?decision=...&reason=... POST кнопки принять/отклонить для WAITING_DECISION pcp-ui-service -> pcp-tgu-service /test/tgu/plans/{planId}/decision -> TestPlanDecisionService.generateDecision() -> HandlePlanDecisionUseCase.handle() planned_plan, plan_issue_attempt, spacecraft_planning_state, processed_plan_decision_event
/api/pcp-request/v1/requests/map?... GET полигоны заявок на карте 2D и в редакторе напрямую в pcp-request-service /v1/requests/map -> RequestController.listRequestsForMap() -> RequestService.listRequestsForMap() -> RequestRepository.findRequests() requests
/api/current-plans/missions/{missionId}/modes GET контуры существующих включений в редакторе pcp-ui-service -> pcp-mission-planing-service /api/missions/{missionId}/modes -> MissionPlaningService.modesByMission() missions, plans, modes, survey_modes, drop_modes, drop_mode_survey, mode_booking

Вкладка "Планы"

Что отображает

  • Список КА: name, NORAD, mission, status.
  • Количество планов по КА в выбранном интервале.
  • Индикатор проблемных статусов: REJECTED, EXPIRED, START_AMBIGUOUS.
  • Timeline persisted TGU-планов по КА.
  • Стрелки между последовательными планами одного КА.
  • Линию текущего времени, если now попадает в выбранный диапазон.
  • Детали выбранного плана:
    • planId;
    • spacecraftId;
    • КА;
    • startTime;
    • endTime;
    • duration;
    • kppId;
    • status.

Чем управляет

  • Фильтр диапазона дат.
  • Быстрые диапазоны: 24 часа, 3 суток, 7 суток.
  • Refresh данных.
  • Поиск по КА.
  • Выбор конкретного КА.
  • Выбор плана.
  • Отправка решения ACCEPTED/REJECTED, но только для плана в статусе WAITING_DECISION.

Execution path решения по плану

User
  |
  v
TguPlanDetails
  |
  |-- Принять -> decision=ACCEPTED, reason=UI_TEST_ACCEPTED
  |
  `-- Отклонить -> decision=REJECTED, reason from prompt
        |
        v
sendPlanDecision()
        |
        v
POST /api/tgu-planning/plans/{planId}/decision
        |
        v
pcp-ui-service
        |
        v
TguPlanningService.sendDecision()
        |
        v
POST pcp-tgu-service /test/tgu/plans/{planId}/decision
        |
        v
TestPlanDecisionService.generateDecision()
        |
        |-- checks plan exists
        |-- checks spacecraft_planning_state exists
        |-- checks activePlanId == planId
        |-- checks activeAttemptId exists and belongs to plan
        |-- checks attempt status STARTING/STARTED
        |
        v
HandlePlanDecisionUseCase.handle()
        |
        |-- insert processed_plan_decision_event, dedup by eventId
        |-- lock plan_issue_attempt by attemptId
        |-- lock planned_plan by planId
        |-- lock/create spacecraft_planning_state
        |
        |-- ACCEPTED:
        |     |-- attempt=ACCEPTED
        |     |-- plan=ACCEPTED
        |     |-- currentBasePlanId=planId
        |     |-- activePlanId/activeAttemptId cleared
        |     |-- enqueue plan_recalculation_job
        |     `-- enqueue accepted_plan_slots_update_job
        |
        `-- REJECTED:
              |-- attempt=REJECTED
              |-- activePlanId/activeAttemptId cleared
              |-- if enough lead time: plan=PLANNED, issueNotBefore=now
              `-- else: plan=EXPIRED, promote next plan or enqueue rebuild

Важный caveat: UI отправляет решение через test-only controller pcp-tgu-service /test/tgu/.... Если tgu.test-controller.enabled=false, эта команда перестанет работать.

Вкладка "Карта 2D"

Что отображает

  • CARTO dark basemap tiles.
  • Lat/lon grid поверх тайлов.
  • Полигоны заявок на съемку из pcp-request-service.
  • Цвета заявок по surveyType:
    • OPTICS;
    • RSA;
    • COMBINED.
  • Hover tooltip по полигону.
  • Выбор полигона заявки на карте.
  • Детальную панель с выбранным планом и выбранным объектом карты.

Чем управляет

  • Панорамирование карты drag-ом.
  • Zoom колесом и кнопками +/-.
  • Reset view.
  • Включение/выключение слоев.
  • Загрузка заявок за отдельный интервал.
  • Быстрые интервалы заявок: сегодня, 7 дней, 30 дней.
  • Скрытие/показ КА в sidebar.

Что сейчас заявлено в UI, но не имеет данных

В главной карте 2D есть переключатели слоев:

  • трасса КА;
  • полоса обзора;
  • работы плана;
  • станции;
  • маркеры КА;
  • заявки на съемку.

Но текущий buildTgu2DMapScene() наполняет только request polygons. Для остальных слоев рисовалки существуют, но данные в scene не передаются. UI показывает предупреждение: Данные слоя недоступны в текущем API.

Execution path карты 2D

User
  |
  v
Tgu2DMapTab
  |
  |-- selectedPlan / range / layers / hiddenSpacecraftIds
  |
  |-- load requests
  |     |
  |     v
  |   fetchRequestsForMap()
  |     |
  |     |-- page size = 500
  |     |-- max pages = 10
  |     |-- max loaded requests = 5000
  |     |-- sort = beginDateTime,asc
  |     |
  |     v
  |   GET /api/pcp-request/v1/requests/map
  |     |
  |     v
  |   pcp-request-service
  |     |
  |     v
  |   RequestController.listRequestsForMap()
  |     |
  |     v
  |   RequestService.listRequestsForMap()
  |     |
  |     v
  |   RequestRepository.findRequests()
  |     |
  |     |-- status filter, optional
  |     |-- surveyType filter, optional
  |     |-- kpp filter, supported by backend but not passed by current UI
  |     |-- highPriorityTransmit filter, supported by backend but not passed by current UI
  |     |-- beginFrom/beginTo/endFrom/endTo
  |     |-- exclude DELETED by default
  |     |
  |     v
  |   requests table
  |
  v
buildTgu2DMapScene()
  |
  |-- parse WKT from request.geometry
  |-- supports POLYGON and MULTIPOLYGON
  |-- build MapPolygon objects with layer=requests
  |
  v
Tgu2DMapView
  |
  |-- drawTiles()
  |     |
  |     `-- https://{a|b|c|d}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png
  |
  |-- drawBaseMap()
  |     |
  |     `-- 30 degree lat/lon grid
  |
  |-- drawRequests()
  |     |
  |     `-- request polygons on canvas
  |
  |-- createPolygonSpatialIndex()
  |-- hitTestPolygons()
  |
  v
Canvas + hover tooltip + selected object details

Фильтр заявок на карте

Для выбранного интервала [from, to] UI передает:

endFrom = from
beginTo = to

То есть выбираются заявки, которые пересекают интервал карты.

Вкладка "Редактор"

Что отображает

  • Выбранный КА и выбранный TGU-план.
  • Черновик включений:
    • shoot — съемка;
    • downlink — сброс.
  • Timeline черновика.
  • Окна видимости цели/станции.
  • Синтетическую трассу КА на карте редактора.
  • Полигоны заявок из pcp-request-service.
  • Контуры SURVEY из pcp-mission-planing-service, если endpoint /current-plans/missions/{id}/modes вернул режимы.
  • Счетчики:
    • всего включений;
    • съемок;
    • сбросов;
    • конфликтов.

Что умеет делать локально

  • Добавить съемку через клик точки на карте.
  • Добавить сброс по станции и окну связи.
  • Перетаскивать включения по timeline.
  • Менять начало/конец включения drag resize.
  • Менять время через stepper.
  • Дублировать включение.
  • Удалять включение.
  • Undo/redo.
  • Проверять пересечения включений по времени.
  • Проверять видимость цели/станции по синтетической орбитальной модели passes.ts.
  • Показывать контекст других КА в rail, но сейчас contextLanes.works пустой.

Что не умеет сохранять

Кнопка Применить вызывает saveEditedPlan(), но функция является заглушкой:

Сохранение правок плана во внешний сервис еще не реализовано в backend.

Backend endpoint для сохранения отредактированного набора включений отсутствует.

Execution path редактора

User
  |
  v
TguEditorTab
  |
  |-- selectedSpacecraftId / selectedPlan from TguPlanningPage
  |
  |-- initialize draft
  |     |
  |     v
  |   seedDraft(selectedPlan)
  |     |
  |     |-- if selectedPlan has embedded works:
  |     |     `-- use embedded works
  |     |
  |     `-- else:
  |           `-- create fallback downlink work:
  |                 id = {planId}:plan-window
  |                 kind = downlink
  |                 start/end = selected plan start/end
  |                 stationId = selectedPlan.kppId
  |
  |-- load request context
  |     |
  |     v
  |   fetchRequestsForMap()
  |     |
  |     v
  |   GET /api/pcp-request/v1/requests/map
  |     |
  |     v
  |   pcp-request-service
  |     |
  |     v
  |   requests table
  |
  |-- load plan modes
  |     |
  |     v
  |   fetchPlanModes(selectedPlan.planId)
  |     |
  |     v
  |   GET /api/current-plans/missions/{selectedPlan.planId}/modes
  |     |
  |     v
  |   pcp-ui-service
  |     |
  |     v
  |   pcp-mission-planing-service
  |     |
  |     v
  |   MissionPlaningService.modesByMission()
  |     |
  |     |-- check mission exists
  |     |-- find modes by mission id
  |     |-- map SurveyModeEntity -> SurveyModeResponseDTO
  |     |-- map DropModeEntity -> DropModeResponseDTO
  |     |
  |     v
  |   mission planning DB
  |
  |-- editor map scene
  |     |
  |     |-- groundTrack(spacecraftId) from frontend synthetic orbit
  |     |-- station markers only if station lat/lon exists
  |     |-- plan mode SURVEY contourWkt -> planWorks polygons
  |     `-- request.geometry WKT -> request polygons
  |
  |-- local draft operations
  |     |
  |     |-- addShoot()
  |     |-- addDownlink()
  |     |-- updateWork()
  |     |-- deleteWork()
  |     |-- duplicateWork()
  |     |-- undo()
  |     |-- redo()
  |     |-- overlaps()
  |     `-- checkVisibility()
  |
  `-- apply draft
        |
        v
      saveEditedPlan()
        |
        v
      stub result only, no backend mutation

Важные caveats редактора

  • fetchPlanModes() использует selectedPlan.planId как missionId для /api/current-plans/missions/{missionId}/modes.
  • Если UUID TGU-плана не совпадает с UUID mission в pcp-mission-planing-service, endpoint вернет 404, а редактор просто останется без режимов плана.
  • Станции строятся из selectedPlan.kppId, но координаты станции из backend не загружаются. Поэтому проверка видимости downlink часто возвращает конфликт Нет координат станции для проверки видимости.
  • Орбитальная модель в редакторе frontend-only и синтетическая: параметры выводятся из hash spacecraftId, а не из реальной баллистики/TLE.

Capability matrix

Область Сейчас умеет Ограничение
Платформы КА читать из TGU/NSI, показывать name/NORAD/mission/status при падении NSI pcp-tgu-service может использовать stale cache, если есть
TGU-планы читать persisted plans, строить timeline UI грузит все планы и фильтрует на клиенте
Решение по плану отправить ACCEPTED/REJECTED для WAITING_DECISION через test-only controller; нужен active plan + active attempt
Карта заявок загрузить и показать WKT-полигоны заявок до 5000 заявок, без server-side фильтров kpp/highPriority в UI
Слои карты UI-переключатели есть кроме заявок, основные слои главной карты не получают данных
Редактор включений локальный draft, drag/resize, add/delete/duplicate, undo/redo, checks сохранения в backend нет
Режимы плана в редакторе пытается читать /current-plans/missions/{id}/modes возможен mismatch planId vs missionId
Станции может показывать station markers только при наличии lat/lon lat/lon станций сейчас не загружаются
Тайлы карты CARTO CDN внешний network dependency браузера

Проверенные исходники

Frontend:

  • services/pcp-tgu-ops-ui/src/App.tsx
  • services/pcp-tgu-ops-ui/src/api/tguApi.ts
  • services/pcp-tgu-ops-ui/src/api/requestApi.ts
  • services/pcp-tgu-ops-ui/src/features/tgu-planning/*
  • services/pcp-tgu-ops-ui/src/features/tgu-map-2d/*
  • services/pcp-tgu-ops-ui/src/features/tgu-editor/*
  • services/pcp-tgu-ops-ui/vite.config.ts
  • services/pcp-tgu-ops-ui/nginx.conf

Backend/BFF:

  • services/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/controller/TguPlanningController.kt
  • services/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/service/TguPlanningService.kt
  • services/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/controller/CurrentPlansController.kt
  • services/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/service/MissionService.kt

TGU:

  • services/pcp-tgu-service/src/main/kotlin/space/nstart/pcp_tgu_service/controller/PlatformController.kt
  • services/pcp-tgu-service/src/main/kotlin/space/nstart/pcp_tgu_service/controller/PlanController.kt
  • services/pcp-tgu-service/src/main/kotlin/space/nstart/pcp_tgu_service/controller/TestTguController.kt
  • services/pcp-tgu-service/src/main/kotlin/space/nstart/pcp_tgu_service/service/PlatformService.kt
  • services/pcp-tgu-service/src/main/kotlin/space/nstart/pcp_tgu_service/service/PlanQueryService.kt
  • services/pcp-tgu-service/src/main/kotlin/space/nstart/pcp_tgu_service/service/TestPlanDecisionService.kt
  • services/pcp-tgu-service/src/main/kotlin/space/nstart/pcp_tgu_service/service/HandlePlanDecisionUseCase.kt
  • services/pcp-tgu-service/src/main/kotlin/space/nstart/pcp_tgu_service/repository/*

Requests:

  • services/pcp-request-service/src/main/kotlin/org/nstart/dep265/requestservice/controller/RequestController.kt
  • services/pcp-request-service/src/main/kotlin/org/nstart/dep265/requestservice/service/RequestService.kt
  • services/pcp-request-service/src/main/kotlin/org/nstart/dep265/requestservice/repository/RequestRepository.kt
  • services/pcp-request-service/src/main/kotlin/org/nstart/dep265/requestservice/dto/RequestApiDtos.kt

Mission planning:

  • services/pcp-mission-planing-service/src/main/kotlin/space/nstart/pcp/pcp_mission_planing_service/controller/MissionController.kt
  • services/pcp-mission-planing-service/src/main/kotlin/space/nstart/pcp/pcp_mission_planing_service/service/MissionPlaningService.kt
  • services/pcp-mission-planing-service/src/main/kotlin/space/nstart/pcp/pcp_mission_planing_service/repository/*
  • libs/pcp-types-lib/src/main/kotlin/space/nstart/pcp/pcp_types_lib/dto/satellite/mission/*