# Observatio Terrae (pcp) — карта сервисов, взаимодействие и контракты

> Базовый справочный документ для доработки системы планирования ДЗЗ.
> Составлен из исходного кода (контроллеры, Kafka listeners/publishers, HTTP-клиенты) и `config-repo`.
> Помечено явно, что **проверено по коду**, а что **требует уточнения** (`⚠`).

Стек: Kotlin + Spring Boot, Spring Cloud Config, Spring Boot Admin, Camunda 8 / Zeebe (оркестрация), Kafka (события), PostgreSQL (БД на сервис, Flyway), Helm + GitLab CI.

---

## 1. Карта сервисов — кто за что отвечает

### Доменные сервисы

| Сервис | Зона ответственности | REST base | Хранит | Kafka (in / out) | Зрелость* |
|---|---|---|---|---|---|
| **pcp-request-service** | Приём и жизненный цикл заявок на съёмку; сетка Земли (earth-grid), геопривязка ячеек, сопоставление маршрутов с заявками | `/v1/requests`, `/v1/cells`, `/v1/grid` | заявки, ячейки сетки, outbox | in: `pcp.route.georeference.v1` · out: `pcp.request.status.v1` (outbox → geoportal) | 🟢 высокая |
| **pcp-route-processing-service** | Приём «паспортов маршрутов», нормализация/геопривязка, ретрансляция дальше; собственный outbox + DLQ | `/api/route-processing` (test) | outbox маршрутов | in: `pcp.request.survey-georeference.v1` · out: `pcp.route.georeference.v1`, `pcp.route.in.v1`, DLQ | 🟢 высокая |
| **pcp-satellite-catalog-service** | Каталог КА (источник истины): спутники, группы, observation/slot-профили | `/api/satellites`, `/api/satellite-groups` | каталог КА, профили | out: `pcp.satellites` (`SatelliteDeletedEvent`) | 🟡 средняя (мало тестов) |
| **pcp-ballistics-service** | Баллистика: орбиты, ЗРВ/RVA, узлы, трассы, time-extract по TLE | `/api/satellites`, `/api/obj-view`, `/api/tle`, `/api/rva` | орбитальные данные | in: `pcp.tle` (IC/ICRV/TLE фильтры), `pcp.satellites` | 🟡 средняя |
| **tle-monitoring-service** | Подтяжка TLE (CelesTrak), мониторинг каталога | — | TLE-история | in: `pcp.satellites` · out: `pcp.tle` ⚠ | 🟡 средняя |
| **pcp-coverage-scheme-service** | Расчёт схемы покрытия (coverage scheme) | `/api/coverage-schemes` | результаты схем | in: `pcp.satellites` | 🟡 средняя |
| **slots-service** | Слоты сброса/ресурсы: расчёт, бронирование, статусы слотов | (см. контроллеры) | слоты, брони | in/out: `pcp.slots.status.v1` (`BookedSlotsStatusChangedEvent`); in: `pcp.satellites` | 🟢 высокая (лучшее покрытие тестами) |
| **pcp-complex-mission-service** | Комплексный план по тепловой карте методом слотов; снапшоты планов | `/api/satellites`, `/api/com-plan` | комплексные планы, снапшоты | in: `pcp.satellites` | 🟢 высокая |
| **pcp-mission-planing-service** | План по конкретному КА: съёмка / сброс / стирание; **хост Zeebe-воркеров** оркестрации | `/api/missions` | миссии, режимы | in: `pcp.slots.status.v1`, `pcp.route.in.v1`, `pcp.satellites` | 🔴 низкая (есть заглушки в `FlowService`) |
| **pcp-dynamic-plan-service** | Динамический/текущий план (greedy-математика, расчёт по интервалам) | `/v1/main/calcPlan` | прогоны (runs), результаты | in: `pcp.satellites` | 🟡 средняя |
| **pcp-tgu-service** | Операторская оркестрация (ТГУ/Mission Ops): окна видимости, выдача планов, решения по планам; **деплой и запуск BPMN** | `/api/plans`, `/api/platforms`, `/test/tgu` | планы КА, dedup-таблицы | in: `pcp.tgu.satellite-plan-decision.v1` · out: `pcp.tgu.visibility-windows-changed.v1` | 🟢 высокая |
| **pcp-stations-service** | Каталог наземных станций приёма | `/api/stations` | станции | — | 🟡 средняя |
| **pcp-ui-service** | BFF/агрегатор для веб-UI и 3D-глобуса (CZML/Cesium); проксирует во все сервисы | `/requests`, `/map`, `/api/*` | — (stateless) | — | 🟡 средняя |

\* Зрелость = оценка по соотношению тестов, наличию idempotency/outbox, чистоте слоёв и отсутствию заглушек (см. предыдущий разбор).

### Инфраструктурные модули

