Files
missions/_docs/02_document/module-layout.md
T
Oleksandr Bezdieniezhnykh 7025f4d075 refactor: enhance JWT authentication and CORS configuration
Updated JWT authentication to use configuration values instead of hardcoded secrets, improving security and flexibility. Enhanced CORS policy to conditionally allow origins based on configuration settings, with logging for permissive defaults. Updated README to reflect project renaming and clarify service context.
2026-05-14 19:48:25 +03:00

12 KiB
Raw Blame History

Module Layout

Status: derived-from-code (post-rename, forward-looking — see Verification Needed) Language: csharp Layout Convention: custom (layer-organized, NOT per-component-directory — see ## Verification Needed below) Root: ./ (no src/ directory; .NET Microsoft.NET.Sdk.Web project at the repo root) Last Updated: 2026-05-14

NOTE (forward-looking): file paths reflect the post-rename + post-GPS-Denied-removal state. Today's source still uses Aircraft* / Flight* / Orthophoto* / GpsCorrection* filenames, csproj is Azaion.Flights.csproj, and namespace is Azaion.Flights.*. Renames + drops are tracked under Jira AZ-EPIC children B5 (namespace), B6 (rename), B7 (GPS-Denied removal), B8 (HTTP routes), B9 (DB migration), B10 (Dockerfile / image / compose).

Layout Rules

This codebase does not follow the "one directory per component" convention from the template. It is organized horizontally by architectural layer:

./
├── Auth/             ← cross-cutting (component 05_identity)
├── Controllers/      ← API surface (one file per feature component, 01 + 02)
├── Database/         ← persistence (component 04)
│   └── Entities/
├── DTOs/             ← payload types (split across components 01, 02, 06)
├── Enums/            ← domain enums (split across components 01, 02, 04)
├── Middleware/       ← cross-cutting (component 06_http_conventions)
├── Services/         ← business logic (one file per feature component, 01 + 02)
├── Entities/         ← EMPTY (scaffolding leftover)
├── Infrastructure/   ← EMPTY (scaffolding leftover)
├── Program.cs        ← composition root (component 07_host)
└── GlobalUsings.cs   ← composition root (component 07_host)

Consequence: each component's Owns glob is a SET OF FILE PATHS spanning multiple directories, NOT a single directory glob. There is no shared/ directory; cross-cutting concerns (05_identity, 06_http_conventions) own their root-level dirs (Auth/, Middleware/) directly.

The C# project has no separate per-component csproj — there is one project (post-rename: Azaion.Missions.csproj; today: Azaion.Flights.csproj) and effectively one root namespace (post-rename: Azaion.Missions.*). Other components reference each other through types directly; there is no compiled "Public API" boundary.

Per-Component Mapping

Component: 01_vehicle_catalog

  • Epic: Jira AZ-EPIC (rename + multi-vehicle support)
  • Directory(ies): spread across Controllers/, Services/, DTOs/, Enums/
  • Public API (types other components reference): Services/VehicleService.cs (consumed by 07_host for DI registration; 02_mission_planning consumes its existence semantics through the DB)
  • Owns (exclusive write) (post-rename):
    • Controllers/VehiclesController.cs
    • Services/VehicleService.cs
    • DTOs/CreateVehicleRequest.cs
    • DTOs/UpdateVehicleRequest.cs
    • DTOs/GetVehiclesQuery.cs
    • DTOs/SetDefaultRequest.cs
  • Internal: none — every file is publicly importable in C# without explicit visibility annotations
  • Imports from: 04_persistence (AppDataConnection, Vehicle entity, VehicleType enum, FuelType enum), 05_identity ([Authorize(Policy = "FL")]), 06_http_conventions (exception → middleware mapping is implicit)
  • Consumed by: 02_mission_planning (FK existence-check on vehicle_id), 07_host (DI registration)

Component: 02_mission_planning

  • Epic: Jira AZ-EPIC
  • Directory(ies): spread across Controllers/, Services/, DTOs/, Enums/
  • Public API (post-rename): Services/MissionService.cs, Services/WaypointService.cs (DI-registered in 07_host)
  • Owns (exclusive write) (post-rename):
    • Controllers/MissionsController.cs
    • Services/MissionService.cs
    • Services/WaypointService.cs
    • DTOs/CreateMissionRequest.cs
    • DTOs/UpdateMissionRequest.cs
    • DTOs/GetMissionsQuery.cs
    • DTOs/CreateWaypointRequest.cs
    • DTOs/UpdateWaypointRequest.cs
    • DTOs/GeoPoint.cs
  • Internal: none
  • Imports from: 04_persistence (incl. WaypointSource + WaypointObjective enums), 05_identity, 06_http_conventions (PaginatedResponse<T>), 01_vehicle_catalog (existence semantics through DB FK)
  • Consumed by: 07_host (DI), and external autopilot / ui (cross-service over HTTP)

Component: 04_persistence

  • Epic: Jira AZ-EPIC
  • Directory(ies): Database/, plus Enums/ObjectStatus.cs (cross-cutting status enum)
  • Public API: Database/AppDataConnection.cs (the DataConnection type other components depend on), Database/DatabaseMigrator.cs (called by 07_host at startup), all 7 entities under Database/Entities/ (referenced by services + DTOs as row maps), the four persisted-column enums under Enums/ (VehicleType, FuelType, WaypointSource, WaypointObjective, ObjectStatus)
  • Owns (exclusive write) (post-rename):
    • Database/AppDataConnection.cs
    • Database/DatabaseMigrator.cs
    • Database/Entities/Vehicle.cs
    • Database/Entities/Mission.cs
    • Database/Entities/Waypoint.cs
    • Database/Entities/MapObject.cs
    • Database/Entities/Media.cs (borrowed schema)
    • Database/Entities/Annotation.cs (borrowed schema)
    • Database/Entities/Detection.cs (borrowed schema)
    • Enums/VehicleType.cs (persisted on vehicles.type; consumed by 01_vehicle_catalog DTOs)
    • Enums/FuelType.cs (persisted on vehicles.fuel_type; consumed by 01_vehicle_catalog DTOs)
    • Enums/WaypointSource.cs (persisted on waypoints.waypoint_source; consumed by 02_mission_planning DTOs)
    • Enums/WaypointObjective.cs (persisted on waypoints.waypoint_objective; consumed by 02_mission_planning DTOs)
    • Enums/ObjectStatus.cs (persisted on map_objects.object_status)
  • Internal: none
  • Imports from: nothing internal
  • Consumed by: 01_vehicle_catalog, 02_mission_planning, 07_host

Component: 05_identity

  • Epic: Jira AZ-EPIC
  • Directory(ies): Auth/
  • Public API: Auth/JwtExtensions.AddJwtAuth(...) (called by 07_host); the "FL" policy NAME (referenced as a string by feature controllers — string-typed dependency, NOT compile-checked)
  • Owns (exclusive write):
    • Auth/JwtExtensions.cs
  • Internal: none
  • Imports from: nothing internal
  • Consumed by: 01_vehicle_catalog, 02_mission_planning, 07_host

Component: 06_http_conventions

  • Epic: Jira AZ-EPIC
  • Directory(ies): Middleware/, plus DTOs/ErrorResponse.cs and DTOs/PaginatedResponse.cs
  • Public API: Middleware/ErrorHandlingMiddleware (registered by 07_host); DTOs/PaginatedResponse<T> (returned by 02_mission_planning); DTOs/ErrorResponse is unused on the wire today (see component description Caveats #2)
  • Owns (exclusive write):
    • Middleware/ErrorHandlingMiddleware.cs
    • DTOs/ErrorResponse.cs
    • DTOs/PaginatedResponse.cs
  • Internal: none
  • Imports from: nothing internal
  • Consumed by: 02_mission_planning (PaginatedResponse<T>), 07_host (middleware registration), all components implicitly (exception → status code mapping)

Component: 07_host

  • Epic: Jira AZ-EPIC
  • Directory(ies): repo root
  • Public API: none (it is the runtime entry point)
  • Owns (exclusive write):
    • Program.cs
    • GlobalUsings.cs
  • Internal: none
  • Imports from: 04_persistence, 05_identity, 06_http_conventions, 01_vehicle_catalog, 02_mission_planning
  • Consumed by: nothing internal — invoked by the .NET runtime via dotnet Azaion.Missions.dll (post-rename) / dotnet Azaion.Flights.dll (today)

Shared / Cross-Cutting

There is no shared/ directory in this codebase. The role canonically taken by shared/* is filled by:

  • 05_identity (Auth/) — auth setup + named policies
  • 06_http_conventions (Middleware/ + 2 DTOs) — error envelope + paginated response envelope
  • 04_persistence — provides shared AppDataConnection to all feature components

All five enums under Enums/ (VehicleType, FuelType, WaypointSource, WaypointObjective, ObjectStatus) are owned by 04_persistence because they are persisted column types — every one of them maps to an INTEGER column in the schema (Database/DatabaseMigrator.cs) and is referenced from a 04_persistence-owned entity (Vehicle, Waypoint, MapObject). Feature components (01, 02) consume them as foundation types, never own them. This was retagged on 2026-05-14 to resolve baseline findings F1 + F2 (see _docs/02_document/architecture_compliance_baseline.md); previously VehicleType / FuelType were tagged under 01 and WaypointSource / WaypointObjective under 02, which created a Foundation ← Feature layering violation.

Allowed Dependencies (layering)

Read top-to-bottom; an upper layer may import from a lower layer but NEVER the reverse.

Layer Components May import from
4. Composition root 07_host 1, 2, 3
3. Feature surfaces 01_vehicle_catalog, 02_mission_planning 1, 2
2. Domain (none today) 1
1. Foundation 04_persistence, 05_identity, 06_http_conventions (none)

There is no "Domain" layer in this codebase — feature components are thin (controller + service + DTOs) and bind directly to persistence entities. This matches typical CRUD-style ASP.NET Core services and is the deliberate shape per ../../suite/_docs/02_missions.md.

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

Layout Conventions (reference)

Language Root Per-component path Public API file Test path
C# (.NET) src/ (canonical) src/<Component>/ src/<Component>/<Component>.cs (namespace root) tests/<Component>.Tests/
C# (this repo) ./ (NOT canonical) spread by horizontal layer (no per-component public-API file; types referenced directly) no tests project

Verification Needed

  • Forward-looking file paths: every "Owns" path above reflects the post-rename target (B5/B6/B7/B8). Today the files still have Aircraft* / Flight* / Orthophoto* / GpsCorrection* names. Implementers of B5B10 should treat this layout as the spec for the rename, not the current ground truth. After B6 ships the layout matches the disk.
  • Layer-organized vs component-organized layout: this codebase organizes files by horizontal layer (Controllers/, Services/, DTOs/, Enums/) not by feature component. The Owns globs are composed from multiple directories, which is unusual and means a single directory rename would touch multiple components' Owns. Question for user: keep as-is (matches the rest of the suite's .NET services? — needs verification against annotations and admin layout) or should a future refactor move toward feature-folders?
  • Entities/ and Infrastructure/ at the root are EMPTYEntities/ is shadowed by Database/Entities/. With GPS-Denied moving out of this repo, the historical "earmarked for orthophoto path resolver" reason is gone. Question for user: delete both empty dirs as part of B5?
  • No src/ directory — the .NET project sits at the repo root. coderule.mdc says "For existing projects, follow the established directory structure." → established structure is "no src/"; this layout DOC respects that. Confirm we should NOT move it.
  • Policy name is string-typed — feature controllers reference "FL" as a raw string. A typo would silently turn into a permanent 403. Question for user: should 05_identity expose a typed PolicyNames.FL constant? Cheap improvement; not a blocker for documentation.
  • Cross-component DTO clusters: DTOs/ directory mixes payloads from 01, 02, and 06. Owns globs are file-by-file. Acceptable for now; a future refactor could split into per-component subfolders (e.g. DTOs/Vehicle/, DTOs/Mission/, DTOs/Common/).
  • No tests/ project exists (per ../../suite/_docs/_process_leftovers/2026-04-22_ci-unit-test-lane-missing-projects.md). Test-spec / test-implement steps in autodev will need to create a sibling Azaion.Missions.Tests csproj — at tests/Azaion.Missions.Tests/ (suite-canonical) or somewhere else? Confirm.
  • Cycles spanning components: none detected. The Vehicle → Mission → Waypoint association graph is intra-component (entirely inside 04_persistence).