Files
ui/_docs/02_document/components/05_flights/description.md
T
Oleksandr Bezdieniezhnykh 510df68bcf [AZ-447] autodev Steps 1-4 baseline: docs, tests, refactor specs
Captures the full output of autodev existing-code Phase A through
Step 4 (Code Testability Revision) for the Azaion UI workspace:

- Step 1 Document: _docs/02_document/ (FINAL_report, architecture,
  glossary, components/, modules/, diagrams/, system-flows,
  module-layout) plus _docs/00_problem/ + _docs/01_solution/ +
  _docs/legacy/ + _docs/how_to_test + README.
- Step 2 Architecture Baseline: architecture_compliance_baseline.md.
- Step 3 Test Spec: _docs/02_document/tests/ (environment,
  test-data, blackbox/performance/resilience/security/
  resource-limit tests, traceability-matrix), enum_spec_snapshot,
  expected_results/results_report.md (98 rows), plus the
  run-tests.sh + run-performance-tests.sh runners.
- Step 4 Code Testability Revision: 01-testability-refactoring/
  run dir (list-of-changes C01-C07, deferred_to_refactor,
  analysis/research_findings + refactoring_roadmap) and the 7
  child task specs AZ-448..AZ-454 under _docs/02_tasks/todo/
  plus _dependencies_table.md.
- _docs/_autodev_state.md pins the cursor at Step 4 / refactor
  Phase 4 entry so /autodev resumes cleanly.

Epic AZ-447 (UI testability gates) tracks the 7 child tasks that
will land in subsequent commits.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 00:38:49 +03:00

13 KiB

05 — Flights & Mission Planning

1. High-Level Overview

Purpose: One logical component covering everything mission/flight related — flight CRUD, waypoint editing, altitude profile, wind/battery calc, raw mission JSON I/O, and GPS-Denied operations (incl. an end-to-end test mode that simulates a real flight from a tlog + video pair). It is currently physically split across two codebases that the project intends to converge.

Architectural Pattern: Page composition (FlightsPage) wiring three sibling panels — FlightListSidebar, FlightParamsPanel, FlightMap — plus modals (AltitudeDialog, JsonEditorDialog) and a GPS-Denied sub-page.

Implementation status — two trees, one component:

Tree What it is Deployed?
src/features/flights/ (15 modules, React 19 + Tailwind) The target implementation. Mostly a mechanical port-in-progress of the tree below. Yes — Dockerfile builds src/ only.
mission-planner/ (37 modules, React 18 + MUI 5) The port source / reference. The richer, more battle-tested mission planner that the new SPA is being adapted from. No. Disjoint dependency island. Deletion candidate after parity.

The two trees are intentionally disjoint at the file level (no cross-imports — 00_discovery.md §1) but they are one component in the design: same domain, same data model, same intent. Findings, port plan, and architecture decisions are tracked in this single component spec. Mission-planner files are listed in §"Module Inventory" below alongside the new SPA files; per-finding origin is preserved.

Upstream dependencies (target tree): 00_foundation, 01_api-transport, 03_shared-ui (FlightContext, ConfirmDialog).

Downstream consumers: 10_app-shell (routes /flights and the GPS-Denied sub-page).

2. Internal Interfaces

Page entries (target tree, src/features/flights/)