| Модуль | Роль |
|---|---|
| **spring-cloud-config-server** | Раздаёт конфигурацию из `config-repo` всем сервисам |
| **pcp-srpring-boot-admin-server** | Spring Boot Admin — мониторинг/health всех сервисов (опечатка в имени: `srpring`) |
| **pcp-tgu-ops-ui** | Отдельная SPA Mission Ops/TGU; карта возможностей и источников данных: [`PCP_TGU_OPS_UI_CAPABILITY_MAP.md`](PCP_TGU_OPS_UI_CAPABILITY_MAP.md) |
| **libs/pcp-types-lib** | Общие DTO и конверт `KafkaMessage<T>`, перечисление `PcpKafkaEvent` |
| **libs/ballistics-lib** | Общие баллистические расчёты |

---

## 2. Диаграммы взаимодействия

### 2.1. Синхронные зависимости (REST) — кто кого вызывает

Рёбра восстановлены из ключей `*-service*` base-url в `config-repo` и имён HTTP-клиентов в коде.

```mermaid
flowchart TD
    UI[pcp-ui-service<br/>BFF / агрегатор]
    REQ[pcp-request-service<br/>заявки + earth-grid]
    CAT[pcp-satellite-catalog-service<br/>каталог КА]
    BAL[pcp-ballistics-service]
    CM[pcp-complex-mission-service]
    MP[pcp-mission-planing-service]
    SL[slots-service]
    CS[pcp-coverage-scheme-service]
    DP[pcp-dynamic-plan-service]
    TGU[pcp-tgu-service]
    ST[pcp-stations-service]
    TLE[tle-monitoring-service]

    UI --> REQ & CM & DP & TGU & CAT & BAL & ST & SL & MP & CS

    CM --> BAL & REQ & CAT & ST & SL & CS
    MP --> BAL & CM & CAT & ST
    SL --> REQ & CAT
    DP --> REQ & BAL & CAT
    CS --> BAL & CM & CAT
    TLE --> CM & CAT
    TGU --> BAL

    TLE -.внешний.-> CTRAK[(CelesTrak)]
    TGU -.внешний.-> ORD[(ordinis.nstart.cloud<br/>классификатор платформ + external points)]
```

Наблюдения по графу:
- `pcp-satellite-catalog-service` и `pcp-ballistics-service` — самые востребованные (почти все зовут их). Кандидаты на повышенные требования к SLA/надёжности.
- `pcp-ui-service` — точка агрегации (BFF), завязан на всё.
- ⚠ Есть взаимный вызов `complex-mission ⇄ coverage-scheme` (CM зовёт CS на расчёт, CS в конфиге знает про CM) — проверить, нет ли циклической зависимости в рантайме.

### 2.2. Событийный слой (Kafka) — потоки данных

```mermaid
flowchart LR
    EXT[Внешний источник / UI ⚠] -->|pcp.request.survey-georeference.v1| RP[route-processing]
    RP -->|pcp.route.georeference.v1| REQ[request-service]
    RP -->|pcp.route.in.v1| MP[mission-planing]
    REQ -->|pcp.request.status.v1 · COMPLETED/EXPIRED| GEO[geoportal · внешний]

    CAT[satellite-catalog] -->|pcp.satellites / SatelliteDeletedEvent| BAL[ballistics]
    CAT --> TLEM[tle-monitoring]
    CAT --> SL[slots]
    CAT --> MP
    CAT --> CM[complex-mission]
    CAT --> DP[dynamic-plan]

    TLEM -->|pcp.tle| BAL

    SL -->|pcp.slots.status.v1 / BookedSlotsStatusChanged| MP
    SL -->|pcp.slots.status.v1| SL

    MissionOps[Mission Ops / КА ⚠] -->|pcp.tgu.satellite-plan-decision.v1| TGU[tgu-service]
    TGU -->|pcp.tgu.visibility-windows-changed.v1| TGU
```

### 2.3. Сквозной сценарий планирования (sequence)

Упрощённый happy-path от заявки до выдачи задания на КА.

```mermaid
sequenceDiagram
    participant U as UI
    participant RQ as request-service
    participant RP as route-processing
    participant CM as complex-mission
    participant SL as slots-service
    participant TGU as tgu-service (Camunda)
    participant MP as mission-planing (Zeebe workers)

    U->>RQ: POST заявка на съёмку
    RP-->>RQ: pcp.route.georeference.v1 (геопривязанные маршруты)
    RQ->>RQ: сопоставление маршрут↔заявка, RequestCompleted (outbox)
    U->>CM: POST /api/com-plan/process (комплексный план)
    CM->>SL: расчёт/бронирование слотов
    CM->>CM: снапшот комплексного плана
    U->>TGU: POST /test/tgu/plans/{id}/issue
    TGU->>TGU: start BPMN createSatelliteMission
    Note over TGU,MP: Zeebe job dispatch по jobType
    TGU-->>MP: calculateSatelliteSurveyMissions
    MP->>MP: план съёмки
    TGU-->>MP: calculateSatelliteDropMissions
    MP->>MP: план сброса
    TGU-->>MP: sendSatellitePlan
    MP-->>TGU: Message_SatellitePlanAccepted ⚠ (сейчас имитация)
    MissionOps-->>TGU: pcp.tgu.satellite-plan-decision.v1 (ACCEPTED/REJECTED)
    TGU->>TGU: updateAcceptedPlanSlots BPMN → updateSlotsStatus
```

