# Module: `Azaion.Missions.DTOs` **Files (15)** -- grouped by concern: | Group | Files | |-------|-------| | Shared value objects | `GeoPoint.cs` | | Shared response wrappers | `PaginatedResponse.cs`, `ErrorResponse.cs` | | Vehicle requests/queries | `CreateVehicleRequest.cs`, `UpdateVehicleRequest.cs`, `GetVehiclesQuery.cs`, `SetDefaultRequest.cs` | | Mission requests/queries | `CreateMissionRequest.cs`, `UpdateMissionRequest.cs`, `GetMissionsQuery.cs` | | Waypoint requests | `CreateWaypointRequest.cs`, `UpdateWaypointRequest.cs` | > **NOTE (forward-looking)**: post-rename file names. Today's source has `CreateAircraftRequest.cs` / `CreateFlightRequest.cs` / etc. Renames tracked under Jira AZ-EPIC child B6. ## Purpose HTTP request/response/query payloads for the controller layer. Plain POCOs with public mutable properties -- no validation attributes, no record types. ## Public Interface ### Shared ```csharp public class GeoPoint { public decimal? Lat { get; set; } public decimal? Lon { get; set; } public string? Mgrs { get; set; } // Military Grid Reference System } public class PaginatedResponse { public List Items { get; set; } = []; public int TotalCount { get; set; } public int Page { get; set; } public int PageSize { get; set; } } public class ErrorResponse { public int StatusCode { get; set; } public string Message { get; set; } = string.Empty; public List? Errors { get; set; } } ``` ### Vehicle ```csharp public class CreateVehicleRequest { public VehicleType Type { get; set; } // Plane | Copter | UGV | GuidedMissile public string Model { get; set; } = string.Empty; public string Name { get; set; } = string.Empty; public FuelType FuelType { get; set; } public decimal BatteryCapacity { get; set; } public decimal EngineConsumption { get; set; } public decimal EngineConsumptionIdle { get; set; } public bool IsDefault { get; set; } } public class UpdateVehicleRequest { // All properties nullable -- partial-update semantics, applied per non-null field public VehicleType? Type; public string? Model; public string? Name; public FuelType? FuelType; public decimal? BatteryCapacity; public decimal? EngineConsumption; public decimal? EngineConsumptionIdle; public bool? IsDefault; } public class GetVehiclesQuery { public string? Name { get; set; } public bool? IsDefault { get; set; } } public class SetDefaultRequest { public bool IsDefault { get; set; } } ``` ### Mission ```csharp public class CreateMissionRequest { public Guid VehicleId { get; set; } public string Name { get; set; } = string.Empty; public DateTime? CreatedDate { get; set; } // Defaults to UtcNow if null } public class UpdateMissionRequest { public string? Name { get; set; } public Guid? VehicleId { get; set; } } public class GetMissionsQuery { public string? Name { get; set; } public DateTime? FromDate { get; set; } public DateTime? ToDate { get; set; } public int Page { get; set; } = 1; public int PageSize { get; set; } = 20; } ``` ### Waypoint ```csharp public class CreateWaypointRequest { public GeoPoint? GeoPoint { get; set; } public WaypointSource WaypointSource { get; set; } public WaypointObjective WaypointObjective { get; set; } public int OrderNum { get; set; } public decimal Height { get; set; } } public class UpdateWaypointRequest { // identical shape to Create public GeoPoint? GeoPoint { get; set; } public WaypointSource WaypointSource { get; set; } public WaypointObjective WaypointObjective { get; set; } public int OrderNum { get; set; } public decimal Height { get; set; } } ``` ## Internal Logic Pure data containers. No methods, no constructors beyond the implicit default. ## Dependencies - `Azaion.Missions.Enums` -- for typed enum properties ## Consumers - `Services.VehicleService`, `Services.MissionService`, `Services.WaypointService` -- request DTOs as method parameters; `PaginatedResponse` returned from `MissionService.GetMissions`. - `Controllers.VehiclesController`, `Controllers.MissionsController` -- `[FromBody]` / `[FromQuery]` binding. ## Data Models Mirror the corresponding entity columns minus identity/timestamps (those are server-assigned). ## Configuration / External Integrations / Security None directly -- all binding is provided by ASP.NET Core model binding with no custom validators or `[Required]` / `[Range]` attributes. ## Tests None present. ## Notes / Smells - **No validation**: nothing prevents `CreateVehicleRequest.Name = ""`, negative `BatteryCapacity`, `OrderNum < 0`, or out-of-range enum values (binding on int will accept any int and persist it). Carry to AC / restrictions in Step 6. - **`UpdateWaypointRequest` is structurally identical to `CreateWaypointRequest`** but uses non-nullable enum/numeric fields, meaning every `PUT` overwrites all fields -- no partial-update semantics for waypoints (unlike vehicle, which uses `?` everywhere). Inconsistency between resources. - **`PaginatedResponse`** is only used for `Mission` listing; `GetVehicles` returns a plain `List` (no pagination, no total count), even though `GetVehiclesQuery` exists. Inconsistent listing contract -- matches spec (vehicles are a small dataset). - **`ErrorResponse`** is defined but not used by `ErrorHandlingMiddleware` (which writes an anonymous object literal). Dead code candidate. - `GeoPoint` allows all-null (Lat, Lon, Mgrs all optional). No invariant ensures at least one location representation is populated. - **Spec divergence (Geopoint)**: `../../suite/_docs/02_missions.md` and `../../suite/_docs/00_database_schema.md` define `Waypoints.GPS` as a single `string GPS` field with auto-conversion (`Lat <-> MGRS`). Code stores three separate columns (`lat NUMERIC`, `lon NUMERIC`, `mgrs TEXT`) and exposes them as three flat properties without conversion logic. Carry to verification log. - **Spec divergence (ErrorResponse)**: spec `errors` is `object?` keyed by field name (per-field validation arrays). Code defines `List? Errors` and the type is unused on the wire (middleware emits an anonymous object instead). Carry to verification log. - **Spec divergence (PaginatedResponse case-style)**: suite-wide standard is camelCase (`items`, `totalCount`, `page`, `pageSize`). `PaginatedResponse` declares PascalCase properties and System.Text.Json's defaults preserve them, so on-the-wire output is `{"Items":..., "TotalCount":..., ...}`. No `JsonNamingPolicy.CamelCase` is configured. - **Spec partial conformance (ErrorResponse / error envelope)**: the static `ErrorResponse` DTO is **unused on the wire** -- `Middleware.ErrorHandlingMiddleware` writes an anonymous object literal instead. That anonymous object happens to use lowercase property names (`statusCode`, `message`), which `System.Text.Json` preserves, so the live error envelope IS camelCase (matching spec on case) but still missing the spec's `errors: object?` field. Were `ErrorResponse` ever used directly it would emit PascalCase (`StatusCode`, `Message`, `Errors`) and additionally have the wrong `Errors` shape (`List?` vs spec's `object?`). Two carry-forward concerns: add the `errors` field to the live envelope, and either remove the dead `ErrorResponse` DTO or fix it to match spec.