Files
dc-observatio/docs/tasks/TASK_tgu-editor-integration.md
T
Дмитрий Соловьев f084775cbb feat(tgu-ops-ui): add spacecraft work editor tab
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.
2026-05-30 15:28:34 +03:00

22 KiB
Raw Blame History

Задача: встроить интерфейс «Редактор включений КА» в 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.
  • APIsrc/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        # ручная проверка: вкладка «Редактор» открывается, см. ниже

Функциональные критерии:

  1. В тулбаре доступна третья вкладка; переключение timeline | map | editor работает, существующие вкладки не сломаны.
  2. Редактор открывается на реальных данных (планы/платформы из tguApi), без мок-D.
  3. Работают: drag/resize включений, добавление съёмки по точке на карте, добавление сброса по станции, undo/redo, проверка конфликтов (живые пересечения + видимость по кнопке).
  4. Карта в редакторе — это tgu-map-2d (нет второго движка карты в бандле).
  5. Тема консистентна с приложением (нет «бесцветных» из-за отсутствующих токенов).
  6. applyDraft не падает и явно сообщает про отсутствующий backend-эндпоинт.

Если какая-то команда не запускалась — указать какая и почему, и описать остаточный риск (по AGENTS.md).


10. Риски, допущения, чего не делать

  • Допущение: структура планов/включений из tguApi достаточна, чтобы построить seedDraft. Если в реальном ответе нет полей под works редактора — зафиксировать gap, сделать адаптер-маппер и описать недостающие поля в отчёте, не менять backend.
  • Риск: React 19 + StrictMode даёт двойной вызов эффектов — проверить runCheck/setTimeout на отсутствие двойных срабатываний.
  • Риск: расширение Tgu2DMapView может задеть Tgu2DMapTab — новые пропсы делать опциональными с дефолтами, существующее поведение не менять.
  • Не делать: правки в Kotlin-сервисах, в чужих фичах сверх необходимого, новый роутинг, новые тяжёлые зависимости, перенос мок-данных и второго движка карты.

11. Обязательный формат финального ответа

По AGENTS.md агент завершает задачу блоками:

  1. Changed files — список изменённых/созданных файлов.
  2. What changed — краткое summary реализации по этапам.
  3. Architecture compliance — почему соблюдены границы слоёв (логика вне компонентов, переиспользование tgu-map-2d/tguApi/темы, отсутствие дублей карты и мок-данных).
  4. Validation — какие команды (npm run test, npm run build, ручная проверка) запускались и результаты.
  5. Risks / assumptions — что не проверено, gap по данным/backend, edge cases.