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
+94
View File
@@ -0,0 +1,94 @@
# 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 B4B12.
---
## 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 and validated locally with a shared HMAC secret — `missions` never calls `admin` 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. Authn/authz cannot depend on a live `admin` callback; tokens validate locally with a shared secret.
## 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) | One-way: issues JWTs that this service validates locally. `admin` outages do NOT take this service down (until tokens expire) |
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<br/>linq2db ITable&lt;T&gt;]
ado --> pg[(postgres-local)]
autopilot[[autopilot]] -- "DB read missions/waypoints<br/>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 HS256 only)
- **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 shared HMAC secret (`JWT_SECRET`); 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<T>` 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` |