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