Files
ui/_docs/02_document/module-layout.md
T
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

16 KiB
Raw Blame History

Module Layout

Status: derived-from-code Language: typescript (React 19 + Vite + Tailwind) Layout Convention: custom (flat-features under src/; no per-component barrels) Root: src/ Last Updated: 2026-05-10

Authoritative file-ownership map for the React UI workspace. Derived from _docs/02_document/00_discovery.md (dependency graph) and the Step 2 component specs at _docs/02_document/components/. Consumed by /implement Step 4 (file ownership), /code-review Phase 7 (architecture violations), and /refactor discovery.

Layout Rules

  1. Each component owns ONE OR MORE top-level directories (or top-level files) under src/. The mapping is NOT 1:1 — 00_foundation owns three sibling directories (src/types/, src/hooks/, src/i18n/), 05_flights spans src/features/flights/ AND a separate mission-planner/ port-source root, and 10_app-shell owns top-level files (App.tsx, main.tsx, index.css, vite-env.d.ts).
  2. Shared code does not live under src/shared/ today — there is no shared/ directory. Two helper modules (11_class-colors/classColors.ts and 06_annotations/CanvasEditor.tsx) are physically misplaced and consumed across components; both are flagged in the ## Verification Needed block. A src/shared/ directory is a Step 4 testability candidate.
  3. Public API per component: NO barrel index.ts exists at any component root. The only index.ts files are src/types/index.ts (a re-export hub for type aliases — used as the de-facto public API for 00_foundation types) and mission-planner/src/types/index.ts. Until Step 4 introduces barrels, Public API is approximated as "every named export from any file under the component's owned directories". Cross-component imports ARE happening at file-name granularity (import { api } from '../api/client', import { CanvasEditor } from '../annotations/CanvasEditor').
  4. Cross-cutting concerns (logging, config, error handling, telemetry): no dedicated infrastructure today. console.error / silent catches are the closest thing — recorded in module findings.
  5. Tests: there are zero tests under src/. The only test file is mission-planner/src/test/jsonImport.test.ts, which can't run because Jest isn't installed (00_discovery.md §11.5). Test layout is therefore TBD; suggest src/<component>/__tests__/ per the standard React convention when tests are added (autodev Step 56).

Per-Component Mapping

