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>
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-requeststripped./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.tsxservices/pcp-tgu-ops-ui/src/api/tguApi.tsservices/pcp-tgu-ops-ui/src/api/requestApi.tsservices/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.tsservices/pcp-tgu-ops-ui/nginx.conf
Backend/BFF:
services/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/controller/TguPlanningController.ktservices/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/service/TguPlanningService.ktservices/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/controller/CurrentPlansController.ktservices/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.ktservices/pcp-tgu-service/src/main/kotlin/space/nstart/pcp_tgu_service/controller/PlanController.ktservices/pcp-tgu-service/src/main/kotlin/space/nstart/pcp_tgu_service/controller/TestTguController.ktservices/pcp-tgu-service/src/main/kotlin/space/nstart/pcp_tgu_service/service/PlatformService.ktservices/pcp-tgu-service/src/main/kotlin/space/nstart/pcp_tgu_service/service/PlanQueryService.ktservices/pcp-tgu-service/src/main/kotlin/space/nstart/pcp_tgu_service/service/TestPlanDecisionService.ktservices/pcp-tgu-service/src/main/kotlin/space/nstart/pcp_tgu_service/service/HandlePlanDecisionUseCase.ktservices/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.ktservices/pcp-request-service/src/main/kotlin/org/nstart/dep265/requestservice/service/RequestService.ktservices/pcp-request-service/src/main/kotlin/org/nstart/dep265/requestservice/repository/RequestRepository.ktservices/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.ktservices/pcp-mission-planing-service/src/main/kotlin/space/nstart/pcp/pcp_mission_planing_service/service/MissionPlaningService.ktservices/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/*