# План перевода запросов с pcp-ui-service на источники _Составлено: 2026-06-10. Связано с задачей #40 бэклога [бэклог-pcp-tgu-ops-ui.md](бэклог-pcp-tgu-ops-ui.md)._ ## Зачем `pcp-ui-service` — наследие старого server-rendered UI (Thymeleaf-страницы + REST-прокси-обвязка над доменными сервисами). Новый фронт `pcp-tgu-ui-service` ходит к бэкендам через `pcp-gateway-service`, и большинство его клиентов уже бьют в доменные сервисы напрямую (`/api/pcp-tgu`, `/api/pcp-mission`, `/api/pcp-ballistics`, `/api/pcp-complex`, `/api/pcp-request`). `pcp-ui-service` остаётся в маршрутизации только как **catch-all** (`ui-catch-all`, `order:1` в `config-repo/pcp-gateway-service.yaml`) для двух поверхностей. Цель — увести эти две поверхности на источники и вывести `pcp-ui-service` из эксплуатации. ## Кто ещё зависит от pcp-ui-service Проверено (grep по `config-repo/`, `services/`, `libs/`): **никто, кроме фронта и catch-all gateway.** Остальные ссылки — это самопрописка сервиса в Spring Boot Admin (`config-repo/pcp-ui-service.yaml`) и комментарии в `pcp-types-lib` про то, что обогащение DTO «исторически делалось в ui-service». Восток-запад (межсервис) сервис не вызывает никто. ## Карта запросов фронта, идущих через pcp-ui-service Через catch-all `pcp-ui-service` сейчас проходят запросы только из **двух** файлов фронта. Всё остальное (`ballisticsApi`, `complexPlanApi`, `missionPlanningApi`, `requestApi`, `tguPlanApi`, `stationsApi`) уже ходит мимо ui-service. ### 1. `src/api/tguApi.ts` → `/api/tgu-planning/*` (+ flight-line) Контроллер `TguPlanningRestController` (`services/pcp-ui-service/.../controller/TguPlanningController.kt`) проксирует через `TguPlanningService`/`BallisticsService`. Источники и реальные пути: | Запрос фронта (через ui-service) | HTTP | Реальный источник | Путь на источнике | |--------------------------------------------------------------|------|------------------------------|----------------------------------------------------| | `/api/tgu-planning/platforms` | GET | pcp-tgu-service | `/api/platforms` | | `/api/tgu-planning/plans?historyDays` | GET | pcp-tgu-service | `/api/plans?historyDays` | | `/api/tgu-planning/spacecraft/{id}/plans?historyDays` | GET | pcp-tgu-service | `/api/plans/{spacecraftId}?historyDays` | | `/api/tgu-planning/plans/{planId}/decision?decision&reason` | POST | pcp-tgu-service (**TEST**) | `/test/tgu/plans/{planId}/decision` | | `/api/tgu-planning/plans/{planId}/dismiss` | POST | pcp-tgu-service | `/api/plans/{planId}/dismiss` | | `/api/tgu-planning/plans/{planId}/restore` | POST | pcp-tgu-service | `/api/plans/{planId}/restore` | | `/api/tgu-planning/plans/{planId}/confirm-layin?reason` | POST | pcp-tgu-service (**TEST**) | `/test/tgu/plans/{planId}/confirm-layin` | | `/api/tgu-planning/spacecraft/{noradId}/flight-line` | GET | pcp-ballistics-service | `/api/satellites/{noradId}/flight-line` (+интервал)| **Что ui-service делает поверх прокси (нельзя потерять при переезде):** - **Перевод ошибок в человекочитаемые сообщения** для решения по плану (`decision`): 404 → «План не найден.» / «Test controller недоступен или отключён.»; 409 → «План не является активным планом, ожидающим решения…»; 5xx → «Test controller недоступен…». Сетевые сбои (`WebClientRequestException`) → 503 «Test controller недоступен…». При переезде эту UX-обвязку нужно перенести во фронт (`tguApi.ts`/общий `http.ts`, см. #17), иначе оператор увидит сырой 4xx/5xx. - `decision` и `confirm-layin` идут в **тест-контроллер** tgu (`/test/tgu/...`), гейтится `tgu.test-controller.enabled` в `config-repo/pcp-tgu-service.yaml`. Это MVP-канал подтверждений (ср. #13). При переезде поведение не меняется — но прод-канал решений остаётся отдельным вопросом. - DTO (`TguPlanResponse`, `TguPlatformResponse`) проксируются **как есть** (`bodyToFlux` того же типа) — форма ответа источника и ui-service идентична, фронт не сломается по схеме. ### 2. `src/features/tgu-editor/editorApi.ts` → `/api/current-plans/missions/{planId}/modes` | Запрос фронта (через ui-service) | HTTP | Реальный источник | Путь на источнике | |---------------------------------------------------|------|-----------------------------|------------------------------------| | `/api/current-plans/missions/{planId}/modes` | GET | pcp-mission-planing-service | `/api/missions/{missionId}/modes` | `CurrentPlansController.modes` → `MissionService.modesByMission` → `${settings.mission-service}` (= `pcp.services.mission` = pcp-mission-planing-service), прямой проброс `List`. Фронтовый `missionPlanningApi.ts` уже ходит в этот же сервис через `/api/pcp-mission` — endpoint переезжает туда же. ## План перевода (порядок шагов) > **Статус (2026-06-10): шаги 1–7 выполнены** — фронт ходит в источники напрямую, catch-all > снят. Шаг 8 (вывод сервиса из эксплуатации) отложен до проверки репойнта на живом стенде; > до этого pcp-ui-service остаётся задеплоен, но без маршрутов (безвреден). Перевод ошибок > решения уже жил во фронте (`errorMessage` в `tguApi.ts`) — серверная обвязка ui-service > дублировала его, при прямом обращении к tgu ничего не потеряно. 1. **flight-line → `/api/pcp-ballistics`.** Перенести `fetchFlightLine` в `ballisticsApi.ts` (там уже `BASE=/api/pcp-ballistics`), путь `/api/satellites/{noradId}/flight-line` + интервал `time_start`/`time_stop`. Сверить формат точек `FlightLinePoint` с тем, что отдаёт баллистика напрямую (ui-service отдавал `collectList().block()` того же flux — форма та же). 2. **platforms / plans / spacecraft-plans → `/api/pcp-tgu`.** Перепривязать GET-методы `tguApi.ts` на `/api/pcp-tgu` + `/api/platforms`, `/api/plans`, `/api/plans/{id}`. `tguPlanApi.ts` уже использует этот префикс — переиспользовать его конвенции/`fetchJson`. 3. **dismiss / restore → `/api/pcp-tgu`** на `/api/plans/{id}/dismiss|restore` (реальный API). 4. **decision / confirm-layin → `/api/pcp-tgu`** на `/test/tgu/plans/{id}/decision|confirm-layin`. **Одновременно** перенести во фронт перевод ошибок (карта статусов → сообщения выше). Учесть зависимость от `tgu.test-controller.enabled`. 5. **modes → `/api/pcp-mission`.** В `editorApi.ts` заменить `/api/current-plans/missions/{id}/modes` на `/api/pcp-mission/api/missions/{id}/modes` (через общий клиент/`apiFetch`). Свериться с `missionPlanningApi.ts`. 6. **Vite/nginx.** Проверить, что `/api/pcp-*` и `/api/pcp-mission` уже проксируются на gateway (да — единый `/api` → gateway). Спец-обработка `/api/tgu-planning`/`/api/current-plans` не нужна. 7. **Снять catch-all.** Удалить маршрут `ui-catch-all` из `config-repo/pcp-gateway-service.yaml` (после того как фронт перестал слать `/api/tgu-planning` и `/api/current-plans`). Проверить, что никакой `/api/**` больше не должен попадать в ui-service. 8. **Вывод сервиса из эксплуатации.** Убрать `pcp-ui-service` из gateway-реестра-потребителей, `docker-compose`/helm/CI (`.gitlab/ci/pcp-ui-service.yml`, include в `.gitlab-ci.yml`, `changes:`-списки), `config-repo/pcp-ui-service.yaml`, Spring Boot Admin. Код сервиса — архивировать/удалить отдельным шагом после стабилизации. ## Риски и на что смотреть - **Потеря UX-перевода ошибок решения** — главный функциональный риск. Перенести в фронт вместе с шагом 4, не откладывать. - **Тест-контроллер как канал решений** — `decision`/`confirm-layin` остаются на `/test/tgu/*`. Это сознательный MVP-срез; прод-канал — отдельная задача (ср. #13). - **Мёртвые поверхности ui-service.** Контроллеры `bookings`, `catalog`, `rva`, `dynamic-plan`, `tle-analysis`, `tle-comparison`, `com-plan`, `requests`, `map`, `satellites/pdcm`, `RvaController` и server-rendered страницы новый фронт **не вызывает** — они умирают вместе с сервисом. Перед удалением кода ещё раз убедиться, что у них нет внешних потребителей (геопортал и т.п.). - **Обогащение DTO в ui-service** (`BookedSlotDetailsDTO`: имя/тип КА добавлялись в ui-service). Если такая обогащённая поверхность понадобится новому фронту — она должна переехать в источник или во фронт, а не остаться «висеть» в умирающем сервисе. Сейчас новый фронт её не использует.