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.
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-14 19:48:25 +03:00
parent 2fe394d732
commit 7025f4d075
74 changed files with 8494 additions and 19 deletions
@@ -0,0 +1,71 @@
# 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.