mirror of
https://github.com/azaion/missions.git
synced 2026-06-22 15:51:08 +00:00
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:
@@ -0,0 +1,87 @@
|
||||
# Flow F1 — Vehicle CRUD
|
||||
|
||||
> Post-rename / post-B7. Today: `[Route("aircrafts")]`, `Aircraft*` files. See `02_mission_planning` is unaffected by route prefix.
|
||||
|
||||
## Description
|
||||
|
||||
Operator manages the inventory of `Vehicle` rows. Six endpoints: POST, PUT, DELETE, GET-list (unpaginated by spec), GET-by-id, PATCH `/default`. Every endpoint is gated by `[Authorize(Policy = "FL")]`. The "exactly one default vehicle" exclusivity rule is **stricter than spec** — the code clears `IsDefault` on every other row before setting it on the target. See `01_vehicle_catalog` Caveats #1, tracked under Jira AZ-551 (B12).
|
||||
|
||||
## Preconditions
|
||||
|
||||
- Service is running and schema is in place (Flow F6 has completed).
|
||||
- Caller holds a JWT with `permissions=FL` (Flow F5 succeeds).
|
||||
|
||||
## Sequence Diagram (POST `/vehicles` with `IsDefault: true`)
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
participant UI as Operator UI
|
||||
participant Pipeline as ASP.NET Pipeline
|
||||
participant Identity as 05_identity
|
||||
participant Errs as 06_http_conventions
|
||||
participant Ctrl as VehiclesController
|
||||
participant Svc as VehicleService
|
||||
participant DB as 04_persistence (postgres-local)
|
||||
|
||||
UI->>Pipeline: POST /vehicles + Bearer JWT + body
|
||||
Pipeline->>Errs: enter middleware (catches exceptions)
|
||||
Errs->>Identity: validate JWT + policy "FL"
|
||||
alt JWT or policy fails
|
||||
Identity-->>UI: 401 / 403
|
||||
else authorized
|
||||
Identity-->>Ctrl: ClaimsPrincipal attached
|
||||
Ctrl->>Svc: CreateVehicle(req)
|
||||
opt req.IsDefault == true
|
||||
Svc->>DB: UPDATE vehicles SET is_default=FALSE WHERE is_default=TRUE
|
||||
note right of Svc: Stricter than spec. Race-prone (no transaction). B12.
|
||||
end
|
||||
Svc->>DB: INSERT INTO vehicles VALUES (...)
|
||||
DB-->>Svc: row id
|
||||
Svc-->>Ctrl: Vehicle entity
|
||||
Ctrl-->>Errs: 201 Created + Vehicle (PascalCase JSON)
|
||||
Errs-->>UI: 201 Created
|
||||
end
|
||||
```
|
||||
|
||||
## Flowchart (DELETE `/vehicles/{id}`)
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([DELETE /vehicles/id]) --> Auth{JWT + FL valid?}
|
||||
Auth -->|no| Reject([401 / 403])
|
||||
Auth -->|yes| Lookup[SELECT 1 FROM vehicles WHERE id=?]
|
||||
Lookup --> Exists{Found?}
|
||||
Exists -->|no| NotFound([KeyNotFoundException → 404])
|
||||
Exists -->|yes| Refs[SELECT 1 FROM missions WHERE vehicle_id=?]
|
||||
Refs --> InUse{Any mission references it?}
|
||||
InUse -->|yes| Conflict([InvalidOperationException → 409])
|
||||
InUse -->|no| Del[DELETE FROM vehicles WHERE id=?]
|
||||
Del --> Done([204 No Content])
|
||||
```
|
||||
|
||||
## Data Flow
|
||||
|
||||
| Step | From | To | Data | Format |
|
||||
|------|------|----|------|--------|
|
||||
| 1 | UI | `VehiclesController` | `CreateVehicleRequest` / `UpdateVehicleRequest` / `SetDefaultRequest` / query string | JSON (PascalCase) |
|
||||
| 2 | `VehicleService` | `vehicles` table | INSERT / UPDATE / DELETE | SQL |
|
||||
| 3 | `vehicles` table | `VehicleService` | row(s) | LinqToDB entity mapping |
|
||||
| 4 | `VehicleService` | UI | `Vehicle` entity | JSON (PascalCase) — entity returned directly, no DTO mapping |
|
||||
|
||||
## Error Scenarios
|
||||
|
||||
| Error | Where | Detection | Recovery |
|
||||
|-------|-------|-----------|----------|
|
||||
| Missing / invalid JWT | Pipeline | `JwtBearerHandler` | `401`; client refreshes token |
|
||||
| Missing `"FL"` claim | Policy evaluator | Claim lookup | `403` |
|
||||
| Vehicle not found | Service entity lookup | `null` result | `KeyNotFoundException` → `404` |
|
||||
| Delete-with-references | `VehicleService.DeleteVehicle` | `IsAny<Mission>` true | `InvalidOperationException` → `409` |
|
||||
| Concurrent default-set | `VehicleService.{Create,Update}Vehicle` / `SetDefault` | none (no transaction) | Race window: 2+ defaults OR zero defaults. B12 |
|
||||
|
||||
## Performance Expectations
|
||||
|
||||
| Metric | Target | Notes |
|
||||
|--------|--------|-------|
|
||||
| End-to-end latency (CRUD) | <10ms typical | Single round-trip against local PostgreSQL |
|
||||
| Throughput | Operator-paced | Not load-tested; catalog is small in practice (tens to low hundreds of rows) |
|
||||
Reference in New Issue
Block a user