[AZ-447] autodev Steps 1-4 baseline: docs, tests, refactor specs

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>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-11 00:38:49 +03:00
parent da0a5aa187
commit 510df68bcf
84 changed files with 13065 additions and 0 deletions
+463
View File
@@ -0,0 +1,463 @@
# 00 — Codebase Discovery
> **Step 0 output for `/document`.** Read by Step 1 (per-module docs) to drive
> processing order, by Step 2 (component assembly) to seed groupings, and by
> Step 3 (system synthesis) for the tech-stack table.
>
> **Scope** (chosen at the autodev gate, 2026-05-10):
> - `src/` — Azaion UI (React 19 SPA, the live front-end of the suite).
> - `mission-planner/` — embedded React 18 + MUI sub-project (port-source for
> `src/features/flights/`). Documented as a separate component group.
> - `_docs/` already contained user-curated reference content
> (`legacy/wpf-era.md`, `ui_design/`, `_autodev_state.md`); the document
> skill writes alongside, not over.
>
> **Out of scope**: `node_modules/`, `dist/`, `bun.lock`, `package-lock.json`,
> `.git/`, `.cursor/`, `_docs/` (read-only inputs), `.idea/`, `.claude/`,
> `.superpowers/`, `mission-planner/public/` static assets.
---
## 1. Workspace at a glance
```
suite/ui/ ← Cursor workspace root
├── src/ ← Azaion UI (React 19, the live SPA)
├── mission-planner/ ← embedded port-source (React 18 + MUI)
├── _docs/ ← user-curated + autodev artifacts
│ ├── legacy/wpf-era.md read-only reference (WPF predecessor)
│ ├── ui_design/ read-only reference (HTML wireframes)
│ ├── _autodev_state.md autodev state pointer
│ └── 02_document/ ← this folder (autodev outputs)
├── .cursor/ skills/rules/agents
├── .woodpecker/build-arm.yml CI: arm64 Docker build → Harbor
├── Dockerfile multi-stage: bun build → nginx static
├── nginx.conf /api/* reverse proxy → suite services
├── index.html SPA shell (mounts /src/main.tsx)
├── package.json react 19, bun 1.3.11, vite 6, tw 4
├── tsconfig.json strict ESM, `@/*` → `src/*`
├── vite.config.ts react + tailwind plugin, /api proxy
├── README.md repo overview + maturation plan
└── .gitignore node_modules, .env.*, playwright-report/
```
`src/` and `mission-planner/` are **disjoint** — no file in one imports from
the other. The Vite alias `@ → src` is defined only in the workspace
`vite.config.ts`; `mission-planner/vite.config.ts` has no aliases. Each has
its own `package.json`, `tsconfig`, `index.html`, and entry point. The
production bundle (`Dockerfile`) builds **only the workspace**, not
`mission-planner/`.
`mission-planner/` ships a (mostly) functional flight-mission UI that the
`src/features/flights/*` files are mechanically translating into the new
SPA. Per the workspace `README.md`, `mission-planner/` is **not** part of
the deployed product.
## 2. Tech stack
### 2a. Workspace `src/` (Azaion UI)
| Concern | Choice | Source |
|----------------|-------------------------------------|--------------------------|
| Language | TypeScript 5.7 (`strict: true`) | `tsconfig.json` |
| UI framework | React 19 (`react-dom/client`) | `package.json` |
| Bundler | Vite 6 | `package.json`, `vite.config.ts` |
| Pkg manager | Bun 1.3.11 (declared via `packageManager`) | `package.json` |
| Styling | Tailwind CSS 4 (`@tailwindcss/vite`) + custom `az-*` tokens in `src/index.css` | `package.json`, `vite.config.ts` |
| Routing | `react-router-dom` 7 | `src/App.tsx` |
| i18n | `i18next` + `react-i18next` (UA / EN) | `src/i18n/i18n.ts` |
| Map | `leaflet` 1.9 + `react-leaflet` 5 + `leaflet-draw` + `leaflet-polylinedecorator` | `package.json`, `src/features/flights/*` |
| Charts | `chart.js` 4 + `react-chartjs-2` | `package.json` |
| DnD | `@hello-pangea/dnd` 18 | `package.json` |
| File upload | `react-dropzone` | `package.json` |
| Icon set | `react-icons` | `package.json` |
| HTTP transport | native `fetch` (custom thin wrapper) | `src/api/client.ts` |
| Realtime | native `EventSource` (SSE) | `src/api/sse.ts` |
| State mgmt | React Context only — `AuthContext`, `FlightContext`. **No** Redux / Zustand / TanStack Query. | `src/auth/`, `src/components/FlightContext.tsx` |
| Tests | **none** (no test framework configured) | (verified via Glob) |
| Build target | static bundle → nginx (multi-stage Dockerfile) | `Dockerfile`, `nginx.conf` |
| Runtime | nginx in container, ARM64 image | `.woodpecker/build-arm.yml` |
### 2b. `mission-planner/` (port-source)
| Concern | Choice | Source |
|----------------|------------------------------------------|------------------------------|
| Language | TypeScript 5.7 (`strict: true`) | `mission-planner/tsconfig.app.json` |
| UI framework | React 18 | `mission-planner/package.json` |
| Bundler | Vite 6 | `mission-planner/vite.config.ts` |
| Pkg manager | npm (lockfile not committed) | (no `bun.lock` in `mission-planner/`) |
| UI library | MUI 5 (`@mui/material` + `@mui/icons-material` + `@emotion/*`) | `mission-planner/package.json` |
| Map | `leaflet` 1.9 + `react-leaflet` 4.2 + `leaflet-draw` + `leaflet-polylinedecorator` | `mission-planner/package.json` |
| Charts | `chart.js` 4 + `react-chartjs-2` | `mission-planner/package.json` |
| DnD | `@hello-pangea/dnd` 16 | `mission-planner/package.json` |
| Flags | `react-world-flags` | `mission-planner/package.json` |
| Tests | Jest implied (`@testing-library/jest-dom` import in `setupTests.ts`, `describe/it/expect` in `src/test/jsonImport.test.ts`) but **no** Jest dep nor config in `package.json` — test currently cannot run as-is. | `mission-planner/package.json`, `src/setupTests.ts`, `src/test/jsonImport.test.ts` |
| Env config | `.env.example` declares `VITE_SATELLITE_TILE_URL` | `mission-planner/.env.example` |
| Build target | not built or shipped by the suite | (Dockerfile copies only workspace `src/`) |
## 3. Configuration & infrastructure files
| Path | Role |
|-------------------------------------|----------------------------------------------------------------------|
| `package.json` (workspace) | scripts: `dev`, `build` (`tsc -b && vite build`), `preview`. No `test`. |
| `tsconfig.json` | `strict: true`, `noUnusedLocals/Parameters: false` (lax), `paths: {"@/*": ["./src/*"]}`. |
| `vite.config.ts` | `@vitejs/plugin-react` + `@tailwindcss/vite`. Dev proxy `/api → http://localhost:8080`. |
| `index.html` | `<div id="root"></div>` + `<script type="module" src="/src/main.tsx">`. Body class hardcodes `bg-[#1e1e1e] text-[#adb5bd]`. |
| `Dockerfile` | Stage 1: `oven/bun:1.3.11-alpine`, `bun install --frozen-lockfile`, `bun run build`. Stage 2: `nginx:alpine`, copies `dist/` to `/usr/share/nginx/html`, exposes 80. `ENV AZAION_REVISION=$CI_COMMIT_SHA`. |
| `nginx.conf` | Reverse-proxies 9 `/api/<service>/` paths → `http://<service>:8080/`. Enumerates: annotations, flights, admin, resource, detect, loader, gps-denied-desktop, gps-denied-onboard, autopilot. SPA fallback `/index.html`. `client_max_body_size 500M`. |
| `.woodpecker/build-arm.yml` | Triggers on push to `dev`/`stage`/`main`. Builds + pushes `${REGISTRY_HOST}/azaion/ui:${branch}-arm` with OCI labels (revision, created, source). |
| `.gitignore` | `node_modules/`, `.env.local`, `.env.development.local`, `.env.test.local`, `.env.production.local`, `package-lock.json`, `yarn.lock`, `/test-results/`, `/playwright-report/`, `/blob-report/`, `/playwright/.cache/`, `/playwright/.auth/`. (Playwright entries are aspirational — no Playwright installed.) |
| `.env.example` (workspace) | **absent** — README §"Local development" notes this as a testability fix scheduled for Step 4. API base URL is currently hardcoded via the dev proxy + nginx routing. |
| `mission-planner/package.json` | scripts: `dev`, `build`, `preview`. **No** `test` script despite the test file. |
| `mission-planner/tsconfig.app.json` | `exclude: ["src/**/*.test.ts", "src/**/*.test.tsx", "src/setupTests.ts"]`. |
| `mission-planner/.env.example` | `VITE_SATELLITE_TILE_URL` only. |
| `mission-planner/public/manifest.json` | PWA manifest (vestigial CRA scaffolding). |
## 4. Entry points
| Project | File | Mounts |
|------------------|-------------------------------------------------|---------------------------------------------------------------------|
| `src/` | `src/main.tsx` | `<StrictMode><BrowserRouter><App /></BrowserRouter></StrictMode>` into `#root`. Imports `./i18n/i18n` for side effects (i18next init) and `./index.css`. |
| `src/` | `src/App.tsx` | Top-level `Routes`. `/login` is public; everything under `/*` is wrapped in `AuthProvider → ProtectedRoute → FlightProvider → Header + nested Routes` (`/flights`, `/annotations`, `/dataset`, `/admin`, `/settings`, `*``/flights`). |
| `mission-planner/` | `mission-planner/src/main.tsx` | `<StrictMode><LanguageProvider><FlightPlan /></LanguageProvider></StrictMode>` into `#root`. Imports `leaflet/dist/leaflet.css` and `leaflet-draw/dist/leaflet.draw.css`. |
| `mission-planner/` | `mission-planner/src/App.tsx` | Empty CRA stub — **not used** by `main.tsx`. (Vestigial.) |
## 5. Test structure
| Project | Test file(s) | Framework | Status |
|----------------|---------------------------------------------|--------------|-------------------------------------------------------------|
| `src/` | none | n/a | **Zero test coverage.** Confirmed via Glob over `src/**/*.{test,spec}.*`. |
| `mission-planner/` | `mission-planner/src/test/jsonImport.test.ts` | Jest (implied — uses `describe/it/expect`) | **Cannot run** — Jest is not in `package.json`; only `@testing-library/jest-dom` is imported in `setupTests.ts`. |
| `mission-planner/` | `mission-planner/src/setupTests.ts` | - | One-line `import '@testing-library/jest-dom'`. |
This vacancy is the explicit input for autodev Steps 37 (test-spec, testability revision, decompose tests, implement tests, run tests).
## 6. Existing documentation
| Path | Status | Owner / used by |
|---------------------------------------|----------------|----------------------------------------------------------------------------|
| `README.md` (workspace) | maintained | Single source of truth for repo intent + maturation plan. |
| `_docs/legacy/wpf-era.md` | reference | Captures WPF predecessor (`Azaion.Annotator`, `Azaion.Dataset`, Cython sidecars) at commit `22529c2`. Authoritative for §10 "What survived into the new world" and §11 "What is intentionally NOT being ported". |
| `_docs/ui_design/README.md` | reference | Authoritative UX spec: pages, breakpoints, panel layouts, keyboard shortcuts, color tokens, affiliation icons, combat readiness, annotation row gradient, video time-window display, confirmation dialogs. |
| `_docs/ui_design/{flights,annotations,dataset_explorer,admin,settings}.html` | reference | HTML wireframes for each page (inherited from WPF UI mockups). |
| `_docs/_autodev_state.md` | maintained | autodev state pointer (this document is being produced under it). |
| `mission-planner/README.md` | stale | CRA boilerplate; does not describe the actual app. |
| Suite-level `../_docs/` | external | Suite-wide architecture, schema, deployment topology. Not owned by this workspace; consulted as needed during Step 3. |
## 7. Dependency graph
`src/` and `mission-planner/` are independent dependency islands. Each is
acyclic by inspection (verified by following the import chains in §8 and §9
from leaves outward).
### 7a. Workspace `src/` (intra-repo edges only; React/leaflet/etc. omitted)
```mermaid
graph LR
main[main.tsx] --> App[App.tsx]
main --> i18n_init[i18n/i18n.ts]
i18n_init --> en[i18n/en.json]
i18n_init --> ua[i18n/ua.json]
App --> AuthProvider[auth/AuthContext.tsx]
App --> FlightProvider[components/FlightContext.tsx]
App --> ProtectedRoute[auth/ProtectedRoute.tsx]
App --> Header[components/Header.tsx]
App --> LoginPage[features/login/LoginPage.tsx]
App --> FlightsPage[features/flights/FlightsPage.tsx]
App --> AnnotationsPage[features/annotations/AnnotationsPage.tsx]
App --> DatasetPage[features/dataset/DatasetPage.tsx]
App --> AdminPage[features/admin/AdminPage.tsx]
App --> SettingsPage[features/settings/SettingsPage.tsx]
AuthProvider --> apiClient[api/client.ts]
AuthProvider --> typesIdx[types/index.ts]
ProtectedRoute --> AuthProvider
FlightProvider --> apiClient
FlightProvider --> typesIdx
Header --> AuthProvider
Header --> FlightProvider
Header --> HelpModal[components/HelpModal.tsx]
Header --> typesIdx
sse[api/sse.ts] --> apiClient
ConfirmDialog[components/ConfirmDialog.tsx]
DetectionClasses[components/DetectionClasses.tsx] --> apiClient
DetectionClasses --> classColors[features/annotations/classColors.ts]
DetectionClasses --> typesIdx
LoginPage --> AuthProvider
AdminPage --> apiClient
AdminPage --> ConfirmDialog
AdminPage --> typesIdx
SettingsPage --> apiClient
SettingsPage --> typesIdx
classColors
flightsTypes[features/flights/types.ts]
flightPlanUtils[features/flights/flightPlanUtils.ts] --> flightsTypes
mapIcons[features/flights/mapIcons.ts]
WaypointList[features/flights/WaypointList.tsx] --> flightsTypes
AltitudeChart[features/flights/AltitudeChart.tsx] --> flightsTypes
WindEffect[features/flights/WindEffect.tsx] --> flightsTypes
MiniMap[features/flights/MiniMap.tsx] --> flightsTypes
MapPoint[features/flights/MapPoint.tsx] --> flightsTypes
MapPoint --> mapIcons
DrawControl[features/flights/DrawControl.tsx] --> flightsTypes
DrawControl --> flightPlanUtils
AltitudeDialog[features/flights/AltitudeDialog.tsx] --> flightsTypes
FlightListSidebar[features/flights/FlightListSidebar.tsx] --> typesIdx
JsonEditorDialog[features/flights/JsonEditorDialog.tsx]
FlightParamsPanel[features/flights/FlightParamsPanel.tsx] --> WaypointList
FlightParamsPanel --> AltitudeChart
FlightParamsPanel --> WindEffect
FlightParamsPanel --> flightsTypes
FlightParamsPanel --> typesIdx
FlightMap[features/flights/FlightMap.tsx] --> DrawControl
FlightMap --> MapPoint
FlightMap --> MiniMap
FlightMap --> mapIcons
FlightMap --> flightsTypes
FlightsPage --> FlightProvider
FlightsPage --> apiClient
FlightsPage --> sse
FlightsPage --> ConfirmDialog
FlightsPage --> FlightListSidebar
FlightsPage --> FlightParamsPanel
FlightsPage --> FlightMap
FlightsPage --> AltitudeDialog
FlightsPage --> JsonEditorDialog
FlightsPage --> flightPlanUtils
FlightsPage --> flightsTypes
FlightsPage --> typesIdx
CanvasEditor[features/annotations/CanvasEditor.tsx] --> typesIdx
CanvasEditor --> classColors
VideoPlayer[features/annotations/VideoPlayer.tsx] --> typesIdx
AnnotationsSidebar[features/annotations/AnnotationsSidebar.tsx] --> apiClient
AnnotationsSidebar --> sse
AnnotationsSidebar --> classColors
AnnotationsSidebar --> typesIdx
MediaList[features/annotations/MediaList.tsx] --> FlightProvider
MediaList --> apiClient
MediaList --> useDebounce[hooks/useDebounce.ts]
MediaList --> ConfirmDialog
MediaList --> typesIdx
AnnotationsPage --> useResizablePanel[hooks/useResizablePanel.ts]
AnnotationsPage --> apiClient
AnnotationsPage --> MediaList
AnnotationsPage --> VideoPlayer
AnnotationsPage --> CanvasEditor
AnnotationsPage --> AnnotationsSidebar
AnnotationsPage --> DetectionClasses
AnnotationsPage --> classColors
AnnotationsPage --> typesIdx
DatasetPage --> apiClient
DatasetPage --> useDebounce
DatasetPage --> useResizablePanel
DatasetPage --> FlightProvider
DatasetPage --> DetectionClasses
DatasetPage --> ConfirmDialog
DatasetPage --> CanvasEditor
DatasetPage --> typesIdx
```
### 7b. `mission-planner/src/`
```mermaid
graph LR
mp_main[main.tsx] --> flightPlan[flightPlanning/flightPlan.tsx]
mp_main --> LanguageProvider[flightPlanning/LanguageContext.tsx]
mp_types[types/index.ts]
mp_config[config.ts]
mp_utils[utils.ts]
translations[constants/translations.ts] --> mp_types
languages[constants/languages.ts] --> mp_types
purposes[constants/purposes.ts] --> mp_types
actionModes[constants/actionModes.ts]
maptypes[constants/maptypes.ts]
tileUrls[constants/tileUrls.ts]
mapIcons[icons/MapIcons.tsx]
pointIcons[icons/PointIcons.tsx]
sidebarIcons[icons/SidebarIcons.tsx]
phoneIcon[icons/PhoneIcon.tsx]
calcDistance[services/calculateDistance.ts] --> mp_types
AircraftService[services/AircraftService.ts] --> mp_types
WeatherService[services/WeatherService.ts] --> mp_types
calcBattery[services/calculateBatteryUsage.ts] --> AircraftService
calcBattery --> WeatherService
calcBattery --> mp_types
Aircraft[flightPlanning/Aircraft.ts] --> mp_utils
WindEffect2[flightPlanning/WindEffect.tsx] --> LanguageProvider
WindEffect2 --> translations
AltitudeChart2[flightPlanning/AltitudeChart.tsx] --> LanguageProvider
AltitudeChart2 --> translations
AltitudeChart2 --> mp_types
AltitudeDialog2[flightPlanning/AltitudeDialog.tsx] --> LanguageProvider
AltitudeDialog2 --> mp_config
AltitudeDialog2 --> translations
AltitudeDialog2 --> purposes
DrawControl2[flightPlanning/DrawControl.tsx] --> mp_types
JsonEditorDialog2[flightPlanning/JsonEditorDialog.tsx] --> LanguageProvider
JsonEditorDialog2 --> translations
TotalDistance[flightPlanning/TotalDistance.tsx] --> LanguageProvider
TotalDistance --> calcDistance
TotalDistance --> translations
TotalDistance --> mp_types
LanguageSwitcher[flightPlanning/LanguageSwitcher.tsx] --> LanguageProvider
LanguageSwitcher --> languages
LanguageSwitcher --> translations
MapPoint2[flightPlanning/MapPoint.tsx] --> LanguageProvider
MapPoint2 --> purposes
MapPoint2 --> translations
MapPoint2 --> pointIcons
MapPoint2 --> mp_types
MiniMap2[flightPlanning/MiniMap.tsx] --> MapView2
MiniMap2 --> maptypes
MiniMap2 --> tileUrls
MiniMap2 --> mp_types
PointsList[flightPlanning/PointsList.tsx] --> AltitudeDialog2
PointsList --> mp_utils
PointsList --> LanguageProvider
PointsList --> translations
PointsList --> calcBattery
PointsList --> calcDistance
PointsList --> mp_types
MapView2[flightPlanning/MapView.tsx] --> DrawControl2
MapView2 --> mp_utils
MapView2 --> AltitudeDialog2
MapView2 --> LanguageProvider
MapView2 --> pointIcons
MapView2 --> translations
MapView2 --> actionModes
MapView2 --> MiniMap2
MapView2 --> MapPoint2
MapView2 --> mapIcons
MapView2 --> maptypes
MapView2 --> purposes
MapView2 --> tileUrls
MapView2 --> mp_types
LeftBoard[flightPlanning/LeftBoard.tsx] --> LanguageProvider
LeftBoard --> PointsList
LeftBoard --> AltitudeChart2
LeftBoard --> TotalDistance
LeftBoard --> LanguageSwitcher
LeftBoard --> translations
LeftBoard --> actionModes
LeftBoard --> sidebarIcons
LeftBoard --> mp_config
LeftBoard --> mp_types
flightPlan --> mp_utils
flightPlan --> MapView2
flightPlan --> AltitudeDialog2
flightPlan --> JsonEditorDialog2
flightPlan --> LeftBoard
flightPlan --> mp_config
flightPlan --> actionModes
flightPlan --> AircraftService
flightPlan --> phoneIcon
flightPlan --> purposes
flightPlan --> mp_types
```
> **Note** — `MiniMap2` imports `UpdateMapCenter` (a *named* helper) **from**
> `MapView2`, while `MapView2` imports `MiniMap2` as a child component. They
> import in opposite directions, which would normally form a dependency
> cycle, but module-level execution is non-circular because each side only
> uses the *type/handle* exposed by the other at call time. **Flagged for
> Step 1** (will document the named export contract precisely) and surfaced
> in §11 below as a structural caveat.
## 8. Cross-feature edges in `src/` (architectural caveats)
These are edges where a "lower-layer" module imports from a "higher-layer"
sibling. Surfaced now so Step 2 (Component Assembly) and Step 2.5
(module-layout.md) can decide whether to formalise them in the layering
table or flag them for the architecture baseline scan (Step 2 of autodev).
| Edge | Direction | Comment |
|-------------------------------------------------------------------------------------|---------------------------------|---------|
| `components/DetectionClasses.tsx``features/annotations/classColors.ts` | shared ← feature-specific | A `shared/` component depends on `features/annotations/`. The shared layer should not know about a specific feature. **Likely candidate for refactor**: extract `classColors.ts` into a feature-neutral location (e.g. `src/components/detection/classColors.ts`) or into a `shared/` module. |
| `features/dataset/DatasetPage.tsx``features/annotations/CanvasEditor.tsx` | feature ← sibling feature | Cross-feature import, but consistent with the legacy WPF design where `Azaion.Dataset` reused `CanvasEditor` from `Azaion.Common.Controls` (see `_docs/legacy/wpf-era.md` §5). The proper fix is to lift `CanvasEditor` out of `features/annotations/` into a shared location. |
| (none observed) | back-edge from `App` to `main` | - |
Also: every page calls `api/client.ts` directly with **string-literal URLs**
(`/api/admin/auth/login`, `/api/flights?...`, `/api/annotations/settings/user`,
etc.). There is no per-service API client module. This is the testability
issue the workspace `README.md` calls out for Step 4 — but since it does
not yet break compilation or layering, it is recorded here, not blocked.
## 9. Topological processing order — `src/` (40 modules, 8 batches)
Layer = max distance from leaves. Step 1 of `/document` MUST process modules
in this order (leaves first), batched by ~5 with a session-break heuristic
between batches.
> JSON files (`i18n/en.json`, `i18n/ua.json`) and `vite-env.d.ts` are
> **inputs**, not modules — they are not separately documented; their content
> is summarised inside the consumers (`i18n/i18n.ts`, the global TS env).
> Counted modules: 40.
| Batch | Modules | Layer |
|-------|--------------------------------------------------------------------------------------|-------|
| **B1** | `types/index.ts`, `hooks/useDebounce.ts`, `hooks/useResizablePanel.ts`, `features/flights/types.ts`, `features/annotations/classColors.ts` | 0 |
| **B2** | `features/flights/mapIcons.ts`, `features/flights/flightPlanUtils.ts`, `api/client.ts`, `i18n/i18n.ts`, `components/HelpModal.tsx` | 01 |
| **B3** | `components/ConfirmDialog.tsx`, `components/DetectionClasses.tsx`, `auth/AuthContext.tsx`, `components/FlightContext.tsx`, `api/sse.ts` | 12 |
| **B4** | `auth/ProtectedRoute.tsx`, `components/Header.tsx`, `features/login/LoginPage.tsx`, `features/admin/AdminPage.tsx`, `features/settings/SettingsPage.tsx` | 23 |
| **B5** | `features/flights/{WaypointList,AltitudeChart,WindEffect,MiniMap,AltitudeDialog}.tsx` | 12 |
| **B6** | `features/flights/{MapPoint,DrawControl,FlightListSidebar,JsonEditorDialog,FlightParamsPanel}.tsx` | 2 |
| **B7** | `features/flights/FlightMap.tsx`, `features/annotations/{CanvasEditor,VideoPlayer,AnnotationsSidebar,MediaList}.tsx` | 23 |
| **B8** | `features/flights/FlightsPage.tsx`, `features/annotations/AnnotationsPage.tsx`, `features/dataset/DatasetPage.tsx`, `App.tsx`, `main.tsx` | 35 |
## 10. Topological processing order — `mission-planner/` (37 modules, 8 batches)
Excluded from analysis: `vite-env.d.ts`, `types/leaflet-polylinedecorator.d.ts`,
`types/react-world-flags.d.ts` (type shims for external libs), `setupTests.ts`,
`App.tsx` (vestigial CRA stub — flagged for delete in §11), and `index.css`,
`*.css` files. The Jest test (`src/test/jsonImport.test.ts`) is documented
inline with `flightPlanning/flightPlan.tsx` (its target), not as a standalone
module. Counted modules: 37.
| Batch | Modules | Layer |
|-------|-----------------------------------------------------------------------------------------------------------------------------------------------|-------|
| **MP-B1** | `types/index.ts`, `utils.ts`, `config.ts`, `constants/{actionModes,maptypes,tileUrls}.ts` | 0 |
| **MP-B2** | `constants/{translations,languages,purposes}.ts`, `services/{calculateDistance,AircraftService,WeatherService}.ts` | 1 |
| **MP-B3** | `services/calculateBatteryUsage.ts`, `flightPlanning/Aircraft.ts`, `flightPlanning/LanguageContext.tsx`, `icons/{MapIcons,PointIcons}.tsx` | 12 |
| **MP-B4** | `icons/{SidebarIcons,PhoneIcon}.tsx`, `flightPlanning/{WindEffect,DrawControl,LanguageSwitcher}.tsx` | 2 |
| **MP-B5** | `flightPlanning/{AltitudeChart,AltitudeDialog,JsonEditorDialog,TotalDistance,MapPoint}.tsx` | 23 |
| **MP-B6** | `flightPlanning/MapView.tsx` (cycle group with `MiniMap.tsx`), `flightPlanning/MiniMap.tsx`, `flightPlanning/PointsList.tsx` | 34 |
| **MP-B7** | `flightPlanning/LeftBoard.tsx`, `flightPlanning/flightPlan.tsx` | 56 |
| **MP-B8** | `main.tsx`, `test/jsonImport.test.ts` (analysis only — covered by `flightPlan.tsx` doc) | 7 |
## 11. Discovery findings to carry forward
The following observations are not documentation gaps; they are **inputs**
for downstream steps. Each lists the step that owns the follow-up.
1. **Workspace `src/` has zero tests.** → Owned by `/test-spec` (Step 3 of autodev) and `/decompose-tests` + `/implement` (Steps 56).
2. **Hardcoded API URL paths** (`/api/admin/...`, `/api/flights/...`, `/api/annotations/...`) inlined throughout features. → Testability fix scheduled by autodev Step 4 (workspace `README.md` §"Local development" already calls this out).
3. **No `.env.example` in workspace.** → Same — Step 4.
4. **Cross-layer imports** (§8): `components/DetectionClasses.tsx``features/annotations/classColors.ts`, `features/dataset/DatasetPage.tsx``features/annotations/CanvasEditor.tsx`. → Surface to autodev Step 2 (Architecture Baseline Scan); the testability refactor (Step 4) may also lift these.
5. **`mission-planner/src/test/jsonImport.test.ts` cannot run** — Jest is not installed and there is no test script. → Out of scope for the live SPA test plan; document in `mission-planner/` component spec but do **not** add Jest just to run this one legacy test.
6. **`mission-planner/src/App.tsx`** is an unused CRA stub; `main.tsx` mounts `FlightPlan` directly. → Note in `mission-planner/` component spec; deletion candidate but only after the `mission-planner``src/features/flights/` port is complete (out of `/document` scope).
7. **`mission-planner/src/flightPlanning/MapView.tsx ↔ MiniMap.tsx`** import each other (`MiniMap` imports the *named* `UpdateMapCenter` helper from `MapView`; `MapView` imports `MiniMap` as a JSX child). → Document the contract precisely in Step 1; analyse together as a 2-module group in MP-B6 per the Step 1 cycle-handling rule.
8. **`react-i18next` is used only in workspace `src/`**; `mission-planner/` uses its own `LanguageContext` + raw translation tables. → Capture the divergence in Step 5 (Solution Extraction) — the port to `src/features/flights/` should consume `react-i18next` instead.
9. **No CI test step** in `.woodpecker/build-arm.yml` — only build + push. → To be added by autodev Step 7 (Run Tests) once the test suite exists.
10. **The body of `index.html`** hardcodes Tailwind arbitrary-value classes for the global background and text color rather than using the `az-bg` / `az-text` tokens defined in `src/index.css`. → Cosmetic; record in the workspace component spec but no action required.
---
**Step 0 status**: complete. Proceeding to Step 1 (per-module documentation,
batch B1).