Getting data into the COP¶
There are two ways external data lands in the web app, and which one you use depends on what the data is — not on who produces it. Pick the path first, then follow its runbook.
| You have… | It is… | Path | Mechanism | Runbook |
|---|---|---|---|---|
Tracks (track_hits) |
high-volume ambient position feeds — AIS, ADS-B, raw radar tracks. Mostly neutral, no per-contact operational judgement. | Feed ingestion | NiFi writes directly to Postgres under a least-privilege role | Provision feed ingestion |
| Detections / targets | operational observations — a sensor/AI/human says "this specific thing, here, now, with this confidence/affiliation". Nominatable to the target board. | Ingest API | producer POSTs to the HTTP /api/feed/* API with a JWT |
Push detections & targets |
The rule of thumb¶
Ambient background picture → tracks. Operational judgement → detections.
track_hits is the dumb backdrop: where is everything. It carries no affiliation, confidence,
or provenance per row — the kind (ais/adsb/radar/geojson) lives on the feed's
layer, and that's it. The moment a producer is asserting something operationally meaningful
about a contact — an affiliation, a confidence, a classification, a signature match — that is a
detection, and it belongs on the operational path (where it gets source_kind, confidence,
affiliation, and can be nominated to a target).
The two paths are also technically distinct: feed ingestion is a direct-DB write (no HTTP, no token — a Postgres role); the ingest API is an authenticated HTTP POST (a signed JWT, scopes, revocation). They share no code.
Worked distinction — same sensor, different path¶
- AIS vessel traffic → a track. It's ambient — thousands of neutral merchant vessels
reporting position. Feed ingestion →
track_hits, layer kindais. No per-contact judgement. - Nightingale radar contacts → detections. Nightingale emits classified
ContactResults (type match, signature, confidence) — that is operational judgement, so each contact is a detection (source_kind=sensor, an affiliation, a confidence), not a flat track. Ingest API →/api/feed/detections. See the push runbook for the Nightingale example end-to-end.
!!! note "Nightingale is mid-migration to the detections path"
Today the NiFi ParseNightingaleToTrackHit processor still routes Nightingale to
track_hits (a flat radar track with a fixed SIDC, discarding the type/signature
richness). The target is ParseNightingaleToDetection → POST /api/feed/detections. The
NiFi-side change is outstanding; the web /api/feed/detections endpoint already exists.
See also¶
- Provision feed ingestion (NiFi →
track_hits) — the tracks path - Push detections & targets (
/api/feed/*) — the operational path - Issue an API credential — the JWT the ingest API requires
- Machine Ingest API — the full
/api/feed/*contract - Glossary —
track_hits, detection,source_kind