feat(military): Wingbits live flight details on click (#1816)

* feat(military): add Wingbits live flight details popup

Add click-to-details popup for military flights on both map and globe views,
enriched with live data from the Wingbits ECS network.

- New proto: GetWingbitsLiveFlight RPC proxies ecs-api.wingbits.com/v1/flights/{icao24}
- Server handler caches live position at 30s TTL via Redis
- MapPopup: show registration, model, climb rate, enriched fields in flight popup
- MapPopup: async loadWingbitsLiveFlight() updates popup with live Wingbits data
- DeckGLMap: trigger Wingbits enrichment on military flight click
- GlobeMap: add full popup on flight click (previously tooltip-only)

* fix: add cache tier for get-wingbits-live-flight route

* feat: extend Wingbits live popup to civilian aircraft positions layer

* fix(wingbits): SSRF guard, feature flag, and indentation fixes

- Validate ICAO24 against /^[0-9a-f]{6}$/ before URL interpolation (SSRF)
- Add isFeatureAvailable('wingbitsEnrichment') guard to getWingbitsLiveFlight
- Gate loading placeholder on feature flag to avoid flicker for unconfigured instances
- Fix renderGdeltArticle and vesselData.clear() indentation

* fix(wingbits): no-store CDN tier + throw on transient ECS errors

- Move get-wingbits-live-flight from fast (s-maxage=300/600) to no-store;
  Redis 30s TTL is the only cache — CDN must not hold stale live positions.
  Matches the pattern used by track-aircraft and vessel-snapshot.
- In fetchWingbitsLiveFlight, throw on non-404 errors (429, 5xx) so
  cachedFetchJson does not store transient failures as NEG_SENTINEL.
  Only 404 (aircraft unknown to Wingbits) is a genuine cacheable miss.
This commit is contained in:
Elie Habib
2026-03-18 20:38:28 +04:00
committed by GitHub
parent 11c444fcc9
commit 91e31dd435
13 changed files with 477 additions and 1 deletions

View File

@@ -312,6 +312,39 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
/api/military/v1/get-wingbits-live-flight:
get:
tags:
- MilitaryService
summary: GetWingbitsLiveFlight
description: GetWingbitsLiveFlight retrieves real-time position data from the Wingbits ECS network for a single aircraft.
operationId: GetWingbitsLiveFlight
parameters:
- name: icao24
in: query
description: ICAO 24-bit hex address (lowercase, 6 characters).
required: false
schema:
type: string
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/GetWingbitsLiveFlightResponse'
"400":
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
default:
description: Error response
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
Error:
@@ -1038,3 +1071,69 @@ components:
expansionZoom:
type: integer
format: int32
GetWingbitsLiveFlightRequest:
type: object
properties:
icao24:
type: string
minLength: 1
description: ICAO 24-bit hex address (lowercase, 6 characters).
required:
- icao24
description: GetWingbitsLiveFlightRequest fetches live Wingbits ECS data for a single aircraft.
GetWingbitsLiveFlightResponse:
type: object
properties:
flight:
$ref: '#/components/schemas/WingbitsLiveFlight'
description: GetWingbitsLiveFlightResponse contains the live flight data, if available.
WingbitsLiveFlight:
type: object
properties:
icao24:
type: string
description: ICAO 24-bit hex address.
callsign:
type: string
description: Live callsign.
lat:
type: number
format: double
description: Latitude in decimal degrees.
lon:
type: number
format: double
description: Longitude in decimal degrees.
altitude:
type: number
format: double
description: Altitude in feet.
speed:
type: number
format: double
description: Ground speed in knots.
heading:
type: number
format: double
description: Track/heading in degrees.
verticalRate:
type: number
format: double
description: Vertical rate in feet per minute (positive = climb, negative = descent).
registration:
type: string
description: Aircraft registration number.
model:
type: string
description: Aircraft model (e.g. "PC-12/45").
operator:
type: string
description: Operator name.
onGround:
type: boolean
description: True if the aircraft is on the ground.
lastSeen:
type: string
format: int64
description: Unix timestamp of the last position update.
description: WingbitsLiveFlight contains real-time flight position data from the Wingbits ECS network.