Component: 00_foundation

  • Epic: TBD (set during autodev Step 4 / Decompose)
  • Directories: src/types/, src/hooks/, src/i18n/
  • Public API (de-facto, no barrel):
    • src/types/index.ts — every exported type alias (Detection, Flight, MediaItem, User, etc.)
    • src/hooks/useDebounce.tsuseDebounce
    • src/hooks/useResizablePanel.tsuseResizablePanel
    • src/i18n/i18n.ts — default export (i18n instance)
  • Internal: src/i18n/en.json, src/i18n/ua.json (data; consumed only by i18n.ts)
  • Owns (exclusive write): src/types/**, src/hooks/**, src/i18n/**
  • Imports from: (none — Layer 0)
  • Consumed by: every other component

Component: 11_class-colors

  • Epic: TBD
  • Directories: (none today — physical file lives at src/features/annotations/classColors.ts, which is owned by 06_annotations on disk). Logical owner is this component; physical move to src/shared/classColors.ts (or src/components/detection/classColors.ts) is a Step 4 testability task.
  • Public API: src/features/annotations/classColors.ts exports getClassColor, getClassNameFallback, getPhotoModeSuffix, FALLBACK_CLASS_NAMES.
  • Internal: module-private CLASS_COLORS constant.
  • Owns: pending — see Verification Needed item #1.
  • Imports from: (none — Layer 0/1, no internal imports)
  • Consumed by: 03_shared-ui (DetectionClasses), 06_annotations (CanvasEditor, AnnotationsPage, AnnotationsSidebar)

Component: 01_api-transport

  • Epic: TBD
  • Directory: src/api/
  • Public API (de-facto): src/api/client.ts exports api (fetch wrapper); src/api/sse.ts exports subscribeSSE / equivalent helper.
  • Internal: none (both files are externally consumed)
  • Owns: src/api/**
  • Imports from: 00_foundation (types)
  • Consumed by: 02_auth, 03_shared-ui, every feature page (04, 05, 06, 07, 08, 09)

Component: 02_auth

  • Epic: TBD
  • Directory: src/auth/
  • Public API: src/auth/AuthContext.tsx exports AuthProvider, useAuth. src/auth/ProtectedRoute.tsx exports ProtectedRoute.
  • Internal: none
  • Owns: src/auth/**
  • Imports from: 00_foundation, 01_api-transport
  • Consumed by: 03_shared-ui (Header reads useAuth), 04_login, 10_app-shell (mounts AuthProvider + ProtectedRoute)

Component: 03_shared-ui

  • Epic: TBD
  • Directory: src/components/
  • Public API (de-facto, all are externally consumed):
    • Header.tsxHeader
    • HelpModal.tsxHelpModal
    • ConfirmDialog.tsxConfirmDialog
    • DetectionClasses.tsxDetectionClasses
    • FlightContext.tsxFlightProvider, useFlight
  • Internal: none — every file in src/components/ is consumed externally today
  • Owns: src/components/**
  • Imports from: 00_foundation, 11_class-colors (physical: ../features/annotations/classColors), 01_api-transport, 02_auth
  • Consumed by: 10_app-shell (mounts Header + FlightProvider), every feature page (consumes useFlight, ConfirmDialog, DetectionClasses)

Component: 04_login

  • Epic: TBD
  • Directory: src/features/login/
  • Public API: LoginPage.tsxLoginPage
  • Internal: none (single-page component)
  • Owns: src/features/login/**
  • Imports from: 00_foundation, 01_api-transport, 02_auth
  • Consumed by: 10_app-shell (route)

Component: 05_flights

  • Epic: TBD (this is the merged Flights & Mission Planning component)
  • Directories (TWO physical roots):
    • src/features/flights/ — deployed target tree (15 modules)
    • mission-planner/ — port-source, NOT deployed (37 modules under mission-planner/src/). Documented inside this component per the user's Step 2 BLOCKING-gate decision (_docs/02_document/state.json::component_05_flights_merge_2026-05-10). The port direction is mission-planner/src/features/flights/; module-layout treats both trees as owned by this component but only the target tree is in the layering table below.
  • Public API (target tree, de-facto): FlightsPage.tsxFlightsPage (route component). Internal sub-components (FlightMap, FlightParamsPanel, FlightListSidebar, WaypointList, AltitudeChart, AltitudeDialog, WindEffect, MiniMap, MapPoint, DrawControl, JsonEditorDialog, mapIcons, flightPlanUtils, types) are NOT consumed outside the component.
  • Public API (port-source mission-planner/): not consumed at all by src/ today (separate Vite entrypoint, main.tsx of its own). Effectively a private vendored sibling.
  • Internal (target tree): every file under src/features/flights/ except FlightsPage.tsx
  • Internal (port-source): every file under mission-planner/
  • Owns: src/features/flights/**, mission-planner/**
  • Imports from (target tree): 00_foundation, 01_api-transport, 02_auth (via ProtectedRoute from shell), 03_shared-ui (uses ConfirmDialog, useFlight)
  • Consumed by: 10_app-shell (route)

Component: 06_annotations

  • Epic: TBD
  • Directory: src/features/annotations/
  • Public API (de-facto):
    • AnnotationsPage.tsxAnnotationsPage (route component)
    • CanvasEditor.tsxCanvasEditoralso imported by 07_dataset (cross-feature edge, see Verification Needed #3)
  • Internal: MediaList.tsx, VideoPlayer.tsx, AnnotationsSidebar.tsx
  • Owns: src/features/annotations/** EXCEPT classColors.ts (logically owned by 11_class-colors; physical home pending refactor)
  • Imports from: 00_foundation, 11_class-colors, 01_api-transport, 03_shared-ui
  • Consumed by: 10_app-shell (route); 07_dataset (imports CanvasEditor directly — see Verification Needed)

Component: 07_dataset

  • Epic: TBD
  • Directory: src/features/dataset/
  • Public API: DatasetPage.tsxDatasetPage
  • Internal: none (single-page)
  • Owns: src/features/dataset/**
  • Imports from: 00_foundation, 11_class-colors (only when class-distribution chart is added — not in code yet), 01_api-transport, 03_shared-ui, 06_annotations (CanvasEditor cross-feature edge)
  • Consumed by: 10_app-shell (route)

Component: 08_admin

  • Epic: TBD
  • Directory: src/features/admin/
  • Public API: AdminPage.tsxAdminPage
  • Internal: none (single-page)
  • Owns: src/features/admin/**
  • Imports from: 00_foundation, 01_api-transport, 03_shared-ui
  • Consumed by: 10_app-shell (route)

Component: 09_settings

  • Epic: TBD
  • Directory: src/features/settings/
  • Public API: SettingsPage.tsxSettingsPage
  • Internal: none (single-page)
  • Owns: src/features/settings/**
  • Imports from: 00_foundation, 01_api-transport, 03_shared-ui
  • Consumed by: 10_app-shell (route)

Component: 10_app-shell

  • Epic: TBD
  • Files (no dedicated directory): src/App.tsx, src/main.tsx, src/index.css, src/vite-env.d.ts
  • Public API: main.tsx is the Vite entrypoint (no symbols are externally imported). App.tsx exports App.
  • Internal: index.css (global Tailwind base + az-* design-token CSS variables), vite-env.d.ts (type shim)
  • Owns: src/App.tsx, src/main.tsx, src/index.css, src/vite-env.d.ts
  • Imports from: every other component (it is the composition root)
  • Consumed by: (none — top of the graph; bundled by Vite)

Shared / Cross-Cutting

No src/shared/ directory exists today. Two cross-cutting concerns are tracked here as proposed shared modules; they require a physical file move scheduled for Step 4 (testability) or Step 8 (refactor).

shared/class-colors (proposed; current physical location: src/features/annotations/classColors.ts)

  • Owner component: 11_class-colors
  • Purpose: Detection-class fallback color, fallback name, PhotoMode suffix.
  • Owned by: pending move task — current physical file is under 06_annotations's owns-glob, which makes it ambiguous. Workaround: until moved, treat classColors.ts as OWNED by tasks targeting 11_class-colors and READ-ONLY to all other tasks (including those targeting 06_annotations).
  • Consumed by: 03_shared-ui/DetectionClasses, 06_annotations (CanvasEditor, AnnotationsPage, AnnotationsSidebar)

shared/canvas-editor (proposed; current physical location: src/features/annotations/CanvasEditor.tsx)

  • Owner component: still 06_annotations for now (it's the dominant consumer)
  • Purpose: Bounding-box draw / move / resize layer; reused by Dataset's inline editor.
  • Status: cross-feature edge (07_dataset imports it). The proper home is a future src/components/canvas/ directory. Decision deferred to Step 2 architecture baseline scan; the implement skill should treat this as a READ-ONLY for 07_dataset tasks.

Allowed Dependencies (layering)

Read top-to-bottom; an upper layer may import from a lower layer but NEVER the reverse. Same-layer imports are permitted only for explicit cross-feature edges listed in the table footnotes.

Layer Components May import from
4. App Shell / Entry 10_app-shell 0, 1, 2, 3 (and any feature in Layer 3)
3. Application / Features 04_login, 05_flights, 06_annotations, 07_dataset, 08_admin, 09_settings 0, 1, 2, 3
2. Composition 02_auth, 03_shared-ui 0, 1
1. Transport 01_api-transport 0
0. Foundation / Shared kernel 00_foundation, 11_class-colors (none)

07_dataset imports 06_annotations/CanvasEditor.tsx — same-layer cross-feature edge. Permitted today; flagged as a refactor target. The implement skill grants 07_dataset tasks READ-ONLY access to that one file specifically.

Violations of this table are Architecture findings in code-review Phase 7 and are High severity.

Verification Needed

The following inferences could not be made cleanly from code alone. They are surfaced for the user to confirm or override at the Step 2.5 BLOCKING gate.

  1. Physical home of 11_class-colors. The component is logically Layer 0/1 shared kernel, but its physical file lives inside 06_annotations's owns-glob (src/features/annotations/classColors.ts). Until the file is moved (proposed: src/shared/classColors.ts), the implement skill must apply the special-case rule documented under shared/class-colors above (READ-ONLY for 06_annotations tasks even though the file is inside that component's directory). Decision needed: schedule the file move at Step 4 / Step 8, or accept the special-case rule indefinitely?

  2. Physical home of CanvasEditor.tsx. Same shape: it lives under 06_annotations and is consumed cross-feature by 07_dataset. Proposed: src/components/canvas/CanvasEditor.tsx (or a new 06b_canvas component). Decision needed: keep the same-layer cross-feature edge, or schedule the lift?

  3. No barrel exports anywhere. The codebase imports cross-component at file-name granularity (import { api } from '../api/client'). This means every internal file is de-facto Public API. Recommendation: Step 4 testability task to add src/<component>/index.ts barrels per component, locking the public surface. Decision needed: add barrels now or stay file-import?

  4. mission-planner/ is owned by 05_flights but lives at the repo root (not under src/). Layout rule #1 says one component owns one or more top-level directories — this satisfies the rule (it owns two: src/features/flights/ AND mission-planner/). Implement-skill consumers must include mission-planner/** in 05_flights's OWNED glob. Decision needed: confirm the implement skill should treat mission-planner/** as OWNED by 05_flights (otherwise it's FORBIDDEN by default).

  5. 05_flights cycle inside the port-source. mission-planner/src/flightPlanning/MapView.tsx ↔ MiniMap.tsx form a circular import (named-handle, see 00_discovery.md §7 footnote). They were analyzed together in batch MP-B6. The cycle is internal to the component and does not cross component boundaries; flagged here for completeness.

  6. 00_foundation owns three sibling directories (types/, hooks/, i18n/). Layout rule #1 permits this. Future option: split into 00a_types, 00b_hooks, 00c_i18n if the directories grow. Decision needed: keep the multi-directory component, or split now?

  7. 10_app-shell owns top-level files instead of a directory (src/App.tsx, src/main.tsx, etc.). Layout rule #1 permits this. The implement-skill OWNED glob for app-shell tasks must therefore be the explicit file list, not a directory glob.

  8. Test layout is undefined (no tests exist). When Steps 56 of autodev produce tests, recommended layout is src/<component-dir>/__tests__/ per React convention; for 05_flights cross-tree tests, prefer src/features/flights/__tests__/ (target tree only).

Layout Conventions (reference)

Language Root Per-component path Public API file Test path
TypeScript / React src/ src/<component>/ (this codebase deviates: features under src/features/<feature>/, shared chrome under src/components/) src/<component>/index.ts (barrel — none exist today) src/<component>/__tests__/ (none exist today)