# Аудит проекта 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()` — остальные клиенты переписывают то же руками. Рекомендация: вынести единый `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** (пакеты/опечатки) — отдельными задачами из-за широкого охвата.