Files
ui/_docs/02_document/00_discovery.md
Oleksandr Bezdieniezhnykh 510df68bcf [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>
2026-05-11 00:38:49 +03:00

464 lines
29 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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).