mirror of
https://github.com/azaion/missions.git
synced 2026-06-21 08:01:07 +00:00
7025f4d075
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.
6.0 KiB
6.0 KiB
Module: Azaion.Missions.Database (connection + migrator)
Files (2): Database/AppDataConnection.cs, Database/DatabaseMigrator.cs
NOTE (forward-looking): post-rename + post-GPS-Denied-removal state. Today's source still has
Azaion.Flights.Databasenamespace, exposesOrthophotos/GpsCorrectionsITables, and migrates 6 tables. After Jira AZ-EPIC children B5 (namespace), B7 (GPS-Denied removal), and B9 (DB migration) land, the shape described here is what stands.
Purpose
AppDataConnection-- single LinqToDBDataConnectionthat exposes oneITable<T>property per persisted entity. Acts as the unit-of-work + query root for all services.DatabaseMigrator-- startup-time idempotent schema bootstrap. Issues a single multi-statement SQL block ofCREATE TABLE IF NOT EXISTS+CREATE INDEX IF NOT EXISTSagainst the connection.
Public Interface
AppDataConnection
public class AppDataConnection(DataOptions options) : DataConnection(options) {
public ITable<Vehicle> Vehicles => GetTable<Vehicle>();
public ITable<Mission> Missions => GetTable<Mission>();
public ITable<Waypoint> Waypoints => GetTable<Waypoint>();
public ITable<MapObject> MapObjects => GetTable<MapObject>();
public ITable<Media> Media => GetTable<Media>(); // schema owned by `annotations`
public ITable<Annotation> Annotations => GetTable<Annotation>(); // schema owned by `annotations`
public ITable<Detection> Detections => GetTable<Detection>(); // schema owned by detection pipeline
}
DatabaseMigrator
public static class DatabaseMigrator {
public static void Migrate(AppDataConnection db); // synchronous; runs once at startup
}
Internal Logic
AppDataConnection
- Inherits LinqToDB's
DataConnection. Constructor parameterDataOptionsis built inProgram.csvianew DataOptions().UsePostgreSQL(connectionString). - Each
ITable<T>property is computed viaGetTable<T>()on every access -- cheap query-root handles, not cached state. - Lifetime is scoped (registered via
builder.Services.AddScoped), so each HTTP request gets its ownDataConnection(and underlying Npgsql connection from the pool).
DatabaseMigrator
Migrate(db)callsdb.Execute(Sql)whereSqlis a single string literal containing:- 4
CREATE TABLE IF NOT EXISTSstatements:vehicles,missions,waypoints,map_objects. - 3
CREATE INDEX IF NOT EXISTSstatements on the foreign-key columns:ix_missions_vehicle_id,ix_waypoints_mission_id,ix_map_objects_mission_id.
- 4
- Foreign-key constraints declared inline via
REFERENCES:missions.vehicle_id REFERENCES vehicles(id)waypoints.mission_id REFERENCES missions(id)map_objects.mission_id REFERENCES missions(id)
- Defaults: enums default to
0, decimals to0, booleans toFALSE, timestamps toNOW(). - Tables intentionally NOT in this migrator:
media,annotations,detection. These are exposed byAppDataConnectionand consumed by services (delete cascades), but their schema is owned by other suite components (annotationsmigratesmedia+annotations; the detection pipeline ownsdetection). All edge-tier services share one local PostgreSQL on the device, somissionscan read/delete from those tables without owning their DDL. - Tables removed from this migrator (per Jira B7 + B9):
orthophotos,gps_corrections. These are now owned by the separategps-deniedservice (per../../suite/_docs/11_gps_denied.md). Migration B9 includes a one-shotDROP TABLE IF EXISTS orthophotos; DROP TABLE IF EXISTS gps_corrections;for fielded edge devices that previously ran the legacy schema.
Dependencies
LinqToDB,LinqToDB.DataAzaion.Missions.Database.Entities(all 7 entity types)
No upward dependencies.
Consumers
Program.cs-- registersAppDataConnectionas scoped, then resolves it once viaapp.Services.CreateScope()to callDatabaseMigrator.Migrate(db)before request handling starts.Services.VehicleService,Services.MissionService,Services.WaypointService-- all takeAppDataConnectionvia primary-constructor injection.
Data Models
See modules/entities.md for column-level shape; see the SQL block in DatabaseMigrator.Sql for the authoritative DDL of the 4 owned tables.
Configuration
AppDataConnection itself reads no env vars; the connection string is supplied by the DI registration in Program.cs.
External Integrations
- PostgreSQL via Npgsql
10.0.2.
Security
- No SQL injection surface -- all services use LINQ expression trees (parameterized).
- The startup migrator runs DDL using whatever permissions the connection has. Production deployments where the app's user lacks
CREATE TABLEwould fail at startup.
Tests
None present.
Notes / Smells
- Migrator is intentionally scoped to this service's owned tables (4 mission-attached tables). The 3 cross-service tables (
media,annotations,detection) are migrated by their owning services into the same shared local PostgreSQL. Confirmed against../../suite/_docs/00_top_level_architecture.md(Database Topology) and../../suite/_docs/01_annotations.md. - No schema versioning --
IF NOT EXISTSis forward-only, additive only. Column drops, type changes, or constraint changes require either manual SQL or a real migration tool. The B9DROP TABLEblock is a one-time exception for the GPS-Denied removal. - Synchronous DDL at startup blocks the host until completion. For an empty DB this is microseconds; for a contended DB it's negligible. Acceptable for a small service.
- No transaction wrapping -- the multi-statement
Executeruns in PostgreSQL's implicit autocommit per statement (LinqToDB doesn't open a transaction unless you ask). AllIF NOT EXISTSstatements are individually idempotent, so partial failure leaves a partially-created schema; next startup completes it. - No
LOWER(...)indexes for case-insensitive name searches invehicles/missions. Likely fine for current scale.