Files
ui/_docs/02_document/modules/mission-planner.md
Oleksandr Bezdieniezhnykh b016fd8207 [AZ-498] [AZ-499] Cycle 2 batch 11: satellite tiles + OWM hardening
AZ-498 — self-hosted satellite tiles + drop classic/satellite toggle:
- Single TILE_URL via getTileUrl() (mirrors getOwmBaseUrl/getApiBase
  pattern from AZ-449/AZ-450); env-var VITE_SATELLITE_TILE_URL with
  dev default http://localhost:5100/tiles/{z}/{x}/{y}.
- FlightMap + MiniMap render one TileLayer with
  crossOrigin="use-credentials" so Leaflet's <img> tile fetcher
  attaches the same-origin satellite-provider auth cookie.
- ImportMetaEnv + .env.example collapse the prior OSM/Esri pair into
  one var. The flights.planner.satellite i18n key is removed in
  lockstep across en.json + ua.json (parity preserved).
- E2E harness wired end-to-end: compose passes the new var to
  azaion-ui; tile-stub serves /tiles/{z}/{x}/{y} with
  Content-Type=image/jpeg + Cache-Control + ETag matching the
  contract; infrastructure.e2e.ts AC-2 asserts the new path; dead
  OSM defenses removed from EXTERNAL_HOSTS route guard.
- Fast-profile MSW handlers rewritten for the cookie-auth path shape.
- 8 colocated fast tests under src/features/flights/__tests__/.

AZ-499 — mission-planner OWM env-var hardening + AZ-482 source-scan
gap close:
- WeatherService.ts reads VITE_OWM_API_KEY + VITE_OWM_BASE_URL;
  fail-soft null when key unset (mirrors AZ-448 main-SPA contract).
  Public signature getWeatherData(lat, lon) preserved.
- mission-planner/.env.example + vite-env.d.ts declare both vars.
- New owm_key_in_source banned-deps kind scans src/ AND
  mission-planner/ for the rotated literal; STC-SEC1C row added to
  scripts/run-tests.sh; check-banned-deps.mjs dispatch extended.
- 7 fast tests under tests/mission_planner_weather.test.ts cover
  AC-1..AC-4 + trailing-slash + happy path + network-error fail-soft.

Spec drift (recorded in batch_11_report.md, user-approved Choose B
on 2026-05-12):
- AZ-498 AC-8 dropped (named tile_split_zoom* files belong to AZ-474
  image-annotation surface, not map tiles).
- 4 missing files added in-scope (msw tiles handler, tile-stub
  server, compose env, dead VITE_TILE_BASE_URL replaced).
- AZ-499 STC-S6 ID conflict resolved by using STC-SEC1C.

Pending USER ACTION (BLOCKING for AZ-499 close):
- Revoke OpenWeatherMap key 335799082893fad97fa36118b131f919 at
  home.openweathermap.org/api_keys; capture evidence on AZ-499.

Cross-workspace deploy gate (handled at autodev Step 16, not a
Step-10 blocker for AZ-498):
- satellite-provider cookie-auth on GET /tiles/{z}/{x}/{y}
  (separate AZAION ticket on the satellite-provider workspace).

Reports: _docs/03_implementation/batch_11_report.md and
_docs/03_implementation/reviews/batch_11_review.md (verdict
PASS_WITH_WARNINGS — 1 Low, pre-existing trim-trailing-slash
duplication across vite roots).

Static gates: STC-ARCH-01, STC-ARCH-02, STC-T1, STC-FP22, STC-FP23,
STC-SEC1C all PASS post-refactor. +15 fast tests; +1 STC-SEC1C row.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 04:34:39 +03:00

11 KiB

Module group: mission-planner/

Single consolidated doc for the entire mission-planner/ sub-project (37 modules across services/, flightPlanning/, icons/, constants/, types/, utils.ts, config.ts, main.tsx, App.tsx).

Why a single doc: mission-planner/ is port-source, not deployed product (per workspace README.md + 00_discovery.md §1). The Dockerfile builds only the workspace src/. Documenting each of the 37 files at the same fidelity as the production SPA would burn context for code that exists only as a reference for the React-19 port. Future deletion of mission-planner/ is a Step 8 / autodev follow-up once src/features/flights/ reaches feature-parity.

Role in the codebase

Aspect Status
Purpose Reference implementation of the flight-mission planner UI being mechanically translated into src/features/flights/. Stand-alone CRA-flavoured Vite + React 18 + MUI 5 app.
Build Has its own vite.config.ts, tsconfig, index.html, package.json. No alias path.
Deployment None — workspace Dockerfile does NOT build it; nginx.conf does NOT serve it.
Tests src/test/jsonImport.test.ts uses describe/it/expect style; Jest is not installed and there is no test script — the test cannot run as-is. Documented gap, no fix planned (out of scope per 00_discovery.md §11.5).
Lifecycle Will be deleted once src/features/flights/ covers all mission-planner features. Not before.

