mirror of
https://github.com/azaion/missions.git
synced 2026-06-22 06:21:07 +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,86 @@
|
||||
# Flow F4 — Waypoint create / read / update / delete
|
||||
|
||||
> Post-rename / post-B7. Waypoint delete is a scoped variant of F3's cross-service cascade — same NO-transaction caveat applies (`architecture.md` ADR-006).
|
||||
|
||||
## Description
|
||||
|
||||
Waypoint CRUD nested under a mission (`/missions/{id}/waypoints/*`). Read-list is **unpaginated by spec**, ordered by `OrderNum`. **`UpdateWaypoint` is a full overwrite** of every field even though the request DTO looks "partial-shaped" (see `02_mission_planning` Caveats #2). Delete walks the cross-service cascade for **one** waypoint (compare F3 which walks for ALL waypoints of a mission).
|
||||
|
||||
## Preconditions
|
||||
|
||||
- Parent mission exists (`KeyNotFoundException` → `404` otherwise on every endpoint).
|
||||
- Caller holds JWT with `permissions=FL` (F5).
|
||||
- Schema in place for borrowed tables (`media`, `annotations`, `detection`) for delete.
|
||||
|
||||
## Sequence Diagram (DELETE one waypoint)
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
participant UI as Operator UI
|
||||
participant Identity as 05_identity
|
||||
participant Ctrl as MissionsController
|
||||
participant WS as WaypointService
|
||||
participant DB as 04_persistence (postgres-local)
|
||||
participant Annot as [[annotations service schema]]
|
||||
participant Det as [[detection pipeline schema]]
|
||||
|
||||
UI->>Identity: DELETE /missions/{id}/waypoints/{wpId} + JWT
|
||||
Identity-->>Ctrl: authorized (policy "FL")
|
||||
Ctrl->>WS: DeleteWaypoint(missionId, wpId)
|
||||
WS->>DB: SELECT 1 FROM waypoints WHERE mission_id=? AND id=?
|
||||
alt Not found
|
||||
DB-->>WS: 0 rows
|
||||
WS-->>UI: 404 Not Found
|
||||
else Found
|
||||
WS->>Annot: SELECT id FROM media WHERE waypoint_id = ? → mediaIds
|
||||
WS->>Annot: SELECT id FROM annotations WHERE media_id IN ? → annotationIds
|
||||
WS->>Det: DELETE FROM detection WHERE annotation_id IN annotationIds
|
||||
WS->>Annot: DELETE FROM annotations WHERE id IN annotationIds
|
||||
WS->>Annot: DELETE FROM media WHERE id IN mediaIds
|
||||
WS->>DB: DELETE FROM waypoints WHERE id = ?
|
||||
WS-->>UI: 204 No Content
|
||||
end
|
||||
```
|
||||
|
||||
## Flowchart (PUT — full overwrite)
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([PUT /missions/id/waypoints/wpId + body]) --> Auth{JWT + FL valid?}
|
||||
Auth -->|no| Reject([401 / 403])
|
||||
Auth -->|yes| Lookup[SELECT * FROM waypoints WHERE mission_id=? AND id=?]
|
||||
Lookup --> Exists{Found?}
|
||||
Exists -->|no| NotFound([404])
|
||||
Exists -->|yes| Overwrite["UPDATE waypoints SET lat=?, lon=?, mgrs=?, alt=?, source=?, objective=?, order_num=?, name=? WHERE id=?"]
|
||||
Overwrite --> Done([200 OK + Waypoint])
|
||||
note1[NOTE: Sending partial body zeroes out missing numeric fields and resets enums to default 0. Spec uses Geopoint type with auto-conversion; code uses 3 flat fields. Carry-forward.]
|
||||
```
|
||||
|
||||
## Data Flow
|
||||
|
||||
| Step | From | To | Data | Format |
|
||||
|------|------|----|------|--------|
|
||||
| 1 | UI | `MissionsController` (nested) | mission id + waypoint id (URL) + `CreateWaypointRequest` / `UpdateWaypointRequest` body | path params + JSON |
|
||||
| 2 | `WaypointService` | `waypoints` table | INSERT / UPDATE / SELECT / DELETE | SQL |
|
||||
| 3 | `WaypointService` | `media` / `annotations` / `detection` (delete only) | `SELECT id` then `DELETE WHERE id IN (...)` | SQL |
|
||||
| 4 | `WaypointService` | UI | `Waypoint` entity / `List<Waypoint>` / `204` | JSON (PascalCase) |
|
||||
|
||||
## Error Scenarios
|
||||
|
||||
| Error | Where | Detection | Recovery |
|
||||
|-------|-------|-----------|----------|
|
||||
| Parent mission not found | Service entity lookup | `null` | `KeyNotFoundException` → `404` |
|
||||
| Waypoint not found in mission | Service entity lookup with both ids | `null` | `KeyNotFoundException` → `404` |
|
||||
| PUT zeroes out coordinates | `WaypointService.UpdateWaypoint` | None | Body intent is "partial" but code overwrites every column → silent data loss for missing fields. Carry-forward (`02_mission_planning` Caveats #2) |
|
||||
| Race on N waypoints reordered as N PUTs | Caller-side | None | No reorder endpoint exists — caller must coordinate; partially-applied reorders leave inconsistent `order_num`s (`02_mission_planning` Caveats #5) |
|
||||
| Delete cascade `relation does not exist` for `media` / `annotations` / `detection` | DELETE steps | Npgsql `PostgresException` (`42P01`) | `500`. Same diagnosis as F3: abnormal edge deployment |
|
||||
| Partial failure mid-delete-cascade | Same as F3 | Npgsql exception | `500` + orphan rows. ADR-006 carry-forward |
|
||||
|
||||
## Performance Expectations
|
||||
|
||||
| Metric | Target | Notes |
|
||||
|--------|--------|-------|
|
||||
| Create / read / update | <10ms typical | Single round-trip |
|
||||
| List (unpaginated) | <30ms typical for ≤1000 waypoints | `ix_waypoints_mission_id` index used; sort by `order_num` is in-memory (no order index) |
|
||||
| Delete (with cross-service cascade) | <30ms typical for ≤100 media rows per waypoint | 5–6 round-trips |
|
||||
Reference in New Issue
Block a user