# 06 — Annotations ## 1. High-Level Overview **Purpose**: Image / video annotation editor — bounding boxes, classes, affiliation, combat readiness, AI detection (sync + async via SSE), and the media-list browser scoped to the active flight. **Architectural Pattern**: Page composition (`AnnotationsPage`) wiring `MediaList` + `VideoPlayer` (or static image) + `CanvasEditor` + `AnnotationsSidebar` + `DetectionClasses`. **Upstream dependencies**: `00_foundation`, `01_api-transport`, `03_shared-ui` (FlightContext, ConfirmDialog, DetectionClasses), `11_class-colors`. **Downstream consumers**: `10_app-shell` (routed at `/annotations`); `07_dataset` imports `CanvasEditor` directly (cross-feature edge — see baseline scan). ## 2. Internal Interfaces | Export | Notes | |--------|-------| | `AnnotationsPage()` | Top-level route component. Manages selected media, panel widths (via `useResizablePanel`), and the open annotation under edit. | Internal modules: | Module | Role | |--------|------| | `AnnotationsPage.tsx` | Orchestrator (route component) | | `MediaList.tsx` | Left panel: thumbnail browser + search/filter; consumes `useFlight()` | | `VideoPlayer.tsx` | HTML5 video + frame seek + per-frame annotation overlays | | `CanvasEditor.tsx` | Bounding-box draw / move / resize layer (also used by `07_dataset`) | | `AnnotationsSidebar.tsx` | Right panel: annotation list, AI-detect controls | ## 3. External API Specification | Method | Path | Purpose | |--------|------|---------| | GET | `/api/annotations/media?flightId=...` | List media | | GET | `/api/annotations/media/{id}` | Media metadata | | GET | `/api/annotations/media/{id}/annotations` | Bbox list | | POST | `/api/annotations` | Create one | | PUT | `/api/annotations/{id}` | Update one | | DELETE | `/api/annotations/{id}` | Delete one | | POST | `/api/detect/{mediaId}` | Sync image AI-detect | | POST | `/api/detect/video/{mediaId}` | Async video AI-detect — should send `X-Refresh-Token`, currently does not (finding #30) | | GET | `/api/detect/classes` | Detection class list | | SSE | `/api/detect/stream/{jobId}` | Async detect progress (subscribed via `01_api-transport/sse.ts`) — but **`AnnotationsPage` does not subscribe today** (finding #10) | ## 5. Implementation Details **State Management**: Page-local for the open annotation + selection; `useResizablePanel` for panel widths (not persisted — finding #11). **Time-window math** (`CanvasEditor`, finding #6, post-cross-check correction): implementation is symmetric ±200 ms (400 ms total). Spec wants asymmetric 50 ms before + 150 ms after (200 ms total). UI is 4× too wide and not centred per spec. **Gradient cap** (finding #9, post-cross-check correction): annotation row alpha gradient maxes at `0x28 = 16 %` opacity due to a `* 40` literal that is decimal, not hex. Wireframe demands `0x40 = 25 %`. **`handleSave` body** (finding #32): currently `{ classNum, x, y, w, h, time }`. Suite spec requires `{ classNum, x, y, w, h, videoTime, Source, WaypointId }`. Owner: this component, also touches Foundation types. **handleDownload (image export)** — risks tainting the `` if the video is from a `blob:` URL with cross-origin frames; finding #12. **Missing affordances** (findings #13–18): - Affiliation icons absent (spec mandates per-bbox). - Combat-readiness indicator absent. - `AFFILIATION_COLORS` defined but unused (dead). - No keyboard shortcuts R / V / PageUp / PageDown. - No camera-config side panel. - No tile zoom indicator for `splitTile` media. **AI-detect controls** (`AnnotationsSidebar`, findings #21–23): - Async progress is not streamed (no SSE subscription). - Errors silently `console.error`'d, no UI feedback. **MediaList** (findings #24–26): - Uses `alert()` for "no media" state. - `blob:` local previews ignore the search filter. - No virtualisation — long flights render all thumbnails. **Cross-feature leak**: `07_dataset` imports `CanvasEditor` directly (caveat from `00_discovery.md` §8). The right home is a shared `components/canvas/` directory; not done in this step. **Enum drift cross-link**: findings #27–34 capture the enum drift (`AnnotationStatus`, `Affiliation`, `CombatReadiness`, `MediaStatus`, `AnnotationSource`) — wire payloads using current `src/types/index.ts` values are wrong. Owner of fix: `00_foundation/types/index.ts`. Two findings (#31, #33) are **NO UI CHANGE — PARENT-DOC FIX** and have already been applied to the suite docs (state.json 02:18Z note); the rest are Step 4. **Key Dependencies**: HTML5 `` + `