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.1 KiB
04 — Persistence (Edge PostgreSQL)
Spec source: ../../../suite/_docs/00_database_schema.md (authoritative ER diagram), ../../../suite/_docs/00_top_level_architecture.md § Database Topology (per-edge-device PostgreSQL pattern).
Implementation status: ✅ implemented -- the 4 owned tables migrate cleanly; the 3 borrowed tables read/delete cleanly under standard edge deployment.
NOTE (forward-looking): post-rename + post-GPS-Denied-removal. Today's source still has 6 owned tables (incl.
orthophotos,gps_corrections) and 9 entity files (incl.Aircraft.cs,Flight.cs,Orthophoto.cs,GpsCorrection.cs). Renames + table drops tracked under Jira AZ-EPIC children B5 (namespace), B6 (rename), B7 (GPS-Denied removal), B9 (DB migration).
Files (post-rename):
- Connection / migrator:
Database/AppDataConnection.cs,Database/DatabaseMigrator.cs - Owned-table entities (4):
Database/Entities/{Vehicle, Mission, Waypoint, MapObject}.cs - Borrowed-table entities (3):
Database/Entities/{Media, Annotation, Detection}.cs - Cross-cutting enum:
Enums/ObjectStatus.cs
1. High-Level Overview
Purpose: All PostgreSQL access for this service against the shared local edge PostgreSQL. Owns the LinqToDB DataConnection (one per HTTP request), the entity row maps, and the in-process schema bootstrap. The shared-DB pattern is documented in ../../../suite/_docs/00_top_level_architecture.md § Database Topology -- every edge service connects to the same postgres-local and migrates only its own tables.
Architectural pattern: linq2db DataConnection + attribute-mapped entities. No repository abstraction.
Upstream dependencies: None.
Downstream consumers: 01_vehicle_catalog (VehicleService), 02_mission_planning (MissionService, WaypointService), 07_host (registers the connection + runs the migrator).
2. Internal Interface
public class AppDataConnection(DataOptions options) : DataConnection(options) {
// Owned tables -- schema migrated by this service
ITable<Vehicle> Vehicles; // owned + written
ITable<Mission> Missions; // owned + written
ITable<Waypoint> Waypoints; // owned + written
ITable<MapObject> MapObjects; // owned schema; written by autopilot
// Borrowed tables -- schema migrated by other suite services
ITable<Media> Media; // owned by `annotations` service
ITable<Annotation> Annotations; // owned by `annotations` service
ITable<Detection> Detections; // owned by detection pipeline
}
public static class DatabaseMigrator { static void Migrate(AppDataConnection db); }
Entity surface -- see modules/entities.md for column-level shape.
3. External API
Not applicable.
4. Data Access Patterns
Tables this service migrates (owned)
| Table | Schema source | Writers | Indexes |
|---|---|---|---|
vehicles |
this migrator | 01_vehicle_catalog |
PK only |
missions |
this migrator | 02_mission_planning |
PK + ix_missions_vehicle_id |
waypoints |
this migrator | 02_mission_planning |
PK + ix_waypoints_mission_id |
map_objects |
this migrator | autopilot (per ../../../suite/_docs/06_autopilot_design.md) |
PK + ix_map_objects_mission_id |
Removed in B7 + B9: orthophotos and gps_corrections. Those tables now live in the separate gps-denied service. DatabaseMigrator includes a one-shot DROP TABLE IF EXISTS orthophotos; DROP TABLE IF EXISTS gps_corrections; for fielded edge devices that previously ran the legacy schema (B9).
Tables this service borrows (NOT migrated here, intentional cross-service ownership)
| Table | Schema source | Writers | This service's interaction |
|---|---|---|---|
media |
annotations migrator |
annotations (Media CRUD) |
Read id, waypoint_id; cascade-delete only (during mission/waypoint delete) |
annotations |
annotations migrator |
annotations (Annotations CRUD) |
Read id, media_id; cascade-delete only |
detection (singular) |
detection pipeline migrator | detections / ai-training |
Read id, annotation_id; cascade-delete only |
This split matches the suite-wide pattern in ../../../suite/_docs/00_top_level_architecture.md § Database Topology and ../../../suite/_docs/01_annotations.md § Database. Each edge service migrates its own tables; all services see the full shared schema through their own DataConnection.
Caching Strategy
None.
Storage Estimates
Not specified in spec.
Data Management
- Seed data: none. The migrator only creates schema.
- Rollback: not built-in. Forward-only-additive (
IF NOT EXISTS); the B9 DROPs are the one explicit destructive step.
5. Implementation Details
State Management: DataConnection is per-HTTP-request scoped (registered via AddScoped in 07_host). Each request gets its own physical Npgsql connection from the pool. All services within one request share that connection.
Algorithmic Complexity: Trivial -- direct column selects, FK joins via [Association], single-table inserts/updates/deletes.
Key Dependencies:
| Library | Version | Purpose |
|---|---|---|
linq2db |
6.2.0 | LINQ -> SQL provider, attribute mapping, async extensions |
Npgsql |
10.0.2 | PostgreSQL driver |
Error Handling: linq2db / Npgsql exceptions propagate up; if they happen to be KeyNotFoundException / Argument... (rare), the global middleware in 06_http_conventions maps them. Otherwise -> 500.
6. Extensions and Helpers
None.
7. Caveats & Edge Cases
- No schema versioning -- additive
IF NOT EXISTSonly. Column drops, type changes, constraint changes require manual SQL or a migration tool. Acceptable today; will become a problem when the schema evolves under a deployed fleet. The B9DROPis the one explicit exception. - No transaction wrapping in
Migrate-- multi-statementExecuteruns as autocommit-per-statement. All statements are individually idempotent so partial failure is recoverable on next startup. - Mixed PK types:
Guidfor in-house tables,stringformedia,annotations(XxHash64-based per../../../suite/_docs/00_database_schema.md). The TEXT-PK entities are the ones whose IDs are computed from file content, allowing dedup across services. - Geopoint columns split into 3 fields (
lat,lon,mgrs) -- diverges from the spec's singlestring GPSrepresentation. Carry the divergence to verification log. detectiontable singularity -- owned by another service; not this service's call to rename.LOWER(...)indexes absent -- case-insensitive name search is full-table scan. Fine while tables are small.- No SQL logging configured -- debug LinqToDB issues by enabling
DataConnection.WriteTraceLineor wrapping the provider; not done today.
8. Dependency Graph
Must be implemented after: nothing internal.
Can be implemented in parallel with: 05_identity, 06_http_conventions.
Blocks: 01_vehicle_catalog, 02_mission_planning, 07_host.
9. Logging Strategy
LinqToDB defaults -- no SQL logging configured.