Port the TGU editor prototype into pcp-tgu-ops-ui as a new editor tab, add draft/conflict/pass logic with tests, extend the 2D map picking API, and include editor styles/theme aliases and task/prototype docs. Validation: npm run test; npm run build in services/pcp-tgu-ops-ui.
22 KiB
Задача: встроить интерфейс «Редактор включений КА» в pcp-tgu-ops-ui
Документ-ТЗ для кодинг-агента. Раздел 0 — промпт для запуска (скопировать в агента). Разделы 1–11 — инструкция, которую агент читает в репозитории и которой следует. Стиль работы, границы слоёв и формат финального ответа — по корневому
AGENTS.md.
0. Промпт для запуска агента (copy-paste)
Ты работаешь в монорепозитории observatio-terrae (pcp).
Задача: встроить прототип интерфейса «Редактор включений КА» в существующее
фронтенд-приложение services/pcp-tgu-ops-ui (Vite + React 19 + TypeScript).
Перед началом обязательно прочитай:
1. /AGENTS.md — правила работы, стиль, формат финального ответа.
2. /docs/tasks/TASK_tgu-editor-integration.md — полное ТЗ этой задачи (этот файл).
3. Исходный прототип: /docs/ui-prototypes/pcp-tgu-editor/ (editor.jsx и соседние).
4. Целевую структуру: services/pcp-tgu-ops-ui/src (App.tsx, features/, api/, styles/).
Это ПОРТ, а не копирование: прототип на Babel-standalone с глобалями и мок-данными;
цель — ESM/TS-модули, реальный API-клиент, существующая тема и паттерны проекта.
Выполняй строго по этапам из раздела 5 ТЗ. Делай минимальные ревьюопригодные изменения,
не трогай чужие сервисы и backend (Kotlin). Карту, орбитальную математику и мок-данные
из прототипа НЕ переноси — переиспользуй features/tgu-map-2d и api/tguApi (раздел 3).
После каждого этапа прогоняй `npm run test` и `npm run build` в модуле.
В конце дай отчёт в формате из раздела «Обязательный формат финального ответа» AGENTS.md.
1. Контекст и цель
pcp-tgu-ops-ui — операторский UI ТГУ (Mission Ops): уже работающее SPA на Vite 7 + React 19 + TypeScript, feature-sliced структура (features/tgu-planning, features/tgu-map-2d), централизованный API-клиент src/api/tguApi.ts (все вызовы через /api/..., dev-proxy на backend :7008), токены темы в src/styles/theme.css, юнит-тесты на Vitest.
Прототип «Редактор» — браузерный demo (React/Babel из CDN, JSX компилируется в браузере, общие глобали D/SENSOR_MODES/window.WorldGeo, мок-данные из data.jsx). Это другой стек, поэтому его нельзя «подключить» файлами — нужно портировать как новую фичу приложения.
Цель: редактор включений КА доступен как третья вкладка приложения (timeline | map | editor), работает на реальных данных через tguApi, переиспользует существующую карту и тему, покрыт тестами и собирается без ошибок.
Функциональность редактора (из прототипа editor.jsx): выбор активного КА/плана, черновик включений (works: shoot — съёмка, downlink — сброс), drag/resize по таймлайну, добавление съёмки по точке на карте и сброса по сеансу со станцией, контекст соседних КА, undo/redo, проверка конфликтов (пересечения по времени — живые; видимость цели/станции — по кнопке), применение правок.
2. Границы задачи (scope)
В scope:
- Новая фича
src/features/tgu-editor/вpcp-tgu-ops-ui. - Третья вкладка
"editor"в существующем переключателе вкладок. - Перенос UI-компонентов редактора на TSX + типизация.
- Чистые модули логики (undo/redo, конфликты) + их тесты.
- Подключение к реальным данным через
tguApi(планы/платформы). - Перемаппинг токенов темы.
Вне scope (НЕ делать без отдельного запроса):
- Изменения в любых Kotlin-сервисах, включая
pcp-tgu-service(backend-эндпоинт сохранения правок — отдельная задача, см. раздел 7). - Перенос карты/орбитальной математики/мок-данных из прототипа (раздел 3).
- Добавление роутера, state-менеджеров, UI-библиотек, новых рантайм-зависимостей без необходимости.
- Рефакторинг существующих фич
tgu-planning/tgu-map-2dсверх минимально необходимого для переиспользования. - Изменения
helm/,settings.gradle.kts, CI (модуль фронта в них и так не участвует).
3. Целевая архитектура и правила переиспользования
Следуй существующему feature-sliced паттерну (см. features/tgu-planning, features/tgu-map-2d): UI-компоненты в *.tsx, типы в model/*.ts, нетривиальная логика — в отдельных чистых *.ts модулях с тестами.
Обязательно переиспользовать (НЕ дублировать):
- Карта —
features/tgu-map-2d(Tgu2DMapView,canvas/drawTracks|drawSwath|drawStations|drawPlanWorks|drawBaseMap,geometry/mapProjection|spatialIndex|bbox). Редактору нужна карта в режиме «выбор точки съёмки» и подсветки трасс — расширяй существующий компонент пропсами (pickMode,onPickPoint,targets), а не переносиmapview.jsx/orbit.jsx/world.js/basemap.js. - API —
src/api/tguApi.ts(fetchPlans,fetchPlatforms, паттернfetchJson/TguApiError). Все сетевые вызовы редактора добавляй сюда же или вfeatures/tgu-editor/editorApi.tsв том же стиле. - Тема —
src/styles/theme.css(см. раздел 6). - Модели —
src/model/tguTypes.ts,src/model/timelineTypes.ts. Переиспользуй существующие типы планов/платформ, не вводи параллельные.
Не переносить из прототипа: mapview.jsx, orbit.jsx, world.js, basemap.js, util.jsx (дублируют то, что уже есть в TS), data.jsx (мок), tabs.jsx (заменяется вкладкой), Editor.html/Map.html (точка входа уже index.html + main.tsx).
Орбитальные функции, которых нет в tgu-map-2d (targetPasses, stationPasses, subPoint, nearestStation), вынеси в чистый общий модуль features/tgu-map-2d/geometry/passes.ts (с тестами) и переиспользуй из карты и редактора. Не размещай бизнес/гео-логику внутри React-компонентов.
4. Инвентаризация и маппинг файлов
Источник: docs/ui-prototypes/pcp-tgu-editor/ (положить туда содержимое архива до начала работ — по образцу уже существующих docs/ui-prototypes/pcp-tgu-mission-ops/).
| Прототип | Действие | Целевой файл |
|---|---|---|
editor.jsx (EditorApp) |
Портировать, убрать ReactDOM.createRoot, сделать экспортируемым компонентом-вкладкой |
features/tgu-editor/TguEditorTab.tsx |
editor.jsx (EditorToolbar) |
Портировать | features/tgu-editor/EditorToolbar.tsx |
editorrail.jsx |
Портировать | features/tgu-editor/EditorRail.tsx |
editortimeline.jsx |
Портировать | features/tgu-editor/EditorTimeline.tsx |
editorpanels.jsx (WorkInspector/ShootPanel/DownlinkPanel) |
Портировать | features/tgu-editor/EditorPanels.tsx |
visibility.jsx |
Портировать визуализацию; гео-расчёты вынести в passes.ts |
features/tgu-editor/VisibilityTracks.tsx |
editor.jsx (undo/redo, mutate, seedDraft) |
Вынести в чистый модуль | features/tgu-editor/editorDraft.ts (+editorDraft.test.ts) |
editor.jsx (overlaps + runCheck) |
Вынести в чистый модуль | features/tgu-editor/editorConflicts.ts (+editorConflicts.test.ts) |
типы work/draft/target |
Создать | features/tgu-editor/model/editorTypes.ts |
mapview.jsx, orbit.jsx, world.js, basemap.js, util.jsx, data.jsx, tabs.jsx, *.html |
НЕ переносить | — |
5. Пошаговый план (атомарные этапы)
Каждый этап завершай прогоном npm run test и npm run build в services/pcp-tgu-ops-ui.
Этап 0 — подготовка. Скопировать прототип в docs/ui-prototypes/pcp-tgu-editor/. Прочитать App.tsx, TguPlanningPage.tsx, TguToolbar.tsx, tguApi.ts, theme.css, Tgu2DMapView.tsx. Зафиксировать в отчёте точки расширения.
Этап 1 — типы и каркас фичи. Создать features/tgu-editor/model/editorTypes.ts (Work с kind: "shoot" | "downlink", origin, modeId, stationId, targetLat/Lon, isNew; Draft, EditorTarget). Создать пустой TguEditorTab.tsx с заголовком-заглушкой. Скомпилироваться.
Этап 2 — чистая логика + тесты. Перенести в editorDraft.ts: seedDraft, mutate, undo, redo, addShoot, addDownlink, updateWork, deleteWork, duplicateWork (как чистые функции над Draft/Work, без React и без Date.now() внутри — id/время передавать параметром для детерминизма тестов). Перенести в editorConflicts.ts: overlaps и проверку видимости. Написать editorDraft.test.ts и editorConflicts.test.ts (undo/redo инварианты, обнаружение пересечений, отсутствие/наличие видимости). Это первоочередное — логика должна быть покрыта до UI.
Этап 3 — токены темы. Реализовать перемаппинг (раздел 6). Убедиться, что портируемые стили резолвятся в палитру приложения.
Этап 4 — UI без карты. Портировать EditorToolbar, EditorRail, EditorTimeline, EditorPanels, VisibilityTracks на TSX. Завязать их на состояние в TguEditorTab (useState/useMemo/useCallback напрямую из react). Drag/resize таймлайна сохранить. Вместо alert() использовать уведомление в стиле decisionNotice/decisionError.
Этап 5 — карта. Расширить Tgu2DMapView пропсами pickMode/onPickPoint/targets (минимально, без поломки текущего использования в Tgu2DMapTab). Подключить в редакторе для выбора точки съёмки и подсветки трасс цели/станции через passes.ts.
Этап 6 — данные. Заменить мок D на реальные данные: планы/платформы грузить через tguApi (как в TguPlanningPage). seedDraft строить из выбранного плана. Активный КА/план брать из пропсов (раздел 7), не из location.search.
Этап 7 — вкладка. В model/timelineTypes.ts/TguPlanningPage.tsx расширить activeTab до "timeline" | "map" | "editor", добавить кнопку вкладки в TguToolbar (onTabChange), отрендерить TguEditorTab при activeTab === "editor", передав selectedSpacecraftId/selectedPlan/appliedRange.
Этап 8 — apply (заглушка). Реализовать applyDraft через типизированную функцию saveEditedPlan в editorApi.ts, помеченную // TODO(backend): эндпоинт сохранения правок плана отсутствует в pcp-tgu-service (раздел 7). Поведение: показать понятное уведомление о том, что сохранение во внешний сервис ещё не реализовано; не падать.
Этап 9 — финализация. Прогнать npm run test и npm run build. Отчёт по формату AGENTS.md.
6. Перемаппинг токенов темы
Прототип использует oklch-токены (--bg-0..3, --ink..--ink-3, --t-optical/radar/combo, --now, --warn, --line, --shadow), которых нет в theme.css приложения (там hex: --bg-base, --bg-panel, --text, --accent, --danger, --warning, ...).
Минимально-инвазивный подход: создать src/styles/editor-tokens.css (импортировать в TguEditorTab или в main.tsx) с алиасами, чтобы портированный код, ссылающийся на старые имена, резолвился в палитру приложения — без переписывания каждого inline-стиля:
:root {
--bg-0: var(--bg-base);
--bg-1: var(--bg-panel);
--bg-2: var(--bg-panel-2);
--bg-3: var(--bg-elevated);
--ink: var(--text);
--ink-1: var(--text);
--ink-2: var(--text-muted);
--ink-3: var(--text-dim);
--now: var(--warning);
--warn: var(--warning);
/* --line, --line-soft, --accent, --shadow совпадают по имени — проверить значения */
/* --t-optical/radar/combo: задать на основе --accent/--warning/--danger или вынести в палитру типов КА */
}
Уточнить фактические значения --line/--line-soft/--accent/--shadow (имена совпадают, значения могут отличаться) и зафиксировать решение в отчёте. Альтернатива (если команда предпочитает) — переписать стили редактора сразу на родные токены приложения; выбрать один путь и не смешивать.
7. Данные и API
- Чтение: планы и платформы — через существующие
fetchPlans/fetchPlatforms(tguApi.ts). Активный КА/план редактор получает пропсами отTguPlanningPage(selectedSpacecraftId,selectedPlan), а не из URL. - Гео/орбиты: через
tgu-map-2d+passes.ts; мокworld.js/data.jsxне использовать. - Сохранение правок (apply): в текущем API
pcp-tgu-serviceнет эндпоинта сохранения отредактированного набора включений (есть только выдача плана иdecision/issue). Поэтому в этой задачеapplyDraftреализуется как заглушка с явнымTODO(backend)и не делает реальной записи.
Предложение контракта для backend-команды (вне scope, зафиксировать в отчёте, не реализовывать):
POST /api/tgu-planning/plans/{planId}/editsс телом{ works: EditedWork[], baseRevision?: string }, идемпотентно поoperationId, возвращает новый план/attempt. Семантику (новый attempt vs патч существующего) согласовать отдельно.
8. Конвенции
Следуй AGENTS.md (раздел про стиль и scope) применительно к TS/React:
- Минимальные, локальные, ревьюопригодные изменения; не переименовывать и не форматировать несвязанные файлы.
- Предпочитать
const, маленькие функции, явные имена; не вводить «умные» абстракции на будущее. - Бизнес/гео-логику не держать в React-компонентах — выносить в чистые
*.tsмодули. - Комментарии — там, где помогают сопровождению (undo/redo инварианты, правила конфликтов, edge cases), а не на каждую строку. Язык комментариев — как в проекте.
- Не глотать ошибки сети молча — использовать паттерн
TguApiError/уведомлений, как в существующем коде. - Не добавлять новые рантайм-зависимости без явной необходимости; React/ReactDOM/Babel из CDN прототипа не тащить — они уже есть в проекте как npm-пакеты.
- TypeScript: без
anyв публичных сигнатурах; типы — вmodel/.
9. Критерии приёмки и команды валидации
Рабочая директория: services/pcp-tgu-ops-ui.
npm install # при необходимости
npm run test # vitest run — все тесты зелёные, включая новые editorDraft/editorConflicts/passes
npm run build # tsc -b && vite build — без ошибок типов и сборки
npm run dev # ручная проверка: вкладка «Редактор» открывается, см. ниже
Функциональные критерии:
- В тулбаре доступна третья вкладка; переключение
timeline | map | editorработает, существующие вкладки не сломаны. - Редактор открывается на реальных данных (планы/платформы из
tguApi), без мок-D. - Работают: drag/resize включений, добавление съёмки по точке на карте, добавление сброса по станции, undo/redo, проверка конфликтов (живые пересечения + видимость по кнопке).
- Карта в редакторе — это
tgu-map-2d(нет второго движка карты в бандле). - Тема консистентна с приложением (нет «бесцветных» из-за отсутствующих токенов).
applyDraftне падает и явно сообщает про отсутствующий backend-эндпоинт.
Если какая-то команда не запускалась — указать какая и почему, и описать остаточный риск (по AGENTS.md).
10. Риски, допущения, чего не делать
- Допущение: структура планов/включений из
tguApiдостаточна, чтобы построитьseedDraft. Если в реальном ответе нет полей подworksредактора — зафиксировать gap, сделать адаптер-маппер и описать недостающие поля в отчёте, не менять backend. - Риск: React 19 + StrictMode даёт двойной вызов эффектов — проверить
runCheck/setTimeoutна отсутствие двойных срабатываний. - Риск: расширение
Tgu2DMapViewможет задетьTgu2DMapTab— новые пропсы делать опциональными с дефолтами, существующее поведение не менять. - Не делать: правки в Kotlin-сервисах, в чужих фичах сверх необходимого, новый роутинг, новые тяжёлые зависимости, перенос мок-данных и второго движка карты.
11. Обязательный формат финального ответа
По AGENTS.md агент завершает задачу блоками:
- Changed files — список изменённых/созданных файлов.
- What changed — краткое summary реализации по этапам.
- Architecture compliance — почему соблюдены границы слоёв (логика вне компонентов, переиспользование
tgu-map-2d/tguApi/темы, отсутствие дублей карты и мок-данных). - Validation — какие команды (
npm run test,npm run build, ручная проверка) запускались и результаты. - Risks / assumptions — что не проверено, gap по данным/backend, edge cases.