chore: сохранение текущих изменений (deploy local-bundle/local-jar, request-service, slots UI markedObjectIds)
Безопасный коммит незакоммиченной работы перед реализацией бронирования слотов. Вне коммита оставлены: package-lock.json (пустой, мусор), requests.json (scratch-данные).
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
# Аудит проекта observatio-terrae
|
||||
|
||||
Дата: 2026-06-06. Автор: Claude (Opus 4.8).
|
||||
Охват: фронтенд `pcp-tgu-ops-ui` + бэкенд-сервисы. Сервис `tle-monitoring-service` по
|
||||
указанию исключён из анализа.
|
||||
|
||||
Метод: статический разбор кода, прогон сборки/тестов фронта, выборочное чтение бэкенд-сервисов
|
||||
(акцент на недавно дорабатываемых: tgu, mission-planing, complex-mission, request), проверка
|
||||
конфигов, CORS, обработки ошибок и гигиены репозитория.
|
||||
|
||||
## Сводка по состоянию
|
||||
|
||||
Базовое здоровье — хорошее. Фронтенд проходит строгую типизацию (`tsc -b`, exit 0) и все
|
||||
тесты (53 теста в 12 файлах, зелёные); в исходниках нет `console.*`, `any`, `@ts-ignore`.
|
||||
Бэкенд использует общий `GlobalExceptionHandler` из `pcp-types-lib`, нет `printStackTrace`,
|
||||
нет `@Disabled`/`@Ignore` тестов. Найденные проблемы — это в основном технический долг,
|
||||
копипаст-артефакты и один реальный риск надёжности в Camunda-воркерах.
|
||||
|
||||
Приоритеты: **B1** (надёжность), **R1/C1** (гигиена/конфиги), затем рефакторинг-долг.
|
||||
|
||||
---
|
||||
|
||||
## Бэкенд
|
||||
|
||||
### B1 (высокий). Camunda job-воркеры молча проглатывают исключения
|
||||
Файл: [FlowService.kt](../services/pcp-mission-planing-service/src/main/kotlin/space/nstart/pcp/pcp_mission_planing_service/service/FlowService.kt)
|
||||
|
||||
Все воркеры объявлены с `autoComplete = false` и обёрнуты в:
|
||||
|
||||
```kotlin
|
||||
catch (ex : Exception) { logger.warn(ex.message) }
|
||||
```
|
||||
|
||||
Если исключение возникает до `client.newCompleteCommand(...).send()`, задача **не завершается и
|
||||
не падает**: воркер «съел» ошибку. Camunda не получает ни complete, ни fail/incident — BPMN-процесс
|
||||
зависает молча до таймаута активации, без видимого инцидента и без явной диагностики. Плюс
|
||||
`logger.warn(ex.message)` теряет stack trace, а `ex.message` может быть `null`.
|
||||
|
||||
Рекомендация: в catch завершать задачу через `client.newFailCommand(job.key)` (с retries) либо
|
||||
бросать исключение наверх, чтобы Camunda создала incident; логировать как `logger.error(msg, ex)`
|
||||
со стек-трейсом. Это касается `surveyPlan`, `surveyDrop`, `sendPlan`, `confirmPlan` и прочих
|
||||
воркеров файла.
|
||||
|
||||
### B2 (средний). Симуляционная заглушка `Thread.sleep(5000)` в проде-пути
|
||||
Файл: [FlowService.kt:97](../services/pcp-mission-planing-service/src/main/kotlin/space/nstart/pcp/pcp_mission_planing_service/service/FlowService.kt#L97)
|
||||
|
||||
В `sendPlan` стоит `Thread.sleep(5000)` с комментарием «Иммитация сообщения о получении
|
||||
подтверждения» — синхронно блокирует поток job-воркера на 5 с и эмулирует приём подтверждения
|
||||
плана. Для MVP-демо допустимо (см. практику осознанных заглушек), но это нужно снять при
|
||||
интеграции с реальной шиной подтверждений; пока имитация маскирует отсутствие реального канала и
|
||||
держит поток пула воркеров.
|
||||
|
||||
### B3 (средний). Несогласованные пакеты — копипаст-артефакты
|
||||
Базовые пакеты ряда сервисов не соответствуют их имени (видимо, форки шаблона):
|
||||
|
||||
| Сервис | Пакет | Проблема |
|
||||
|---|---|---|
|
||||
| pcp-ballistics-service | `space.nstart.pcp.pcp_request_service` | пакет от request-сервиса |
|
||||
| pcp-complex-mission-service | `space.nstart.pcp.pcp_satellites_service` | чужое имя |
|
||||
| pcp-ui-service | `space.nstart.pcp.slots_service` | совпадает со slots-service |
|
||||
| slots-service | `space.nstart.pcp.slots_service` | тот же пакет, что у ui-service |
|
||||
| pcp-tgu-service | `space.nstart.pcp_tgu_service` | пропущен сегмент `.pcp.` |
|
||||
| pcp-request-service | `org.nstart.dep265.requestservice` | другой корень (`org` вместо `space`) |
|
||||
|
||||
Последствия: grep/навигация по пакету выводит на «не тот» сервис, IDE-импорты обманчивы,
|
||||
|
||||
ui-service и slots-service неотличимы по пакету. Переименование пакетов затрагивает много файлов —
|
||||
делать осознанно, отдельной задачей; новые сервисы заводить уже с корректным пакетом.
|
||||
|
||||
### B4 (низкий). Опечатка «srpring» растиражирована
|
||||
`pcp-srpring-boot-admin-server` — опечатка в имени каталога и пакета, продублированная в
|
||||
`settings.gradle.kts`, `build.gradle.kts`, `.gitlab-ci.yml`, `deploy/local-bundle/docker-compose.yml`,
|
||||
`config-repo/application-docker-local.yaml`. Косметика, но фиксируется во всей инфраструктуре, потому
|
||||
исправлять дорого — оставить как известный долг или чинить вместе с B3.
|
||||
|
||||
### B5 (низкий). Потеря stack trace при логировании
|
||||
~9 мест вида `logger.warn(ex.message)` / `logger.error(ex.message)` логируют только текст без
|
||||
исключения. Для диагностики предпочтительно `logger.error("...", ex)`.
|
||||
|
||||
### B6 (инфо). Опечатки в лог-сообщениях
|
||||
Напр. «Утверждение поана» (план), «Иммитация» (имитация) в FlowService.
|
||||
|
||||
---
|
||||
|
||||
## Фронтенд (pcp-tgu-ops-ui)
|
||||
|
||||
### F1 (средний). Дублирование HTTP-/error-обвязки в API-клиентах
|
||||
`extractErrorText` скопирован в 5 файлах: `tguApi.ts`, `ballisticsApi.ts`, `missionPlanningApi.ts`,
|
||||
`complexPlanApi.ts`, `tguPlanApi.ts`. Шаблон `try { fetch } catch { TguApiError("network") }` +
|
||||
разбор `!response.ok` повторяется ~22 раза (7 в missionPlanningApi, 5 в tguPlanApi и т.д.).
|
||||
В `tguApi.ts` уже есть аккуратный `fetchJson<T>()` — остальные клиенты переписывают то же руками.
|
||||
|
||||
Рекомендация: вынести единый `src/api/http.ts` (обёртка `fetchJson` + `extractErrorText` +
|
||||
маппинг ошибок) и переиспользовать. Сократит ~150 строк и устранит расхождения (см. F5).
|
||||
|
||||
### F2 (низкий). Островок нетипизированного JS во вкладке «Группировка»
|
||||
`features/constellation/*` — это `.jsx`/`.js` (`ConstellationDashboard.jsx`, `sim.js`, `data.js`,
|
||||
`MapView.jsx`, `Panels.jsx`, `Timeline.jsx`, `util.js`), включён через `allowJs`. Остальное
|
||||
приложение — строгий TS. Прототипный код подключён в прод через `ConstellationTab.tsx` (обёртка с
|
||||
`as ComponentType`). Типы в нём фактически `any` — провал строгой типизации в этой ветке UI.
|
||||
Долг: постепенно перевести на `.tsx` или хотя бы добавить декларации типов на границе.
|
||||
|
||||
### F3 (низкий). Мёртвый barrel `constellation/index.js`
|
||||
`features/constellation/index.js` (реэкспорт `SIM`, `SATELLITES`, `STATIONS`, ...) нигде не
|
||||
импортируется — можно удалить.
|
||||
|
||||
### F4 (низкий). God-компонент `TguEditorTab.tsx` (1727 строк)
|
||||
Самый крупный файл фронта; держит десятки `useState`/`useRef`, режимы правой панели, построение
|
||||
маршрутов, валидацию, undo/redo. Хорошо закомментирован, но монолитен. Кандидат на декомпозицию
|
||||
(вынос хуков `useDraftHistory`, `useRouteBuilder`, разнесение панелей) для снижения связности.
|
||||
|
||||
### F5 (инфо). Расхождение приоритета полей ошибки
|
||||
В `tguApi.extractErrorText` порядок полей `reason, message, error, detail`, а в
|
||||
`missionPlanningApi.extractErrorText` — `message, error, reason, detail`. При едином ответе бэка
|
||||
пользователь увидит разный текст из разных клиентов. Устранится при выносе общей обвязки (F1).
|
||||
|
||||
---
|
||||
|
||||
## Гигиена репозитория
|
||||
|
||||
### R1 (средний). Крупные дампы данных в корне репозитория (в git)
|
||||
Отслеживаются git и лежат в корне:
|
||||
- `pcp_requests_converted_create_requests.json` (~228 КБ)
|
||||
- `response_заданияКубернетс.json` (~157 КБ)
|
||||
- `response_заданияЕмельянов.json` (~66 КБ)
|
||||
|
||||
Это тестовые выгрузки, засоряющие корень и историю. Перенести в `docs/`/`*/src/test/resources`
|
||||
или убрать из git (оставив в `.gitignore`).
|
||||
|
||||
### R2 (низкий). Посторонние артефакты в корне (не в git)
|
||||
- `node_modules/` в корне + пустой `package-lock.json` (`"packages": {}`, 0 зависимостей) —
|
||||
корневого Node-проекта нет, фронт живёт в `services/pcp-tgu-ops-ui`. Мусор от случайного
|
||||
`npm install` в корне; удалить, при желании добавить `/package-lock.json` в `.gitignore`.
|
||||
- `obj_terra.zip` (~1.5 МБ) в корне — не в git, но захламляет дерево.
|
||||
|
||||
### R3 (низкий). 26 устаревших каталогов `bin/` на диске
|
||||
Скомпилированные `bin/main/...` (gitignored) задваивают исходники: любой `grep` по `services`
|
||||
выдаёт каждый файл дважды (src + bin) — шум при навигации. Прогнать `./gradlew clean` /
|
||||
удалить `bin/` каталоги.
|
||||
|
||||
---
|
||||
|
||||
## Конфигурация и безопасность
|
||||
|
||||
### C1 (средний). Несогласованное задание паролей БД в config-repo
|
||||
В большинстве сервисов пароль зашит как `password: password`, и только
|
||||
[pcp-tgu-service.yaml](../config-repo/pcp-tgu-service.yaml) использует переопределяемый паттерн
|
||||
`password: ${DB_PASSWORD:password}`. Для локалки риск низкий, но шаблон важен: привести все
|
||||
сервисы к `${DB_PASSWORD:...}` (и прочие креды — к env-переменным), чтобы прод/стенды
|
||||
переопределялись без правки config-repo.
|
||||
|
||||
### C2 (низкий). CORS: широкий в ui-service, отсутствует в остальных
|
||||
[WebConfig.kt](../services/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/configuration/WebConfig.kt)
|
||||
задаёт `allowedOriginPatterns("*")` + `allowCredentials=true` — широко; для прода имеет смысл
|
||||
сузить origin до конкретных хостов. Остальные сервисы, которые фронт зовёт напрямую (tgu,
|
||||
mission, request, ballistics, complex, stations), CORS-конфига не имеют — сейчас работает только
|
||||
потому, что обращение идёт через Vite-прокси/nginx (same-origin). Прямые кросс-доменные вызовы к
|
||||
ним из браузера упадут — это ограничение стоит держать в курсе при изменении схемы доступа.
|
||||
|
||||
---
|
||||
|
||||
## Что в порядке (намеренно не правим)
|
||||
- Заглушки/тест-контроллеры/пустой контракт валидации миссии — осознанные MVP-срезы, не дефекты.
|
||||
- Прямые вызовы микросервисов из фронта через прокси (без BFF) — принятое решение этапа.
|
||||
- Naive `LocalDateTime` как локальное настенное время — намеренная договорённость проекта.
|
||||
|
||||
## Рекомендованный порядок работ
|
||||
1. **B1** — починить обработку ошибок в Camunda-воркерах (надёжность процессов).
|
||||
2. **R1, C1** — убрать дампы из корня; унифицировать env-пароли.
|
||||
3. **F1** — общий `http.ts`, заодно закрыть F5.
|
||||
4. **B2** — снять `Thread.sleep`-имитацию при появлении реального канала подтверждений.
|
||||
5. Фоном: **R2/R3** (чистка), **F2/F4** (типизация constellation, декомпозиция редактора),
|
||||
**B3/B4** (пакеты/опечатки) — отдельными задачами из-за широкого охвата.
|
||||
@@ -38,6 +38,11 @@ _Обновлено: 2026-06-11_
|
||||
|
||||
### Бэкенд / инфраструктура
|
||||
- [ ] **#7** — Перевести сервис станций на ordinis (по примеру получения аппаратов в сервисе tgu).
|
||||
- [ ] **#47** — Перевести сервисы с Jackson 2 на Jackson 3 и убрать двойной стек. Под Spring Boot 4.0.2 MVC уже десериализует входящий JSON через **Jackson 3** (`tools.jackson.*`), а весь код монорепы написан под **Jackson 2** (`com.fasterxml.jackson`, `versions.jackson_databind=2.18.2`); в `pcp-request-service` для внутреннего парсинга держится отдельный Jackson 2-бин (`JacksonConfig`). Из-за этой рассинхронизации словили баг: Jackson 3 по умолчанию включает `FAIL_ON_NULL_FOR_PRIMITIVES`, и явный `null` на примитивном `Double coverageRequiredPercent` ронял создание заявки (контракт-тесты не ловили — они на Jackson 2). Срочности/EOL-риска нет, это техдолг и консистентность.
|
||||
- **Сейчас, дёшево (часы):** системно снять класс багов «null на примитиве» — выставить `spring.jackson.deserialization.fail-on-null-for-primitives=false` в config-repo request-service (проверить, что свойство применяется к Jackson 3-бину; если нет — через `Jackson3ObjectMapperBuilderCustomizer`). Не латать каждое поле по очереди.
|
||||
- **Среднесрок, по сервису:** мигрировать по одному, пилот — `pcp-request-service` (~7 файлов main, ~0.5–1 день). Аннотации **не трогаем** — `jackson-annotations` в Jackson 3 остались в пакете `com.fasterxml.jackson.annotation` (у нас это основная масса: `@JsonIgnoreProperties` ×36, `@JsonProperty` ×16, `@JsonInclude` ×15…). Менять только databind-поверхность: `ObjectMapper` ×23, `TypeReference` ×8, `JsonNode` ×5, `jacksonObjectMapper()` ×12 → пакеты `tools.jackson.databind/core/module.kotlin`; в Jackson 3 `JsonProcessingException` стала unchecked. Дропнуть Jackson 2-зависимости и Jackson 2-бин `JacksonConfig`.
|
||||
- **Главный риск — Kafka:** `KafkaConsumerConfig`/сериализаторы завязаны на `com.fasterxml` ObjectMapper. Перед стартом — спайк (~полдня): умеет ли `spring-kafka` в нашем Boot 4 Jackson 3-сериализаторы. Если нет — Kafka-слой мигрируем отдельно, HTTP/внутренний JSON переводим независимо.
|
||||
- **Масштаб (src/main):** 67 файлов в 10 сервисах — pcp-dynamic-plan-service 22, pcp-ui-service 16 (выводится из эксплуатации, ср. #40 — можно не мигрировать), pcp-request-service 7, slots-service/pcp-tgu-service по 5, остальные 1–4. **Грубая оценка всей репы — ~6–10 человеко-дней**, основной риск — Kafka. Big-bang не нужен: шаг 1 закрывает причину бага, полную миграцию вести фоново сервис за сервисом.
|
||||
- [ ] **#45** — Собрать native-образ сервиса (Kotlin/Native, `kompile`) и контейнер на его основе. Цель — быстрый старт и меньший footprint в сравнении с JVM-образом. Уточнить: какой сервис(ы) переводим первым, совместимость с рефлексией/AOT-конфигом (reachability metadata), сборку в CI и базовый образ контейнера.
|
||||
- [ ] **#37** — Рассинхрон номеров витков между баллистическими источниками. Для одного и того же КА/времени `flight-line` (трасса, `/api/tgu-planning/spacecraft/{norad}/flight-line`) и `survey-route/build` (контур, pcp-mission-planing) отдают **разный номер витка**: на Emissio 1 (norad 2) 2026-06-06 12:50–12:55 трасса помечена витком 142, а контур/сохранённые режимы — витком 144 (по широте ~74° с.ш. согласованы, расходится только нумерация). В редакторе карта фильтрует трассу/полосу обзора по видимому витку (`buildEditorMapScene` → `visibleRevolutions`), поэтому при сужении селектора до «виток N» точки трассы с другим номером выпадают и пропадает орбитальный контекст. Свести нумерацию витков к единому источнику (или маппинг на границе), чтобы трасса и маршрут согласовывались по витку.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user