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.
7.8 KiB
Module: Azaion.Missions.Database.Entities
Files (7): Vehicle.cs, Mission.cs, Waypoint.cs, MapObject.cs, Media.cs, Annotation.cs, Detection.cs
NOTE (forward-looking): this doc reflects the post-rename state. Today's source still has
Aircraft.cs,Flight.cs,Orthophoto.cs,GpsCorrection.cs. The renames + GPS-Denied removal are tracked under Jira AZ-EPIC children B6 (domain rename) and B7 (GPS-Denied removal).
Purpose
LinqToDB row-mapping classes. Each entity uses [Table("snake_case_name")] + [Column("snake_case")] + [PrimaryKey] to map to a PostgreSQL table. Two entities (Mission, Waypoint) include [Association]-based navigation; the rest are flat row maps.
Public Interface
Vehicle (table vehicles)
[Table("vehicles")]
public class Vehicle {
[PrimaryKey, Column("id")] public Guid Id;
[Column("type")] public VehicleType Type; // Plane | Copter | UGV | GuidedMissile
[Column("model")] public string Model = "";
[Column("name")] public string Name = "";
[Column("fuel_type")] public FuelType FuelType;
[Column("battery_capacity")] public decimal BatteryCapacity;
[Column("engine_consumption")] public decimal EngineConsumption;
[Column("engine_consumption_idle")] public decimal EngineConsumptionIdle;
[Column("is_default")] public bool IsDefault;
}
Mission (table missions)
[Table("missions")]
public class Mission {
[PrimaryKey, Column("id")] public Guid Id;
[Column("created_date")] public DateTime CreatedDate;
[Column("name")] public string Name = "";
[Column("vehicle_id")] public Guid VehicleId;
[Association(ThisKey=VehicleId, OtherKey=Vehicle.Id)] public Vehicle? Vehicle;
[Association(ThisKey=Id, OtherKey=Waypoint.MissionId)] public List<Waypoint> Waypoints = [];
}
Waypoint (table waypoints)
[Table("waypoints")]
public class Waypoint {
[PrimaryKey, Column("id")] public Guid Id;
[Column("mission_id")] public Guid MissionId;
[Column("lat")] public decimal? Lat;
[Column("lon")] public decimal? Lon;
[Column("mgrs")] public string? Mgrs;
[Column("waypoint_source")] public WaypointSource WaypointSource;
[Column("waypoint_objective")] public WaypointObjective WaypointObjective;
[Column("order_num")] public int OrderNum;
[Column("height")] public decimal Height;
[Association(ThisKey=MissionId, OtherKey=Mission.Id)] public Mission? Mission;
}
MapObject (table map_objects)
[Table("map_objects")]
public class MapObject {
[PrimaryKey, Column("id")] public Guid Id;
[Column("mission_id")] public Guid MissionId;
[Column("h3_index")] public string H3Index = ""; // Uber H3 hex grid
[Column("mgrs")] public string Mgrs = "";
[Column("lat")] public decimal? Lat;
[Column("lon")] public decimal? Lon;
[Column("class_num")] public int ClassNum;
[Column("label")] public string Label = "";
[Column("size_width_m")] public decimal SizeWidthM;
[Column("size_length_m")] public decimal SizeLengthM;
[Column("confidence")] public decimal Confidence;
[Column("object_status")] public ObjectStatus ObjectStatus;
[Column("first_seen_at")] public DateTime FirstSeenAt;
[Column("last_seen_at")] public DateTime LastSeenAt;
}
Media / Annotation / Detection (cross-service stubs -- see "Notes / Smells")
[Table("media")]
public class Media {
[PrimaryKey, Column("id")] public string Id = ""; // TEXT primary key
[Column("waypoint_id")] public Guid? WaypointId;
}
[Table("annotations")]
public class Annotation {
[PrimaryKey, Column("id")] public string Id = ""; // TEXT
[Column("media_id")] public string MediaId = ""; // TEXT FK to media.id
}
[Table("detection")] // SINGULAR table name -- diverges from every other entity (owned by detection pipeline)
public class Detection {
[PrimaryKey, Column("id")] public Guid Id;
[Column("annotation_id")] public string AnnotationId = "";
}
Internal Logic
Pure POCOs. The only behavior comes from LinqToDB attribute mapping ([Table], [Column], [PrimaryKey], [Association]).
Dependencies
LinqToDB.Mapping(NuGet)Azaion.Missions.Enums(forVehicle,Waypoint,MapObject)
Consumers
Database.AppDataConnection-- exposesITable<T>for each entity.Database.DatabaseMigrator-- implicitly (defines DDL for the same names; does NOT reference entity types).Services.VehicleService,Services.MissionService,Services.WaypointService-- entity types are returned/constructed.
Data Model Highlights
vehicles --< missions --< waypoints --? media --< annotations --< detection
\--< map_objects
Missionis the central aggregate root: most domain rows hang offmission_id.Waypointis a sub-aggregate ofMissionand is the join point forMedia.MapObjectis detection output (class_num + confidence + spatial index) tied to a mission, NOT to a specific waypoint. Schema is owned by this service, but rows are written byautopilot(per../../suite/_docs/06_autopilot_design.md).
Cross-service stubs
Media, Annotation, Detection are intentional read-only stubs -- only Id and one foreign key each. They're queried/deleted by MissionService.DeleteMission and WaypointService.DeleteWaypoint but never written by this service. Schema-wise they are owned by other suite components (annotations for media + annotations, the detection pipeline for detection), per ../../suite/_docs/00_top_level_architecture.md and ../../suite/_docs/01_annotations.md. The shared edge-PostgreSQL pattern means each service migrates its own tables but all services see the full schema.
These three are deliberately NOT in DatabaseMigrator.Sql -- their schema is created by the owning services on the same shared local PostgreSQL.
Configuration / External Integrations / Security
None directly. Persistence is delegated to LinqToDB + Npgsql.
Tests
None present.
Notes / Smells
Detectiontable singular whilevehicles,missions,waypoints,map_objects,media,annotationsare plural. Owned by another service -- naming is THEIR call to make consistent.- Mixed PK types:
Vehicle,Mission,Waypoint,MapObject,DetectionuseGuid;Media,Annotationusestring(TEXT, XxHash64-based per../../suite/_docs/00_database_schema.md). - No domain methods -- all business rules (e.g., the "default vehicle" exclusivity in
VehicleService) live in services, not in the entities. Consistent and intentional for a thin-data-model approach. Media.WaypointIdis nullable while every other foreign key here is not. SuggestsMediacan attach to a non-waypoint context (e.g., mission-level media); enforcement is onannotations's side.- Geopoint divergence (carry to verification log): spec stores
Waypoints.GPSas a singlestring GPSfield withLat <-> MGRSauto-conversion (per../../suite/_docs/02_missions.mdand../../suite/_docs/00_database_schema.md). Code splits it into 3 separate columns. Resolution lives outside the GPS-Denied removal scope -- carry forward.