# 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` 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) |