Enhanced the .gitignore to exclude test results and updated the Dockerfile to include a new entrypoint script for improved container initialization. Refactored JWT configuration to support additional parameters for automatic refresh intervals, ensuring better control over token management. Updated the ConfigurationResolver to enforce required environment variables without hardcoded fallbacks, enhancing security and flexibility.
15 KiB
Input Data Parameters — Azaion.Missions
Status: derived-from-code (autodev
/documentStep 6, 2026-05-14). Schemas below match the actualDatabase/Entities/*.csLinqToDB mappings andDTOs/*.csrequest shapes (post-B6 names). Today's source still uses pre-rename names; the doc-vs-code mapping is in_docs/02_document/04_verification_log.md§ 0.
1. Configuration input (env vars)
All four required values are resolved through Infrastructure/ConfigurationResolver.cs → ResolveRequiredOrThrow(envName, configKey). Resolution order is env var first, then IConfiguration config key, else throw InvalidOperationException at startup. There are NO hardcoded dev fallbacks anymore.
| Variable | Config key | Type | Required | Resolution | Format / constraints | Used by |
|---|---|---|---|---|---|---|
DATABASE_URL |
Database:Url |
string | yes (always) | ResolveRequiredOrThrow |
Either postgresql://user:pass@host:port/db (converted via local helper ConvertPostgresUrl; NO URL-decoding of user/password — credentials with @, :, /, % need raw Npgsql form) OR a raw Npgsql connection string |
Program.cs (DI registration of AppDataConnection) |
JWT_ISSUER |
Jwt:Issuer |
string | yes (always) | ResolveRequiredOrThrow |
The expected iss claim value on every accepted JWT; usually the admin service's stable identifier |
Program.cs, Auth/JwtExtensions.cs → ValidIssuer |
JWT_AUDIENCE |
Jwt:Audience |
string | yes (always) | ResolveRequiredOrThrow |
The expected aud claim value on every accepted JWT; usually the suite-wide audience identifier shared by all backend validators |
Program.cs, Auth/JwtExtensions.cs → ValidAudience |
JWT_JWKS_URL |
Jwt:JwksUrl |
string | yes (always) | ResolveRequiredOrThrow |
HTTPS URL to admin's JWKS endpoint. HttpDocumentRetriever { RequireHttps = true } rejects http:// at fetch time (not at startup config resolution). Cached via ConfigurationManager<JsonWebKeySet>, refreshed on the default schedule |
Program.cs, Auth/JwtExtensions.cs |
ASPNETCORE_ENVIRONMENT |
(built-in) | string | no | ASP.NET Core convention | Case-insensitive match on Production triggers the CORS strict gate in CorsConfigurationValidator |
Program.cs, Infrastructure/CorsConfigurationValidator.cs |
CorsConfig:AllowedOrigins |
(config) | string list | conditionally required | IConfiguration.GetSection("CorsConfig").Get<CorsConfig>() |
List of allowed origins. In Production, MUST be non-empty OR AllowAnyOrigin=true, else startup throws |
Program.cs, Infrastructure/CorsConfigurationValidator.cs |
CorsConfig:AllowAnyOrigin |
(config) | bool | no | same | Opt-in to permissive CORS in production explicitly (use sparingly) | same |
AZAION_REVISION |
— | string | no | Dockerfile ARG baked from CI_COMMIT_SHA |
git SHA | Dockerfile only; surfaced via docker inspect |
ASPNETCORE_URLS |
— | string | no | ASP.NET Core convention | URL list (default http://+:8080) |
ASP.NET Core host |
Important: The legacy JWT_SECRET env var is no longer consulted. The ADR-005 "dev fallback secret silently accepted in production" failure mode is structurally eliminated; only the unconditional-Swagger branch of ADR-005 survives.
2. HTTP request DTOs (post-B6 shapes)
2.1 Vehicle (/vehicles)
public class CreateVehicleRequest {
public VehicleType Type { get; set; } // enum int: Plane=0, Copter=1, UGV=2, GuidedMissile=3
public string Model { get; set; } = "";
public string Name { get; set; } = "";
public FuelType FuelType { get; set; } // enum int: Electric=0, Gasoline=1, Diesel=2
public decimal BatteryCapacity { get; set; }
public decimal EngineConsumption { get; set; }
public decimal EngineConsumptionIdle { get; set; }
public bool IsDefault { get; set; }
}
public class UpdateVehicleRequest { // all properties nullable -- partial update
public VehicleType? Type;
public string? Model;
public string? Name;
public FuelType? FuelType;
public decimal? BatteryCapacity;
public decimal? EngineConsumption;
public decimal? EngineConsumptionIdle;
public bool? IsDefault;
}
public class GetVehiclesQuery {
public string? Name { get; set; } // case-INSENSITIVE contains (LOWER(name) LIKE %lower(input)%)
public bool? IsDefault { get; set; } // exact match
}
public class SetDefaultRequest {
public bool IsDefault { get; set; }
}
Validation: NONE today. No [Required], no [Range], no min-length. Empty Name, negative BatteryCapacity, out-of-range enum int values are accepted. Carry-forward improvement.
2.2 Mission (/missions)
public class CreateMissionRequest {
public Guid VehicleId { get; set; }
public string Name { get; set; } = "";
public DateTime? CreatedDate { get; set; } // defaults to UtcNow if null
}
public class UpdateMissionRequest { // partial update
public string? Name { get; set; }
public Guid? VehicleId { get; set; }
}
public class GetMissionsQuery {
public string? Name { get; set; } // case-INSENSITIVE contains
public DateTime? FromDate { get; set; }
public DateTime? ToDate { get; set; }
public int Page { get; set; } = 1;
public int PageSize { get; set; } = 20;
// Results ordered by CreatedDate DESC (newest first).
}
Validation: existence check on VehicleId (returns 400 today via ArgumentException; spec wants 404 — carry-forward divergence). No bounds on Page / PageSize (negative or huge values accepted by binding).
2.3 Waypoint (/missions/{id}/waypoints)
public class GeoPoint { // shared value object; all fields nullable
public decimal? Lat { get; set; }
public decimal? Lon { get; set; }
public string? Mgrs { get; set; } // Military Grid Reference System
}
public class CreateWaypointRequest {
public GeoPoint? GeoPoint { get; set; } // nullable: all-null is accepted today (no invariant)
public WaypointSource WaypointSource { get; set; } // enum int
public WaypointObjective WaypointObjective { get; set; } // enum int
public int OrderNum { get; set; }
public decimal Height { get; set; }
}
public class UpdateWaypointRequest { // identical SHAPE to Create -- non-nullable enums/numerics
public GeoPoint? GeoPoint { get; set; }
public WaypointSource WaypointSource { get; set; }
public WaypointObjective WaypointObjective { get; set; }
public int OrderNum { get; set; }
public decimal Height { get; set; }
}
Validation: NONE. No min-length, no enum range check, no Lat/Lon bounds, no MGRS format validation. GeoPoint may be all-null. UpdateWaypoint is structurally NOT partial — every field gets overwritten on PUT (inconsistent with vehicle's partial-update pattern).
Spec divergence (Geopoint): spec stores Waypoints.GPS as a single string GPS field with Lat <-> MGRS auto-conversion (../../suite/_docs/02_missions.md, ../../suite/_docs/00_database_schema.md). Code stores 3 separate columns with NO conversion. Carry-forward.
3. Persisted data — owned tables (post-B7+B9)
FKs in this section are declared as DB-level REFERENCES constraints in DatabaseMigrator.cs, not just logical. Date columns use PostgreSQL TIMESTAMP (no timezone, NOT TIMESTAMPTZ) — DateTime.Kind is normalized to Unspecified on read.
3.1 vehicles (owned)
| Column | Type | Nullable | Default | Notes |
|---|---|---|---|---|
id |
UUID | NO | — | primary key |
type |
INTEGER | NO | 0 |
VehicleType enum int (Plane / Copter / UGV / GuidedMissile) |
model |
TEXT | NO | — | |
name |
TEXT | NO | — | |
fuel_type |
INTEGER | NO | 0 |
FuelType enum int |
battery_capacity |
NUMERIC | NO | 0 |
|
engine_consumption |
NUMERIC | NO | 0 |
|
engine_consumption_idle |
NUMERIC | NO | 0 |
|
is_default |
BOOLEAN | NO | FALSE |
"exactly one default" enforced by VehicleService (stricter than spec — B12 decision) |
3.2 missions (owned)
| Column | Type | Nullable | Default | Notes |
|---|---|---|---|---|
id |
UUID | NO | — | primary key |
created_date |
TIMESTAMP | NO | NOW() |
server-assigned UtcNow if not supplied; TIMESTAMP (no timezone) |
name |
TEXT | NO | — | |
vehicle_id |
UUID | NO | — | REFERENCES vehicles(id) — DB-level FK; PostgreSQL error 23503 raised if parent vehicle was deleted between service-layer existence check and insert |
Index: ix_missions_vehicle_id on vehicle_id.
3.3 waypoints (owned)
| Column | Type | Nullable | Default | Notes |
|---|---|---|---|---|
id |
UUID | NO | — | primary key |
mission_id |
UUID | NO | — | REFERENCES missions(id) — DB-level FK |
lat |
NUMERIC | YES | — | spec divergence — see § 2.3 |
lon |
NUMERIC | YES | — | spec divergence |
mgrs |
TEXT | YES | — | spec divergence |
waypoint_source |
INTEGER | NO | 0 |
WaypointSource enum int |
waypoint_objective |
INTEGER | NO | 0 |
WaypointObjective enum int |
order_num |
INTEGER | NO | 0 |
listing order |
height |
NUMERIC | NO | 0 |
metres |
Index: ix_waypoints_mission_id on mission_id.
3.4 map_objects (owned schema; written by autopilot)
| Column | Type | Nullable | Default | Notes |
|---|---|---|---|---|
id |
UUID | NO | — | primary key |
mission_id |
UUID | NO | — | REFERENCES missions(id) — DB-level FK |
h3_index |
TEXT | NO | — | Uber H3 hex grid cell |
mgrs |
TEXT | NO | — | |
lat |
NUMERIC | YES | — | |
lon |
NUMERIC | YES | — | |
class_num |
INTEGER | NO | 0 |
detection class id |
label |
TEXT | NO | '' |
|
size_width_m |
NUMERIC | NO | 0 |
|
size_length_m |
NUMERIC | NO | 0 |
|
confidence |
NUMERIC | NO | 0 |
0..1 |
object_status |
INTEGER | NO | 0 |
ObjectStatus enum int |
first_seen_at |
TIMESTAMP | NO | NOW() |
TIMESTAMP (no timezone) |
last_seen_at |
TIMESTAMP | NO | NOW() |
TIMESTAMP (no timezone) |
Index: ix_map_objects_mission_id on mission_id.
autopilot is the writer (per ../../suite/_docs/06_autopilot_design.md); this service owns the schema and cascade-deletes only.
4. Persisted data — borrowed read-only stubs
| Table | Schema owner | This service uses for |
|---|---|---|
media |
annotations (per ../../suite/_docs/01_annotations.md) |
id resolution + cascade-delete walk on mission/waypoint delete |
annotations |
annotations |
id resolution + cascade-delete walk |
detection (singular by upstream owner) |
Detection pipeline | cascade-delete walk |
Stub schemas (just enough to query / delete by id):
[Table("media")] public class Media { [PrimaryKey, Column("id")] public string Id = ""; [Column("waypoint_id")] public Guid? WaypointId; }
[Table("annotations")] public class Annotation { [PrimaryKey, Column("id")] public string Id = ""; [Column("media_id")] public string MediaId = ""; }
[Table("detection")] public class Detection { [PrimaryKey, Column("id")] public Guid Id; [Column("annotation_id")] public string AnnotationId = ""; }
Migrations for these tables are owned by the respective sibling services. If they have not migrated on a given device, this service's cascade-delete walk fails on relation does not exist (abnormal deployment).
5. Removed in B7 (post-B7+B9 schema)
These tables and entities are out of this repo; cleanup happens once on legacy devices via the B9 DROP TABLE IF EXISTS block in DatabaseMigrator:
| Table | Pre-B7 owner | Post-B7 owner |
|---|---|---|
orthophotos |
this repo (Orthophoto entity, 03_gps_denied component) |
gps-denied service (separate repo) |
gps_corrections |
this repo (GpsCorrection entity, 03_gps_denied component) |
gps-denied service |
gps-denied references mission_id / waypoint_id as plain GUIDs in its OWN tables — no runtime coupling, no FK declaration, no cascade by this service.
6. Enum values
| Enum | Values | Persisted as | Defined in |
|---|---|---|---|
VehicleType |
Plane=0, Copter=1, UGV=2, GuidedMissile=3 |
INTEGER | Enums/VehicleType.cs (post-B6) |
FuelType |
Electric=0, Gasoline=1, Diesel=2 |
INTEGER | Enums/FuelType.cs |
WaypointSource |
Operator=0, Mission=1, ... |
INTEGER | Enums/WaypointSource.cs |
WaypointObjective |
Surveillance=0, Strike=1, ... |
INTEGER | Enums/WaypointObjective.cs |
ObjectStatus |
Active=0, Lost=1, ... |
INTEGER | Enums/ObjectStatus.cs (used only by MapObject) |
Per _docs/02_document/modules/enums.md, integer values are NOT range-validated on input — model binding accepts any int.
7. Inbound data shapes (HTTP)
| Endpoint | Method | Body / Query | Returns |
|---|---|---|---|
/vehicles |
GET | ?name=&isDefault= |
List<Vehicle> (PascalCase JSON; not paginated; ordered by Name ASC; name filter is case-INSENSITIVE) |
/vehicles/{id} |
GET | — | Vehicle |
/vehicles |
POST | CreateVehicleRequest |
Vehicle (created) |
/vehicles/{id} |
PUT | UpdateVehicleRequest (partial) |
Vehicle (updated) |
/vehicles/{id}/setDefault |
POST | SetDefaultRequest |
Vehicle |
/vehicles/{id} |
DELETE | — | 204 / 409 if referenced |
/missions |
GET | ?name=&fromDate=&toDate=&page=&pageSize= |
PaginatedResponse<Mission> (ordered by CreatedDate DESC; name filter case-INSENSITIVE) |
/missions/{id} |
GET | — | Mission |
/missions |
POST | CreateMissionRequest |
Mission (created) |
/missions/{id} |
PUT | UpdateMissionRequest (partial) |
Mission (updated) |
/missions/{id} |
DELETE | — | 204 / 404; runs F3 cascade |
/missions/{id}/waypoints |
GET | — | List<Waypoint> (unpaginated, ordered by OrderNum) |
/missions/{id}/waypoints |
POST | CreateWaypointRequest |
Waypoint (created) |
/missions/{id}/waypoints/{wpId} |
PUT | UpdateWaypointRequest (full overwrite) |
Waypoint |
/missions/{id}/waypoints/{wpId} |
DELETE | — | 204; runs F4 scoped cascade |
/health |
GET | — anonymous | 200 { "status": "healthy" } |
All routes except /health require JWT bearer with permissions=FL claim.