Directory map

mission-planner/src/
├── main.tsx                          → mounts <LanguageProvider><FlightPlan /> into #root
├── App.tsx                           UNUSED — empty CRA stub; main.tsx mounts FlightPlan directly
├── config.ts                         COORDINATE_PRECISION, downang, upang, defaults
├── utils.ts                          newGuid (Math.random v4)
├── types/index.ts                    FlightPoint, CalculatedPointInfo, MapRectangle, AircraftParams,
│                                     WeatherData, MovingPointInfo, ActionMode, MapType, large
│                                     TranslationStrings interface tree
├── constants/
│   ├── actionModes.ts                points / workArea / prohibitedArea
│   ├── maptypes.ts                   classic / satellite
│   ├── tileUrls.ts                   OSM + Esri ArcGIS tile URLs
│   ├── translations.ts               English + Ukrainian dictionaries (raw, no i18next)
│   ├── languages.ts                  ISO codes + flag codes for LanguageSwitcher
│   └── purposes.ts                   tank, artillery
├── services/
│   ├── calculateDistance.ts          Haversine + plane climb/cruise/descend
│   ├── AircraftService.ts            mockGetAirplaneParams (returns hardcoded fixed-wing)
│   ├── WeatherService.ts             OpenWeatherMap fetch (env-vars: VITE_OWM_API_KEY + VITE_OWM_BASE_URL; fail-soft `null` when key unset, AZ-499)
│   └── calculateBatteryUsage.ts      Drag + thrust lookup; same algorithm as src/features/flights/flightPlanUtils.calculateBatteryPercentUsed
├── icons/
│   ├── MapIcons.tsx                  Leaflet icon factories
│   ├── PointIcons.tsx                Per-purpose marker icons
│   ├── SidebarIcons.tsx              MUI-styled side-panel SVGs
│   └── PhoneIcon.tsx                 Rotate-phone overlay (mobile orientation hint)
└── flightPlanning/
    ├── flightPlan.tsx                Top-level page (369 lines) — owns state, dialogs, JSON I/O
    ├── MapView.tsx                   MapContainer + draw handlers + click-to-add (414 lines)
    ├── MiniMap.tsx                   Floating thumbnail; cyclic edge with MapView
    ├── MapPoint.tsx                  Draggable waypoint + popup
    ├── DrawControl.tsx               Rectangle draw tool
    ├── PointsList.tsx                Reorderable waypoint list
    ├── LeftBoard.tsx                 Side panel composing list + chart + totals + lang switcher
    ├── AltitudeChart.tsx             Chart.js altitude visualizer
    ├── AltitudeDialog.tsx            Add/Edit waypoint modal
    ├── JsonEditorDialog.tsx          Edit-as-JSON modal
    ├── TotalDistance.tsx             Total distance + time + battery readout
    ├── LanguageContext.tsx           React Context for current locale (NOT i18next)
    ├── LanguageSwitcher.tsx          Locale dropdown
    ├── WindEffect.tsx                Wind heading / speed inputs + arrow preview
    └── Aircraft.ts                   Aircraft helper (filename casing odd — TypeScript file, capitalised)

Mapping mission-planner/src/features/flights/

The React 19 port translates module-for-module wherever possible. Status as of this commit:

mission-planner/src/... Ported to src/features/flights/... Status
flightPlanning/flightPlan.tsx FlightsPage.tsx Ported with backend wiring (Flights API + SSE). MP-side has none.
flightPlanning/MapView.tsx FlightMap.tsx Ported.
flightPlanning/MiniMap.tsx MiniMap.tsx Ported.
flightPlanning/MapPoint.tsx MapPoint.tsx Ported.
flightPlanning/DrawControl.tsx DrawControl.tsx Ported.
flightPlanning/PointsList.tsx WaypointList.tsx Ported (renamed for parity with backend Waypoint entity).
flightPlanning/LeftBoard.tsx FlightParamsPanel.tsx Partial — MP-side hosts LanguageSwitcher, the SPA delegates language to global Header + react-i18next.
flightPlanning/AltitudeChart.tsx AltitudeChart.tsx Ported.
flightPlanning/AltitudeDialog.tsx AltitudeDialog.tsx Ported (file name kept; should be WaypointDialog).
flightPlanning/JsonEditorDialog.tsx JsonEditorDialog.tsx Ported.
flightPlanning/WindEffect.tsx WindEffect.tsx Ported.
flightPlanning/TotalDistance.tsx (inlined into FlightParamsPanel) Ported as a <div> strip in the params panel; no separate module.
flightPlanning/LanguageContext.tsx + LanguageSwitcher.tsx (replaced by react-i18next) Not ported as such — language is global via i18next.
flightPlanning/Aircraft.ts (no equivalent) Aircraft is server-side; the SPA fetches /api/flights/aircrafts.
services/calculateDistance.ts flightPlanUtils.calculateDistance Ported.
services/calculateBatteryUsage.ts flightPlanUtils.calculateBatteryPercentUsed + calculateAllPoints Ported.
services/WeatherService.ts flightPlanUtils.getWeatherData Ported. Env-vars VITE_OWM_API_KEY + VITE_OWM_BASE_URL since AZ-499 (mirrors AZ-448 / AZ-449); same fail-soft null contract.
services/AircraftService.ts flightPlanUtils.getMockAircraftParams (mock only) Real fetch is /api/flights/aircrafts in FlightsPage.
constants/translations.ts + LanguageContext.tsx src/i18n/{en,ua}.json + i18n/i18n.ts Migrated to i18next.
constants/{actionModes,maptypes,tileUrls,purposes,languages}.ts features/flights/types.ts (PURPOSES, TILE_URL, ActionMode) Consolidated into one file. TILE_URL collapsed from the prior classic/satellite pair to a single self-hosted satellite URL by AZ-498.
icons/{MapIcons,PointIcons,SidebarIcons,PhoneIcon}.tsx features/flights/mapIcons.ts Only the marker icons survived; SidebarIcons + PhoneIcon dropped (no rotate-phone overlay in the SPA today).
utils.ts (newGuid) flightPlanUtils.newGuid Ported.
config.ts features/flights/types.COORDINATE_PRECISION Single constant migrated.
App.tsx (none) Was already an unused CRA stub in MP; nothing to port.
main.tsx (none) Replaced by the workspace src/main.tsx.
setupTests.ts, test/jsonImport.test.ts (none) Cannot run; not migrated.

Things still in MP that are NOT in the SPA port

  • Rotate-phone overlay (icons/PhoneIcon.tsx): MP shows a rotate-phone hint when held in portrait. The SPA does not.
  • Per-purpose marker icons (icons/PointIcons.tsx): MP draws a different marker per meta purpose. The SPA uses three colour-coded icons (start / mid / end).
  • Aircraft.ts helper class: never used in the SPA — aircraft state is fetched and treated as a plain DTO.
  • OpenWeather call directly from WeatherService.ts: same flaw as the SPA port (no proxy). Hardcoded key fixed by AZ-499 (env-vars + fail-soft); proxy story still owned by the broader F1 mission-planner deduplication track.
  • MUI 5: MP uses MUI for dialogs / inputs / icons. The SPA replaced everything with hand-rolled Tailwind components matching _docs/ui_design/README.md. MUI is not a dep of the workspace.

Findings carried into Step 4 / 6 / 8

  1. mission-planner/src/App.tsx is an unused CRA stubmain.tsx mounts FlightPlan directly. Deletion candidate but only after the port is complete (per 00_discovery.md §11.6). Step 8.
  2. mission-planner/src/test/jsonImport.test.ts cannot run (Jest not installed; no test script). Out of scope. Step 8 deletion or migration to the suite-level e2e harness.
  3. flightPlanning/MapView.tsx ↔ MiniMap.tsx import each other (MiniMap imports the named UpdateMapCenter helper from MapView; MapView imports MiniMap as a JSX child). Module-level execution is non-circular because each side only uses the type/handle exposed at call time. Ported to src/features/flights/FlightMap.tsx + MiniMap.tsx without the cycle.
  4. MP uses raw translation tables keyed by ISO code, not i18next. The SPA correctly migrated to react-i18next; the legacy Russian-language references (if any in translations.ts) are out of scope.
  5. mission-planner/.env.example declares VITE_SATELLITE_TILE_URL — same env-driven pattern that the workspace src/ should adopt for the Esri tile URL (currently hardcoded). Carry idea to Step 4.
  6. mission-planner/package.json lockfile is uncommitted (bun.lock is workspace-only; MP uses npm without a committed lock). Reproducibility risk if anyone runs MP. Step 8 — when MP is deleted this becomes moot.
  7. Dependency divergence: MP uses react-leaflet 4.2 vs workspace 5.x; @hello-pangea/dnd 16 vs 18; chart.js shared. None of this affects the deployed bundle. Step 8 — delete MP.

Tests

The single jsonImport.test.ts cannot run. None of the other 36 modules have tests.

Cross-doc references

  • _docs/02_document/00_discovery.md §1, §2b, §7b, §10, §11 — discovery-level facts about MP.
  • Workspace README.md — declares MP as not-deployed.
  • mission-planner/README.md — stale CRA boilerplate, do not trust.
  • The 14 src/features/flights/ modules — see consolidated src__features__flights.md.