mirror of
https://github.com/azaion/ui.git
synced 2026-06-21 14:11:12 +00:00
c368f60853
Move src/features/annotations/classColors.ts to its own component directory src/class-colors/ with a proper barrel; update the 4 consumer imports to go through the barrel; remove the F3-pending exemption from STC-ARCH-01 and from the architecture test fixture; clean up the 5 coupled doc/script touchpoints. Closes baseline finding F3 and retires the 5-coupled-places carry-over surface logged in LESSONS.md 2026-05-12. - Add `class-colors` to scripts/check-arch-imports.mjs COMPONENT_DIRS so deep imports past the new barrel are caught symmetric to every other component. - Replace the architecture test "exemption WORKS" fixture with the stronger "deep import into class-colors NOW FAILS" assertion (Risk 4 mitigation). - module-layout.md: Layout Rules + Per-Component Mapping (11_class-colors, 06_annotations, 03_shared-ui) + Verification Needed #1 + shared/class-colors block all updated to reflect the new home. - 11_class-colors/description.md: Caveats §7 + Module Inventory updated. - architecture_compliance_baseline.md: F3 marked CLOSED with full pre-resolution context preserved (mirrors AZ-485/F4 + AZ-486/F7 pattern); F4 carry-forward exemption note retired. - 04_verification_log.md: open questions #1 + #8 marked RESOLVED. - Build passes with no circular-import warnings (AC-4); fast suite 231/13 skipped green (AC-5); static profile green (AC-3 — zero exemptions remain). Batch report: _docs/03_implementation/batch_14_cycle3_report.md Co-authored-by: Cursor <cursoragent@cursor.com>
248 lines
21 KiB
Markdown
248 lines
21 KiB
Markdown
# Module Layout
|
||
|
||
**Status**: derived-from-code
|
||
**Language**: typescript (React 19 + Vite + Tailwind)
|
||
**Layout Convention**: custom (flat-features under `src/`; per-component barrels at `src/<component>/index.ts` since AZ-485)
|
||
**Root**: `src/`
|
||
**Last Updated**: 2026-05-11
|
||
|
||
> 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. One helper module (`06_annotations/CanvasEditor.tsx`) remains physically misplaced and consumed across components; it is flagged in the `## Verification Needed` block. (`11_class-colors` was lifted to its own component directory `src/class-colors/` by AZ-511 / F3.) A `src/shared/` directory is a Step 4 testability candidate.
|
||
3. **Public API per component is the barrel `src/<component>/index.ts`** (AZ-485 / F4). Every component except `10_app-shell` (which is a top-level file collection — `App.tsx`, `main.tsx`, etc., never imported as a unit) exposes its Public API through a root barrel. Cross-component imports MUST go through the barrel — `import { api } from '../api'`, not `from '../api/client'`. The `STC-ARCH-01` static gate (`scripts/check-arch-imports.mjs`, wired into `scripts/run-tests.sh --static-only`) fails the build on cross-component deep imports. Intra-component imports (relative `./`) remain free. **No exemptions today** (the prior F3 carry-over for `features/annotations/classColors` was removed by AZ-511 when the file moved to its own component).
|
||
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 5–6).
|
||
|
||
## Per-Component Mapping
|
||
|
||
### Component: `00_foundation`
|
||
|
||
- **Epic**: TBD (set during autodev Step 4 / Decompose)
|
||
- **Directories**: `src/types/`, `src/hooks/`, `src/i18n/`
|
||
- **Public API** (no `src/<component>/index.ts` barrel — `00_foundation` spans three sibling directories; the existing `src/types/index.ts` is the type-alias barrel and `src/hooks/` + `src/i18n/` are imported directly per file):
|
||
- `src/types/index.ts` — every exported type alias (`Detection`, `Flight`, `MediaItem`, `User`, etc.)
|
||
- `src/hooks/useDebounce.ts` — `useDebounce`
|
||
- `src/hooks/useResizablePanel.ts` — `useResizablePanel`
|
||
- `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**: AZ-509 (carve-out delivered by AZ-511)
|
||
- **Directories**: `src/class-colors/` (lifted from `src/features/annotations/` by AZ-511; see `architecture_compliance_baseline.md` F3 — CLOSED)
|
||
- **Public API** (via `src/class-colors/index.ts` barrel): `getClassColor`, `getClassNameFallback`, `getPhotoModeSuffix`, `FALLBACK_CLASS_NAMES`.
|
||
- **Internal**: module-private `CLASS_COLORS` constant inside `classColors.ts`.
|
||
- **Owns**: `src/class-colors/**`
|
||
- **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** (via `src/api/index.ts` barrel): `api`, `setToken`, `getToken`, `getApiBase`, `setNavigateToLogin`, `createSSE`, `endpoints` (the typed URL-builder object that is the single source of truth for every `/api/<service>/...` path the UI talks to today — AZ-486 / F7; `STC-ARCH-02` enforces it).
|
||
- **Internal**: none (every file is externally consumed; the colocated `endpoints.test.ts` IS the wire-contract documentation per `module-layout.md`'s "code-derived documentation" pattern).
|
||
- **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** (via `src/auth/index.ts` barrel): `AuthProvider`, `useAuth`, `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** (via `src/components/index.ts` barrel — all symbols externally consumed):
|
||
- `Header.tsx` → `Header`
|
||
- `HelpModal.tsx` → `HelpModal`
|
||
- `ConfirmDialog.tsx` → `ConfirmDialog`
|
||
- `DetectionClasses.tsx` → `DetectionClasses`
|
||
- `FlightContext.tsx` → `FlightProvider`, `useFlight`
|
||
- **Internal**: none — every file in `src/components/` is consumed externally today
|
||
- **Owns**: `src/components/**`
|
||
- **Imports from**: `00_foundation`, `11_class-colors` (via `src/class-colors/index.ts` barrel since AZ-511), `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** (via `src/features/login/index.ts` barrel): `LoginPage`.
|
||
- **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, via `src/features/flights/index.ts` barrel): `FlightsPage` (route component). Internal sub-components (`FlightMap`, `FlightParamsPanel`, `FlightListSidebar`, `WaypointList`, `AltitudeChart`, `AltitudeDialog`, `WindEffect`, `MiniMap`, `MapPoint`, `DrawControl`, `JsonEditorDialog`, `mapIcons`, `flightPlanUtils`, `types`) are NOT re-exported through the barrel.
|
||
- **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** (via `src/features/annotations/index.ts` barrel):
|
||
- `AnnotationsPage` (route component)
|
||
- `CanvasEditor` — **also imported by `07_dataset`** (cross-feature edge, see `architecture_compliance_baseline.md` F2). The barrel re-exports `CanvasEditor` to keep the consumer compliant with STC-ARCH-01 until F2 closes the edge.
|
||
- **Internal**: `MediaList.tsx`, `VideoPlayer.tsx`, `AnnotationsSidebar.tsx`
|
||
- **Owns**: `src/features/annotations/**`
|
||
- **Imports from**: `00_foundation`, `11_class-colors` (via barrel since AZ-511), `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** (via `src/features/dataset/index.ts` barrel): `DatasetPage`.
|
||
- **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** (via `src/features/admin/index.ts` barrel): `AdminPage`.
|
||
- **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** (via `src/features/settings/index.ts` barrel): `SettingsPage`.
|
||
- **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`. **No barrel** — the component is a top-level file collection, never imported as a unit. STC-ARCH-01's component allowlist intentionally omits `10_app-shell`.
|
||
- **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)
|
||
|
||
### Component: `Blackbox Tests` (cross-cutting)
|
||
|
||
- **Epic**: AZ-455
|
||
- **Directories**: `tests/` (fast-profile shared helpers, MSW, fixtures, setup), `e2e/` (Playwright config, suite-e2e docker-compose, stubs, runner, e2e specs, e2e fixtures), plus colocated `*.test.{ts,tsx}` and `*.spec.{ts,tsx}` files under any production component directory.
|
||
- **Public API**: none (tests are not consumed by production code).
|
||
- **Internal**: every file under owned paths.
|
||
- **Owns** (exclusive write):
|
||
- `tests/**`
|
||
- `e2e/**`
|
||
- `**/*.test.{ts,tsx}` and `**/*.spec.{ts,tsx}` — colocated test files (Vitest convention) override every production component's `Owns` glob for that filename pattern only.
|
||
- `vitest.config.ts`, `tsconfig.test.json`
|
||
- `scripts/run-tests.sh`, `scripts/run-performance-tests.sh` (extension only — the files were created in autodev Step 4 as Step 6 placeholders).
|
||
- `package.json` test-scoped sections only: `scripts.test*`, `scripts.lint:tests`, `devDependencies` for runners (`vitest`, `@vitest/*`, `@playwright/test`, `msw`, `@testing-library/*`), and any test-only `peerDependencies` overrides.
|
||
- ESLint test-override blocks (`overrides` entries scoped to `tests/**`, `e2e/**`, `**/*.test.{ts,tsx}`).
|
||
- **Imports from**:
|
||
- **Test bodies** (files matching `**/*.test.{ts,tsx}` / `**/*.spec.{ts,tsx}` and any e2e spec under `e2e/tests/`): `00_foundation` only (and only `src/types/index.ts` — typed wire-contract enums per `_docs/02_document/tests/environment.md` § Black-box discipline / `P9`). NEVER any other production component's internal files. The static profile enforces this via ripgrep.
|
||
- **Test infrastructure** (everything else under `tests/**` and `e2e/**` — `setup.ts`, MSW handlers, fixtures, helpers/wrappers, Playwright configs, runner Dockerfiles, stub services): MAY import production accessors from any layer when the accessor was created specifically for testability (e.g. `setToken` / `setNavigateToLogin` on `01_api-transport`'s `client.ts`, `AuthProvider` on `02_auth`, `i18n` on `00_foundation`). These helpers ARE the production-equivalent composition root for tests; black-box discipline applies to what test bodies observe, not to how the test environment is wired. Imports MUST still be public-API entry points (no reaching into internal files of other components).
|
||
- **Consumed by**: (none — tests are not part of production runtime).
|
||
- **Notes**:
|
||
- Every test task spec under epic AZ-455 carries `**Component**: Blackbox Tests` and resolves its file ownership through this entry.
|
||
- Colocated test files are OWNED by the test task that creates them, even when the parent directory belongs to a production component. The production files in that same directory remain READ-ONLY for the test task (compile-time imports of the production module under test are permitted; modifications are not).
|
||
- Test-related `package.json` edits (devDependencies, test scripts) are OWNED here. Production `dependencies` and non-test `scripts` are FORBIDDEN — those remain owned by the production component whose runtime they affect (typically `10_app-shell`).
|
||
- `mission-planner/` test files (e.g., `mission-planner/src/test/jsonImport.test.ts`) are OWNED here for the same reason; the `mission-planner/**` production glob remains owned by `05_flights`.
|
||
|
||
## 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 — RESOLVED by AZ-511
|
||
|
||
The class-colors helper is no longer "proposed shared / physical-misplaced". It moved to its own component directory `src/class-colors/` with a proper barrel; see Per-Component Mapping for `11_class-colors` above. The entry is kept here as a back-pointer for readers following older links.
|
||
|
||
- **Owner component**: `11_class-colors`
|
||
- **Physical location**: `src/class-colors/`
|
||
- **Public API**: `src/class-colors/index.ts`
|
||
- **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`<sup>†</sup>, `08_admin`, `09_settings` | 0, 1, 2, 3<sup>†</sup> |
|
||
| 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) |
|
||
|
||
<sup>†</sup> `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.
|
||
|
||
The `Blackbox Tests` cross-cutting component sits **outside** this table. It imports from `00_foundation` only (specifically `src/types/index.ts` for typed wire-contract enums) and is consumed by no production component. The static-profile ripgrep checks enforce that no test imports from any other production component's internal files.
|
||
|
||
## 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`**~~ — **RESOLVED by AZ-511 (F3)**. The file moved to `src/class-colors/classColors.ts` with a `src/class-colors/index.ts` barrel; consumers import via the barrel; STC-ARCH-01 has no exemptions. The `06_annotations` owns-glob no longer carves out `classColors.ts`.
|
||
|
||
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~~ — **resolved by AZ-485 (F4)**. Every component now exposes a `src/<component>/index.ts` barrel; cross-component imports go through it; `STC-ARCH-01` enforces it. The original F3-pending exemption (`classColors`) was closed by AZ-511 — there are no STC-ARCH-01 exemptions today.
|
||
|
||
3a. ~~Hardcoded `/api/<service>/` URLs scattered across callsites~~ — **resolved by AZ-486 (F7)**. The single source of truth is `src/api/endpoints.ts` (re-exported via the `01_api-transport` barrel from rule #3). Every production callsite of `api.*` and `createSSE()` uses an `endpoints.*` builder; the colocated `src/api/endpoints.test.ts` pins every URL string and serves as the wire-contract documentation. The `STC-ARCH-02` static gate (`scripts/check-arch-imports.mjs --mode=api-literals`, wired into `scripts/run-tests.sh --static-only`) fails the build on any new hardcoded `/api/<service>/` literal under `src/`. Exemptions: `src/api/endpoints.ts` (the contract owner) and any `*.test.ts` / `*.test.tsx` under `src/` (test files are exempt because tests legitimately assert URL strings — MSW handlers, contract tests, etc.).
|
||
|
||
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 5–6 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; present for every component except `10_app-shell` — see Layout Rule #3) | `src/<component>/__tests__/` (none exist today) |
|