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.
20 KiB
Azaion.Missions — Final Documentation Report
Status: complete (autodev
/documentStep 7, 2026-05-14). Mode: retrospective documentation of an existing codebase, post-Step 4 verification + Step 4.5 user-confirmed glossary & vision. Forward-looking caveat: every artefact in this set describes the post-rename, post-GPS-Denied-removal target. Today's source still uses pre-rename names; the doc-vs-code reconciliation table lives in04_verification_log.md§ 0 and the implementation deltas are tracked under Jira AZ-EPIC AZ-539 children B4–B12 (see_docs/_process_leftovers/2026-05-14_rename-flights-to-missions.md).
Executive Summary
missions is the edge-tier .NET 10 REST service that owns the mission domain (vehicles, missions, waypoints) of an Azaion deployment. The autodev /document skill produced a complete bottom-up documentation set across 8 steps: discovery → 12 module docs → 6 component specs → module-layout (file ownership + 5-layer dependency table) → architecture / system-flows / data-model / deployment → verification (9 inline corrections, 2 drift items captured) → user-confirmed glossary & architecture vision → retrospective solution / problem / restrictions / acceptance-criteria / security-approach. This terminates Phase A Step 1 of the autodev existing-code flow; Step 2 (Architecture Baseline Scan) is the next auto-chained step.
Problem Statement
The system is the per-device authority for vehicle inventory (Plane / Copter / UGV / GuidedMissile), mission plans, and ordered waypoints — and is the single orchestrator of the cross-service cascade-delete that keeps media / annotations / detection / map_objects consistent when missions or waypoints are removed. It runs as one container per device alongside annotations, the detection pipeline, autopilot, gps-denied, and the React ui, sharing one local PostgreSQL with per-service table ownership enforced by convention. JWTs are validated locally with a shared HMAC secret — the service never calls back to the central admin issuer. Full statement in _docs/00_problem/problem.md.
Architecture Overview
Pattern: thin ASP.NET Core controller → service class → linq2db active-record over a per-HTTP-request scoped AppDataConnection. No repository abstraction; no in-process message queue / event bus; no background workers.
Technology stack: C# / .NET 10 (net10.0) on ASP.NET Core, linq2db 6.2.0 over PostgreSQL via Npgsql 10.0.2, JWT bearer (HS256, shared secret), Swashbuckle 10.1.5 (Swagger UI mounted unconditionally — ADR-005).
Deployment: docker compose per edge device (Jetson Orin / OrangePI / operator-PC); multi-arch ARM64 + AMD64 image built by Woodpecker; Watchtower handles container restarts; flight-gate prevents container restart mid-mission; vertical scale only (one instance per device).
8 ADRs (see architecture.md § 8): one Postgres per device (ADR-001), PascalCase wire shape carry-forward (ADR-002), manual cascade-delete (ADR-003), IF NOT EXISTS schema bootstrap (ADR-004), Swagger + dev fallbacks ungated (ADR-005), cascade-not-transaction-wrapped carry-forward (ADR-006), GPS-Denied moved out (ADR-007), one-csproj layering by convention (ADR-008).
Component Summary
| # | Component | Purpose | Dependencies (logical layer) | Spec / Epic |
|---|---|---|---|---|
| 01 | 01_vehicle_catalog |
Vehicle CRUD + is_default exclusivity (stricter than spec — B12 decision pending) |
Layer 3 → 04_persistence, 05_identity |
suite spec § 6.1; B6 / B12 |
| 02 | 02_mission_planning |
Mission + Waypoint CRUD + cross-service cascade-delete walk | Layer 4 → 01_vehicle_catalog (existence check), 04_persistence, 05_identity, 06_http_conventions |
suite spec § 6.2; B6 / B7 / B8 |
| 04 | 04_persistence |
AppDataConnection (linq2db ITable<T>) + DatabaseMigrator (CREATE TABLE IF NOT EXISTS + B9 one-shot DROP) |
Layer 1 → linq2db + Npgsql only | B7 / B9 |
| 05 | 05_identity |
JwtExtensions.AddJwtAuth — HS256 local validation + "FL" policy |
Layer 2 → ASP.NET Core only | suite-level remediation (AZ-487/AZ-494 carry-forward) |
| 06 | 06_http_conventions |
ErrorHandlingMiddleware + PaginatedResponse<T> + dead ErrorResponse DTO |
Layer 2 → ASP.NET Core only | ADR-002 carry-forward |
| 07 | 07_host |
Program.cs composition root: env adapter, JWT registration, scoped DI, run migrator, register middleware, MapGet("/health"), mount Swagger |
Layer 5 → every other component | B5 (csproj rename) / B10 (image tag) |
Implementation order (based on dependency graph in module-layout.md):
- Layer 1:
04_persistence— depends only on linq2db + Npgsql. - Layer 2:
05_identity,06_http_conventions— depend on ASP.NET Core only. - Layer 3:
01_vehicle_catalog. - Layer 4:
02_mission_planning(readsvehiclesfor existence checks; usesPaginatedResponse<T>). - Layer 5:
07_host(composition root).
No circular dependencies between components.
System Flows
| Flow | Description | Key components | Criticality |
|---|---|---|---|
| F1 | Vehicle CRUD | 01_vehicle_catalog → 04_persistence |
High |
| F2 | Mission create / read / update with vehicle_id existence check |
02_mission_planning → 04_persistence, with 01_vehicle_catalog lookup |
High |
| F3 | Mission delete with cross-service cascade (touches map_objects, media, annotations, detection, waypoints, missions) |
02_mission_planning → 04_persistence + cross-service tables |
Critical (data integrity; not transaction-wrapped today — ADR-006) |
| F4 | Waypoint CRUD (delete is a scoped F3 cascade) | 02_mission_planning (WaypointService) → 04_persistence |
High |
| F5 | JWT bearer validation (cross-cutting; local HS256 only) | 05_identity (pipeline middleware) |
Critical (every authenticated route) |
| F6 | Service startup + idempotent schema migration (B9 one-shot DROP TABLE IF EXISTS for fielded legacy devices) |
07_host → 04_persistence |
High |
| F7 | Anonymous GET /health probe (process-liveness only; no DB ping) |
07_host |
Medium |
Full sequences and per-flow Mermaid diagrams in system-flows.md and diagrams/flows/flow_*.md.
Risk Summary
The codebase has no automated tests today, so "risks" here are observed-from-code carry-forward concerns (architecture.md § Carry-forward + 00_discovery.md § Spec ↔ Code Divergences), classified by impact. Mitigation column points at the responsible Jira child or the suite-level ticket.
| Level | Count | Items |
|---|---|---|
| Critical | 1 | Cascade-delete is NOT transaction-wrapped (ADR-006) — partial failure leaves orphan rows. One-line fix, recommended to land with B6 |
| High | 3 | (a) JWT_SECRET / DATABASE_URL dev fallbacks not gated on IsDevelopment() (ADR-005, suite-tracked); (b) JWT iss/aud validation disabled (CMMC L2 row 3, AZ-487/AZ-494 suite-tracked); (c) Wire-shape divergence — entity/DTO bodies PascalCase, error envelope missing errors field (ADR-002 carry-forward) |
| Medium | 4 | (a) "Exactly one default vehicle" stricter than spec + race-prone (B12 / AZ-551 — decision-only ticket); (b) vehicle_id-not-found returns 400 instead of spec's 404 (carry-forward); (c) Swagger UI mounted unconditionally (ADR-005); (d) CORS open in all environments (carry-forward) |
| Low | 4 | (a) ErrorResponse DTO is dead on the wire and has wrong shape; (b) Geopoint stored as 3 flat columns instead of spec's auto-converting string GPS; (c) FL permission code retains legacy "Flight" wording post-rename (suite-level fleet-wide change); (d) FuelType enum may not fit single-use GuidedMissile |
Mitigation status: every Critical/High item is either covered by an open Jira ticket (B6, B12, AZ-487/AZ-494) or explicitly logged as a suite-level carry-forward in 04_verification_log.md. No Critical/High item is unaccounted for.
Test Coverage
No automated tests exist today. Verification of every documented behaviour is by code inspection only. The autodev existing-code flow's Phase A Steps 3 → 7 is the planned path to convert _docs/00_problem/acceptance_criteria.md (10 AC groups, ~60 individual criteria) into runnable test cases.
| Component | Integration | Performance | Security | Acceptance | AC coverage today |
|---|---|---|---|---|---|
01_vehicle_catalog |
0 | 0 | 0 | 0 | AC-1 (9 criteria) — inspection only |
02_mission_planning |
0 | 0 | 0 | 0 | AC-2 (8) + AC-3 (7) + AC-4 (7) — inspection only |
04_persistence |
0 | 0 | 0 | 0 | AC-6 (10) — inspection only |
05_identity |
0 | 0 | 0 | 0 | AC-5 (9) + AC-9 (4) — inspection only |
06_http_conventions |
0 | 0 | 0 | 0 | AC-8 (7) — inspection only |
07_host |
0 | 0 | 0 | 0 | AC-6 (10) + AC-7 (4) + AC-10 (6) — inspection only |
Overall AC coverage by automated tests: 0 / ~60 (0%) — the gap that Phase A Steps 3–7 will close.
Rename Epic Roadmap (Jira AZ-EPIC AZ-539)
The full doc-vs-code rename + GPS-Denied removal is tracked as one Jira Epic + 12 child tickets. B1–B3 (the documentation half) landed in this turn; B4–B12 (the code half) are still To Do.
| Order | Plan ID | Jira | Type | SP | Status | Component / artefact |
|---|---|---|---|---|---|---|
| Epic | — | AZ-539 | Epic | — | To Do | umbrella |
| 1 | B1 | AZ-540 | Task | 3 | Done (this turn) | local docs (this repo's _docs/) |
| 2 | B2 | AZ-541 | Task | 3 | Done (this turn) | suite docs (../../suite/_docs/) |
| 3 | B3 | AZ-542 | Task | 3 | Done (this turn) | local + suite state bookkeeping |
| 4 | B4 | AZ-543 | Task | 3 | To Do | repo rename (Gitea + suite .gitmodules + git mv) |
| 5 | B5 | AZ-544 | Story | 3 | To Do | csproj + namespace Azaion.Flights → Azaion.Missions |
| 6 | B6 | AZ-545 | Story | 5 | To Do | domain rename Aircraft → Vehicle, Flight → Mission, AircraftType → VehicleType { Plane, Copter, UGV, GuidedMissile } |
| 7 | B7 | AZ-546 | Story | 3 | To Do | drop GPS-Denied entities, "GPS" policy, cascade branches, migrator entries |
| 8 | B8 | AZ-547 | Story | 3 | To Do | HTTP routes /aircrafts → /vehicles, /flights → /missions |
| 9 | B9 | AZ-548 | Story | 5 | To Do | DB migration: ALTER TABLE rename + DROP TABLE IF EXISTS for legacy GPS-Denied |
| 10 | B10 | AZ-549 | Task | 2 | To Do | Dockerfile entrypoint + Woodpecker image tag + suite compose service block |
| 11 | B11 | AZ-550 | Story | 5 | To Do | consumer cutover (autopilot + ui + suite e2e) |
| 12 | B12 | AZ-551 | Task | 2 | To Do | decision-only: lift "exactly one default" into spec + transaction-wrap, OR drop from code |
Total estimated effort (remaining): 35 SP across 9 To-Do tickets. Implementation order has hard dependencies (B5 → B6 → B7 → B8 → B9 → B10 → B11; B4 ride-along; B12 independent decision).
Key Decisions Made (during documentation)
| # | Decision | Rationale | Alternatives rejected |
|---|---|---|---|
| 1 | Document the post-rename target rather than today's pre-rename source | Aligns with the user's intended end state and the Jira Epic; avoids documenting code that's about to be deleted (B7) | (a) Document today's code as-is — rejected: would require a near-total rewrite the moment B5–B7 land. (b) Document both — rejected: doubles maintenance burden until B5–B7 ship |
| 2 | Each forward-looking doc carries an explicit "post-rename" note pointing at the responsible Jira child | Future readers can reconcile what they see in code against the doc without re-running discovery | Implicit forward-looking — rejected: too easy to mistake a doc for current state |
| 3 | Treat the verification step as rename-aware | The doc-vs-code rename mapping is captured once in 04_verification_log.md § 0; mismatches not covered by the mapping are the only flagged drift |
Treat every rename as a verification failure — rejected: would flag every entity name and produce noise |
| 4 | Component count went 7 → 6 (dropped 03_gps_denied) and 01_aircraft_catalog → 01_vehicle_catalog |
Matches the post-rename suite spec; logged in state.json.decomposition_revised |
Keep 7 with 03_gps_denied as deprecated — rejected: would conflict with B7's removal scope |
| 5 | architecture.md § "Architecture Vision" + glossary.md were both confirmed by the user (Step 4.5) |
Downstream skills (refactor, decompose, new-task) treat these as authoritative | Skip the glossary — rejected: existing-code projects benefit most from explicit terminology reconciliation |
| 6 | Solution / problem / restrictions / acceptance / security all describe today's behaviour with carry-forward divergences explicitly called out | Tests against the docs will catch unintended behaviour changes; spec-conformance fixes are intentional | Rewrite the docs to match the suite spec — rejected: would misrepresent the running code |
Open Questions (for Phase A Step 2 onward)
| # | Question | Impact | Where it surfaces next |
|---|---|---|---|
| 1 | Will B12 / AZ-551 lift "exactly one default vehicle" into spec (with transaction-wrap) or drop the rule from code? | AC-1.2 / AC-1.3 / AC-1.4 will change shape; the F1 test scenarios in Step 3 will pin whichever resolution the user picks | B12 / AZ-551 ticket |
| 2 | Should B6 also land the cascade transaction-wrap (ADR-006 carry-forward, one-line fix)? | Closes the only Critical risk; B6 is a rename pass and the transaction wrap can ride along cheaply | B6 / AZ-545 review |
| 3 | When does the suite-wide camelCase wire-shape migration happen (ADR-002 carry-forward)? | Affects every Mission / Vehicle / PaginatedResponse consumer (UI + autopilot); not in this Epic |
Suite-level ticket (not yet filed) |
| 4 | Does gps-denied need to be deployed BEFORE B9's DROP TABLE IF EXISTS runs on fielded devices? |
Out-of-band ordering matters: AC-10.5; F6 error scenario | B9 / B10 acceptance review |
| 5 | Will B11 cover any other consumers besides UI + autopilot? | Determines B11 scope | B11 / AZ-550 review |
These do not block Step 2 (Architecture Baseline Scan); they are inputs to subsequent test-spec / refactor / new-task work.
Artifact Index
Documentation (this repo, _docs/)
| File | Description |
|---|---|
_docs/00_problem/problem.md |
High-level problem statement (post-rename target) |
_docs/00_problem/restrictions.md |
Hardware / software / environment / operational restrictions (4 categories, 41 items) |
_docs/00_problem/acceptance_criteria.md |
10 AC groups (~60 criteria), every criterion grounded in code |
_docs/00_problem/input_data/data_parameters.md |
Env vars, HTTP DTOs, table schemas (4 owned + 3 borrowed), enum values, endpoint matrix |
_docs/00_problem/security_approach.md |
Authn / authz / data protection / input validation / CORS / 8 production-deploy footguns / threat-model summary |
_docs/01_solution/solution.md |
Retrospective solution: per-component table + cross-cutting choices + implementation order + testing strategy |
_docs/02_document/00_discovery.md |
Suite context, repository layout, tech stack, entry points, configuration, dependency graph (5 layers), spec ↔ code divergences (15 items) |
_docs/02_document/04_verification_log.md |
Step 4 verification: rename-aware mode, counts, per-symbol sweep, drift mapping table |
_docs/02_document/architecture.md |
Architecture (Vision + 8 sections + 8 ADRs); confirmed by user at Step 4.5 |
_docs/02_document/system-flows.md |
F1–F7 narrative + cross-cutting concerns + per-flow error tables |
_docs/02_document/data_model.md |
Entity / table / cross-service ownership map |
_docs/02_document/glossary.md |
Glossary; confirmed by user at Step 4.5 |
_docs/02_document/module-layout.md |
File ownership + 5-layer dependency table; status derived-from-code |
_docs/02_document/components/01_vehicle_catalog/description.md |
Component spec (post-rename) |
_docs/02_document/components/02_mission_planning/description.md |
Component spec |
_docs/02_document/components/04_persistence/description.md |
Component spec |
_docs/02_document/components/05_identity/description.md |
Component spec |
_docs/02_document/components/06_http_conventions/description.md |
Component spec |
_docs/02_document/components/07_host/description.md |
Component spec |
_docs/02_document/modules/{auth,controller_missions,controller_vehicles,database,dtos,entities,enums,middleware,program,service_mission,service_vehicle,service_waypoint}.md |
12 module docs |
_docs/02_document/diagrams/components.md |
Mermaid component relationship diagram |
_docs/02_document/diagrams/flows/flow_{vehicle_crud,mission_lifecycle,mission_cascade_delete,waypoint_lifecycle,jwt_validation,startup_migration,health_probe}.md |
Per-flow Mermaid sequence diagrams |
_docs/02_document/deployment/{containerization,ci_cd_pipeline,environment_strategy,observability}.md |
Deployment notes |
State / process artefacts
| File | Description |
|---|---|
_docs/_autodev_state.md |
Autodev orchestrator state (this skill: Phase A Step 1, complete on Step 7 write) |
_docs/02_document/state.json |
Document skill internal state |
_docs/_process_leftovers/2026-05-14_rename-flights-to-missions.md |
Rename leftover index — kept until B4–B12 ship |
_docs/tasks/done/AZ-540_missions_rename_b1_local_docs.md |
B1 task spec (Done) |
_docs/tasks/done/AZ-542_missions_rename_b3_state_bookkeeping.md |
B3 task spec (Done) |
_docs/tasks/todo/AZ-544_missions_rename_b5_csproj_namespace.md |
B5 task spec |
_docs/tasks/todo/AZ-545_missions_rename_b6_domain_rename.md |
B6 task spec |
_docs/tasks/todo/AZ-546_missions_rename_b7_drop_gps_denied.md |
B7 task spec |
_docs/tasks/todo/AZ-547_missions_rename_b8_http_routes.md |
B8 task spec |
_docs/tasks/todo/AZ-548_missions_rename_b9_db_migration.md |
B9 task spec |
_docs/tasks/todo/AZ-551_missions_rename_b12_default_vehicle_rule.md |
B12 task spec |
Suite-level cross-references (read-only from this repo)
| File | Description |
|---|---|
../../suite/_docs/02_missions.md |
Primary spec (post-rename) |
../../suite/_docs/00_top_level_architecture.md |
Topology, error envelope, pagination |
../../suite/_docs/00_database_schema.md |
Authoritative ER diagram |
../../suite/_docs/00_roles_permissions.md |
FL permission origin |
../../suite/_docs/11_gps_denied.md |
Separate gps-denied service (post-B7) |
../../suite/_docs/05_security/cmmc_l2_scorecard.md |
CMMC L2 row 3 finding (AZ-487/AZ-494) |
../../suite/_docs/_repo-config.yaml |
Repo registry (post-rename name: missions) |
Next Step in the Autodev Existing-Code Flow
Phase A Step 2 — Architecture Baseline Scan: invoke code-review/SKILL.md in baseline mode (Phase 1 + Phase 7) against the full codebase, save the output to _docs/02_document/architecture_compliance_baseline.md. The scan compares the running code against the just-confirmed architecture.md + module-layout.md and flags pre-existing High/Critical structural issues. After the baseline is clean, the autodev auto-chains to Step 3 (Test Spec) — which produces _docs/02_document/tests/traceability-matrix.md and per-flow scenario files for F1–F7, the seed set for the test suite implementation in Steps 5–7.