# Problem — Azaion.Missions > **Status**: derived-from-code (autodev `/document` Step 6, 2026-05-14). > **Mode**: retrospective synthesis from the verified `_docs/02_document/` set + the canonical suite spec at `../../suite/_docs/02_missions.md`. > **Forward-looking caveat**: same as `solution.md` § header — references to "the system" mean the post-rename, post-GPS-Denied-removal target. Today's source still uses pre-rename names; deltas tracked under Jira AZ-EPIC (AZ-539) children B4–B12. --- ## What is this system? `missions` is the **edge-tier .NET 10 REST service** that owns the **mission domain** of an Azaion deployment: it is the local source of truth for the operator's vehicle inventory, mission plans, and ordered waypoints, and it is the orchestrator of the cross-service cascade-delete that keeps the rest of the device's edge stack consistent when missions or waypoints are removed. It is one of ~6 backend services running side-by-side **on each customer device** (Jetson Orin / OrangePI / operator-PC). All edge services share **one local PostgreSQL** on the device; each migrates only the tables it owns. JWTs are minted by the central `admin` service using ECDSA-SHA256 and validated locally against `admin`'s JWKS, which `missions` fetches once at startup (and refreshes on schedule) and caches; request-path validation is local and does not call back. ## What problem does it solve? When a human operator plans, runs, and tears down missions on the edge: 1. **Inventory** — the operator must register the vehicles they own (Plane / Copter / UGV / GuidedMissile) and pick a default for one-click mission setup. 2. **Mission planning** — the operator must define a named mission against a chosen vehicle and lay out an ordered set of waypoints (lat/lon or MGRS, with per-waypoint source / objective / height). 3. **Mission lifecycle** — when a mission or waypoint is deleted, every downstream artefact (media uploaded by `annotations`, AI annotations, AI detections, autopilot-emitted `map_objects`) MUST be cleaned up in FK-safe order so the local DB doesn't accumulate orphans. 4. **Cross-service cohesion** — sibling services (`autopilot`, `annotations`, detection pipeline, `gps-denied`, `ui`) must be able to read mission/waypoint data without round-trips to the central admin and without their own copies. The shared local DB is that contract. 5. **Local trust** — the operator's device may be intermittently offline from the central network. Once the JWKS has been cached, authn/authz does not depend on a live `admin` callback; tokens validate locally against the cached ECDSA public keys. `admin` must be reachable at the moment of the first JWKS fetch after a cold start (then again periodically on the manager's refresh schedule). ## Who are the users? | Persona | Role | How they interact | |---------|------|-------------------| | **Operator** | Human running missions in the field | Through the React `ui` (REST + JWT). Sole human user of this service today | | **`autopilot`** | Sibling edge service (consumes missions/waypoints, writes `map_objects`) | Reads `missions` / `waypoints` from the shared DB; writes `map_objects` to a table this service owns the schema for and cascade-deletes | | **`annotations`** | Sibling edge service (owns `media` / `annotations` table schemas) | Indirect — `missions` cascade-deletes from `media` / `annotations` when missions/waypoints are removed | | **Detection pipeline** | Sibling edge service (owns the `detection` table schema) | Indirect — same pattern as `annotations` | | **`gps-denied`** *(post-B7)* | Sibling edge service (owns `orthophotos` + `gps_corrections`) | None at runtime — references `mission_id` / `waypoint_id` as plain GUIDs in its own tables; manages its own cleanup | | **`admin`** | Central .NET service (token issuer + JWKS publisher) | This service fetches admin's public JWKS once at startup and on the `ConfigurationManager` refresh schedule; request-path validation does not call back. `admin` outage after the JWKS has been cached does NOT take this service down (until cache + tokens expire). `admin` outage at the time of the first JWKS fetch causes the first protected request to fail 500 | There are **no application-level admin / superuser roles inside this service** — every protected endpoint is gated by the single `"FL"` permission. The role → permission matrix is suite-level (`../../suite/_docs/00_roles_permissions.md`). ## How does it work at a high level? ASP.NET Core thin controller → service class → linq2db active-record over a per-HTTP-request scoped `AppDataConnection`. No repository abstraction; no in-process message queue or event bus; no background workers. ```mermaid flowchart LR ui[[Operator UI]] -- "REST + JWT" --> mc[MissionsController / VehiclesController] mc --> svc[MissionService / VehicleService / WaypointService] svc --> ado[AppDataConnection
linq2db ITable<T>] ado --> pg[(postgres-local)] autopilot[[autopilot]] -- "DB read missions/waypoints
DB write map_objects" --> pg svc -. "cascade delete on mission/waypoint delete" .-> pg ``` Seven flows make up the runtime surface (`_docs/02_document/system-flows.md`): - **F1** Vehicle CRUD - **F2** Mission create / read / update - **F3** Mission delete + **cross-service cascade** (the most critical flow; not transaction-wrapped today — ADR-006) - **F4** Waypoint create / read / update / delete (delete is a scoped F3) - **F5** JWT bearer validation (cross-cutting; local ECDSA-SHA256 against admin's cached JWKS; `iss` + `aud` validated; `alg` pinned) - **F6** Service startup + idempotent schema migration - **F7** Anonymous `GET /health` probe ## Cross-cutting contracts owned here 1. **JWT validation contract** — trust admin-issued tokens via ECDSA-SHA256 signature verification against admin's published JWKS (cached locally), with `iss == JWT_ISSUER` + `aud == JWT_AUDIENCE` + `exp` (30s skew) all enforced and `alg` pinned to `EcdsaSha256`; reject everything else with `401`/`403`. 2. **Mission ownership graph & cascade-delete** — only place in the system that knows `mission → {map_objects, waypoints → media → annotations → detection}`. 3. **Suite-standard wire shapes** *(currently divergent — see `_docs/02_document/architecture.md` ADR-002)* — error envelope and `PaginatedResponse` are shared with `annotations`, `admin`, `satellite-provider`. ## Out of scope for this service - **GPS-Denied** (orthophoto upload, live-GPS, GPS correction) — separate `gps-denied` service after B7. - **Token issuance** — `admin` mints tokens; this service only validates. - **Detection / AI** — owned by the detection pipeline; this service only cascade-deletes orphaned rows on mission/waypoint delete. - **Media storage** — `annotations` owns `media` (text PK + waypoint FK); this service only cascade-deletes. - **Multi-instance HA** — exactly one container per device; horizontal scale-out explicitly not supported. ## Cross-reference index | Concern | Where | |---------|-------| | Spec (canonical, post-rename) | `../../suite/_docs/02_missions.md` | | Top-level architecture (envelope, pagination, topology) | `../../suite/_docs/00_top_level_architecture.md` | | Authoritative ER diagram | `../../suite/_docs/00_database_schema.md` | | Roles & `FL` permission origin | `../../suite/_docs/00_roles_permissions.md` | | GPS-Denied (separate service) | `../../suite/_docs/11_gps_denied.md` | | Verified architecture (this repo) | `_docs/02_document/architecture.md` | | Verified system flows (this repo) | `_docs/02_document/system-flows.md` | | Glossary (confirmed-by-user) | `_docs/02_document/glossary.md` | | Verification log (drift mapping) | `_docs/02_document/04_verification_log.md` | | Solution (retrospective) | `_docs/01_solution/solution.md` | | Restrictions (retrospective) | `_docs/00_problem/restrictions.md` | | Acceptance criteria (retrospective) | `_docs/00_problem/acceptance_criteria.md` | | Input data | `_docs/00_problem/input_data/data_parameters.md` | | Security approach | `_docs/00_problem/security_approach.md` | | Rename leftover (Jira index) | `_docs/_process_leftovers/2026-05-14_rename-flights-to-missions.md` |