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,82 @@
# Flow F2 — Mission create / read / update
> Post-rename. Today: `[Route("flights")]`, `Flight*` files.
## Description
Mission CRUD excluding delete (delete is the cross-service cascade in F3). Create / update validate that the referenced `vehicle_id` exists; list (`GET /missions`) is the only paginated endpoint in this service.
## Preconditions
- Service is running, schema in place (F6).
- Caller holds JWT with `permissions=FL` (F5).
- For create / update with `VehicleId`: the referenced vehicle exists (F1).
## Sequence Diagram (POST `/missions`)
```mermaid
sequenceDiagram
autonumber
participant UI as Operator UI
participant Identity as 05_identity
participant Errs as 06_http_conventions
participant Ctrl as MissionsController
participant MS as MissionService
participant DB as 04_persistence (postgres-local)
UI->>Identity: POST /missions + JWT + { Name, VehicleId }
Identity-->>Ctrl: authorized (policy "FL")
Ctrl->>MS: CreateMission(req)
MS->>DB: SELECT 1 FROM vehicles WHERE id = @VehicleId
alt Vehicle missing
DB-->>MS: 0 rows
MS-->>Errs: throw ArgumentException("VehicleId not found")
note right of MS: Spec says 404; code returns 400. Carry-forward.
Errs-->>UI: 400 Bad Request (PascalCase error envelope)
else Vehicle exists
DB-->>MS: 1 row
MS->>DB: INSERT INTO missions (id, name, vehicle_id, created_date) VALUES (...)
DB-->>MS: row inserted
MS-->>Ctrl: Mission entity
Ctrl-->>UI: 201 Created + Mission (Vehicle / Waypoints serialize as null / [] — no eager load)
end
```
## Flowchart (GET `/missions` paginated)
```mermaid
flowchart TD
Start([GET /missions?Name=&FromDate=&ToDate=&Page=&PageSize=]) --> Auth{JWT + FL valid?}
Auth -->|no| Reject([401 / 403])
Auth -->|yes| Build[Build LINQ predicate from optional filters]
Build --> Count[COUNT * over filtered set]
Count --> Page[SELECT ... ORDER BY created_date DESC LIMIT pageSize OFFSET]
Page --> Wrap[Wrap in PaginatedResponse Items, TotalCount, Page, PageSize]
Wrap --> Done([200 OK + envelope, PascalCase])
```
## Data Flow
| Step | From | To | Data | Format |
|------|------|----|------|--------|
| 1 | UI | `MissionsController` | `CreateMissionRequest` / `UpdateMissionRequest` / `GetMissionsQuery` | JSON / query string (PascalCase) |
| 2 | `MissionService` | `vehicles` table | existence check `SELECT 1` | SQL |
| 3 | `MissionService` | `missions` table | INSERT / UPDATE / SELECT | SQL |
| 4 | `MissionService` | UI | `Mission` entity / `PaginatedResponse<Mission>` | JSON (PascalCase) |
## Error Scenarios
| Error | Where | Detection | Recovery |
|-------|-------|-----------|----------|
| `VehicleId` missing on create / update | `MissionService.CreateMission` / `UpdateMission` | existence check returns false | `ArgumentException``400` (spec wants `404` — minor divergence, B-set carry-forward) |
| TOCTOU: vehicle deleted between existence check and insert | `MissionService.CreateMission` | FK constraint violation | Npgsql `PostgresException` → middleware → `500`. UX gap (should be `400`); rare in practice |
| Mission not found | `MissionService.GetMission` / `UpdateMission` | entity lookup `null` | `KeyNotFoundException``404` |
| Page / PageSize out of range | None enforced | n/a | LinqToDB `Skip(negative)` / `Take(0)` returns empty set; no error returned to client |
## Performance Expectations
| Metric | Target | Notes |
|--------|--------|-------|
| End-to-end latency (single mission) | <15ms typical | Two round-trips on create (existence check + insert); one on read |
| Paginated list latency | <30ms typical for ≤1000 rows | No index on `created_date` — full scan + sort. Add `ix_missions_created_date` if list latency becomes an issue |
| Throughput | Operator-paced | Not load-tested |