---

## 3. Контракты между сервисами

### 3.1. Оркестрация Camunda 8 / Zeebe

**Деплой BPMN:** `pcp-tgu-service` через `@Deployment` при старте грузит:
`classpath:BPMN/createSatelliteMission.bpmn`, `classpath:BPMN/updateAcceptedPlanSlots.bpmn`.

**Zeebe job workers** (реализованы в `pcp-mission-planing-service/FlowService`):

| jobType | Назначение | Вход (process variables) | Выход | Примечание |
|---|---|---|---|---|
| `calculateSatelliteSurveyMissions` | План съёмки | `satellitePlanId`, `spacecraftId`, `planStartTime`, `planEndTime` | `modes: Int` | `autoComplete=false` |
| `calculateSatelliteDropMissions` | План сброса | `satellitePlanId` | `modes: Int` | — |
| `sendSatellitePlan` | Отправка плана на КА | `satellitePlanId` | — | ⚠ сейчас `Thread.sleep` + имитация подтверждения |
| `updateSlotsStatus` | Подтверждение, обновление слотов | `satellitePlanId` | `slots: List` | используется в `updateAcceptedPlanSlots` |

**Camunda message:** `Message_SatellitePlanAccepted`, `correlationKey = satellitePlanId`.

> ⚠ `schemes/pcp_v1.bpmn` — большой концептуальный процесс (шлюзы, параллельные ветки, подпроцессы), **не задеплоен** и без jobType. Реально работает только минимальный `createSatelliteMission.bpmn` (start → 3 service task → end, без обработки ошибок).

### 3.2. Kafka-топики (реестр)

Конверт по умолчанию — `KafkaMessage<T>` из `pcp-types-lib`: поля `type`, `data`, `traceId`, `correlationId`, `id`, `source`, `time`. Тип события — enum `PcpKafkaEvent`.

| Топик | Producer | Consumer(s) | Тип события / payload | Ключ |
|---|---|---|---|---|
| `pcp.satellites` | satellite-catalog | ballistics, tle-monitoring, slots, mission-planing, complex-mission, dynamic-plan | `SatelliteDeletedEvent` (`satelliteId`, `noradId`) | `satelliteId` |
| `pcp.tle` | tle-monitoring / catalog ⚠ | ballistics (фильтры IC/ICRV/TLE) | TLE / `ICPlacedEvent` / `ICRVPlacedEvent` / `ICUpdatedEvent` | ⚠ |
| `pcp.request.survey-georeference.v1` | внешний / UI ⚠ | route-processing | RoutePassport (сырой) | ⚠ |
| `pcp.request.survey-georeference-dlq.v1` | route-processing | (DLQ) | — | — |
| `pcp.route.georeference.v1` | route-processing | request-service | `RoutePassportDto` (геопривязанный) | ⚠ |
| `pcp.route.in.v1` | route-processing | mission-planing (`ModeStatusChangedEvent`) | processed route / mode-status | ⚠ |
| `pcp.request.in.v1` | request-service / UI ⚠ | ⚠ требует уточнения | `RequestPlacedEvent` | ⚠ |
| `pcp.request.status.v1` | request-service (outbox) | **geoportal** (внешний) | `REQUEST_TERMINAL_STATUS` (COMPLETED/EXPIRED) | `aggregateId` (UUID заявки) |
| `pcp.slots.status.v1` | slots-service | mission-planing, slots-service (self) | `BookedSlotsStatusChangedEvent` | ⚠ |
| `pcp.tgu.satellite-plan-decision.v1` | Mission Ops / КА ⚠ | tgu-service | `PlanDecisionMessage` (ACCEPTED/REJECTED, `attemptId`) | ⚠ |
| `pcp.tgu.visibility-windows-changed.v1` | tgu-service | tgu-service | `VisibilityWindowsChangedMessage` | ⚠ |

> ⚠ Реализация консьюмеров неоднородна: одни читают типизированный `KafkaMessage<T>`, другие парсят сырое дерево и ждут поле `data`; используются обе версии Jackson (2 и 3). Это первый кандидат на унификацию контракта.

### 3.3. REST-эндпоинты (контракты API по сервисам)

