# Data Parameters — Azaion UI

> Output of `/document` Step 6d. The Azaion UI is a **thin client over a typed
> REST + SSE contract**; it carries no database. "Input data" therefore means
> the data shapes the SPA consumes (REST response payloads, SSE event
> payloads, env config). All claims trace to `_docs/02_document/data_model.md`,
> `architecture.md` § 4–5, and per-component descriptions.

**Status**: synthesised-from-verified-docs (Step 6d — `/document`)
**Date**: 2026-05-10

---

## Categories of input data

The SPA consumes four categories:

1. **Typed REST entities** — see `_docs/02_document/data_model.md` for the
   full ER map; key shapes summarised below.
2. **SSE event payloads** — `live-gps`, `annotation-status`, planned
   `detect-stream`.
3. **Configuration / environment variables** — runtime config injected at
   build time or via env.
4. **Static assets** — translation bundles, icons, design tokens (compiled
   into the bundle).

---

## 1. Typed REST entities (defined in `src/types/index.ts`)

> Every entity below mirrors the suite's REST contract. Values listed here
> match the **suite spec**, which is the source of truth per principle P9.
> Where the UI's current TypeScript enum drifts from the spec, the row notes
> the drift and the Step 4 fix.

### Auth

| Entity | Fields | Source |
|--------|--------|--------|
| `AuthUser` | `id`, `email`, `name`, `role`, `permissions: string[]`, `aircraftId?` | `02_auth`; `admin/` service |
| `LoginRequest` | `{ email, password }` | `POST /api/admin/auth/login` body |
| `LoginResponse` | `{ bearer, user: AuthUser }` (refresh cookie set server-side) | `POST /api/admin/auth/login` 200 |

### Flights

| Entity | Fields | Source |
|--------|--------|--------|
| `Flight` | `id`, `name`, `aircraftId`, `startDate?`, `endDate?`, `description?` | `flights/` service |
| `Waypoint` | **Spec**: `{ Geopoint: { Lat, Lon, MGRS }, Source, Objective, OrderNum, Height }`. **UI today**: `{ name, latitude, longitude, order }` — drift, finding #20 / Step 4 fix | `05_flights`; `flights/` service |
| `Aircraft` | `id`, `name`, `model`, `isDefault`, `serialNumber?` | `flights/` (read+write); `08_admin` mutation |
| `LiveGpsEvent` (SSE) | `{ flightId, lat, lon, alt, heading, speed, ts }` | `createSSE('/api/flights/${id}/live-gps')`; F13 |

### Annotations + Media