Export Notes
FlightsPage() Top-level route component for /flights. Uses useFlight(), fetches flight detail by id, exposes save/delete/duplicate. Wires react-leaflet, leaflet-draw, and chart.js.
GpsDeniedPage() (planned route, see §6) Sub-page for GPS-denied operations and test mode. Today a partial inline panel inside FlightsPage (finding #25) — slated to become its own route.

Internal modules — target tree (src/features/flights/)

Module Role
FlightsPage.tsx Orchestrator (route component)
FlightMap.tsx Leaflet map + draw control + waypoint markers + minimap
FlightListSidebar.tsx Left panel: flight list, search, new/duplicate/delete
FlightParamsPanel.tsx Right panel: name, aircraft, takeoff/landing, altitude chart, waypoint list, wind effect
WaypointList.tsx DnD-sortable waypoints (@hello-pangea/dnd)
AltitudeChart.tsx chart.js altitude profile
WindEffect.tsx Wind-vector visualisation
MiniMap.tsx Inline overview map
MapPoint.tsx Single waypoint marker
DrawControl.tsx leaflet-draw integration
AltitudeDialog.tsx Per-waypoint altitude/purpose modal
JsonEditorDialog.tsx Raw mission-JSON editor
flightPlanUtils.ts Distance / battery / weather computation helpers
mapIcons.ts Leaflet icon factory
types.ts Local feature types (waypoint shape, mission JSON shape)

Internal modules — port source (mission-planner/)

Group Modules Role / what the target should learn
Entry main.tsx, App.tsx (vestigial CRA stub) Composition root + LanguageProvider. The CRA stub App.tsx is a deletion candidate post-port.
Page composition flightPlanning/flightPlan.tsx, LeftBoard.tsx Canonical page shape (sidebar + map).
Map flightPlanning/MapView.tsx (cycle-paired with MiniMap.tsx), MiniMap.tsx, DrawControl.tsx, MapPoint.tsx Reference Leaflet integration. Cycle: MiniMap imports the named helper UpdateMapCenter from MapView; MapView imports MiniMap as JSX child. Document the contract precisely if porting both at once.
Panels flightPlanning/PointsList.tsx, AltitudeChart.tsx, AltitudeDialog.tsx, WindEffect.tsx, TotalDistance.tsx, JsonEditorDialog.tsx, LanguageSwitcher.tsx, Aircraft.ts Reference panel shapes. Several have richer behaviour than the current SPA siblings.
Services services/calculateBatteryUsage.ts, AircraftService.ts, WeatherService.ts, calculateDistance.ts Authoritative battery / weather / distance logic. The target's flightPlanUtils.ts is currently an inferior port (silent errors, sequential await, hardcoded API key).
i18n flightPlanning/LanguageContext.tsx, constants/translations.ts, constants/languages.ts Local translation pattern. The port should converge to 00_foundation/i18n instead.
Constants constants/{actionModes,maptypes,tileUrls,purposes}.ts Reference constant tables.
Icons icons/{MapIcons,PointIcons,SidebarIcons,PhoneIcon}.tsx Reference icon factory.
Utilities utils.ts, config.ts, types/index.ts Reference helpers + types.
Test (vestigial) test/jsonImport.test.ts, setupTests.ts One Jest test that cannot run today (Jest not in package.json). Out of scope for the live SPA test plan.

3. External API Specification

Endpoints consumed (target tree + planned for GPS-Denied):

Method Path Purpose
GET /api/flights List + page (pageSize=1000 ceiling from FlightContext)
GET /api/flights/{id} Detail + waypoints
POST /api/flights Create
PUT /api/flights/{id} Update flight metadata
DELETE /api/flights/{id} Delete
POST/DELETE /api/flights/{id}/waypoints Add / remove waypoints
POST /api/gps-denied-desktop/... GPS-denied desktop service (mission setup, plan upload) — partial today
POST /api/gps-denied-onboard/... GPS-denied onboard service (frame + IMU consumer) — target of test-mode SITL output
GET OpenWeatherMap (third-party, direct from browser) Wind/temperature lookup. Will be proxied via suite as part of Step 4 (hardcoded key removal).

Concrete GPS-Denied endpoint shapes are not yet finalised in the suite spec — flagged for confirmation in autodev Step 3 (Test Spec) and Step 6 (Problem Extraction).

5. Implementation Details

State Management: Page-local React state for the active flight; FlightContext (in 03_shared-ui) for the list of flights.

Save model — current shape, target tree (finding #19): on Save, the UI deletes all existing waypoints and POSTs each one again. N delete + M POST round-trips. Lossy — concurrent edits race; if a POST fails halfway through, the saved flight is left with truncated waypoints. The mission-planner/ reference does this differently (single mission-JSON PUT) and is the recommended target shape.

Waypoint POST shape mismatch (PRIORITY, finding #20): target tree sends {name, latitude, longitude, order}; suite spec wants {Geopoint:{Lat,Lon,MGRS}, Source, Objective, OrderNum, Height}. Strict server returns 400. Owner of fix: this component + 00_foundation/types/index.ts::Waypoint.

Battery / weather calc (target tree flightPlanUtils.ts):

  • Hardcoded OpenWeather API key in source ('335799082893fad97fa36118b131f919') — committed secret. Step 4 fix.
  • Sequential await per segment — perf trap on long missions.
  • Silent try/catch swallows weather errors.
  • Mixes km / m altitudes; ambiguous battery-capacity unit (Wh vs Ws).
  • Port source (mission-planner/services/) has a cleaner, more correct implementation — use it as the reference.

Map / icons:

  • Target tree mapIcons.ts::defaultIcon CDN URL pinned to leaflet@1.7.1 while package.json has 1.9.4.
  • MiniMap map-tile licence attribution missing in some configurations.

Modal a11y (AltitudeDialog, JsonEditorDialog) — no aria-modal / role="dialog" / focus trap. Step 4. Same gap on the port-source counterparts.

Tech-stack divergence between the two trees (carry into the port plan):

Concern mission-planner/ src/features/flights/ (target)
React 18 19
UI library MUI 5 Tailwind 4 + custom az-* tokens
i18n local LanguageContext react-i18next (Foundation)
react-leaflet 4.2 5
@hello-pangea/dnd 16 18

Key Dependencies (target tree): leaflet 1.9, react-leaflet 5, leaflet-draw, leaflet-polylinedecorator, chart.js 4, @hello-pangea/dnd 18.

6. GPS-Denied sub-feature

Today a partial UI panel exists inside FlightsPage (target tree finding #25). The component design promotes this to a first-class sub-page with two tabs.

6a. Operations tab — current intent (already present, partial)

  • Upload / select a mission plan.
  • Configure GPS-denied desktop parameters.
  • Hand off to onboard.

The exact endpoints are partially wired today and tracked under "External API Specification" above.

6b. Test mode — new subitem (per _docs/how_to_test.md)

Source of truth: _docs/how_to_test.md. Architecture Vision artifact (/document Step 4.5) MUST surface this verbatim.

Goal: enable end-to-end testing of the GPS-denied onboard system without a real flight, using a recorded telemetry log + video pair.

User journey:

  1. Upload tlog file (MAVLink telemetry log).
  2. Upload video synced with the tlog (the two are usually not time-aligned at the file level — the system aligns them).
  3. The system:
    • Extracts timestamps, IMU, and GPS samples from the tlog.
    • Auto-syncs video to tlog by detecting the take-off moment in the IMU stream and matching it to the corresponding frame in the video. Most test sessions are quadcopter "ground-to-ground" flights; the start-on-ground signature in the IMU is the alignment anchor.
    • Spawns a SITL (Software-In-The-Loop) instance.
    • Feeds IMU samples + video frames into the GPS-denied onboard system in lockstep.
  4. The user observes the onboard system's outputs (position estimate, drift, GPS-recovery moments) on the same map / chart components used for live flights — reusing FlightMap, AltitudeChart, and a results overlay.

Scope notes for downstream skills:

  • This sub-feature is not implemented today. It is a planned addition that this component will own.
  • The tlog parser, IMU/video sync, and SITL controller are suite-side services; this component contributes the upload UI, the run controller, and the result overlay.
  • Test-mode I/O endpoints will live under /api/gps-denied-desktop/test/... (proposed; confirm in autodev Step 3 / Step 6).
  • The existing /document Step 1 finding "GPS-Denied panel partial" remains valid for the Operations tab and is broadened to track the Test mode tab as well.

7. Caveats & Edge Cases

26 numbered findings consolidated in src__features__flights.md. Highest-priority Step 4 items:

  1. Hardcoded OpenWeather API key — rotate + remove + proxy via suite.
  2. Waypoint POST shape mismatch + delete-then-recreate save model — likely-broken on a strict suite server. Reference port-source's PUT-mission-JSON model.
  3. flightPlanUtils.ts units / silent errors / sequential awaits. Replace with port-source services.
  4. Modal a11y + flight dropdown a11y (overlap with Shared UI).
  5. Leaflet 1.7.1 CDN URL drift.

Mission-planner-side caveats (port-only):

  • mission-planner/src/test/jsonImport.test.ts cannot run (Jest absent). Do not add Jest just for this one test.
  • mission-planner/src/App.tsx is a CRA stub. Delete only after parity.
  • MapView.tsx ↔ MiniMap.tsx named-handle cycle. Document precisely.

GPS-Denied-side caveats:

  • Operations tab is partial (finding #25 unchanged).
  • Test mode is unimplemented — no risk of regression today, but the design must accommodate the eventual test-mode entry point in routing and in FlightContext.

8. Dependency Graph

Must be implemented after: 00_foundation, 01_api-transport, 03_shared-ui.

Can be implemented in parallel with: every other feature page.

Blocks: 10_app-shell (routes to /flights as default authenticated landing; will also host the GPS-Denied sub-route).

Internal port order (within this component): port services/ (battery/weather/distance) → port flightPlanning/ panels (AltitudeChart, WindEffect, PointsList) → port MapView/MiniMap cycle group → fold the mission-planner/ tree out as the target reaches parity.

Module Inventory

Tree Module Doc
src/features/flights/* (15 modules) _docs/02_document/modules/src__features__flights.md
mission-planner/* (37 modules) _docs/02_document/modules/mission-planner.md