**request-service** (`/v1`)
```
GET    /v1/requests/{id}
GET    /v1/requests/{requestId}/with-cells
DELETE /v1/requests/{id}
GET    /v1/cells/with-requests
GET    /v1/grid/settings        PUT /v1/grid/settings        POST /v1/grid/rebuild
```

**satellite-catalog-service** (`/api/satellites`, `/api/satellite-groups`)
```
GET/PUT/DELETE /api/satellites/{satellite_id}
GET            /api/satellites/by-norad/{norad_id}
GET/POST/PUT/DELETE /api/satellites/{satellite_id}/observation-profile
GET/POST/PUT/DELETE /api/satellites/{satellite_id}/slot-profile
POST           /api/satellites/batch
GET/PUT/DELETE /api/satellite-groups/{group_id}
```

**ballistics-service** (`/api`)
```
POST /api/satellites/{satellite_id}/extract-time     POST /api/satellites/{satellite_id}/clear
GET  /api/satellites/{norad_id}/orbit | /asc-node | /flight-line | /rva
GET  /api/satellites/orbit/availability[/{id}]
POST /api/obj-view/mpl-square | /mpl-point           GET /api/obj-view/cell-coverage/{number}
POST /api/tle/parse | /api/tle/rva
```

**complex-mission-service** (`/api`)
```
POST /api/com-plan/process | /clear                  GET/DELETE /api/com-plan/runs/{id}
GET  /api/com-plan/runs | /runs/{id}/modes | /cell-with-mars/{cell_number}
GET  /api/satellites/{satellite_id}[/mission|/modes|/snapshots|/mission/statistics|/mission-for-paint]
GET  /api/satellites/snapshots[/{snapshot_id}[/modes]] | /modes      POST /api/satellites/prepare
```

**mission-planing-service** (`/api/missions`)
```
GET    /api/missions/{mission_id}[/modes]            GET /api/missions/modes/satellite
POST   /api/missions/{mission_id}/drops/calculate    POST /api/missions/{mission_id}/surveys/calculate
POST   /api/missions/{mission_id}/confirm            PUT /api/missions/survey-modes/{mode_id}/status
PUT/DELETE /api/missions/{mission_id}
```

**slots-service / coverage-scheme / dynamic-plan / stations / tgu**
```
coverage-scheme : POST /api/coverage-schemes/calculate
dynamic-plan    : POST /v1/main/calcPlan ; GET /v1/main/calcPlan/runs|/{runId}[/result|/routes|/intervals]
stations        : GET /api/stations[/{station_id}] ; POST /api/stations ; DELETE /api/stations/{station_id}
tgu             : GET /api/plans/{spacecraftId} ; /api/platforms ;
                  POST /test/tgu/plans/{planId}/issue|/decision ; /spacecraft/{id}/refresh-visibility|/rebuild-plans
```

**ui-service** — BFF, агрегирует вызовы: `/requests/*`, `/map`, `/api/requests`, `/api/slots/booking/request`,
`/api/com-plan/*`, `/api/tgu-planning/*`, `/api/current-plans/*`, `/api/dynamic-plan/*`, `/api/stations/*`.

### 3.4. Внешние интеграции

| Откуда | Куда | Назначение |
|---|---|---|
| tle-monitoring-service | CelesTrak | загрузка TLE |
| tgu-service | `https://ordinis.nstart.cloud/api/v1/spacecraft/records` | классификатор платформ (фильтр `OPERATIONAL`), кэш 15m |
| tgu-service | external points API (`pcp.services.ballistics`) | внешние точки (lookahead 3 дня) |

---

## 4. Открытые вопросы для уточнения перед доработкой

Эти пункты помечены `⚠` выше — их стоит зафиксировать до изменений:

1. Producer топиков `pcp.request.survey-georeference.v1` и `pcp.request.in.v1` (внешняя система или UI?).
2. ~~Consumer `pcp.request.completed.v1`~~ — уточнено: потребитель терминальных статусов заявки = внешний **geoportal**, топик переименован в `pcp.request.status.v1` (COMPLETED/EXPIRED, #35).
3. Producer `pcp.tgu.satellite-plan-decision.v1` — реальный Mission Ops/КА vs текущая имитация в `FlowService`.
4. Точные DTO payload для `pcp.tle`, `pcp.route.in.v1`, `pcp.slots.status.v1` — зафиксировать схемы.
5. Возможная циклическая зависимость `complex-mission ⇄ coverage-scheme` в рантайме.
6. Расхождение задеплоенного `createSatelliteMission.bpmn` и концептуального `schemes/pcp_v1.bpmn` — какой считать целевым.

---

*Документ описывает текущее состояние «как есть». При доработке обновлять разделы 2–3 синхронно с изменениями контроллеров, listener'ов и `config-repo`.*
