mirror of
https://github.com/azaion/missions.git
synced 2026-06-21 23:11: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.
3.8 KiB
3.8 KiB
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)
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)
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 |