# План перевода запросов с 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<ModeResponseDTO>`.
Фронтовый `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).
  Если такая обогащённая поверхность понадобится новому фронту — она должна переехать в
  источник или во фронт, а не остаться «висеть» в умирающем сервисе. Сейчас новый фронт её
  не использует.
