Captures the full output of autodev existing-code Phase A through Step 4 (Code Testability Revision) for the Azaion UI workspace: - Step 1 Document: _docs/02_document/ (FINAL_report, architecture, glossary, components/, modules/, diagrams/, system-flows, module-layout) plus _docs/00_problem/ + _docs/01_solution/ + _docs/legacy/ + _docs/how_to_test + README. - Step 2 Architecture Baseline: architecture_compliance_baseline.md. - Step 3 Test Spec: _docs/02_document/tests/ (environment, test-data, blackbox/performance/resilience/security/ resource-limit tests, traceability-matrix), enum_spec_snapshot, expected_results/results_report.md (98 rows), plus the run-tests.sh + run-performance-tests.sh runners. - Step 4 Code Testability Revision: 01-testability-refactoring/ run dir (list-of-changes C01-C07, deferred_to_refactor, analysis/research_findings + refactoring_roadmap) and the 7 child task specs AZ-448..AZ-454 under _docs/02_tasks/todo/ plus _dependencies_table.md. - _docs/_autodev_state.md pins the cursor at Step 4 / refactor Phase 4 entry so /autodev resumes cleanly. Epic AZ-447 (UI testability gates) tracks the 7 child tasks that will land in subsequent commits. Co-authored-by: Cursor <cursoragent@cursor.com>
23 KiB
Azaion UI — Final Documentation Report
Output of
/documentStep 7. Integrates all artifacts produced in Steps 0–6. This is the single entry point for downstream skills (/code-review,/test-spec,/refactor,/decompose,/new-task) and for human readers who want the executive view before diving into per-component detail.
Status: complete
Date: 2026-05-10
Scope: full codebase (src/ + mission-planner/ port-source)
1. Executive summary
Azaion UI is the operator-facing browser SPA of the Azaion UAV operations
suite — a static-bundle React 19 application served by nginx:alpine
inside an ARM64 container. It is the in-progress React rewrite of the
legacy WPF stack (Azaion.Annotator + Azaion.Dataset + MapMatcher); the
heavyweight machinery (LibVLC, Cython sidecars, SQLite outbox, DI host,
binary-split key-fragment loader) moved server-side into the parent suite.
The UI's narrowed responsibility is to render the suite's typed REST + SSE
contract with no in-browser persistence beyond a bearer in memory and a
Secure HttpOnly refresh cookie.
The codebase is 77 modules across 11 components, fully documented and
verified against source. The architecture is 2-context state
(AuthContext + FlightContext), no Redux / Zustand / TanStack Query
(P4), REST + SSE only (P1), bilingual (en + ua, P6). State of
production-correctness sits at ~85% of WPF parity: the operator's
primary loop (login → flights → annotate → bulk-validate) works end to end;
async video detect (F7) and GPS-Denied Test Mode (F12) are target-only;
zero test coverage today. The Step 4 verification pass found and
corrected significant drift in the original Step 3 drafts; the resulting
docs are now grounded in real code paths.
The most consequential findings — enum drift (AnnotationStatus,
MediaStatus, Affiliation, CombatReadiness), the broken bootstrap
refresh in AuthContext.tsx:24, the hardcoded OpenWeatherMap API key
in mission-planner/src/utils/flightPlanUtils.ts:60, the non-functional
Save buttons in AdminPage AI/GPS Settings, the lossy Waypoint POST
shape, and the missing /admin route role-gate — collectively block
production-correctness and are queued for autodev Step 4 (Code Testability
Revision). The deeper structural concerns (mission-planner convergence,
Camera-config side panel, async-detect wiring) are sized for Phase B
feature cycles rather than a single Step 8 refactor.
2. Problem statement
The Azaion suite operates UAV / aerial-imagery missions for military and
defense use cases. Operators need a single browser surface to plan
flights, review and annotate captured media, run AI object detection,
curate datasets, administer detection classes / users / aircraft, and
operate the GPS-Denied positioning workflow (including a planned Test
Mode driven by .tlog + video pairs through SITL).
This SPA is that surface. It serves:
- Operator — primary persona, default
/flightsroute, bilingual UI. - Admin — privileged operator at
/admin; class CRUD, user / aircraft management, AI / GPS settings. - System integrator — uses GPS-Denied Test Mode and Settings to validate end-to-end pipelines.
It is internal, not public. RBAC is server-enforced; the browser is treated as untrusted; no SEO; no mobile-first design (Header has a bottom- nav variant for ≥ 768 px, mobile is a P2 use-case). Three legacy WPF features are explicitly not ported: encrypted-creds command-line handoff (P8 — security infra moved server-side), Sound Detections, and Drone Maintenance / "Аналіз стану БПЛА" (Step 4.5 decisions — dropped).
Full statement: _docs/00_problem/problem.md.
3. Architecture overview
Tech stack (one-liner): React 19 + TypeScript 5.7 strict + Vite 6 +
Bun 1.3.11 + Tailwind 4 (az-* design tokens) + react-router-dom@7 +
leaflet@1.9.4 + react-leaflet@5 + chart.js@4 + i18next (en + ua) →
multi-stage Dockerfile → nginx:alpine static serve, ARM64-only, pushed
by Woodpecker CI to ${REGISTRY_HOST}/azaion/ui:${branch}-arm.
Layering (module-layout.md):
- L0 — Foundation:
00_foundation,11_class-colors - L1 — Transport:
01_api-transport(fetch+EventSourcewrappers) - L2 — Auth & Shared UI:
02_auth,03_shared-ui - L3 — Feature pages:
04_login,05_flights,06_annotations,07_dataset,08_admin,09_settings - L4 — App shell:
10_app-shell
Cross-cutting principles (binding constraints — architecture.md
§ Architecture Vision):
P1 REST + SSE only · P2 Static bundle + nginx · P3 Bearer in memory + HttpOnly refresh cookie · P4 Two-context state · P5 ARM-first edge · P6 Bilingual (en + ua) · P7 Lift cross-cutting at 2+ touches · P8 WPF parity is a goal not a constraint · P9 Spec is source of truth for numeric enums · P10 No hardcoded credentials · P11 Persist what you type · P12 Admin can edit existing detection classes.
Full architecture: _docs/02_document/architecture.md.
4. Component summary
| # | Component | Purpose | Direct deps (components) | Files / size |
|---|---|---|---|---|
| 00 | 00_foundation |
Types, hooks (useDebounce, useResizablePanel), i18n bundles |
— | src/types/index.ts, src/hooks/*, src/i18n/*, src/components/DetectionClasses.tsx |
| 01 | 01_api-transport |
fetch wrapper (client.ts) + EventSource wrapper (sse.ts); 401-retry refresh |
00 | src/api/client.ts, src/api/sse.ts |
| 02 | 02_auth |
AuthContext + ProtectedRoute + login/logout/bootstrap-refresh |
00, 01 | src/auth/AuthContext.tsx, src/auth/ProtectedRoute.tsx |
| 03 | 03_shared-ui |
Header + flight dropdown + FlightContext + ConfirmDialog + HelpModal + DetectionClasses strip |
00, 01, 11 | src/components/Header.tsx, FlightContext.tsx, ConfirmDialog.tsx, HelpModal.tsx, DetectionClasses.tsx |
| 04 | 04_login |
Public /login route |
00, 02 | src/features/login/LoginPage.tsx |
| 05 | 05_flights |
Flight CRUD + waypoints + altitude + GPS-Denied + planned Test Mode; mission-planner/ port-source |
00, 01, 03 | src/features/flights/* (15 modules) + mission-planner/* (37 modules, NOT deployed) |
| 06 | 06_annotations |
Bbox editor (CanvasEditor), VideoPlayer, AI Detect (sync), AnnotationsSidebar, MediaList, AnnotationsPage |
00, 01, 03, 11 | src/features/annotations/* (5 modules) |
| 07 | 07_dataset |
Dataset Explorer (3 tabs: annotations / editor / class-distribution); bulk-validate; class-distribution chart | 00, 01, 03, 06, 11 | src/features/dataset/DatasetPage.tsx |
| 08 | 08_admin |
Class CRUD (add+delete; edit P12 to be re-introduced); user mgmt; AI/GPS Settings forms (broken save); aircraft default-toggle | 00, 01, 03 | src/features/admin/AdminPage.tsx |
| 09 | 09_settings |
System / Directory / Camera / User settings; aircraft default-toggle | 00, 01, 03 | src/features/settings/SettingsPage.tsx |
| 10 | 10_app-shell |
App.tsx + main.tsx + routing tree + global CSS |
00, 02, 03, 04, 05, 06, 07, 08, 09 | src/App.tsx, src/main.tsx, src/index.css, index.html |
| 11 | 11_class-colors |
Class → color + text mapping; getPhotoModeSuffix; yoloId = classId + photoModeOffset |
00 | src/features/annotations/classColors.ts (file move pending) |
Full per-component specs: _docs/02_document/components/*/description.md.
5. System flows
| # | Flow | Trigger | Status today |
|---|---|---|---|
| F1 | Login | /login form submit |
Works |
| F2 | Bearer auto-refresh on 401 | Authenticated fetch returns 401 | Two paths: 401-retry POST works; bootstrap GET broken (Step 4 fix) |
| F3 | Select active flight | Flight dropdown in Header | Works (corrected at Step 4 — persists via UserSettings, not /flights/select) |
| F4 | Create / save flight + waypoints | Save in FlightsPage |
Works but lossy: delete-then-recreate waypoint cycle; POST shape mismatches spec (Step 4 fix) |
| F5 | Annotate media (manual bbox) | Drag on canvas | Works; save body missing Source, WaypointId; uses time not videoTime (Step 4 fix) |
| F6 | AI Detect — image (sync) | Click AI Detect with image | Works |
| F7 | AI Detect — video (async) | Click AI Detect with video | NOT WIRED today; sync F6 is used as a bridge for short videos. Phase B target. |
| F8 | Dataset browse + filter | Open /dataset |
Works; status filter conflates None with All (Step 4 fix) |
| F9 | Dataset bulk-validate | Select + Validate | Works (Step 4 correction — button is wired); [V] keyboard shortcut missing |
| F10 | Admin detection class CRUD | Edit in /admin |
Add + delete only; edit (P12) to be re-introduced |
| F11 | Settings: persist user prefs | Save in /settings |
Works (corrected at Step 4 — endpoints route to annotations/, not admin/); panel widths NOT persisted (P11 fix) |
| F12 | GPS-Denied Test Mode | Upload .tlog + video |
NOT WIRED today; Phase B target. |
| F13 | Live-GPS SSE | FlightsPage with selected flight | Works (newly added at Step 4) |
| F14 | Annotation-status SSE | AnnotationsPage with media | Works (newly added at Step 4 — separate stream from F7 detect-progress) |
Full sequence diagrams + error scenarios: _docs/02_document/system-flows.md.
6. Risk observations (from 04_verification_log.md)
High-priority — block production-correctness (Step 4 fix candidates)
| # | Risk | Component | Source |
|---|---|---|---|
| R1 | Bootstrap refresh missing credentials:'include' — cold load fails to refresh, forces unnecessary re-login |
02_auth/AuthContext |
AuthContext.tsx:24; F2 |
| R2 | Numeric enum drift (AnnotationStatus, MediaStatus, Affiliation, CombatReadiness) — wire payloads will be wrong |
00_foundation |
src/types/index.ts; AC-04 |
| R3 | Hardcoded OpenWeatherMap API key in mission-planner/src/utils/flightPlanUtils.ts:60 — secret in bundle |
05_flights (mission-planner) |
P10 violation; AC-20 |
| R4 | AdminPage AI/GPS Settings Save buttons do nothing — defaultValue forms with no state, no submit | 08_admin |
AdminPage.tsx; finding B4 |
| R5 | Lossy Waypoint POST shape — UI sends {name, latitude, longitude, order}; spec wants {Geopoint:{Lat,Lon,MGRS}, Source, Objective, OrderNum, Height} — likely 400s on a strict server |
05_flights |
finding #20 |
| R6 | Annotation save body missing Source, WaypointId; field renamed time → videoTime |
06_annotations |
finding #32 |
| R7 | /admin route lacks client-side role-gate — non-admin sees broken admin UI flicker before server 403 |
10_app-shell + 08_admin |
AC-22 |
| R8 | Async video detect (F7) NOT WIRED — sync /api/detect/${id} is silently used for video; long videos blow access-token TTL (no X-Refresh-Token) |
06_annotations |
F7; finding #29 |
Medium-priority — quality / a11y / hygiene
| # | Risk | Component | Source |
|---|---|---|---|
| R9 | Annotation overlay window symmetric ±200 ms instead of asymmetric [-50, +150] ms (matches WPF) |
06_annotations/CanvasEditor |
finding #6; AC-28 |
| R10 | useResizablePanel reads UserSettings.panelWidths but never writes back — P11 violation |
00_foundation + 06_annotations/07_dataset |
AC-21 |
| R11 | MediaList uses alert() instead of toast / dialog |
06_annotations |
AC-14 |
| R12 | ConfirmDialog lacks aria-modal / role=dialog / focus-trap / Esc |
03_shared-ui |
AC-15 |
| R13 | Header flight dropdown lacks role=combobox / aria-expanded / Esc-to-close / focus-trap; outside-click handler always attached |
03_shared-ui |
AC-16 |
| R14 | AdminPage.handleDeleteClass lacks ConfirmDialog despite being destructive |
08_admin |
AC-30 |
| R15 | 09_settings numeric inputs use parseInt(v) || 0 — empty silently writes 0 |
09_settings |
AC-26 |
| R16 | 09_settings save handlers lack try/finally — PUT failure leaves saving:true permanently |
09_settings |
AC-27 |
| R17 | i18next.lng hardcoded 'en' — no detector / no persistence |
00_foundation |
AC-13 |
| R18 | Hardcoded English strings in AdminPage, HelpModal |
08_admin + 03_shared-ui |
P6 violation |
| R19 | mapIcons.ts defaultIcon CDN URL pinned to leaflet@1.7.1 while package uses 1.9.4 |
05_flights |
finding |
| R20 | magic mediaType=1 literal in 06_annotations and 07_dataset |
06_annotations + 07_dataset |
AC-29 |
| R21 | classNum=0 sentinel collides with real class 0 in dataset filters |
07_dataset |
finding #9 |
| R22 | Dataset status filter conflates None with All |
07_dataset |
finding |
| R23 | DatasetPage editor tab does not save | 07_dataset |
finding #4 |
| R24 | AnnotationsPage.handleDownload tainted-canvas risk |
06_annotations |
finding |
| R25 | AnnotationsPage.handleSave fallback hides save loss |
06_annotations |
finding |
| R26 | mission-planner/flightPlanUtils.ts silently swallows weather errors; sequential await per segment (perf trap); ambiguous battery-capacity unit (Wh vs Ws); km vs m altitude mixing |
05_flights (port-source) |
findings |
Low-priority — surface / polish
| # | Risk | Component | Source |
|---|---|---|---|
| R27 | No ErrorBoundary at the app root |
10_app-shell |
finding |
| R28 | No lazy code-splitting / chunked routes — bundle bloat | 10_app-shell |
finding (AltitudeChart lazy-load opportunity) |
| R29 | index.html body class hardcodes hex literals instead of az-* tokens |
10_app-shell |
discovery #11.10 |
| R30 | runUnlockSequence 4×600 ms theatrical animation in LoginPage |
04_login |
finding B4 |
| R31 | FlightContext.selectFlight is fire-and-forget — no error path |
03_shared-ui |
finding B3 |
| R32 | FlightContext.GET /api/flights?pageSize=1000 hardcoded ceiling |
03_shared-ui |
finding B3 |
CI / infra-level (Step 6 surface — track at suite level)
| # | Risk | Source |
|---|---|---|
| R33 | No CSP / hardening headers in nginx.conf |
security_approach.md § 9 |
| R34 | No vulnerability scan / SBOM emission / image signing in CI | architecture.md § 3 "Missing from the pipeline today" |
| R35 | No test step in CI today | .woodpecker/build-arm.yml |
| R36 | No AMD64 build (ARM64-only image) | .woodpecker/build-arm.yml |
| R37 | No browser-list config (browser support matrix not enforced) | architecture.md § 6 |
| R38 | No bundle-size budget gate | architecture.md § 6; AC-11 |
| R39 | EventSource refresh-rotation breaks open SSE; no reconnect logic | architecture.md § Architecture Vision; AC-24 |
| R40 | No centralized client telemetry (only browser-console logging) | deployment/observability.md |
7. Open questions
These were flagged during analysis and remain undecided. They do NOT block
downstream skills; each is owned by a specific phase per architecture.md
§ Architecture Vision Open Questions.
| # | Question | Owner / planned resolution |
|---|---|---|
| Q1 | Test framework choice (Vitest / Jest / Playwright / Bun:test) | Autodev Step 5 — Decompose Tests |
| Q2 | IsSeed annotation visual (8 px IndianRed border) — does the modern API still expose isSeed? |
Phase B feature cycle |
| Q3 | Camera-config side panel (GSD = altitude × focal × sensor) — per-user, per-flight, or per-detect-job? | Phase B feature cycle |
| Q4 | Status-bar clock + help-text-blink — port WPF UX or replace with toasts? | Phase B feature cycle |
| Q5 | OpenWeatherMap routing — .env (interim) or proxy via flights/ (preferred long-term)? |
Step 4 (interim); Phase B (proxy) |
| Q6 | mission-planner/ end-state — delete after parity port (preferred per Step 4.5) or keep as continuously-vendored reference? |
Final Phase B cycle |
| Q7 | Sync /api/detect/${id} for video — when in Phase B does the async pipeline (F7) ship? |
Phase B feature cycle |
| Q8 | Module-layout Verification Needed (8 items) — class-colors file move, CanvasEditor cross-feature import, barrel exports, mission-planner/ ownership timing, foundation multi-dir, app-shell location, test layout, 11_class-colors location |
Step 4 / Phase B (per item) |
8. Artifact index
All paths are workspace-relative. Each artifact's Status field declares
who confirmed it (derived-from-code / synthesised-from-verified-docs /
confirmed-by-user).
_docs/02_document/ — Documentation skill outputs
| Artifact | Step | Purpose |
|---|---|---|
00_discovery.md |
0 | Tech stack, dep graph, topological order, entry points, leaves |
modules/*.md (22 files) |
1 | Per-module documentation — covers all 77 source modules |
components/00_foundation/description.md |
2 | Foundation component spec |
components/01_api-transport/description.md |
2 | API transport spec |
components/02_auth/description.md |
2 | Auth spec |
components/03_shared-ui/description.md |
2 | Shared UI spec |
components/04_login/description.md |
2 | Login spec |
components/05_flights/description.md |
2 | Flights spec (incl. mission-planner port-source) |
components/06_annotations/description.md |
2 | Annotations spec (incl. WPF gap analysis §6b) |
components/07_dataset/description.md |
2 | Dataset spec (incl. WPF gap analysis §6b) |
components/08_admin/description.md |
2 | Admin spec |
components/09_settings/description.md |
2 | Settings spec |
components/10_app-shell/description.md |
2 | App-shell spec |
components/11_class-colors/description.md |
2 | Class-colors spec (lifted at Step 2) |
diagrams/components.md |
2 | Mermaid component dependency graph |
module-layout.md |
2.5 | File-ownership map (consumed by /implement, /code-review, /refactor) |
architecture.md |
3a + 4.5 | System architecture + § Architecture Vision (12 principles, mission-planner convergence plan) |
system-flows.md |
3b | F1–F14 sequence diagrams + error scenarios |
data_model.md |
3c | Entity-relationship + numeric-enum drift map |
deployment/containerization.md |
3d | Multi-stage Dockerfile, ARM64, nginx static serve |
deployment/ci_cd_pipeline.md |
3d | Woodpecker pipeline structure |
deployment/environment_strategy.md |
3d | Dev / Stage / Production |
deployment/observability.md |
3d | Current state (no centralized telemetry) |
04_verification_log.md |
4 | Coverage summary, corrections by document, pre-existing findings re-checked |
glossary.md |
4.5 | Confirmed terminology + synonym/drift pairs |
01_legacy_coverage_gaps.md |
(Step 2 → Step 4.5 update) | WPF parity rollup; Sound Detections + Drone Maintenance marked "Intentionally not ported" |
FINAL_report.md |
7 | This document |
state.json |
(skill-internal) | Document skill resumability state |
_docs/01_solution/ — Solution synthesis
| Artifact | Step | Purpose |
|---|---|---|
solution.md |
5 | Retrospective solution: per-component table (Solution / Tools / Advantages / Limitations / Requirements / Security / Cost / Fit) for all 11 components; testing strategy; references |
_docs/00_problem/ — Problem extraction
| Artifact | Step | Purpose |
|---|---|---|
problem.md |
6a | High-level problem statement + users + how-it-works + non-goals |
restrictions.md |
6b | Hardware (4) / Software (14) / Environment (10) / Operational (15) restrictions |
acceptance_criteria.md |
6c | 34 measurable ACs + 5 anti-criteria; coverage status |
input_data/data_parameters.md |
6d | Typed REST entities + SSE payloads + env vars + static assets |
security_approach.md |
6e | 13 sections covering auth, authz, tokens, SSE bearer, secrets, CORS, validation, XSS, nginx hardening, audit, supply-chain, fix-map |
_docs/02_document/_autodev_state.md (parent: _docs/_autodev_state.md)
| Artifact | Purpose |
|---|---|
_docs/_autodev_state.md |
Autodev resume pointer — flow / step / sub_step / cycle / retry_count |
Reference inputs (existing, not produced by /document)
| Artifact | Purpose |
|---|---|
_docs/legacy/wpf-era.md |
Legacy WPF reference — used as the WPF parity baseline |
_docs/how_to_test.md |
GPS-Denied Test Mode reference |
_docs/ui_design/* |
UI design wireframes — used in Step 4 cross-check |
suite/_docs/* (parent suite) |
Service contracts — used for enum drift cross-check |
suite/annotations-research (detached @ 22529c2) |
Read-only legacy WPF source — used in Step 2 / Step 4 cross-check |
9. Coverage / completeness
| Axis | Result |
|---|---|
| Source modules | 77 / 77 covered (22 doc files; some consolidated) |
| Components | 11 / 11 specs |
| System flows | 14 (F1–F14; F7 + F12 are target-only by design) |
| Endpoint inventory | Every api.*() and createSSE() call in src/ is reflected in architecture.md § 5 |
| Test coverage | 0 tests in src/ — no test framework configured today |
| BLOCKING gates passed | Step 2 (components), Step 2.5 (module-layout), Step 4 (verification), Step 4.5 (glossary + vision), Step 6 (problem docs) — all confirmed by user |
10. What comes next (autodev existing-code flow)
/document Step 1 of the autodev flow is now complete. The next steps
are state-driven from _docs/_autodev_state.md:
- Step 2 — Architecture Baseline Scan (
code-reviewskill in baseline mode) → produces_docs/02_document/architecture_compliance_baseline.mdmarking pre-existing architecture violations (cycles, cross-component private imports, mission-planner convergence as a Critical Architecture finding). - Step 3 — Test Spec (
test-specskill) → produces_docs/02_document/tests/traceability-matrix.mdand per-AC scenario files. - Step 4 — Code Testability Revision (
refactorskill in guided mode) → addresses the High-priority risks above as a minimal, surgical testability prep. - Step 5 — Decompose Tests (
decomposeskill in tests-only mode) → selects test framework (Q1) and creates per-AC test tasks. - Steps 6–8 → Implement Tests / Run Tests / optional Refactor.
- Phase B (Steps 9–17, looping) → Mission-planner convergence happens one feature group per cycle.
11. Ownership map (downstream-skill consumers)
| Downstream skill | Artifacts it reads first |
|---|---|
/code-review (baseline mode) |
architecture.md § Architecture Vision, module-layout.md, 00_discovery.md § 8 (cross-layer imports) |
/test-spec |
acceptance_criteria.md, system-flows.md, architecture.md § 6 NFRs |
/refactor (guided mode for Step 4) |
04_verification_log.md (high-priority risks), acceptance_criteria.md, module-layout.md |
/decompose (tests-only mode) |
tests/traceability-matrix.md (produced by /test-spec), module-layout.md, restrictions.md |
/implement |
per-task spec files in _docs/02_tasks/todo/, module-layout.md (file ownership) |
/new-task (Phase B) |
architecture.md § Architecture Vision, glossary.md, 01_legacy_coverage_gaps.md |
End of report.