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>
11 KiB
Module group: mission-planner/
Single consolidated doc for the entire
mission-planner/sub-project (37 modules acrossservices/,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 workspaceREADME.md+00_discovery.md §1). The Dockerfile builds only the workspacesrc/. 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 ofmission-planner/is a Step 8 / autodev follow-up oncesrc/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 permetapurpose. The SPA uses three colour-coded icons (start / mid / end). Aircraft.tshelper 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
mission-planner/src/App.tsxis an unused CRA stub —main.tsxmountsFlightPlandirectly. Deletion candidate but only after the port is complete (per00_discovery.md §11.6). Step 8.mission-planner/src/test/jsonImport.test.tscannot run (Jest not installed; no test script). Out of scope. Step 8 deletion or migration to the suite-level e2e harness.flightPlanning/MapView.tsx ↔ MiniMap.tsximport each other (MiniMapimports the namedUpdateMapCenterhelper fromMapView;MapViewimportsMiniMapas a JSX child). Module-level execution is non-circular because each side only uses the type/handle exposed at call time. Ported tosrc/features/flights/FlightMap.tsx + MiniMap.tsxwithout the cycle.- 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 intranslations.ts) are out of scope. mission-planner/.env.exampledeclaresVITE_SATELLITE_TILE_URL— same env-driven pattern that the workspacesrc/should adopt for the Esri tile URL (currently hardcoded). Carry idea to Step 4.mission-planner/package.jsonlockfile is uncommitted (bun.lockis workspace-only; MP uses npm without a committed lock). Reproducibility risk if anyone runs MP. Step 8 — when MP is deleted this becomes moot.- Dependency divergence: MP uses
react-leaflet4.2 vs workspace 5.x;@hello-pangea/dnd16 vs 18;chart.jsshared. 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 consolidatedsrc__features__flights.md.