| Entity | Fields | Source |
|--------|--------|--------|
| `Media` | `id`, `flightId`, `mediaType: MediaType`, `mediaStatus: MediaStatus`, `filename`, `waypointId?`, `videoTime?`, `thumbnail?` | `annotations/` service |
| `MediaType` enum | **Spec**: `None=0`, `Image=1`, `Video=2`. **UI**: same. | `00_foundation`; P9 |
| `MediaStatus` enum | **Spec**: must include `None`, `Confirmed`, `Error` plus the existing `New`, `AiProcessing`, `AiProcessed`, `ManualCreated`. **UI today**: only `New=0` / `AiProcessing=1` / `AiProcessed=2` / `ManualCreated=3` — drift, Step 4 fix | `00_foundation`; finding |
| `AnnotationListItem` | `id`, `mediaId`, `videoTime`, `status: AnnotationStatus`, `source: AnnotationSource`, `detections: Detection[]`, `isSeed?: boolean` | `annotations/` |
| `AnnotationStatus` enum | **Spec**: `None=0`, `Created=10`, `Edited=20`, `Validated=30`, `Deleted=40`. **UI today**: `Created=0`, `Edited=1`, `Validated=2` — drift, Step 4 fix per P9 | `00_foundation`; `04_verification_log.md` |
| `AnnotationSource` enum | `AI=0`, `Manual=1` (matches spec) | `00_foundation` |
| `Detection` | `{ classNum: number, x, y, w, h: number, affiliation: Affiliation, combatReadiness: CombatReadiness, confidence?: number }` (normalised pixel coords) | `06_annotations` |
| `Affiliation` enum | **Spec**: must include `None` plus `Unknown`, `Friendly`, `Hostile`. **UI today**: `Unknown=0`, `Friendly=1`, `Hostile=2` — drift, Step 4 fix | finding |
| `CombatReadiness` enum | **Spec**: must include `Unknown` plus `NotReady`, `Ready`. **UI today**: `NotReady=0`, `Ready=1` — drift, Step 4 fix | finding |
| `DetectionClass` | `{ id, name, color, photoMode, maxSizeM }` | `08_admin` (write) + `annotations/` (read) |
| Annotation save body | **Required** (per finding #32): `Source`, `WaypointId`, `videoTime`, plus `mediaId`, `detections`, `status`. **UI today**: missing `Source` and `WaypointId`; uses `time` instead of `videoTime` — Step 4 fix | `06_annotations/AnnotationsPage.tsx` |
| `AnnotationStatusEvent` (SSE) | `{ annotationId, mediaId, oldStatus, newStatus, ts }` | `createSSE('/api/annotations/annotations/events')`; F14 |

### Dataset

| Entity | Fields | Source |
|--------|--------|--------|
| `DatasetItem` | `id`, `mediaId`, `classNum`, `status: AnnotationStatus`, `thumbnail`, `isSeed?: boolean`, `isSplit?: boolean` (parent-suite-doc fix applied for `isSplit`) | `07_dataset`; `annotations/` |
| `ClassDistributionItem` | `{ classNum, label, color, count }` | `annotations/` |
| Bulk-validate body | `{ ids: number[], targetStatus: AnnotationStatus.Validated }` | `POST /api/annotations/dataset/bulk-status` |

### Settings + Admin

| Entity | Fields | Source |
|--------|--------|--------|
| `SystemSettings` | as defined per `09_settings/SettingsPage.tsx` (settings keys per the suite spec) | `annotations/` (`/api/annotations/settings/system`) |
| `DirectorySettings` | per `SettingsPage` directory tab | `annotations/` (`/api/annotations/settings/directories`) |
| `CameraSettings` | per `SettingsPage` camera tab | `annotations/` |
| `UserSettings` | `selectedFlightId?: number`, `panelWidths?: { ... }`, plus other per-user UI state | `annotations/` (`/api/annotations/settings/user`) |
| `User` | `id`, `email`, `role`, `isActive`, `createdAt?` | `admin/` |

### Pagination

| Entity | Shape | Source |
|--------|-------|--------|
| `PaginatedResponse<T>` | `{ items: T[], totalCount: number, page: number, pageSize: number }` | shared envelope used by every list endpoint |

---

## 2. SSE event payloads

| Stream | URL | Payload shape | Where consumed |
|--------|-----|---------------|----------------|
| Live-GPS per flight (F13) | `GET /api/flights/${flightId}/live-gps?token=${bearer}` | `LiveGpsEvent` (see above) | `src/features/flights/FlightsPage.tsx:67` |
| Annotation-status events (F14) | `GET /api/annotations/annotations/events?token=${bearer}` | `AnnotationStatusEvent` | `src/features/annotations/AnnotationsSidebar.tsx:25` |
| Async detect progress (F7) | `GET /api/detect/stream/${jobId}?token=${bearer}` — **target-only, NOT wired today** | `{ jobId, progress: 0..1, detections?: Detection[], status, ts }` (anticipated) | not consumed today; planned per `04_verification_log.md` F7 |

Bearer goes in the **query string** (`?token=...`) per `ADR-008` — `EventSource`
cannot send headers. Refresh-rotation breaks live SSE; reconnect is missing
today (Step 8 hardening per `architecture.md` § Architecture Vision).

---

## 3. Configuration / environment variables

| Variable | Where read | Type | Default | Source |
|----------|-----------|------|---------|--------|
| `VITE_OPENWEATHERMAP_API_KEY` | (target — Step 4 fix) `mission-planner/src/utils/flightPlanUtils.ts` | string (secret) | currently hardcoded `'335799082893fad97fa36118b131f919'` (must rotate) | P10 violation, Step 4 fix |
| `VITE_SATELLITE_TILE_URL` | mission-planner Leaflet `TileLayer` | URL | none (unset breaks satellite imagery) | mission-planner only today |
| `AZAION_REVISION` | stamped into the production image at build time | string (commit SHA) | `$CI_COMMIT_SHA` from CI | `Dockerfile`; `.woodpecker/build-arm.yml` |
| `REGISTRY_HOST` | CI registry push | string | per pipeline secret | `.woodpecker/build-arm.yml` |
| `i18next.lng` | `src/i18n/i18n.ts` | language code | hardcoded `'en'` (Step 4 fix — should resolve from detector) | `i18n.ts`; AC-13 |
| nginx upstream hosts | `nginx.conf` | hostnames per service | docker-compose service names | `nginx.conf` |

The SPA bundle MUST NOT carry secrets at build time — except OpenWeatherMap
once it is moved to `.env` (per P10 the proper long-term answer is to proxy
the OWM call through `flights/` so no key reaches the browser; the `.env`
move is the interim Step 4 testability fix).

---

## 4. Static assets

| Asset | Location | Notes |
|-------|----------|-------|
| Translation bundles | `src/i18n/en.json`, `src/i18n/ua.json` | English + Ukrainian; key parity is mandatory (AC-12) |
| Design tokens | `src/index.css` (`az-bg`, `az-text`, `az-orange`, `az-success`, `az-danger`, `az-primary`, ...) | Tailwind 4; `ADR-005` |
| Map icons | `src/features/flights/mapIcons.ts` | defaultIcon CDN URL pinned to `leaflet@1.7.1` (drift — finding) |
| Aircraft / waypoint icons | bundled SVG / PNG under `src/features/flights/icons/*` (mission-planner port-source still has the larger set) | `05_flights` |
| Detection-class colors | `src/features/annotations/classColors.ts` (logically owned by `11_class-colors`) | file-move pending (P11 / module-layout Verification Needed) |

---

## 5. Data flow summary

1. **Plan flight** — UI fetches `aircrafts` from `flights/`; submits flight +
   waypoints; receives the persisted flight (today: delete-then-recreate
   waypoint cycle, finding #19; lossy POST shape, finding #20).
2. **Capture media** — out-of-band via the loader / annotations services;
   the UI surfaces uploaded items via `MediaList` polling.
3. **Annotate** — operator edits → `POST /api/annotations/annotations`;
   `F14` SSE pushes other-user status changes (admin-wide stream,
   client-side filtered).
4. **AI Detect (sync image)** — `POST /api/detect/${id}` returns inline
   detections. **Used for both image and video today** (silent UX hazard
   for long videos — `F7` to ship in Phase B).
5. **AI Detect (async video — target)** — `POST /api/detect/video/${id}`
   returns a job ID → SSE on `/api/detect/stream/${jobId}` streams progress.
   Long videos require `X-Refresh-Token` header per `_docs/10_auth.md`.
6. **Curate dataset** — UI queries `annotations/` with status filters;
   bulk-validate transitions to `AnnotationStatus.Validated`; class-distribution
   chart loads from `/api/annotations/dataset/class-distribution`.
7. **Settings** — system / directory / camera saves go to `annotations/`;
   aircraft default-toggle goes to `flights/` (cross-service mutation,
   accepted).
8. **GPS-Denied Test Mode (target — F12)** — `.tlog` + video upload to
   `gps-denied-desktop/`; SITL drives `gps-denied-onboard/`; results render
   back through `flights/` GPS-Denied tab.

Full sequence diagrams: `_docs/02_document/system-flows.md`.
