mirror of
https://github.com/azaion/missions.git
synced 2026-06-21 08:01:07 +00:00
7025f4d075
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.
72 lines
4.4 KiB
Markdown
72 lines
4.4 KiB
Markdown
# Module: `Azaion.Missions.Controllers.MissionsController`
|
||
|
||
**File**: `Controllers/MissionsController.cs`
|
||
|
||
> **NOTE (forward-looking)**: post-rename + post-route-change. Today's source is `Controllers/FlightsController.cs` mounted at `[Route("flights")]` with nested waypoint routes under `/flights/{id}/waypoints/...`. Renames + route changes tracked under Jira AZ-EPIC children B6 + B8.
|
||
|
||
## Purpose
|
||
|
||
REST surface for the `missions` resource AND its nested `waypoints` sub-resource. Wraps `MissionService` for the parent and `WaypointService` for the nested routes.
|
||
|
||
## Public Interface
|
||
|
||
### Missions
|
||
|
||
| HTTP | Route | Action | Body / Query | Returns |
|
||
|------|-------|--------|--------------|---------|
|
||
| `POST` | `/missions` | `Create` | `CreateMissionRequest` | `201` + `Location: /missions/{id}`, body: `Mission` |
|
||
| `PUT` | `/missions/{id:guid}` | `Update` | `UpdateMissionRequest` | `200`, body: `Mission` |
|
||
| `GET` | `/missions/{id:guid}` | `Get` | -- | `200`, body: `Mission` |
|
||
| `GET` | `/missions` | `GetAll` | `GetMissionsQuery` (`Name?`, `FromDate?`, `ToDate?`, `Page=1`, `PageSize=20`) | `200`, body: `PaginatedResponse<Mission>` |
|
||
| `DELETE` | `/missions/{id:guid}` | `Delete` | -- | `204` |
|
||
|
||
### Waypoints (nested under a mission)
|
||
|
||
| HTTP | Route | Action | Body | Returns |
|
||
|------|-------|--------|------|---------|
|
||
| `POST` | `/missions/{id:guid}/waypoints` | `CreateWaypoint` | `CreateWaypointRequest` | `201` + `Location: /missions/{id}/waypoints/{wpId}`, body: `Waypoint` |
|
||
| `PUT` | `/missions/{id:guid}/waypoints/{waypointId:guid}` | `UpdateWaypoint` | `UpdateWaypointRequest` | `200`, body: `Waypoint` |
|
||
| `DELETE` | `/missions/{id:guid}/waypoints/{waypointId:guid}` | `DeleteWaypoint` | -- | `204` |
|
||
| `GET` | `/missions/{id:guid}/waypoints` | `GetWaypoints` | -- | `200`, body: `List<Waypoint>` (no pagination) |
|
||
|
||
Class-level decorators: `[ApiController]`, `[Route("missions")]`, `[Authorize(Policy = "FL")]`.
|
||
|
||
## Internal Logic
|
||
|
||
Same pattern as `VehiclesController`: each action awaits the appropriate service method and wraps in `Created` / `Ok` / `NoContent`.
|
||
|
||
## Dependencies
|
||
|
||
- `MissionService`, `WaypointService` (constructor-injected; primary constructor)
|
||
- `Azaion.Missions.DTOs`
|
||
|
||
## Consumers
|
||
|
||
- HTTP clients.
|
||
- Cross-service callers in the suite: `autopilot` reads `GET /missions/{id}` + `GET /missions/{id}/waypoints` to drive UAV behavior; `ui` paginates `/missions`. Both will need to be updated to the new prefix as part of B11 (consumer updates).
|
||
|
||
## Data Models
|
||
|
||
Returns `Mission` (which has `Vehicle?` + `List<Waypoint>` association properties) and `Waypoint` (with `Mission?` association property) directly. Whether associations are populated on the wire depends on LinqToDB query behavior -- by default, `FirstOrDefaultAsync(predicate)` does NOT eager-load associations, so `mission.Vehicle` and `mission.Waypoints` will serialize as `null`/empty in JSON. Verify in Step 4 against actual API responses if available.
|
||
|
||
## Configuration / External Integrations
|
||
|
||
None directly.
|
||
|
||
## Security
|
||
|
||
- All routes behind `[Authorize(Policy = "FL")]`.
|
||
- Composite-key handling in waypoint operations means a stolen waypoint id alone is not enough -- the attacker must also know the parent mission id.
|
||
|
||
## Tests
|
||
|
||
None present.
|
||
|
||
## Notes / Smells
|
||
|
||
1. **Inconsistent listing pagination** -- `GET /missions` paginates, `GET /missions/{id}/waypoints` and `GET /vehicles` do not. Verification flag.
|
||
2. **Nested resource modeling** -- waypoints are exposed only as a sub-resource of a mission, never as `/waypoints/{id}`. Consistent with the data model (`mission_id` is `NOT NULL`).
|
||
3. **`Update` of a mission allows changing `vehicle_id`** but the controller doesn't reflect any business constraint (e.g., immutable after start). All such constraints would need to live in the service.
|
||
4. **No bulk endpoints** -- no batch create / batch delete for waypoints despite the natural use case ("upload a route plan").
|
||
5. **Entity body PascalCase wire shape** -- the whole API has no `JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase`, so `Mission`, `Waypoint`, and `PaginatedResponse<Mission>` responses serialize PascalCase property names. Spec says camelCase (per `../../suite/_docs/00_top_level_architecture.md`). Note: the global error envelope produced by `ErrorHandlingMiddleware` is already camelCase (anonymous object literal) -- this divergence applies only to entity / DTO bodies (see `middleware.md` Notes #1–#2 for the distinction). Carry to verification log.
|