RS1 (#29): планировщик истечения заявок — RequestExpiryService
(@Scheduled + FOR UPDATE SKIP LOCKED, мультиинстанс-safe), refreshStatus
вызывается и при создании заявки.
RS7 (#35): единый топик pcp.request.status.v1 → geoportal (COMPLETED/EXPIRED
в payload), замена orphan pcp.request.completed.v1; эмиссия из matching и
expiry через тот же outbox; backoff/next_attempt_at/cap для outbox FAILED.
RS3 (#31): DefaultErrorHandler + DeadLetterPublishingRecoverer
(DLQ pcp.route.georeference-dlq.v1), bounded retry, контрактные ошибки в DLQ.
RS6 (#34): проброс coverageRequiredPercent из API, разведение терминов
покрытие/важность.
Доки: бэклог, аудит сервиса заданий, карты взаимодействий.
RS2 (#30) отложено до #28, RS5 (#33) — до роста требований к точности.
(по достижению покрытия) и [RequestExpiryService](../services/pcp-request-service/src/main/kotlin/org/nstart/dep265/requestservice/service/RequestExpiryService.kt)
(по истечению срока). Outbox получил `attempts`/`next_attempt_at`: при сбое — удвоение backoff от
`initial-backoff-ms` до `max-backoff-ms`, после `max-attempts` событие становится терминальным `FAILED`
и из выборки выпадает. Конфиг — `pcp.outbox.*`. Мелкий зазор: заявка, **созданная** уже просроченной,
терминальное событие не порождает (вырожденный кейс; обычные пути ACTIVE→COMPLETED/EXPIRED покрыты).
## Что в порядке (намеренно не отмечаем как проблемы)
- Конкурентность и мультиинстанс: row-lock на заявку, `SKIP LOCKED` в outbox, advisory-lock на сетку,
`@Version`, дедуп по уникальным ключам — сделано грамотно.
- Transactional outbox: терминальный эвент `REQUEST_TERMINAL_STATUS` пишется в той же транзакции, что и завершение/истечение заявки.
- ⏸ **RS2** (#30) — фильтр совместимости аппарата. Отложено **до #28**: паспорт маршрута не несёт явный `surveyType`, контракт фиксируется в аудите связи сервисов.
- ⏸ **RS5** (#33) — геодезическая площадь. Отложено до роста требований к точности (переключение `area()` затрагивает matching и тесты; покрытие — отношение площадей).
У каждой задачи есть стабильный номер `#N` — он не меняется при правках списка, на него удобно ссылаться. Новые задачи получают следующий свободный номер.
_Обновлено: 2026-06-05_
> Задачи #12–#25 заведены по результатам аудита. Подробности, обоснование и рекомендации
> по каждой — в [аудит-проекта-2026-06-06.md](аудит-проекта-2026-06-06.md) (ссылки на коды находок B/F/R/C).
_Обновлено: 2026-06-06_
---
@@ -31,12 +34,49 @@ _Обновлено: 2026-06-05_
### Бэкенд / инфраструктура
- [ ]**#7** — Перевести сервис станций на ordinis (по примеру получения аппаратов в сервисе tgu).
### Проверка сервисов
- [ ]**#27** — Проверить сервис получения паспорта маршрута по отдельности.
- [ ]**#28** — Проверить связь сервиса заданий и сервиса получения паспорта маршрута между собой.
### Баги
- [ ]**#8** — Ошибка при попытке принять план на вкладке «Планы».
### Аудит — надёжность и бэкенд
_Источник и рекомендации: [аудит-проекта-2026-06-06.md](аудит-проекта-2026-06-06.md)._
- [ ]**#12** — (B1, высокий) Camunda job-воркеры в `FlowService` молча глотают исключения (`catch { logger.warn(ex.message) }`) при `autoComplete=false`: задача не завершается и не падает, BPMN-процесс зависает без инцидента. Завершать через `newFailCommand`/проброс наверх, логировать `error(msg, ex)`.
- [ ]**#13** — (B2, средний) Снять симуляционную заглушку `Thread.sleep(5000)` («имитация подтверждения плана») в `FlowService.sendPlan` при появлении реального канала подтверждений.
- [ ]**#14** — (B3, средний) Привести в порядок несогласованные пакеты-копипасты (ballistics→`pcp_request_service`, complex-mission→`pcp_satellites_service`, ui-service и slots-service делят `slots_service`, request→`org.nstart.dep265`, tgu→без `.pcp.`). Отдельной задачей из-за широкого охвата.
- [ ]**#15** — (B4, низкий) Опечатка «srpring» в `pcp-srpring-boot-admin-server` растиражирована по каталогу, пакету, CI, docker-compose, gradle. Чинить вместе с #14.
- [ ]**#16** — (B5, низкий) ~9 мест `logger.warn/error(ex.message)` теряют stack trace — заменить на `logger.error("...", ex)`.
### Аудит — фронтенд
_Источник и рекомендации: [аудит-проекта-2026-06-06.md](аудит-проекта-2026-06-06.md)._
- [ ]**#18** — (F2, низкий) Перевести нетипизированный островок `features/constellation/*` (`.jsx`/`.js`, `allowJs`) на TS или добавить декларации типов на границе.
_Источник и рекомендации: [аудит-проекта-2026-06-06.md](аудит-проекта-2026-06-06.md)._
- [ ]**#21** — (R1, средний) Убрать из git крупные дампы в корне (`pcp_requests_converted_create_requests.json` ~228 КБ, `response_заданияКубернетс.json` ~157 КБ, `response_заданияЕмельянов.json` ~66 КБ) — перенести в `src/test/resources`/`docs` или удалить с добавлением в `.gitignore`.
- [ ]**#22** — (R2, низкий) Удалить посторонние артефакты в корне: `node_modules/` + пустой `package-lock.json`, `obj_terra.zip`; при желании добавить `/package-lock.json` в `.gitignore`.
- [ ]**#24** — (C1, средний) Унифицировать креды БД в config-repo: привести все сервисы к переопределяемому `password: ${DB_PASSWORD:...}` (как в tgu-service), убрать зашитые `password: password`.
- [ ]**#25** — (C2, низкий) Сузить CORS для прода в `pcp-ui-service` (`allowedOriginPatterns("*")` + `allowCredentials`) до конкретных origin; держать в курсе отсутствие CORS у напрямую вызываемых сервисов (работает только через прокси/nginx).
### Аудит — сервис заданий (pcp-request-service)
_Источник и рекомендации: [аудит-сервис-заданий.md](аудит-сервис-заданий.md) (коды находок RS1–RS7)._
- [ ]**#30** — (RS2, высокий) Матчинг засчитывает покрытие по любому геометрическому пересечению, игнорируя совместимость аппарата (`survey_type`, крен, разрешение, угол Солнца). Добавить фильтр совместимости маршрут↔заявка перед зачётом покрытия; тип сенсора в паспорте маршрута согласовать в рамках #28. _Отложено до #28 (решение, 2026-06-06): `RoutePassportDto` не несёт явный `surveyType` — контракт фиксируется в рамках аудита связи сервисов #28, тогда же делаем фильтр._
- [ ]**#33** — (RS5, низкий) Площади считаются планарно в градусах (JTS `area` на EPSG:4326) — искажение для крупных/высокоширотных заявок. Перейти на геодезию (`ST_Area(geography)` или равновеликая проекция), когда вырастут требования к точности. _Отложено по решению аудита: покрытие считается отношением площадей (планар ≈ геодезия для обычных AOI), а переключение `area()` затрагивает matching и точечные ассерты тестов — вводим при росте требований к точности._
---
## Выполнено
- [x]**#34** — (RS6) Проброс требуемого процента покрытия из API + разведение терминов. _Готово: в `CreateRequestDto` добавлено опциональное поле `coverageRequiredPercent` (0 < x ≤ 100, по умолчанию 100), оно пробрасывается в сущность и используется как порог COMPLETED; захардкоженная константа убрана. В KDoc/коде разведены «прогресс покрытия» (`coverageRequiredPercent`) и «важность заявки» (`importance`, карта приоритетов ячеек). Тесты: `RequestServiceTest`, `RequestApiDtoContractTest`._
- [x]**#31** — (RS3) DLQ и error-handler для Kafka-листенера маршрутов. _Готово: `KafkaConsumerConfig` — `DefaultErrorHandler` + `DeadLetterPublishingRecoverer` в топик `pcp.route.georeference-dlq.v1`, экспоненциальный bounded retry, контрактные ошибки (`JsonProcessingException`/`ConstraintViolationException`) → DLQ без ретраев, диагностические заголовки. Настройки `app.kafka.consumer.route.*`, активируется при заданном `spring.kafka.bootstrap-servers`. Тест `KafkaConsumerConfigTest`._
- [x]**#35** — (RS7) Уведомление **geoportal** о финале заявки. _Готово: единый топик `pcp.request.status.v1` (заменил orphan `pcp.request.completed.v1`) с терминальным статусом в payload (`COMPLETED`/`EXPIRED`). Эмиссия из двух мест через тот же transactional outbox: `RouteMatchingService` (по покрытию) и `RequestExpiryService` (по сроку, #29). Сервис `RequestCompletedOutboxService`→`RequestStatusOutboxService`, eventType `REQUEST_TERMINAL_STATUS`. Outbox получил backoff: колонки `attempts`/`next_attempt_at`, удвоение `initial→max`, предел `max-attempts` (терминальный FAILED). Конфиг `pcp.outbox.*`. Тесты: `OutboxPublisherServiceTest`, `OutboxEventRepositoryJpaTest`, `RequestStatusOutboxServiceTest`, `RequestExpiryServiceTest`, `RouteMatchingServiceTest`. Док: интеракции обновлены. Известный мелкий зазор: заявка, созданная уже просроченной, события не шлёт (вырожденный кейс)._
- [x]**#29** — (RS1) Планировщик истечения заявок. _Готово: `RequestExpiryService` (`@Scheduled`, `FOR UPDATE SKIP LOCKED`, батчи с верхним лимитом) переводит просроченные `ACCEPTED`/`ACTIVE` в `EXPIRED`; несколько инстансов безопасны. `refreshStatus` теперь вызывается и при создании заявки — статус приёма отражает окно (`ACCEPTED`/`ACTIVE`/`EXPIRED`), а не всегда `ACCEPTED`. Конфиг `pcp.request.expiry.*` в config-repo. Тесты: `RequestExpiryServiceTest` (юнит) + `RequestRepositoryJpaTest` (H2). Разблокирует EXPIRED-эмиссию в #35._
- [x]**#32** — (RS4) Удалить мёртвый конфиг сервиса заданий. _Готово: из `config-repo/pcp-request-service.yaml` убраны `app.request.cleanup-cron`/`cleanup-retention-days` и неиспользуемый топик `app.kafka.topics.request` (`pcp.request.in.v1`); кода под ними не было, `@Value`-привязок нет._
- [x]**#26** — Проверить сервис заданий (`pcp-request-service`) по отдельности. _Готово: аудит в [аудит-сервис-заданий.md](аудит-сервис-заданий.md) — карта взаимодействий, учёт покрытия, жизненный цикл, мультиинстанс; находки RS1–RS7 (RS1/RS2 — высокий приоритет)._
- [x]**#9** — Расширить вправо левую панель информации на вкладке «Редактор» (цифры у границы смотрелись плохо). _Готово: commit 69dfd80, рейл 15.5rem → 17rem._
- [x]**#10** — Проставлять статусы слотов только после того, как план заложен на КА. _Готово: commit 69dfd80, слоты занимаются по `LAID_IN`, а не по `ACCEPT`._
- [x]**#11** — Запретить нажимать «Подтвердить закладку», пока начало закладки в будущем. _Готово: commit 69dfd80._
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.